Skip to main content

otter_support/
fake-rng.rs

1// Copyright 2020-2021 Ian Jackson and contributors to Otter
2// SPDX-License-Identifier: AGPL-3.0-or-later
3// There is NO WARRANTY.
4
5use crate::prelude::*;
6
7use parking_lot::Mutex;
8use rand::distributions::uniform::SampleUniform;
9
10#[derive(Deserialize,Debug,Clone,Default)]
11#[serde(transparent)]
12pub struct FakeRngSpec(Option<Vec<String>>);
13
14#[derive(Serialize,Deserialize,Error,Debug,Clone)]
15#[error("RNG is real")]
16pub struct RngIsReal;
17
18impl FakeRngSpec {
19  pub fn make_game_rng(self) -> RngWrap { RngWrap( match self.0 {
20    None => None,
21    Some(ents) => Some(Mutex::new(FakeRng {
22      i: 0,
23      ents,
24    })) }
25  )}
26}
27
28#[derive(Debug)]
29pub struct RngWrap (
30  Option<Mutex<FakeRng>>
31);
32
33#[derive(Debug)]
34struct FakeRng {
35  i: usize,
36  ents: Vec<String>,
37}
38
39impl RngWrap {
40  pub fn is_fake(&self) -> bool { self.0.is_some() }
41
42  #[throws(RngIsReal)]
43  pub fn set_fake(&self, v: Vec<String>, _: AuthorisationSuperuser) {
44    let mut fake = self.0.as_ref().ok_or(RngIsReal)?.lock();
45    fake.i = 0;
46    fake.ents = v;
47  }
48
49  #[throws(as Option)]
50  fn next_fake(&self) -> String {
51    let mut fake = self.0.as_ref()?.lock();
52    let e = fake.ents.get(fake.i)?.clone();
53    fake.i += 1;
54    fake.i %= fake.ents.len();
55    e
56  }
57
58  pub fn shuffle<T:Copy>(&self, slice: &mut [T]) { match self.next_fake() {
59    None => {
60      let mut rng = thread_rng();
61      slice.shuffle(&mut rng);
62    },
63    Some(s) => {
64      let l = slice.len();
65      let n: usize = s.parse().unwrap_or(0);
66      let front = slice[0..n].to_owned();
67      slice.copy_within(n.., 0);
68      slice[l-n..].copy_from_slice(&front);
69    },
70  } }
71
72  pub fn range<T>(&self, range: std::ops::Range<T>) -> T
73  where T: SampleUniform + FromStr + Ord + Default
74  {
75    match self.next_fake() {
76      None => {
77        let mut rng = thread_rng();
78        rng.gen_range(range)
79      },
80      Some(s) => (||{
81        let n: T = s.parse().ok()?;
82        range.contains(&n).then(|| n)
83      })().unwrap_or_default(),
84    }
85  }
86}