chiark / gitweb /
fake rng: provide facility
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Thu, 11 Mar 2021 17:32:59 +0000 (17:32 +0000)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Thu, 11 Mar 2021 17:32:59 +0000 (17:32 +0000)
Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
src/config.rs
src/fake-rng.rs [new file with mode: 0644]
src/lib.rs
src/prelude.rs

index 173717dfa409c6330c4fe3e71459322bf7faad14..252ba54cba55cdecfee7d54ba048a67ad7ee4670 100644 (file)
@@ -36,6 +36,7 @@ pub struct ServerConfigSpec {
   pub shapelibs: Option<Vec<shapelib::Config1>>,
   pub sendmail: Option<String>,
   pub debug_js_inject_file: Option<String>,
+  #[serde(default)] pub fake_rng: FakeRngSpec,
   /// Disable this for local testing only.  See LICENCE.
   pub check_bundled_sources: Option<bool>,
 }
@@ -63,6 +64,7 @@ pub struct ServerConfig {
   pub sendmail: String,
   pub debug_js_inject: Arc<String>,
   pub check_bundled_sources: bool,
+  pub fake_rng: RngWrap,
 }
 
 impl TryFrom<ServerConfigSpec> for WholeServerConfig {
@@ -74,9 +76,11 @@ impl TryFrom<ServerConfigSpec> for WholeServerConfig {
       http_port, public_url, sse_wildcard_url, rocket_workers,
       template_dir, nwtemplate_dir, wasm_dir,
       log, bundled_sources, shapelibs, sendmail,
-      debug_js_inject_file, check_bundled_sources,
+      debug_js_inject_file, check_bundled_sources, fake_rng,
     } = spec;
 
+    let fake_rng = fake_rng.start();
+
     if let Some(cd) = change_directory {
       env::set_current_dir(&cd)
         .context(cd)
@@ -178,7 +182,7 @@ impl TryFrom<ServerConfigSpec> for WholeServerConfig {
       http_port, public_url, sse_wildcard_url, rocket_workers,
       template_dir, nwtemplate_dir, wasm_dir,
       bundled_sources, shapelibs, sendmail,
-      debug_js_inject, check_bundled_sources,
+      debug_js_inject, check_bundled_sources, fake_rng,
     };
     WholeServerConfig {
       server: Arc::new(server),
diff --git a/src/fake-rng.rs b/src/fake-rng.rs
new file mode 100644 (file)
index 0000000..0904b08
--- /dev/null
@@ -0,0 +1,60 @@
+// Copyright 2020-2021 Ian Jackson and contributors to Otter
+// SPDX-License-Identifier: AGPL-3.0-or-later
+// There is NO WARRANTY.
+
+use crate::prelude::*;
+
+use parking_lot::Mutex;
+
+#[derive(Deserialize,Debug,Clone,Default)]
+#[serde(transparent)]
+pub struct FakeRngSpec(Vec<String>);
+
+impl FakeRngSpec {
+  pub fn start(self) -> RngWrap { RngWrap(
+    if self.0.is_empty() { None }
+    else { Some(Arc::new(FakeRng {
+      i: Mutex::new(0),
+      ents: self.0,
+    })) }
+  )}
+}
+
+#[derive(Debug,Clone)]
+pub struct RngWrap (
+  Option<Arc<FakeRng>>
+);
+
+#[derive(Debug)]
+struct FakeRng {
+  i: Mutex<usize>,
+  ents: Vec<String>,
+}
+
+impl RngWrap {
+  pub fn is_fake(&self) -> bool { self.0.is_some() }
+
+  #[throws(as Option)]
+  fn next(&self) -> &str {
+    let fake = self.0.as_ref()?;
+    let mut i = fake.i.lock();
+    let e = fake.ents[*i].as_str();
+    *i += 1;
+    *i %= fake.ents.len();
+    e
+  }
+
+  pub fn shuffle<T:Copy>(&self, slice: &mut [T]) { match self.next() {
+    None => {
+      let mut rng = thread_rng();
+      slice.shuffle(&mut rng);
+    },
+    Some(s) => {
+      let l = slice.len();
+      let n: usize = s.parse().unwrap_or(0);
+      let front = slice[0..n].to_owned();
+      slice.copy_within(n.., 0);
+      slice[l-n..].copy_from_slice(&front);
+    },
+  } }
+} 
index b569821b5cdced072cfdc91e3cb2b23bb44ff621..7796d6981a0fef0905f83afcdd0a93f0f72c43f1 100644 (file)
@@ -34,3 +34,4 @@ pub mod utils;
 #[path = "shapelib-toml.rs"]      pub mod shapelib_toml;
 #[path = "slotmap-slot-idx.rs"]   pub mod slotmap_slot_idx;
 #[path = "toml-de.rs"]            pub mod toml_de;
+#[path = "fake-rng.rs"]           pub mod fake_rng;
index ca98ece10d23079a535c5da1477c3a48a557ea0c..ea38053644bc5064cbb983c5cf3f437b60f1aff6 100644 (file)
@@ -115,6 +115,7 @@ pub use crate::commands::{MgmtGameUpdateMode};
 pub use crate::config::*;
 pub use crate::debugreader::DebugReader;
 pub use crate::error::*;
+pub use crate::fake_rng::*;
 pub use crate::gamestate::*;
 pub use crate::global::*;
 pub use crate::hidden::*;