use rand::rngs::StdRng;
use rand::{RngExt, SeedableRng};
use std::collections::HashMap;
#[derive(Debug)]
pub struct DeterministicRng {
rng: StdRng,
seed: u64,
}
impl DeterministicRng {
#[must_use]
pub fn new(seed: u64) -> Self {
Self {
rng: StdRng::seed_from_u64(seed),
seed,
}
}
#[must_use]
pub fn seed(&self) -> u64 {
self.seed
}
pub fn reset(&mut self) {
self.rng = StdRng::seed_from_u64(self.seed);
}
#[must_use]
pub fn fork(&mut self) -> Self {
let new_seed = self.random_u64();
Self::new(new_seed)
}
pub fn random_u64(&mut self) -> u64 {
self.rng.random()
}
pub fn random_u32(&mut self) -> u32 {
self.rng.random()
}
pub fn random_bool(&mut self) -> bool {
self.rng.random()
}
pub fn random_f64(&mut self) -> f64 {
self.rng.random()
}
pub fn random_range_u32(&mut self, min: u32, max: u32) -> u32 {
if min >= max {
return min;
}
min + (self.rng.random::<u32>() % (max - min))
}
pub fn random_string(&mut self, len: usize) -> String {
(0..len)
.map(|_| {
let byte = self.random_range_u32(b'a' as u32, b'z' as u32 + 1) as u8;
byte as char
})
.collect()
}
pub fn random_alphanumeric(&mut self, len: usize) -> String {
const CHARS: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
(0..len)
.map(|_| {
let idx = self.random_range_u32(0, CHARS.len() as u32) as usize;
CHARS[idx] as char
})
.collect()
}
pub fn choose<'a, T>(&mut self, choices: &'a [T]) -> Option<&'a T> {
if choices.is_empty() {
None
} else {
let idx = self.random_range_u32(0, choices.len() as u32) as usize;
Some(&choices[idx])
}
}
}
#[derive(Debug)]
pub struct RngRegistry {
rngs: HashMap<String, DeterministicRng>,
base_seed: u64,
}
impl RngRegistry {
#[must_use]
pub fn new(base_seed: u64) -> Self {
Self {
rngs: HashMap::new(),
base_seed,
}
}
pub fn get_rng(&mut self, name: &str) -> &mut DeterministicRng {
self.rngs.entry(name.to_string()).or_insert_with(|| {
let name_hash = name
.bytes()
.fold(0u64, |acc, b| acc.wrapping_mul(31).wrapping_add(b as u64));
let derived_seed = self.base_seed.wrapping_add(name_hash);
DeterministicRng::new(derived_seed)
})
}
pub fn reset_all(&mut self) {
for rng in self.rngs.values_mut() {
rng.reset();
}
}
#[must_use]
pub fn len(&self) -> usize {
self.rngs.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.rngs.is_empty()
}
}