use super::{OsRng, Rng};
const WYRAND_INC: u64 = 0xa076_1d64_78bd_642f;
const WYRAND_MIX: u64 = 0xe703_7ed1_a0b4_28db;
pub struct WyRand {
state: u64,
}
impl WyRand {
#[must_use]
pub fn new(seed: u64) -> Self {
Self { state: seed }
}
#[must_use]
pub fn from_os_rng() -> Self {
Self::new(OsRng::new().next_u64())
}
#[inline]
fn step(&mut self) -> u64 {
self.state = self.state.wrapping_add(WYRAND_INC);
wymix(self.state, self.state ^ WYRAND_MIX)
}
}
#[inline(always)]
fn wymix(a: u64, b: u64) -> u64 {
let m = (a as u128).wrapping_mul(b as u128);
((m >> 64) as u64) ^ (m as u64)
}
impl Default for WyRand {
fn default() -> Self {
Self::from_os_rng()
}
}
impl Rng for WyRand {
fn next_u32(&mut self) -> u32 {
(self.step() >> 32) as u32
}
fn next_u64(&mut self) -> u64 {
self.step()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn wyrand_nonzero_output() {
let mut rng = WyRand::new(12345);
let v: u64 = (0..8).map(|_| rng.next_u64()).fold(0, |a, b| a | b);
assert_ne!(v, 0);
}
#[test]
fn wyrand_different_seeds_differ() {
let mut a = WyRand::new(1);
let mut b = WyRand::new(2);
assert_ne!(a.next_u64(), b.next_u64());
}
#[test]
fn wyrand_sequence_advances() {
let mut rng = WyRand::new(0);
let v0 = rng.next_u64();
let v1 = rng.next_u64();
assert_ne!(v0, v1);
}
#[test]
fn wyrand_next_u32_high_bits() {
let mut a = WyRand::new(42);
let mut b = WyRand::new(42);
assert_eq!(a.next_u32(), (b.next_u64() >> 32) as u32);
}
}