1use crate::rand::{Rng, SeedableRng};
4use core::fmt::{self, Debug, Display, Formatter};
5#[cfg(feature = "zeroize")]
6use zeroize::Zeroize;
7
8const PCG_DEFAULT_MULTIPLIER_128: u128 = 47026247687942121848144207491837523525;
9
10#[cfg_attr(feature = "zeroize", derive(Zeroize))]
14#[cfg_attr(feature = "zeroize", zeroize(drop))]
15pub struct Pcg64 {
16 seed: u128,
17 state: u128,
18 inc: u128,
19}
20
21impl Pcg64 {
22 #[cfg(feature = "std")]
24 #[must_use]
25 pub fn new() -> Self {
26 let mut entropy: [u8; core::mem::size_of::<u128>()] = Default::default();
27 crate::entropy::system(&mut entropy);
28 Self {
29 seed: u128::from_ne_bytes(entropy),
30 inc: 0,
31 state: 0,
32 }
33 }
34
35 #[must_use]
37 pub const fn new_seed(seed: u128) -> Self {
38 Self {
39 seed,
40 inc: 0,
41 state: 0,
42 }
43 }
44
45 fn step(&mut self) {
46 self.state = self
47 .state
48 .wrapping_mul(PCG_DEFAULT_MULTIPLIER_128)
49 .wrapping_add(self.inc);
50 }
51
52 fn rand128(&mut self) -> u64 {
53 self.state = 0;
54 self.inc = self.seed.wrapping_shl(1) | 1;
55 self.step();
56 self.state = self.state.wrapping_add(self.seed);
57 self.step();
58 self.step();
59 self.state.wrapping_shr(64) as u64 ^ self.state as u64
60 }
61}
62
63#[cfg(feature = "std")]
64impl Default for Pcg64 {
65 fn default() -> Self {
67 let mut entropy: [u8; core::mem::size_of::<u128>()] = Default::default();
68 crate::entropy::system(&mut entropy);
69 Self {
70 seed: u128::from_ne_bytes(entropy),
71 inc: 0,
72 state: 0,
73 }
74 }
75}
76
77impl Rng<8> for Pcg64 {
78 fn rand(&mut self) -> [u8; 8] {
79 let ret = self.rand128();
80 self.seed = self.state ^ (ret as u128).wrapping_shr(64);
81 ret.to_ne_bytes()
82 }
83}
84
85impl SeedableRng<16, 8> for Pcg64 {
86 fn reseed(&mut self, seed: [u8; 16]) {
87 self.seed = u128::from_ne_bytes(seed);
88 }
89}
90
91impl Clone for Pcg64 {
92 fn clone(&self) -> Self {
93 Self {
94 seed: self.seed,
95 inc: self.inc,
96 state: self.state,
97 }
98 }
99}
100
101impl Display for Pcg64 {
102 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
103 write!(f, "Pcg64 ({:p})", self)
104 }
105}
106
107impl Debug for Pcg64 {
108 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
109 f.debug_struct("Pcg64")
110 .field("seed", &format_args!("0x{:x}", self.seed))
111 .field("state", &format_args!("0x{:x}", self.state))
112 .field("inc", &format_args!("0x{:x}", self.inc))
113 .finish()
114 }
115}