Skip to main content

osom_lib_prng/
stream_prng.rs

1//! Holds the implementation of the stream-based PRNG.
2
3use core::ops::RangeBounds;
4
5use osom_lib_reprc::{macros::reprc, traits::ReprC};
6use osom_lib_try_clone::TryClone;
7
8use crate::{
9    prngs::helpers::{
10        generate_f32_in_range, generate_f64_in_range, generate_i32_in_range, generate_i64_in_range,
11        generate_u32_in_range, generate_u64_in_range,
12    },
13    traits::{PRNConcreteBoundedGenerator, PRNConcreteGenerator, PRNGenerator, PRStream, Seedable},
14};
15
16/// The standard stream-based PRNG. It accepts a stream and implements
17/// the [`PRNGenerator`] trait on top of it.
18#[derive(Debug, PartialEq, Eq, Clone)]
19#[reprc]
20pub struct StreamPRNG<T: PRStream> {
21    stream: T,
22}
23
24impl<T: PRStream + TryClone> TryClone for StreamPRNG<T> {
25    type Error = <T as TryClone>::Error;
26
27    fn try_clone(&self) -> Result<Self, Self::Error> {
28        let stream = self.stream.try_clone()?;
29        Ok(Self { stream })
30    }
31}
32
33impl<T: PRStream> StreamPRNG<T> {
34    /// Creates a new [`StreamPRNG`] from a given stream.
35    #[inline(always)]
36    pub fn new(stream: T) -> Self {
37        Self { stream }
38    }
39}
40
41#[allow(clippy::cast_possible_truncation)]
42impl<T: PRStream> PRNGenerator for StreamPRNG<T> {
43    unsafe fn fill_raw(&mut self, dst_ptr: *mut u8, dst_len: usize) {
44        unsafe { self.stream.fill_raw(dst_ptr, dst_len) };
45    }
46}
47
48impl<const N: usize, T: PRStream> PRNConcreteGenerator<StreamPRNG<T>> for [u8; N] {
49    #[inline(always)]
50    fn generate(generator: &mut StreamPRNG<T>) -> Self {
51        const {
52            assert!(size_of::<Self>() == N);
53        }
54        if N == 0 {
55            return [0u8; N];
56        }
57        let mut item = core::mem::MaybeUninit::<Self>::uninit();
58        unsafe {
59            generator.fill_raw(item.as_mut_ptr().cast(), N);
60            item.assume_init()
61        }
62    }
63}
64
65impl<T: PRStream> PRNConcreteGenerator<StreamPRNG<T>> for bool {
66    fn generate(generator: &mut StreamPRNG<T>) -> Self {
67        (generator.generate::<u8>() & 1) == 1
68    }
69}
70
71impl<T: PRStream> PRNConcreteGenerator<StreamPRNG<T>> for u8 {
72    fn generate(generator: &mut StreamPRNG<T>) -> Self {
73        u8::from_le_bytes(generator.generate::<[u8; 1]>())
74    }
75}
76
77impl<T: PRStream> PRNConcreteGenerator<StreamPRNG<T>> for i8 {
78    fn generate(generator: &mut StreamPRNG<T>) -> Self {
79        i8::from_le_bytes(generator.generate::<[u8; 1]>())
80    }
81}
82
83impl<T: PRStream> PRNConcreteGenerator<StreamPRNG<T>> for u16 {
84    fn generate(generator: &mut StreamPRNG<T>) -> Self {
85        u16::from_le_bytes(generator.generate::<[u8; 2]>())
86    }
87}
88
89impl<T: PRStream> PRNConcreteGenerator<StreamPRNG<T>> for i16 {
90    fn generate(generator: &mut StreamPRNG<T>) -> Self {
91        i16::from_le_bytes(generator.generate::<[u8; 2]>())
92    }
93}
94
95impl<T: PRStream> PRNConcreteGenerator<StreamPRNG<T>> for u32 {
96    fn generate(generator: &mut StreamPRNG<T>) -> Self {
97        u32::from_le_bytes(generator.generate::<[u8; 4]>())
98    }
99}
100
101impl<T: PRStream> PRNConcreteGenerator<StreamPRNG<T>> for i32 {
102    fn generate(generator: &mut StreamPRNG<T>) -> Self {
103        i32::from_le_bytes(generator.generate::<[u8; 4]>())
104    }
105}
106
107impl<T: PRStream> PRNConcreteGenerator<StreamPRNG<T>> for u64 {
108    fn generate(generator: &mut StreamPRNG<T>) -> Self {
109        u64::from_le_bytes(generator.generate::<[u8; 8]>())
110    }
111}
112
113impl<T: PRStream> PRNConcreteGenerator<StreamPRNG<T>> for i64 {
114    fn generate(generator: &mut StreamPRNG<T>) -> Self {
115        i64::from_le_bytes(generator.generate::<[u8; 8]>())
116    }
117}
118
119impl<T: PRStream> PRNConcreteGenerator<StreamPRNG<T>> for u128 {
120    fn generate(generator: &mut StreamPRNG<T>) -> Self {
121        u128::from_le_bytes(generator.generate::<[u8; 16]>())
122    }
123}
124
125impl<T: PRStream> PRNConcreteGenerator<StreamPRNG<T>> for i128 {
126    fn generate(generator: &mut StreamPRNG<T>) -> Self {
127        i128::from_le_bytes(generator.generate::<[u8; 16]>())
128    }
129}
130
131impl<T: PRStream> PRNConcreteBoundedGenerator<StreamPRNG<T>> for u32 {
132    fn generate<TBounds: RangeBounds<Self>>(generator: &mut StreamPRNG<T>, range: TBounds) -> Self {
133        generate_u32_in_range(generator, range)
134    }
135}
136
137impl<T: PRStream> PRNConcreteBoundedGenerator<StreamPRNG<T>> for u64 {
138    fn generate<TBounds: RangeBounds<Self>>(generator: &mut StreamPRNG<T>, range: TBounds) -> Self {
139        generate_u64_in_range(generator, range)
140    }
141}
142
143impl<T: PRStream> PRNConcreteBoundedGenerator<StreamPRNG<T>> for i32 {
144    fn generate<TBounds: RangeBounds<Self>>(generator: &mut StreamPRNG<T>, range: TBounds) -> Self {
145        generate_i32_in_range(generator, range)
146    }
147}
148
149impl<T: PRStream> PRNConcreteBoundedGenerator<StreamPRNG<T>> for i64 {
150    fn generate<TBounds: RangeBounds<Self>>(generator: &mut StreamPRNG<T>, range: TBounds) -> Self {
151        generate_i64_in_range(generator, range)
152    }
153}
154
155impl<T: PRStream> PRNConcreteBoundedGenerator<StreamPRNG<T>> for f32 {
156    fn generate<TBounds: RangeBounds<Self>>(generator: &mut StreamPRNG<T>, range: TBounds) -> Self {
157        generate_f32_in_range(generator, range)
158    }
159}
160
161impl<T: PRStream> PRNConcreteBoundedGenerator<StreamPRNG<T>> for f64 {
162    fn generate<TBounds: RangeBounds<Self>>(generator: &mut StreamPRNG<T>, range: TBounds) -> Self {
163        generate_f64_in_range(generator, range)
164    }
165}
166
167impl<TSeed: ReprC + Copy, T: PRStream + Seedable<TSeed>> Seedable<TSeed> for StreamPRNG<T> {
168    fn with_seed(seed: TSeed) -> Self {
169        Self::new(T::with_seed(seed))
170    }
171}