#[derive(Debug, Clone)]
pub struct WyRand {
state: u64,
}
impl WyRand {
#[inline]
pub const fn new(seed: u64) -> Self {
Self { state: seed }
}
pub fn from_entropy() -> Self {
let mut seed = [0u8; 8];
getrandom::getrandom(&mut seed).expect("failed to get entropy");
Self::new(u64::from_le_bytes(seed))
}
#[inline(always)]
pub fn next_u64(&mut self) -> u64 {
self.state = self.state.wrapping_add(0xa076_1d64_78bd_642f);
let t = (self.state as u128).wrapping_mul((self.state ^ 0xe703_7ed1_a0b4_28db) as u128);
((t >> 64) ^ t) as u64
}
#[inline]
#[allow(dead_code)]
pub fn next_bounded(&mut self, bound: u64) -> u64 {
let r = self.next_u64();
((r as u128 * bound as u128) >> 64) as u64
}
#[inline]
#[allow(dead_code)]
pub const fn state(&self) -> u64 {
self.state
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn deterministic_with_seed() {
let mut rng1 = WyRand::new(12345);
let mut rng2 = WyRand::new(12345);
for _ in 0..100 {
assert_eq!(rng1.next_u64(), rng2.next_u64());
}
}
#[test]
fn different_seeds_differ() {
let mut rng1 = WyRand::new(12345);
let mut rng2 = WyRand::new(54321);
assert_ne!(rng1.next_u64(), rng2.next_u64());
}
#[test]
fn bounded_in_range() {
let mut rng = WyRand::new(42);
for bound in [1, 10, 100, 1000, u64::MAX] {
for _ in 0..1000 {
let val = rng.next_bounded(bound);
assert!(val < bound);
}
}
}
#[test]
fn from_entropy_works() {
let rng = WyRand::from_entropy();
let _ = rng.state();
}
}