1use std::marker::PhantomData;
2
3use self::{
4 lcg::{Integer, Lcg, Parameters},
5 output::Output
6};
7
8pub mod lcg;
9pub mod output;
10pub mod variants;
11
12#[cfg(feature = "rand")]
13mod rand;
14
15#[derive(Clone, Debug, Eq, Hash, PartialEq)]
16pub struct Pcg<L, P, S, O> {
17 pub lcg: Lcg<L, S>,
18 pub output: PhantomData<(P, O)>
19}
20
21impl<L, P, S, O> Pcg<L, P, S, O>
22where
23 L: Copy + Default + Into<Parameters<S>>,
24 P: Output<S, O>,
25 S: Integer
26{
27 pub fn new(seed: S) -> Self {
28 Self::with_parameters(seed, L::default())
29 }
30}
31
32impl<L, P, S, O> Pcg<L, P, S, O>
33where
34 L: Copy + Into<Parameters<S>>,
35 P: Output<S, O>,
36 S: Integer
37{
38 pub fn with_parameters(seed: S, parameters: L) -> Self {
39 let increment = parameters.into().increment;
40
41 let mut lcg = Lcg {
42 state: if increment == S::ZERO { seed | S::ONE } else { seed.add(increment) },
43 parameters
44 };
45
46 let _ = lcg.generate();
47 Self { lcg, output: PhantomData }
48 }
49
50 pub fn current(&self) -> O {
51 P::output(self.lcg.current())
52 }
53
54 pub fn generate(&mut self) -> O {
55 let state = self.lcg.state;
56 let _ = self.lcg.generate();
57 P::output(state)
58 }
59
60 pub fn jump_forward(&mut self, steps: S) -> O {
61 let state = self.lcg.jump_forward(steps.sub(S::ONE));
62 let _ = self.lcg.generate();
63 P::output(state)
64 }
65
66 pub fn jump_backward(&mut self, steps: S) -> O {
67 let state = self.lcg.jump_backward(steps.add(S::ONE));
68 let _ = self.lcg.generate();
69 P::output(state)
70 }
71}
72
73#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
74pub struct DefaultLcgParameters<S>(PhantomData<S>);
75
76#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
77pub struct DefaultCheapLcgParameters<S>(PhantomData<S>);
78
79#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
80pub struct DefaultMcgParameters<S>(PhantomData<S>);
81
82#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
83pub struct DefaultCheapMcgParameters<S>(PhantomData<S>);
84
85macro_rules! impl_default_parameters {
86 ($ty:ty, $mul:literal, $inc:literal) => {
87 impl_default_parameters!($ty, $mul, $inc, cheap_mul: $mul);
88 };
89
90 ($ty:ty, $mul:literal, $inc:literal, cheap_mul: $cheap_mul:literal) => {
91 impl DefaultLcgParameters<$ty> {
92 #[inline]
93 pub const fn multiplier() -> $ty {
94 $mul
95 }
96
97 #[inline]
98 pub const fn increment() -> $ty {
99 $inc
100 }
101 }
102
103 impl From<DefaultLcgParameters<$ty>> for Parameters<$ty> {
104 #[inline]
105 fn from(_: DefaultLcgParameters<$ty>) -> Parameters<$ty> {
106 Parameters { multiplier: $mul, increment: $inc }
107 }
108 }
109
110 impl DefaultCheapLcgParameters<$ty> {
111 #[inline]
112 pub const fn multiplier() -> $ty {
113 $cheap_mul
114 }
115
116 #[inline]
117 pub const fn increment() -> $ty {
118 $inc
119 }
120 }
121
122 impl From<DefaultCheapLcgParameters<$ty>> for Parameters<$ty> {
123 #[inline]
124 fn from(_: DefaultCheapLcgParameters<$ty>) -> Parameters<$ty> {
125 Parameters { multiplier: $cheap_mul, increment: $inc }
126 }
127 }
128
129 impl DefaultMcgParameters<$ty> {
130 #[inline]
131 pub const fn multiplier() -> $ty {
132 $mul
133 }
134 }
135
136 impl From<DefaultMcgParameters<$ty>> for Parameters<$ty> {
137 #[inline]
138 fn from(_: DefaultMcgParameters<$ty>) -> Parameters<$ty> {
139 Parameters { multiplier: $mul, increment: 0 }
140 }
141 }
142
143 impl DefaultCheapMcgParameters<$ty> {
144 #[inline]
145 pub const fn multiplier() -> $ty {
146 $cheap_mul
147 }
148 }
149
150 impl From<DefaultCheapMcgParameters<$ty>> for Parameters<$ty> {
151 #[inline]
152 fn from(_: DefaultCheapMcgParameters<$ty>) -> Parameters<$ty> {
153 Parameters { multiplier: $cheap_mul, increment: 0 }
154 }
155 }
156 };
157}
158
159impl_default_parameters!(u8, 0x8d, 0x4d);
160impl_default_parameters!(u16, 0x321d, 0xbb75);
161impl_default_parameters!(u32, 0x2c9277b5, 0xac564b05);
162impl_default_parameters!(u64, 0x5851f42d4c957f2d, 0x14057b7ef767814f);
163
164impl_default_parameters!(
165 u128,
166 0x2360ed051fc65da44385df649fccf645,
167 0x5851f42d4c957f2d14057b7ef767814f,
168 cheap_mul: 0xda942042e4dd58b5
169);