use rand::distr::{Distribution, StandardUniform};
use rand::rngs::StdRng;
use rand::{Rng, SeedableRng};
pub struct SeededRng {
inner: Option<StdRng>,
}
impl SeededRng {
pub fn new(seed: Option<u64>) -> Self {
let inner = seed.map(StdRng::seed_from_u64);
Self { inner }
}
pub fn random<T>(&mut self) -> T
where
StandardUniform: Distribution<T>,
{
match self.inner.as_mut() {
Some(rng) => rng.random(),
None => rand::random(),
}
}
}
impl std::fmt::Debug for SeededRng {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let is_seeded = self.inner.is_some();
f.debug_struct("SeededRng")
.field("seeded", &is_seeded)
.finish()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn seeded_rng_is_deterministic() {
let mut rng1 = SeededRng::new(Some(12345));
let mut rng2 = SeededRng::new(Some(12345));
let values1: [u8; 10] = [
rng1.random(),
rng1.random(),
rng1.random(),
rng1.random(),
rng1.random(),
rng1.random(),
rng1.random(),
rng1.random(),
rng1.random(),
rng1.random(),
];
let values2: [u8; 10] = [
rng2.random(),
rng2.random(),
rng2.random(),
rng2.random(),
rng2.random(),
rng2.random(),
rng2.random(),
rng2.random(),
rng2.random(),
rng2.random(),
];
assert_eq!(values1, values2, "Same seed should produce same values");
}
#[test]
fn different_seeds_produce_different_values() {
let mut rng1 = SeededRng::new(Some(12345));
let mut rng2 = SeededRng::new(Some(54321));
let value1: u64 = rng1.random();
let value2: u64 = rng2.random();
assert_ne!(
value1, value2,
"Different seeds should produce different values"
);
}
}