1#![allow(
2 clippy::cast_possible_truncation,
3 clippy::cast_possible_wrap,
4)]
5
6use core::{convert::Infallible, ops::RangeBounds};
7
8use osom_lib_reprc::macros::reprc;
9use osom_lib_try_clone::TryClone;
10
11use crate::{
12 errors::{DeserializeError, SerializeError},
13 prngs::helpers::{
14 calculate_crc8, fill_raw_from_array_generator, generate_f32_in_range, generate_f64_in_range,
15 generate_i32_in_range, generate_i64_in_range, generate_u32_in_range, generate_u64_in_range
16 },
17 traits::{
18 DeserializationResult, PRNConcreteBoundedGenerator, PRNConcreteGenerator, PRNGSerialize, PRNGenerator, Seedable, Splittable
19 }
20};
21
22#[derive(Debug, PartialEq, Eq, Clone, Copy)]
30#[reprc]
31#[repr(transparent)]
32#[must_use]
33pub struct GeneralLinearCongruentialGenerator128<const A: u128, const C: u128> {
34 state: u128,
35}
36
37impl<const A: u128, const C: u128> TryClone for GeneralLinearCongruentialGenerator128<A, C> {
38 type Error = Infallible;
39
40 fn try_clone(&self) -> Result<Self, Self::Error> {
41 Ok(*self)
42 }
43}
44
45impl<const A: u128, const C: u128> GeneralLinearCongruentialGenerator128<A, C> {
46 #[inline(always)]
48 pub const fn next(&mut self) -> u128 {
49 let new_value = self.state.wrapping_mul(A).wrapping_add(C);
50 self.state = new_value;
51 new_value
52 }
53}
54
55impl<const A: u128, const C: u128> Seedable<u128> for GeneralLinearCongruentialGenerator128<A, C> {
56 fn with_seed(seed: u128) -> Self {
57 let state = core::hint::select_unpredictable(seed != 0, seed, 1);
58 Self { state }
59 }
60}
61
62impl<const A: u128, const C: u128> Seedable<u64> for GeneralLinearCongruentialGenerator128<A, C> {
63 fn with_seed(seed: u64) -> Self {
64 let mut splitmix = crate::prngs::SplitMix64::with_seed(seed);
65 let upper = u128::from(splitmix.next());
66 let lower = u128::from(splitmix.next());
67 Self::with_seed((upper << 64) + lower)
68 }
69}
70
71impl<const A: u128, const C: u128> PRNGenerator for GeneralLinearCongruentialGenerator128<A, C> {
72 unsafe fn fill_raw(&mut self, dst_ptr: *mut u8, dst_len: usize) {
73 fill_raw_from_array_generator(|| self.next().to_le_bytes(), dst_ptr, dst_len);
74 }
75}
76
77impl<const A: u128, const C: u128> PRNConcreteGenerator<GeneralLinearCongruentialGenerator128<A, C>> for bool {
78 fn generate(generator: &mut GeneralLinearCongruentialGenerator128<A, C>) -> Self {
79 (generator.next() & 1) == 1
80 }
81}
82
83impl<const N: usize, const A: u128, const C: u128> PRNConcreteGenerator<GeneralLinearCongruentialGenerator128<A, C>> for [u8; N] {
84 fn generate(generator: &mut GeneralLinearCongruentialGenerator128<A, C>) -> Self {
85 if N == 0 {
86 return [0u8; N];
87 }
88 let mut item = core::mem::MaybeUninit::<Self>::uninit();
89 unsafe {
90 generator.fill_raw(item.as_mut_ptr().cast(), size_of::<Self>());
91 item.assume_init()
92 }
93 }
94}
95
96impl<const A: u128, const C: u128> PRNConcreteGenerator<GeneralLinearCongruentialGenerator128<A, C>> for u8 {
97 fn generate(generator: &mut GeneralLinearCongruentialGenerator128<A, C>) -> Self {
98 u8::from_le_bytes(generator.generate::<[u8; 1]>())
99 }
100}
101
102impl<const A: u128, const C: u128> PRNConcreteGenerator<GeneralLinearCongruentialGenerator128<A, C>> for i8 {
103 fn generate(generator: &mut GeneralLinearCongruentialGenerator128<A, C>) -> Self {
104 i8::from_le_bytes(generator.generate::<[u8; 1]>())
105 }
106}
107
108impl<const A: u128, const C: u128> PRNConcreteGenerator<GeneralLinearCongruentialGenerator128<A, C>> for u32 {
109 fn generate(generator: &mut GeneralLinearCongruentialGenerator128<A, C>) -> Self {
110 u32::from_le_bytes(generator.generate::<[u8; 4]>())
111 }
112}
113
114impl<const A: u128, const C: u128> PRNConcreteGenerator<GeneralLinearCongruentialGenerator128<A, C>> for i32 {
115 fn generate(generator: &mut GeneralLinearCongruentialGenerator128<A, C>) -> Self {
116 i32::from_le_bytes(generator.generate::<[u8; 4]>())
117 }
118}
119
120impl<const A: u128, const C: u128> PRNConcreteGenerator<GeneralLinearCongruentialGenerator128<A, C>> for u64 {
121 fn generate(generator: &mut GeneralLinearCongruentialGenerator128<A, C>) -> Self {
122 u64::from_le_bytes(generator.generate::<[u8; 8]>())
123 }
124}
125
126impl<const A: u128, const C: u128> PRNConcreteGenerator<GeneralLinearCongruentialGenerator128<A, C>> for i64 {
127 fn generate(generator: &mut GeneralLinearCongruentialGenerator128<A, C>) -> Self {
128 i64::from_le_bytes(generator.generate::<[u8; 8]>())
129 }
130}
131
132impl<const A: u128, const C: u128> PRNConcreteGenerator<GeneralLinearCongruentialGenerator128<A, C>> for u128 {
133 fn generate(generator: &mut GeneralLinearCongruentialGenerator128<A, C>) -> Self {
134 generator.next()
135 }
136}
137
138impl<const A: u128, const C: u128> PRNConcreteGenerator<GeneralLinearCongruentialGenerator128<A, C>> for i128 {
139 fn generate(generator: &mut GeneralLinearCongruentialGenerator128<A, C>) -> Self {
140 generator.generate::<u128>() as i128
141 }
142}
143
144
145impl<const A: u128, const C: u128> PRNGSerialize for GeneralLinearCongruentialGenerator128<A, C> {
146 type SerializeError = SerializeError;
147
148 type DeserializeError = DeserializeError;
149
150 const MAX_SERIALIZED_SIZE: usize = size_of::<u128>() + 4;
151
152 fn serialize(&self, buffer: &mut [u8]) -> Result<usize, Self::SerializeError> {
153 if buffer.len() < Self::MAX_SERIALIZED_SIZE {
154 return Err(SerializeError::BufferTooSmall);
155 }
156 buffer[0] = b'L';
157 buffer[1] = b'C';
158 buffer[2] = b'G';
159 let state = self.state.to_le_bytes();
160 buffer[3] = calculate_crc8(&state);
161 buffer[4..Self::MAX_SERIALIZED_SIZE].copy_from_slice(&state);
162 Ok(Self::MAX_SERIALIZED_SIZE)
163 }
164
165 fn deserialize(buffer: &[u8]) -> Result<DeserializationResult<Self>, Self::DeserializeError> {
166 if buffer.len() < Self::MAX_SERIALIZED_SIZE {
167 return Err(DeserializeError::BufferTooSmall);
168 }
169
170 if buffer[0..3] != [b'L', b'C', b'G'] {
171 return Err(DeserializeError::InvalidFormat);
172 }
173
174 let crc8_expected_value = buffer[3];
175
176 let mut data = [0u8; size_of::<u128>()];
177 data.copy_from_slice(&buffer[4..Self::MAX_SERIALIZED_SIZE]);
178 let crc8_value = calculate_crc8(&data);
179 if crc8_expected_value != crc8_value {
180 return Err(DeserializeError::InvalidFormat);
181 }
182
183 let state = u128::from_le_bytes(data);
184
185 let result = DeserializationResult {
186 read_bytes: Self::MAX_SERIALIZED_SIZE,
187 value: Self::with_seed(state),
188 };
189 Ok(result)
190 }
191}
192
193impl<const A: u128, const C: u128> Splittable for GeneralLinearCongruentialGenerator128<A, C> {
194 fn split(&mut self) -> Self {
195 let next = self.generate::<u64>();
196 Self::with_seed(next)
197 }
198}
199
200impl<const A: u128, const C: u128> PRNConcreteBoundedGenerator<GeneralLinearCongruentialGenerator128<A, C>> for u32 {
201 fn generate<TBounds: RangeBounds<Self>>(generator: &mut GeneralLinearCongruentialGenerator128<A, C>, range: TBounds) -> Self {
202 generate_u32_in_range(generator, range)
203 }
204}
205
206impl<const A: u128, const C: u128> PRNConcreteBoundedGenerator<GeneralLinearCongruentialGenerator128<A, C>> for u64 {
207 fn generate<TBounds: RangeBounds<Self>>(generator: &mut GeneralLinearCongruentialGenerator128<A, C>, range: TBounds) -> Self {
208 generate_u64_in_range(generator, range)
209 }
210}
211
212impl<const A: u128, const C: u128> PRNConcreteBoundedGenerator<GeneralLinearCongruentialGenerator128<A, C>> for i32 {
213 fn generate<TBounds: RangeBounds<Self>>(generator: &mut GeneralLinearCongruentialGenerator128<A, C>, range: TBounds) -> Self {
214 generate_i32_in_range(generator, range)
215 }
216}
217
218impl<const A: u128, const C: u128> PRNConcreteBoundedGenerator<GeneralLinearCongruentialGenerator128<A, C>> for i64 {
219 fn generate<TBounds: RangeBounds<Self>>(generator: &mut GeneralLinearCongruentialGenerator128<A, C>, range: TBounds) -> Self {
220 generate_i64_in_range(generator, range)
221 }
222}
223
224
225impl<const A: u128, const C: u128> PRNConcreteBoundedGenerator<GeneralLinearCongruentialGenerator128<A, C>> for f32 {
226 fn generate<TBounds: RangeBounds<Self>>(generator: &mut GeneralLinearCongruentialGenerator128<A, C>, range: TBounds) -> Self {
227 generate_f32_in_range(generator, range)
228 }
229}
230
231impl<const A: u128, const C: u128> PRNConcreteBoundedGenerator<GeneralLinearCongruentialGenerator128<A, C>> for f64 {
232 fn generate<TBounds: RangeBounds<Self>>(generator: &mut GeneralLinearCongruentialGenerator128<A, C>, range: TBounds) -> Self {
233 generate_f64_in_range(generator, range)
234 }
235}
236
237pub type LinearCongruentialGenerator128 = GeneralLinearCongruentialGenerator128<
254 0xdb36357734e34abb0050d0761fcdfc15,
255 0x86e9>;