macro_rules! from_splitmix {
($seed:expr) => {{
let mut rng = crate::SplitMix64::seed_from_u64($seed);
Self::from_rng(&mut rng)
}};
}
macro_rules! starstar_u64 {
($x:expr) => {
$x.wrapping_mul(5).rotate_left(7).wrapping_mul(9)
};
}
macro_rules! starstar_u32 {
($x:expr) => {
$x.wrapping_mul(0x9E3779BB).rotate_left(5).wrapping_mul(5)
};
}
macro_rules! plusplus_u64 {
($x:expr, $y:expr, $rot:expr) => {
$x.wrapping_add($y).rotate_left($rot).wrapping_add($x)
};
}
macro_rules! plusplus_u32 {
($x:expr, $y:expr) => {
$x.wrapping_add($y).rotate_left(7).wrapping_add($x)
};
}
macro_rules! impl_jump {
(u32, $self:expr, [$j0:expr, $j1:expr]) => {
const JUMP: [u32; 2] = [$j0, $j1];
let mut s0 = 0;
let mut s1 = 0;
for j in &JUMP {
for b in 0..32 {
if (j & 1 << b) != 0 {
s0 ^= $self.s0;
s1 ^= $self.s1;
}
$self.next_u32();
}
}
$self.s0 = s0;
$self.s1 = s1;
};
(u64, $self:expr, [$j0:expr, $j1:expr]) => {
const JUMP: [u64; 2] = [$j0, $j1];
let mut s0 = 0;
let mut s1 = 0;
for j in &JUMP {
for b in 0..64 {
if (j & 1 << b) != 0 {
s0 ^= $self.s0;
s1 ^= $self.s1;
}
$self.next_u64();
}
}
$self.s0 = s0;
$self.s1 = s1;
};
(u32, $self:expr, [$j0:expr, $j1:expr, $j2:expr, $j3:expr]) => {
const JUMP: [u32; 4] = [$j0, $j1, $j2, $j3];
let mut s0 = 0;
let mut s1 = 0;
let mut s2 = 0;
let mut s3 = 0;
for j in &JUMP {
for b in 0..32 {
if (j & 1 << b) != 0 {
s0 ^= $self.s[0];
s1 ^= $self.s[1];
s2 ^= $self.s[2];
s3 ^= $self.s[3];
}
$self.next_u32();
}
}
$self.s[0] = s0;
$self.s[1] = s1;
$self.s[2] = s2;
$self.s[3] = s3;
};
(u64, $self:expr, [$j0:expr, $j1:expr, $j2:expr, $j3:expr]) => {
const JUMP: [u64; 4] = [$j0, $j1, $j2, $j3];
let mut s0 = 0;
let mut s1 = 0;
let mut s2 = 0;
let mut s3 = 0;
for j in &JUMP {
for b in 0..64 {
if (j & 1 << b) != 0 {
s0 ^= $self.s[0];
s1 ^= $self.s[1];
s2 ^= $self.s[2];
s3 ^= $self.s[3];
}
$self.next_u64();
}
}
$self.s[0] = s0;
$self.s[1] = s1;
$self.s[2] = s2;
$self.s[3] = s3;
};
(u64, $self:expr, [$j0:expr, $j1:expr, $j2:expr, $j3:expr,
$j4:expr, $j5:expr, $j6:expr, $j7:expr]) => {
const JUMP: [u64; 8] = [$j0, $j1, $j2, $j3, $j4, $j5, $j6, $j7];
let mut s = [0; 8];
for j in &JUMP {
for b in 0..64 {
if (j & 1 << b) != 0 {
s[0] ^= $self.s[0];
s[1] ^= $self.s[1];
s[2] ^= $self.s[2];
s[3] ^= $self.s[3];
s[4] ^= $self.s[4];
s[5] ^= $self.s[5];
s[6] ^= $self.s[6];
s[7] ^= $self.s[7];
}
$self.next_u64();
}
}
$self.s = s;
};
}
macro_rules! impl_xoroshiro_u32 {
($self:expr) => {
$self.s1 ^= $self.s0;
$self.s0 = $self.s0.rotate_left(26) ^ $self.s1 ^ ($self.s1 << 9);
$self.s1 = $self.s1.rotate_left(13);
};
}
macro_rules! impl_xoroshiro_u64 {
($self:expr) => {
$self.s1 ^= $self.s0;
$self.s0 = $self.s0.rotate_left(24) ^ $self.s1 ^ ($self.s1 << 16);
$self.s1 = $self.s1.rotate_left(37);
};
}
macro_rules! impl_xoroshiro_u64_plusplus {
($self:expr) => {
$self.s1 ^= $self.s0;
$self.s0 = $self.s0.rotate_left(49) ^ $self.s1 ^ ($self.s1 << 21);
$self.s1 = $self.s1.rotate_left(28);
};
}
macro_rules! impl_xoshiro_u32 {
($self:expr) => {
let t = $self.s[1] << 9;
$self.s[2] ^= $self.s[0];
$self.s[3] ^= $self.s[1];
$self.s[1] ^= $self.s[2];
$self.s[0] ^= $self.s[3];
$self.s[2] ^= t;
$self.s[3] = $self.s[3].rotate_left(11);
};
}
macro_rules! impl_xoshiro_u64 {
($self:expr) => {
let t = $self.s[1] << 17;
$self.s[2] ^= $self.s[0];
$self.s[3] ^= $self.s[1];
$self.s[1] ^= $self.s[2];
$self.s[0] ^= $self.s[3];
$self.s[2] ^= t;
$self.s[3] = $self.s[3].rotate_left(45);
};
}
macro_rules! impl_xoshiro_large {
($self:expr) => {
let t = $self.s[1] << 11;
$self.s[2] ^= $self.s[0];
$self.s[5] ^= $self.s[1];
$self.s[1] ^= $self.s[2];
$self.s[7] ^= $self.s[3];
$self.s[3] ^= $self.s[4];
$self.s[4] ^= $self.s[5];
$self.s[0] ^= $self.s[6];
$self.s[6] ^= $self.s[7];
$self.s[6] ^= t;
$self.s[7] = $self.s[7].rotate_left(21);
};
}
macro_rules! impl_state_pair {
($type:ident, $word:ty) => {
impl $type {
pub fn state(&self) -> [u8; 2 * core::mem::size_of::<$word>()] {
const N: usize = core::mem::size_of::<$word>();
const {
assert!(core::mem::size_of::<Self>() == 2 * N);
}
let mut out = [0u8; 2 * N];
out[..N].copy_from_slice(&self.s0.to_le_bytes());
out[N..].copy_from_slice(&self.s1.to_le_bytes());
out
}
}
};
}
macro_rules! impl_state_array_of_four {
($type:ident, $word:ty) => {
impl $type {
pub fn state(&self) -> [u8; 4 * core::mem::size_of::<$word>()] {
const N: usize = core::mem::size_of::<$word>();
const {
assert!(core::mem::size_of::<Self>() == 4 * N);
}
let mut out = [0u8; 4 * N];
out[..N].copy_from_slice(&self.s[0].to_le_bytes());
out[N..2 * N].copy_from_slice(&self.s[1].to_le_bytes());
out[2 * N..3 * N].copy_from_slice(&self.s[2].to_le_bytes());
out[3 * N..].copy_from_slice(&self.s[3].to_le_bytes());
out
}
}
};
}
macro_rules! impl_state_seed512 {
($type:ident) => {
impl $type {
pub fn state(&self) -> crate::Seed512 {
let mut out = [0u8; 64];
for (i, word) in self.s.iter().enumerate() {
out[i * 8..(i + 1) * 8].copy_from_slice(&word.to_le_bytes());
}
crate::Seed512(out)
}
}
};
}
static ZERO_SEED_FALLBACK: [u8; 64] = [
0xaf, 0xcd, 0x1d, 0x7b, 0x39, 0xa8, 0x20, 0xe2, 0xf4, 0x65, 0xb9, 0xa1, 0x6a, 0x9e, 0x78, 0x6e,
0x4f, 0x45, 0x09, 0x80, 0x18, 0x5d, 0xc4, 0x06, 0xec, 0x81, 0x4c, 0x72, 0xa8, 0xb8, 0x8b, 0xf8,
0x9b, 0x74, 0xa8, 0x51, 0x6a, 0x89, 0x39, 0x1b, 0xea, 0xa2, 0x7e, 0x74, 0x0c, 0x9f, 0xcb, 0x53,
0xe1, 0x32, 0x45, 0x1f, 0xbe, 0x9a, 0x82, 0x2c, 0x3c, 0xab, 0x16, 0xc9, 0x3a, 0x13, 0x84, 0xc5,
];
#[inline]
pub(crate) fn zero_seed_fallback<const N: usize>(seed: &[u8; N]) -> &[u8; N] {
const { assert!(N <= ZERO_SEED_FALLBACK.len()) };
if seed.iter().any(|&b| b != 0) {
seed
} else {
ZERO_SEED_FALLBACK.first_chunk::<N>().unwrap()
}
}
#[derive(Clone)]
pub struct Seed512(pub [u8; 64]);
impl Seed512 {
pub fn iter(&self) -> core::slice::Iter<'_, u8> {
self.0.iter()
}
}
impl core::fmt::Debug for Seed512 {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
self.0[..].fmt(f)
}
}
impl Default for Seed512 {
fn default() -> Seed512 {
Seed512([0; 64])
}
}
impl AsRef<[u8]> for Seed512 {
fn as_ref(&self) -> &[u8] {
&self.0
}
}
impl AsMut<[u8]> for Seed512 {
fn as_mut(&mut self) -> &mut [u8] {
&mut self.0
}
}
#[cfg(test)]
mod tests {
use super::ZERO_SEED_FALLBACK;
use crate::SplitMix64;
use rand_core::{Rng, SeedableRng};
#[test]
fn zero_seed_fallback_matches_splitmix() {
let mut sm = SplitMix64::seed_from_u64(0);
let mut expected = [0u8; 64];
sm.fill_bytes(&mut expected);
assert_eq!(ZERO_SEED_FALLBACK, expected);
}
}