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