squirrel_rng/
lib.rs

1#![cfg_attr(all(not(test), not(feature = "std")), no_std)]
2
3pub use rand::{Rng, RngCore, SeedableRng};
4
5#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
6pub struct SquirrelRng {
7    position: u32,
8    seed: u32,
9}
10
11impl SquirrelRng {
12    #[cfg(feature = "std")]
13    pub fn new() -> Self {
14        Self::from_rng(&mut rand::rng())
15    }
16
17    pub fn with_seed(seed: u32) -> Self {
18        Self { position: 0, seed }
19    }
20
21    pub fn with_position(self, position: u32) -> Self {
22        Self { position, ..self }
23    }
24}
25
26#[cfg(feature = "std")]
27impl Default for SquirrelRng {
28    fn default() -> Self {
29        SquirrelRng::new()
30    }
31}
32
33impl RngCore for SquirrelRng {
34    #[inline]
35    fn next_u32(&mut self) -> u32 {
36        let result = squirrel3(self.position, self.seed);
37        self.position = self.position.wrapping_add(1);
38        result
39    }
40
41    #[inline]
42    fn next_u64(&mut self) -> u64 {
43        next_u64_via_u32(self)
44    }
45
46    #[inline]
47    fn fill_bytes(&mut self, dest: &mut [u8]) {
48        fill_bytes_via_next(self, dest);
49    }
50}
51
52impl SeedableRng for SquirrelRng {
53    type Seed = [u8; 4];
54
55    fn from_seed(seed: Self::Seed) -> Self {
56        Self::with_seed(u32::from_le_bytes(seed))
57    }
58}
59
60#[inline]
61pub fn squirrel3(position: u32, seed: u32) -> u32 {
62    const BIT_NOISE1: u32 = 0x68E31DA4;
63    const BIT_NOISE2: u32 = 0xB5297A4D;
64    const BIT_NOISE3: u32 = 0x1B56C4E9;
65
66    let mut mangled = position;
67    mangled = mangled.wrapping_mul(BIT_NOISE1);
68    mangled = mangled.wrapping_add(seed);
69    mangled ^= mangled >> 8;
70    mangled = mangled.wrapping_add(BIT_NOISE2);
71    mangled ^= mangled << 8;
72    mangled = mangled.wrapping_mul(BIT_NOISE3);
73    mangled ^= mangled >> 8;
74    mangled
75}
76
77// These two implementations are taken directly from the rand library.
78
79/// Implement `next_u64` via `next_u32`, little-endian order.
80pub fn next_u64_via_u32<R: RngCore + ?Sized>(rng: &mut R) -> u64 {
81    // Use LE; we explicitly generate one value before the next.
82    let x = u64::from(rng.next_u32());
83    let y = u64::from(rng.next_u32());
84    (y << 32) | x
85}
86
87/// Implement `fill_bytes` via `next_u64` and `next_u32`, little-endian order.
88///
89/// The fastest way to fill a slice is usually to work as long as possible with
90/// integers. That is why this method mostly uses `next_u64`, and only when
91/// there are 4 or less bytes remaining at the end of the slice it uses
92/// `next_u32` once.
93fn fill_bytes_via_next<R: RngCore + ?Sized>(rng: &mut R, dest: &mut [u8]) {
94    let mut left = dest;
95    while left.len() >= 8 {
96        let (l, r) = { left }.split_at_mut(8);
97        left = r;
98        let chunk: [u8; 8] = rng.next_u64().to_le_bytes();
99        l.copy_from_slice(&chunk);
100    }
101    let n = left.len();
102    if n > 4 {
103        let chunk: [u8; 8] = rng.next_u64().to_le_bytes();
104        left.copy_from_slice(&chunk[..n]);
105    } else if n > 0 {
106        let chunk: [u8; 4] = rng.next_u32().to_le_bytes();
107        left.copy_from_slice(&chunk[..n]);
108    }
109}
110
111#[cfg(test)]
112mod tests {
113    use rand::RngCore;
114
115    use crate::SquirrelRng;
116
117    #[test]
118    fn copy_with_position_does_not_modify_original() {
119        let mut a = SquirrelRng::with_seed(3);
120        let mut b = a.with_position(1);
121
122        let second_value = b.next_u32();
123
124        assert_ne!(a.next_u32(), second_value);
125        assert_eq!(a.next_u32(), second_value);
126    }
127}