1use core::convert::Infallible;
15use rand::rand_core::{SeedableRng, TryRng};
16
17#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
27#[cfg_attr(
28 feature = "serde",
29 derive(serde::Serialize, serde::Deserialize)
30)]
31pub struct Xoshiro256PlusPlus {
32 state: [u64; 4],
36}
37
38#[inline]
42fn splitmix64(state: &mut u64) -> u64 {
43 *state = state.wrapping_add(0x9E37_79B9_7F4A_7C15);
44 let mut z = *state;
45 z = (z ^ (z >> 30)).wrapping_mul(0xBF58_476D_1CE4_E5B9);
46 z = (z ^ (z >> 27)).wrapping_mul(0x94D0_49BB_1331_11EB);
47 z ^ (z >> 31)
48}
49
50impl Xoshiro256PlusPlus {
51 pub fn from_seed(seed: [u8; 32]) -> Self {
63 let mut sm = u64::from_le_bytes([
64 seed[0], seed[1], seed[2], seed[3], seed[4], seed[5],
65 seed[6], seed[7],
66 ]) ^ u64::from_le_bytes([
67 seed[8], seed[9], seed[10], seed[11], seed[12], seed[13],
68 seed[14], seed[15],
69 ]) ^ u64::from_le_bytes([
70 seed[16], seed[17], seed[18], seed[19], seed[20], seed[21],
71 seed[22], seed[23],
72 ]) ^ u64::from_le_bytes([
73 seed[24], seed[25], seed[26], seed[27], seed[28], seed[29],
74 seed[30], seed[31],
75 ]);
76 if sm == 0 {
77 sm = 0xBAD1_DEAA_5BD1_CAFE;
78 }
79 let s0 = splitmix64(&mut sm);
80 let s1 = splitmix64(&mut sm);
81 let s2 = splitmix64(&mut sm);
82 let s3 = splitmix64(&mut sm);
83 Self {
84 state: [s0, s1, s2, s3],
85 }
86 }
87
88 pub fn from_u64_seed(mut seed: u64) -> Self {
99 if seed == 0 {
100 seed = 0xBAD1_DEAA_5BD1_CAFE;
101 }
102 let s0 = splitmix64(&mut seed);
103 let s1 = splitmix64(&mut seed);
104 let s2 = splitmix64(&mut seed);
105 let s3 = splitmix64(&mut seed);
106 Self {
107 state: [s0, s1, s2, s3],
108 }
109 }
110
111 #[inline]
122 pub fn next_u64(&mut self) -> u64 {
123 let res = self.state[0]
124 .wrapping_add(self.state[3])
125 .rotate_left(23)
126 .wrapping_add(self.state[0]);
127
128 let t = self.state[1] << 17;
129
130 self.state[2] ^= self.state[0];
131 self.state[3] ^= self.state[1];
132 self.state[1] ^= self.state[2];
133 self.state[0] ^= self.state[3];
134
135 self.state[2] ^= t;
136 self.state[3] = self.state[3].rotate_left(45);
137
138 res
139 }
140
141 #[inline]
153 pub fn next_u32(&mut self) -> u32 {
154 (self.next_u64() >> 32) as u32
155 }
156
157 pub fn fill_bytes(&mut self, dest: &mut [u8]) {
175 #[cfg(feature = "simd")]
176 crate::xoshiro_simd::fill_bytes(self, dest);
177 #[cfg(not(feature = "simd"))]
178 self.fill_bytes_scalar(dest);
179 }
180
181 pub(crate) fn fill_bytes_scalar(&mut self, dest: &mut [u8]) {
185 let mut i = 0;
186 while i + 8 <= dest.len() {
187 let bytes = self.next_u64().to_le_bytes();
188 dest[i..i + 8].copy_from_slice(&bytes);
189 i += 8;
190 }
191 if i < dest.len() {
192 let bytes = self.next_u64().to_le_bytes();
193 let remaining = dest.len() - i;
194 dest[i..].copy_from_slice(&bytes[..remaining]);
195 }
196 }
197
198 #[doc(hidden)]
202 #[cfg(feature = "simd")]
203 pub(crate) fn state_snapshot(&self) -> [u64; 4] {
204 self.state
205 }
206
207 #[doc(hidden)]
210 #[cfg(feature = "simd")]
211 pub(crate) fn set_state(&mut self, state: [u64; 4]) {
212 self.state = state;
213 }
214
215 pub fn jump(&mut self) {
226 const JUMP: [u64; 4] = [
227 0x180E_C6D3_3CFD_0ABA,
228 0xD5A6_1266_F0C9_392C,
229 0xA958_2618_E03F_C9AA,
230 0x39AB_DC45_29B1_661C,
231 ];
232
233 let mut s0 = 0u64;
234 let mut s1 = 0u64;
235 let mut s2 = 0u64;
236 let mut s3 = 0u64;
237
238 for &jump in &JUMP {
239 for b in 0..64 {
240 if (jump & (1u64 << b)) != 0 {
241 s0 ^= self.state[0];
242 s1 ^= self.state[1];
243 s2 ^= self.state[2];
244 s3 ^= self.state[3];
245 }
246 let _ = self.next_u64();
247 }
248 }
249
250 self.state = [s0, s1, s2, s3];
251 }
252}
253
254impl TryRng for Xoshiro256PlusPlus {
255 type Error = Infallible;
256
257 fn try_next_u32(&mut self) -> Result<u32, Self::Error> {
258 Ok(self.next_u32())
259 }
260
261 fn try_next_u64(&mut self) -> Result<u64, Self::Error> {
262 Ok(self.next_u64())
263 }
264
265 fn try_fill_bytes(
266 &mut self,
267 dest: &mut [u8],
268 ) -> Result<(), Self::Error> {
269 self.fill_bytes(dest);
270 Ok(())
271 }
272}
273
274impl SeedableRng for Xoshiro256PlusPlus {
275 type Seed = [u8; 32];
276
277 fn from_seed(seed: Self::Seed) -> Self {
278 Self::from_seed(seed)
279 }
280}
281
282#[cfg(test)]
283mod tests {
284 use super::*;
285
286 #[test]
287 fn produces_nonzero_from_zero_seed() {
288 let mut rng = Xoshiro256PlusPlus::from_seed([0u8; 32]);
289 assert_ne!(rng.next_u64(), 0);
291 }
292
293 #[test]
294 fn produces_nonzero_from_one_seed() {
295 let mut rng = Xoshiro256PlusPlus::from_seed([1u8; 32]);
296 assert_ne!(rng.next_u64(), 0);
297 }
298
299 #[test]
300 fn deterministic_for_same_seed() {
301 let seed = [42u8; 32];
302 let mut a = Xoshiro256PlusPlus::from_seed(seed);
303 let mut b = Xoshiro256PlusPlus::from_seed(seed);
304 for _ in 0..16 {
305 assert_eq!(a.next_u64(), b.next_u64());
306 }
307 }
308
309 #[test]
310 fn jump_diverges_from_baseline() {
311 let seed = [123u8; 32];
312 let mut a = Xoshiro256PlusPlus::from_seed(seed);
313 let mut b = Xoshiro256PlusPlus::from_seed(seed);
314 a.jump();
315 assert_ne!(a.next_u64(), b.next_u64());
316 }
317
318 #[test]
319 fn fill_bytes_handles_unaligned_lengths() {
320 let mut rng = Xoshiro256PlusPlus::from_seed([7u8; 32]);
321 let mut buf = [0u8; 17]; rng.fill_bytes(&mut buf);
323 assert!(buf.iter().any(|&b| b != 0));
326 }
327
328 #[test]
329 fn next_u32_uses_high_bits() {
330 let rng = Xoshiro256PlusPlus::from_seed([99u8; 32]);
331 let high = (rng.clone().next_u64() >> 32) as u32;
332 let mut copy = rng;
333 assert_eq!(copy.next_u32(), high);
334 }
335}
336
337#[cfg(test)]
338mod additional_xoshiro_tests {
339 use super::*;
340
341 #[test]
342 fn test_xoshiro_from_u64_seed() {
343 let mut rng = Xoshiro256PlusPlus::from_u64_seed(123);
344 let mut rng2 = Xoshiro256PlusPlus::from_u64_seed(123);
345 assert_eq!(rng.next_u64(), rng2.next_u64());
346 }
347}
348
349#[cfg(test)]
350mod xoshiro_coverage {
351 use super::*;
352 #[cfg(feature = "alloc")]
353 use alloc::format;
354 #[cfg(all(not(feature = "alloc"), feature = "std"))]
355 use std::format;
356
357 #[test]
358 fn test_xoshiro_fill_bytes_large() {
359 let mut rng = Xoshiro256PlusPlus::from_u64_seed(42);
360 let mut buf = [0u8; 100];
361 rng.fill_bytes(&mut buf);
362 assert!(buf.iter().any(|&x| x != 0));
363 }
364
365 #[test]
366 fn test_xoshiro_next_u32() {
367 let mut rng = Xoshiro256PlusPlus::from_u64_seed(42);
368 let _ = rng.next_u32();
369 }
370
371 #[test]
372 fn test_xoshiro_debug_display() {
373 let rng = Xoshiro256PlusPlus::from_u64_seed(42);
374 let s = format!("{:?}", rng);
375 assert!(s.contains("Xoshiro256PlusPlus"));
376 }
377}
378
379#[cfg(test)]
380mod xoshiro_final_coverage {
381 use super::*;
382
383 #[test]
384 fn test_xoshiro_try_next() {
385 let mut rng = Xoshiro256PlusPlus::from_u64_seed(42);
386 assert!(rng.try_next_u32().is_ok());
387 assert!(rng.try_next_u64().is_ok());
388 }
389
390 #[test]
391 fn test_xoshiro_seedable_rng() {
392 let seed = [1u8; 32];
393 let mut rng =
394 <Xoshiro256PlusPlus as SeedableRng>::from_seed(seed);
395 assert_ne!(rng.next_u64(), 0);
396 }
397}
398
399#[cfg(test)]
400mod xoshiro_zero_test {
401 use super::*;
402
403 #[test]
404 fn test_xoshiro_all_zero_seed() {
405 let seed = [0u8; 32];
406 let mut rng = Xoshiro256PlusPlus::from_seed(seed);
407 assert_ne!(rng.next_u64(), 0);
408 }
409}
410
411#[cfg(test)]
412mod xoshiro_edge_cases {
413 use super::*;
414
415 #[test]
416 fn test_xoshiro_from_u64_seed_zero() {
417 let mut rng = Xoshiro256PlusPlus::from_u64_seed(0);
418 assert_ne!(rng.next_u64(), 0);
419 }
420}