#[cfg(feature = "rand_core")]
use core::convert::Infallible;
#[cfg(feature = "debug")]
use core::fmt::Debug;
use super::constants::{WY0, WY1};
#[cfg(feature = "rand_core")]
use rand_core::{Rng, SeedableRng, TryRng};
use crate::utils::wymix;
#[cfg(feature = "serde1")]
use serde::{Deserialize, Serialize};
#[derive(Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "hash", derive(Hash))]
#[repr(transparent)]
pub struct WyRandLegacy {
state: u64,
}
impl WyRandLegacy {
#[inline]
#[must_use]
pub const fn new(state: u64) -> Self {
Self { state }
}
#[inline]
pub const fn rand(&mut self) -> u64 {
let (value, state) = Self::gen_u64(self.state);
self.state = state;
value
}
#[inline(always)]
const fn gen_u64(mut seed: u64) -> (u64, u64) {
seed = seed.wrapping_add(WY0);
(wymix(seed, seed ^ WY1), seed)
}
}
#[cfg(feature = "debug")]
impl Debug for WyRandLegacy {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("WyRandLegacy").finish()
}
}
#[cfg(feature = "rand_core")]
impl TryRng for WyRandLegacy {
type Error = Infallible;
fn try_next_u32(&mut self) -> Result<u32, Self::Error> {
Ok(self.rand() as u32)
}
fn try_next_u64(&mut self) -> Result<u64, Self::Error> {
Ok(self.rand())
}
fn try_fill_bytes(&mut self, dst: &mut [u8]) -> Result<(), Self::Error> {
rand_core::utils::fill_bytes_via_next_word(dst, || self.try_next_u64())
}
}
#[cfg(feature = "rand_core")]
impl SeedableRng for WyRandLegacy {
type Seed = [u8; core::mem::size_of::<u64>()];
#[inline]
fn from_seed(seed: Self::Seed) -> Self {
Self::new(u64::from_ne_bytes(seed))
}
#[inline]
fn from_rng<R: Rng + ?Sized>(rng: &mut R) -> Self {
Self::new(rng.next_u64())
}
#[inline]
fn try_from_rng<R: TryRng + ?Sized>(rng: &mut R) -> Result<Self, R::Error> {
Ok(Self::new(rng.try_next_u64()?))
}
}
#[cfg(test)]
mod tests {
extern crate alloc;
use super::*;
#[cfg(feature = "debug")]
#[test]
fn no_leaking_debug() {
use alloc::format;
let rng = WyRandLegacy::new(Default::default());
assert_eq!(
format!("{rng:?}"),
"WyRandLegacy",
"Debug should not be leaking internal state"
);
}
#[test]
fn clone_rng() {
let rng = WyRandLegacy::new(Default::default());
let mut cloned = rng.clone();
assert_eq!(
&rng.state, &cloned.state,
"the two RNG instances are not the same after cloning"
);
cloned.rand();
assert_ne!(
&rng.state, &cloned.state,
"the two RNG instances are the same after one was used"
);
}
#[cfg(feature = "rand_core")]
#[test]
fn rand_core_integration() {
fn rand_generic<R: Rng>(mut r: R) -> u32 {
r.next_u32()
}
fn rand_dyn(r: &mut dyn Rng) -> u32 {
r.next_u32()
}
let mut rng = WyRandLegacy::from_seed(Default::default());
assert_eq!(rand_generic(&mut rng), 2_405_016_974);
assert_eq!(rand_dyn(&mut rng), 4_283_336_045);
}
#[cfg(feature = "rand_core")]
#[test]
fn rand_core_from_rng() {
let mut source = WyRandLegacy::from_seed(Default::default());
let mut rng = WyRandLegacy::from_rng(&mut source);
assert_eq!(rng.next_u32(), 4242651740);
}
#[cfg(all(feature = "serde1", feature = "debug"))]
#[test]
fn serde_tokens() {
use serde_test::{assert_tokens, Token};
let seed = 12345;
let rng = WyRandLegacy::new(seed);
assert_tokens(
&rng,
&[
Token::Struct {
name: "WyRandLegacy",
len: 1,
},
Token::BorrowedStr("state"),
Token::U64(seed),
Token::StructEnd,
],
);
}
#[cfg(feature = "hash")]
#[allow(deprecated)]
#[test]
fn hash() {
use core::hash::{Hash, Hasher, SipHasher};
let rng = WyRandLegacy::new(123);
let state: u64 = 123;
let mut hasher = SipHasher::default();
rng.hash(&mut hasher);
let hashed_rng = hasher.finish();
let mut hasher = SipHasher::default();
state.hash(&mut hasher);
let hashed_state = hasher.finish();
assert_eq!(hashed_rng, hashed_state);
}
}