osom_lib_prng/traits.rs
1//! Holds definitions of various PRNG traits.
2
3use core::ops::RangeBounds;
4
5use osom_lib_reprc::{macros::reprc, traits::ReprC};
6
7use crate::errors::{DeserializeError, SerializeError};
8
9/// Generates pseudo random instance of current type.
10///
11/// Similar to [`PRNGenerator`] but works with a single type
12/// only.
13pub trait PRNConcreteGenerator<TGenerator: PRNGenerator>: Sized + ReprC {
14 /// Generates a new pseudo random instance of itself.
15 #[must_use]
16 fn generate(generator: &mut TGenerator) -> Self;
17}
18
19/// Represents a trait for generating pseudo-random data
20pub trait PRNConcreteBoundedGenerator<TGenerator: PRNGenerator>: Sized + ReprC {
21 /// Generates a new pseudo random instance of itself in given range.
22 #[must_use]
23 fn generate<TBounds: RangeBounds<Self>>(generator: &mut TGenerator, range: TBounds) -> Self;
24}
25
26/// Generates pseudo random numbers.
27pub trait PRNGenerator: Sized + ReprC + Clone {
28 /// Fills the given raw buffer with randomness.
29 ///
30 /// # Safety
31 ///
32 /// This function assumes that both `dst_ptr` and `dst_len`
33 /// correspond to valid chunk of memory. Otherwise the behaviour
34 /// is undefined.
35 unsafe fn fill_raw(&mut self, dst_ptr: *mut u8, dst_len: usize);
36
37 /// Fills the given buffer with randomness.
38 #[inline(always)]
39 fn fill(&mut self, dst: &mut [u8]) {
40 unsafe {
41 self.fill_raw(dst.as_mut_ptr(), dst.len());
42 }
43 }
44
45 /// Generates pseudo random instance of given type if supported.
46 /// This function should support at least i32, u32, i64 and u64
47 /// types.
48 #[inline(always)]
49 #[must_use]
50 fn generate<T>(&mut self) -> T
51 where
52 T: PRNConcreteGenerator<Self>,
53 {
54 T::generate(self)
55 }
56
57 /// Generates a pseudo random number in given range, if supported.
58 #[must_use]
59 fn generate_in_range<T, TBounds: RangeBounds<T>>(&mut self, range: TBounds) -> T
60 where
61 T: PRNConcreteBoundedGenerator<Self>,
62 {
63 T::generate(self, range)
64 }
65}
66
67/// A marker trait for cryptographically secure PRNGs.
68///
69/// # Safety
70///
71/// It is up to the implementor to ensure this invariant.
72pub unsafe trait CryptographicallySecure: PRNGenerator {}
73
74/// A trait for splittable PRNGs. This means that
75/// given PRNG can split into two generators. This
76/// is different from creating a new PRNG (with a random
77/// seed), because splitting is a deterministic process.
78///
79/// Also this is different from cloning, since clones
80/// generally generate the same sequences of numbers
81/// (since clones have the exact same state).
82/// We want the result of splitting look like
83/// it is independent (even though in reality it is not).
84///
85/// It is especially useful for deterministic, multi-threaded
86/// simulations where each thread needs a PRNG.
87pub trait Splittable: PRNGenerator {
88 /// Create a new PRNG from the current one. In a
89 /// deterministic, yet non-obvious (pseudo random) way.
90 #[must_use]
91 fn split(&mut self) -> Self;
92}
93
94/// Represents deserialization result.
95#[derive(Debug)]
96#[reprc]
97pub struct DeserializationResult<T: ReprC> {
98 /// The real amount of bytes read from the buffer.
99 pub read_bytes: usize,
100
101 /// The actual deserialized value.
102 pub value: T,
103}
104
105/// Represents platform independent (de)serialization trait
106/// of given pseudo random number generator.
107pub trait PRNGSerialize: PRNGenerator {
108 /// Concrete serialization error.
109 type SerializeError: Into<SerializeError> + ReprC;
110
111 /// Concrete deserialization error.
112 type DeserializeError: Into<DeserializeError> + ReprC;
113
114 /// The maximum size of serialized value, in bytes. This should be used by callers
115 /// to determine how big the buffer needs to be for [`PRNGSerialize::serialize`]
116 /// to succeed.
117 ///
118 /// Typically this should be in the order of few kb max
119 /// (e.g. for the 128-bit linear congruential generator that would be the current
120 /// state, i.e. only 16 bytes if we don't count the multiplier and the increment).
121 /// But of course there is no such guarantee in general.
122 const MAX_SERIALIZED_SIZE: usize;
123
124 /// Serializes self into the buffer. Returns the actual amount of bytes that
125 /// were written on success.
126 ///
127 /// # Errors
128 ///
129 /// For errors see concrete [`PRNGSerialize::SerializeError`] type.
130 fn serialize(&self, buffer: &mut [u8]) -> Result<usize, Self::SerializeError>;
131
132 /// Deserializes self from the passed buffer. Returns deserialization info
133 /// on success, i.e. the actual value and the amount of bytes read from the
134 /// buffer.
135 ///
136 /// # Errors
137 ///
138 /// For errors see concrete [`PRNGSerialize::DeserializeError`] type.
139 fn deserialize(buffer: &[u8]) -> Result<DeserializationResult<Self>, Self::DeserializeError>;
140}
141
142/// Represents a pseudo random stream. These are easily convertible
143/// into PRNGs through the [`StreamPRNG`][`crate::stream_prng::StreamPRNG`] wrapper.
144pub trait PRStream: Sized + Clone + ReprC {
145 /// Fills the given raw buffer with randomness.
146 ///
147 /// # Safety
148 ///
149 /// This function assumes that both `dst_ptr` and `dst_len`
150 /// correspond to valid chunk of memory. Otherwise the behaviour
151 /// is undefined.
152 unsafe fn fill_raw(&mut self, dst_ptr: *mut u8, dst_len: usize);
153
154 /// Fills the given block with randomness.
155 #[inline(always)]
156 fn fill_block(&mut self, block: &mut [u8]) {
157 unsafe {
158 self.fill_raw(block.as_mut_ptr(), block.len());
159 }
160 }
161
162 /// Generates the next block of given length.
163 #[inline(always)]
164 #[must_use]
165 fn next_block<const N: usize>(&mut self) -> [u8; N] {
166 let mut block = [0u8; N];
167 self.fill_block(&mut block);
168 block
169 }
170}
171
172/// A trait for seeding PRNGs.
173pub trait Seedable<TSeed: ReprC + Copy> {
174 /// Creates a new instance from a given seed.
175 #[must_use]
176 fn with_seed(seed: TSeed) -> Self;
177}