#[derive(Debug, Clone)]
pub struct Rng {
inner: fastrand::Rng,
}
impl Rng {
#[must_use]
pub fn from_seed(seed: u64) -> Self {
Self {
inner: fastrand::Rng::with_seed(seed),
}
}
pub fn f32(&mut self) -> f32 {
self.inner.f32()
}
pub fn u32(&mut self, range: std::ops::Range<u32>) -> u32 {
self.inner.u32(range)
}
pub fn i32(&mut self, range: std::ops::Range<i32>) -> i32 {
self.inner.i32(range)
}
#[allow(clippy::cast_possible_truncation)] pub fn usize(&mut self, range: std::ops::Range<usize>) -> usize {
self.inner.u64(range.start as u64..range.end as u64) as usize
}
pub fn bool(&mut self) -> bool {
self.inner.bool()
}
}
#[cfg(test)]
mod tests {
use super::*;
use wasm_bindgen_test::wasm_bindgen_test;
#[wasm_bindgen_test(unsupported = test)]
fn same_seed_same_sequence() {
let mut a = Rng::from_seed(42);
let mut b = Rng::from_seed(42);
for _ in 0..100 {
assert_eq!(a.u32(0..1000), b.u32(0..1000));
assert_eq!(a.f32().to_bits(), b.f32().to_bits());
assert_eq!(a.bool(), b.bool());
}
}
#[wasm_bindgen_test(unsupported = test)]
fn different_seeds_diverge() {
let mut a = Rng::from_seed(1);
let mut b = Rng::from_seed(2);
let sa: Vec<u32> = (0..16).map(|_| a.u32(0..u32::MAX)).collect();
let sb: Vec<u32> = (0..16).map(|_| b.u32(0..u32::MAX)).collect();
assert_ne!(sa, sb);
}
#[wasm_bindgen_test(unsupported = test)]
fn values_stay_in_range() {
let mut rng = Rng::from_seed(7);
for _ in 0..1000 {
let v = rng.usize(3..9);
assert!((3..9).contains(&v));
let f = rng.f32();
assert!((0.0..1.0).contains(&f));
}
}
}