1macro_rules! from_splitmix {
11 ($seed:expr) => {{
12 let mut rng = crate::SplitMix64::seed_from_u64($seed);
13 Self::from_rng(&mut rng)
14 }};
15}
16
17macro_rules! starstar_u64 {
19 ($x:expr) => {
20 $x.wrapping_mul(5).rotate_left(7).wrapping_mul(9)
21 };
22}
23
24macro_rules! starstar_u32 {
26 ($x:expr) => {
27 $x.wrapping_mul(0x9E3779BB).rotate_left(5).wrapping_mul(5)
28 };
29}
30
31macro_rules! plusplus_u64 {
33 ($x:expr, $y:expr, $rot:expr) => {
34 $x.wrapping_add($y).rotate_left($rot).wrapping_add($x)
35 };
36}
37
38macro_rules! plusplus_u32 {
40 ($x:expr, $y:expr) => {
41 $x.wrapping_add($y).rotate_left(7).wrapping_add($x)
42 };
43}
44
45macro_rules! impl_jump {
47 (u32, $self:expr, [$j0:expr, $j1:expr]) => {
48 const JUMP: [u32; 2] = [$j0, $j1];
49 let mut s0 = 0;
50 let mut s1 = 0;
51 for j in &JUMP {
52 for b in 0..32 {
53 if (j & 1 << b) != 0 {
54 s0 ^= $self.s0;
55 s1 ^= $self.s1;
56 }
57 $self.next_u32();
58 }
59 }
60 $self.s0 = s0;
61 $self.s1 = s1;
62 };
63 (u64, $self:expr, [$j0:expr, $j1:expr]) => {
64 const JUMP: [u64; 2] = [$j0, $j1];
65 let mut s0 = 0;
66 let mut s1 = 0;
67 for j in &JUMP {
68 for b in 0..64 {
69 if (j & 1 << b) != 0 {
70 s0 ^= $self.s0;
71 s1 ^= $self.s1;
72 }
73 $self.next_u64();
74 }
75 }
76 $self.s0 = s0;
77 $self.s1 = s1;
78 };
79 (u32, $self:expr, [$j0:expr, $j1:expr, $j2:expr, $j3:expr]) => {
80 const JUMP: [u32; 4] = [$j0, $j1, $j2, $j3];
81 let mut s0 = 0;
82 let mut s1 = 0;
83 let mut s2 = 0;
84 let mut s3 = 0;
85 for j in &JUMP {
86 for b in 0..32 {
87 if (j & 1 << b) != 0 {
88 s0 ^= $self.s[0];
89 s1 ^= $self.s[1];
90 s2 ^= $self.s[2];
91 s3 ^= $self.s[3];
92 }
93 $self.next_u32();
94 }
95 }
96 $self.s[0] = s0;
97 $self.s[1] = s1;
98 $self.s[2] = s2;
99 $self.s[3] = s3;
100 };
101 (u64, $self:expr, [$j0:expr, $j1:expr, $j2:expr, $j3:expr]) => {
102 const JUMP: [u64; 4] = [$j0, $j1, $j2, $j3];
103 let mut s0 = 0;
104 let mut s1 = 0;
105 let mut s2 = 0;
106 let mut s3 = 0;
107 for j in &JUMP {
108 for b in 0..64 {
109 if (j & 1 << b) != 0 {
110 s0 ^= $self.s[0];
111 s1 ^= $self.s[1];
112 s2 ^= $self.s[2];
113 s3 ^= $self.s[3];
114 }
115 $self.next_u64();
116 }
117 }
118 $self.s[0] = s0;
119 $self.s[1] = s1;
120 $self.s[2] = s2;
121 $self.s[3] = s3;
122 };
123 (u64, $self:expr, [$j0:expr, $j1:expr, $j2:expr, $j3:expr,
124 $j4:expr, $j5:expr, $j6:expr, $j7:expr]) => {
125 const JUMP: [u64; 8] = [$j0, $j1, $j2, $j3, $j4, $j5, $j6, $j7];
126 let mut s = [0; 8];
127 for j in &JUMP {
128 for b in 0..64 {
129 if (j & 1 << b) != 0 {
130 s[0] ^= $self.s[0];
131 s[1] ^= $self.s[1];
132 s[2] ^= $self.s[2];
133 s[3] ^= $self.s[3];
134 s[4] ^= $self.s[4];
135 s[5] ^= $self.s[5];
136 s[6] ^= $self.s[6];
137 s[7] ^= $self.s[7];
138 }
139 $self.next_u64();
140 }
141 }
142 $self.s = s;
143 };
144}
145
146macro_rules! impl_xoroshiro_u32 {
148 ($self:expr) => {
149 $self.s1 ^= $self.s0;
150 $self.s0 = $self.s0.rotate_left(26) ^ $self.s1 ^ ($self.s1 << 9);
151 $self.s1 = $self.s1.rotate_left(13);
152 };
153}
154
155macro_rules! impl_xoroshiro_u64 {
157 ($self:expr) => {
158 $self.s1 ^= $self.s0;
159 $self.s0 = $self.s0.rotate_left(24) ^ $self.s1 ^ ($self.s1 << 16);
160 $self.s1 = $self.s1.rotate_left(37);
161 };
162}
163
164macro_rules! impl_xoroshiro_u64_plusplus {
166 ($self:expr) => {
167 $self.s1 ^= $self.s0;
168 $self.s0 = $self.s0.rotate_left(49) ^ $self.s1 ^ ($self.s1 << 21);
169 $self.s1 = $self.s1.rotate_left(28);
170 };
171}
172
173macro_rules! impl_xoshiro_u32 {
175 ($self:expr) => {
176 let t = $self.s[1] << 9;
177
178 $self.s[2] ^= $self.s[0];
179 $self.s[3] ^= $self.s[1];
180 $self.s[1] ^= $self.s[2];
181 $self.s[0] ^= $self.s[3];
182
183 $self.s[2] ^= t;
184
185 $self.s[3] = $self.s[3].rotate_left(11);
186 };
187}
188
189macro_rules! impl_xoshiro_u64 {
191 ($self:expr) => {
192 let t = $self.s[1] << 17;
193
194 $self.s[2] ^= $self.s[0];
195 $self.s[3] ^= $self.s[1];
196 $self.s[1] ^= $self.s[2];
197 $self.s[0] ^= $self.s[3];
198
199 $self.s[2] ^= t;
200
201 $self.s[3] = $self.s[3].rotate_left(45);
202 };
203}
204
205macro_rules! impl_xoshiro_large {
207 ($self:expr) => {
208 let t = $self.s[1] << 11;
209
210 $self.s[2] ^= $self.s[0];
211 $self.s[5] ^= $self.s[1];
212 $self.s[1] ^= $self.s[2];
213 $self.s[7] ^= $self.s[3];
214 $self.s[3] ^= $self.s[4];
215 $self.s[4] ^= $self.s[5];
216 $self.s[0] ^= $self.s[6];
217 $self.s[6] ^= $self.s[7];
218
219 $self.s[6] ^= t;
220
221 $self.s[7] = $self.s[7].rotate_left(21);
222 };
223}
224
225macro_rules! impl_state_pair {
227 ($type:ident, $word:ty) => {
228 impl $type {
229 pub fn state(&self) -> [u8; 2 * core::mem::size_of::<$word>()] {
240 const N: usize = core::mem::size_of::<$word>();
241 const {
242 assert!(core::mem::size_of::<Self>() == 2 * N);
243 }
244 let mut out = [0u8; 2 * N];
245 out[..N].copy_from_slice(&self.s0.to_le_bytes());
246 out[N..].copy_from_slice(&self.s1.to_le_bytes());
247 out
248 }
249 }
250 };
251}
252
253macro_rules! impl_state_array_of_four {
255 ($type:ident, $word:ty) => {
256 impl $type {
257 pub fn state(&self) -> [u8; 4 * core::mem::size_of::<$word>()] {
268 const N: usize = core::mem::size_of::<$word>();
269 const {
270 assert!(core::mem::size_of::<Self>() == 4 * N);
271 }
272 let mut out = [0u8; 4 * N];
273 out[..N].copy_from_slice(&self.s[0].to_le_bytes());
274 out[N..2 * N].copy_from_slice(&self.s[1].to_le_bytes());
275 out[2 * N..3 * N].copy_from_slice(&self.s[2].to_le_bytes());
276 out[3 * N..].copy_from_slice(&self.s[3].to_le_bytes());
277 out
278 }
279 }
280 };
281}
282
283macro_rules! impl_state_seed512 {
285 ($type:ident) => {
286 impl $type {
287 pub fn state(&self) -> crate::Seed512 {
298 let mut out = [0u8; 64];
299 for (i, word) in self.s.iter().enumerate() {
300 out[i * 8..(i + 1) * 8].copy_from_slice(&word.to_le_bytes());
301 }
302 crate::Seed512(out)
303 }
304 }
305 };
306}
307
308static ZERO_SEED_FALLBACK: [u8; 64] = [
313 0xaf, 0xcd, 0x1d, 0x7b, 0x39, 0xa8, 0x20, 0xe2, 0xf4, 0x65, 0xb9, 0xa1, 0x6a, 0x9e, 0x78, 0x6e,
314 0x4f, 0x45, 0x09, 0x80, 0x18, 0x5d, 0xc4, 0x06, 0xec, 0x81, 0x4c, 0x72, 0xa8, 0xb8, 0x8b, 0xf8,
315 0x9b, 0x74, 0xa8, 0x51, 0x6a, 0x89, 0x39, 0x1b, 0xea, 0xa2, 0x7e, 0x74, 0x0c, 0x9f, 0xcb, 0x53,
316 0xe1, 0x32, 0x45, 0x1f, 0xbe, 0x9a, 0x82, 0x2c, 0x3c, 0xab, 0x16, 0xc9, 0x3a, 0x13, 0x84, 0xc5,
317];
318
319#[inline]
322pub(crate) fn zero_seed_fallback<const N: usize>(seed: &[u8; N]) -> &[u8; N] {
323 const { assert!(N <= ZERO_SEED_FALLBACK.len()) };
324 if seed.iter().any(|&b| b != 0) {
325 seed
326 } else {
327 ZERO_SEED_FALLBACK.first_chunk::<N>().unwrap()
328 }
329}
330
331#[derive(Clone)]
336pub struct Seed512(pub [u8; 64]);
337
338impl Seed512 {
339 pub fn iter(&self) -> core::slice::Iter<'_, u8> {
341 self.0.iter()
342 }
343}
344
345impl core::fmt::Debug for Seed512 {
346 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
347 self.0[..].fmt(f)
348 }
349}
350
351impl Default for Seed512 {
352 fn default() -> Seed512 {
353 Seed512([0; 64])
354 }
355}
356
357impl AsRef<[u8]> for Seed512 {
358 fn as_ref(&self) -> &[u8] {
359 &self.0
360 }
361}
362
363impl AsMut<[u8]> for Seed512 {
364 fn as_mut(&mut self) -> &mut [u8] {
365 &mut self.0
366 }
367}
368
369#[cfg(test)]
370mod tests {
371 use super::ZERO_SEED_FALLBACK;
372 use crate::SplitMix64;
373 use rand_core::{Rng, SeedableRng};
374
375 #[test]
376 fn zero_seed_fallback_matches_splitmix() {
377 let mut sm = SplitMix64::seed_from_u64(0);
378 let mut expected = [0u8; 64];
379 sm.fill_bytes(&mut expected);
380 assert_eq!(ZERO_SEED_FALLBACK, expected);
381 }
382}