use rand_core::{SeedableRng, RngCore, Error};
use rand_core::impls::fill_bytes_via_next;
use rand_core::le::read_u64_into;
use std::ops::BitXor;
use crate::impl_core;
#[cfg(feature = "serde1")]
use serde::{Deserialize, Serialize};
macro_rules! make_xorwow64 {
($(#[$meta:meta])*
$name: ident) => (
$(#[$meta])*
#[derive(Debug, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct $name {
s: [u64; 2]
}
)
}
make_xorwow64!(
WrapA);
make_xorwow64!(
WrapB);
make_xorwow64!(
XorA);
make_xorwow64!(
XorB);
macro_rules! impl_xorwow64 {
($name: ident, $mod: ident, $shift: expr) => {
impl $name {
fn clock(&mut self) {
self.s[0] ^= self.s[0] << $shift.0;
self.s[0] ^= self.s[0] >> $shift.1;
self.s[0] ^= self.s[0] << $shift.2;
self.s[1] = self.s[1].wrapping_add(0x587CC7F5F9DD5);
}
pub fn return_u32(&mut self) -> u32 {
self.clock();
(self.s[0].$mod(self.s[1])) as u32
}
pub fn return_u64(&mut self) -> u64 {
self.clock();
self.s[0].$mod(self.s[1])
}
pub fn dump_state(&self) -> [u64; 2] {
self.s
}
}
}
}
impl_xorwow64!(WrapA, wrapping_add, (13, 7, 17));
impl_xorwow64!(WrapB, wrapping_add, (13, 19, 28));
impl_xorwow64!(XorA, bitxor, (13, 7, 17));
impl_xorwow64!(XorB, bitxor, (13, 19, 28));
macro_rules! impl_seedable {
($name: ident) => {
impl SeedableRng for $name {
type Seed = [u8; 16];
fn from_seed(seed: [u8; 16]) -> Self {
let mut state = [0u64; 2];
read_u64_into(&seed, &mut state);
if state[0] == 0u64 {
state[0] = u64::MAX;
}
Self { s: state }
}
fn seed_from_u64(seed: u64) -> Self {
let mut state = [0u64; 2];
if seed == 0u64 {
state[0] = u64::MAX;
} else {
state[0] = seed;
}
state[1] = seed;
Self { s: state }
}
}
};
}
impl_seedable!(WrapA);
impl_seedable!(WrapB);
impl_seedable!(XorA);
impl_seedable!(XorB);
impl_core!(WrapA);
impl_core!(WrapB);
impl_core!(XorA);
impl_core!(XorB);