Skip to main content

repl_core/
determinism.rs

1use chrono::{DateTime, Duration, Utc};
2use rand::prelude::*;
3use rand_chacha::ChaCha8Rng;
4
5/// A random number generator that can be seeded for deterministic output.
6pub struct DeterministicRng {
7    rng: ChaCha8Rng,
8}
9
10impl DeterministicRng {
11    pub fn new(seed: u64) -> Self {
12        Self {
13            rng: ChaCha8Rng::seed_from_u64(seed),
14        }
15    }
16
17    pub fn next_u64(&mut self) -> u64 {
18        self.rng.next_u64()
19    }
20}
21
22/// A clock that can be frozen and advanced manually for deterministic time.
23pub struct Clock {
24    frozen_time: Option<DateTime<Utc>>,
25}
26
27impl Default for Clock {
28    fn default() -> Self {
29        Self::new()
30    }
31}
32
33impl Clock {
34    pub fn new() -> Self {
35        Self { frozen_time: None }
36    }
37
38    pub fn now(&self) -> DateTime<Utc> {
39        self.frozen_time.unwrap_or_else(Utc::now)
40    }
41
42    pub fn freeze(&mut self, time: DateTime<Utc>) {
43        self.frozen_time = Some(time);
44    }
45
46    pub fn advance(&mut self, duration: Duration) {
47        if let Some(time) = &mut self.frozen_time {
48            *time += duration;
49        }
50    }
51}