rand_core/block.rs
1//! The [`Generator`] trait and [`BlockRng`]
2//!
3//! Trait [`Generator`] may be implemented by block-generators; that is PRNGs
4//! whose output is a *block* of words, such as `[u32; 16]`.
5//!
6//! The struct [`BlockRng`] wraps such a [`Generator`] together with an output
7//! buffer and implements several methods (e.g. [`BlockRng::next_word`]) to
8//! assist in the implementation of [`TryRng`]. Note that (unlike in earlier
9//! versions of `rand_core`) [`BlockRng`] itself does not implement [`TryRng`]
10//! since in practice we found it was always beneficial to use a wrapper type
11//! over [`BlockRng`].
12//!
13//! # Example
14//!
15//! ```
16//! use core::convert::Infallible;
17//! use rand_core::{Rng, SeedableRng, TryRng};
18//! use rand_core::block::{Generator, BlockRng};
19//!
20//! struct MyRngCore {
21//! // Generator state ...
22//! # state: [u32; 8],
23//! }
24//!
25//! impl Generator for MyRngCore {
26//! type Output = [u32; 8];
27//!
28//! fn generate(&mut self, output: &mut Self::Output) {
29//! // Write a new block to output...
30//! # *output = self.state;
31//! }
32//! }
33//!
34//! // Our RNG is a wrapper over BlockRng
35//! pub struct MyRng(BlockRng<MyRngCore>);
36//!
37//! impl SeedableRng for MyRng {
38//! type Seed = [u8; 32];
39//! fn from_seed(seed: Self::Seed) -> Self {
40//! let core = MyRngCore {
41//! // ...
42//! # state: rand_core::utils::read_words(&seed),
43//! };
44//! MyRng(BlockRng::new(core))
45//! }
46//! }
47//!
48//! impl TryRng for MyRng {
49//! type Error = Infallible;
50//!
51//! #[inline]
52//! fn try_next_u32(&mut self) -> Result<u32, Infallible> {
53//! Ok(self.0.next_word())
54//! }
55//!
56//! #[inline]
57//! fn try_next_u64(&mut self) -> Result<u64, Infallible> {
58//! Ok(self.0.next_u64_from_u32())
59//! }
60//!
61//! #[inline]
62//! fn try_fill_bytes(&mut self, bytes: &mut [u8]) -> Result<(), Infallible> {
63//! Ok(self.0.fill_bytes(bytes))
64//! }
65//! }
66//!
67//! // And if applicable: impl TryCryptoRng for MyRng {}
68//!
69//! let mut rng = MyRng::seed_from_u64(0);
70//! println!("First value: {}", rng.next_u32());
71//! # assert_eq!(rng.next_u32(), 1171109249);
72//! ```
73//!
74//! [`TryRng`]: crate::TryRng
75//! [`SeedableRng`]: crate::SeedableRng
76
77use crate::utils::Word;
78use core::fmt;
79
80/// A random (block) generator
81pub trait Generator {
82 /// The output type.
83 ///
84 /// For use with [`rand_core::block`](crate::block) code this must be `[u32; _]` or `[u64; _]`.
85 type Output;
86
87 /// Generate a new block of `output`.
88 ///
89 /// This must fill `output` with random data.
90 fn generate(&mut self, output: &mut Self::Output);
91
92 /// Destruct the output buffer
93 ///
94 /// This method is called on [`Drop`] of the [`Self::Output`] buffer.
95 /// The default implementation does nothing.
96 #[inline]
97 fn drop(&mut self, output: &mut Self::Output) {
98 let _ = output;
99 }
100}
101
102/// RNG functionality for a block [`Generator`]
103///
104/// This type encompasses a [`Generator`] [`core`](Self::core) and a buffer.
105/// It provides optimized implementations of methods required by an [`Rng`].
106///
107/// All values are consumed in-order of generation. No whole words (e.g. `u32`
108/// or `u64`) are discarded, though where a word is partially used (e.g. for a
109/// byte-fill whose length is not a multiple of the word size) the rest of the
110/// word is discarded.
111///
112/// [`Rng`]: crate::Rng
113#[derive(Clone)]
114pub struct BlockRng<G: Generator> {
115 results: G::Output,
116 /// The *core* part of the RNG, implementing the `generate` function.
117 pub core: G,
118}
119
120// Custom Debug implementation that does not expose the contents of `results`.
121impl<G> fmt::Debug for BlockRng<G>
122where
123 G: Generator + fmt::Debug,
124{
125 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
126 fmt.debug_struct("BlockRng")
127 .field("core", &self.core)
128 .finish_non_exhaustive()
129 }
130}
131
132impl<G: Generator> Drop for BlockRng<G> {
133 fn drop(&mut self) {
134 self.core.drop(&mut self.results);
135 }
136}
137
138impl<W: Word + Default, const N: usize, G: Generator<Output = [W; N]>> BlockRng<G> {
139 /// Create a new `BlockRng` from an existing RNG implementing
140 /// `Generator`. Results will be generated on first use.
141 #[inline]
142 pub fn new(core: G) -> BlockRng<G> {
143 let mut results = [W::default(); N];
144 results[0] = W::from_usize(N);
145 BlockRng { core, results }
146 }
147
148 /// Reconstruct from a core and a remaining-results buffer.
149 ///
150 /// This may be used to deserialize using a `core` and the output of
151 /// [`Self::remaining_results`].
152 ///
153 /// Returns `None` if `remaining_results` is too long.
154 pub fn reconstruct(core: G, remaining_results: &[W]) -> Option<Self> {
155 let mut results = [W::default(); N];
156 if remaining_results.len() < N {
157 let index = N - remaining_results.len();
158 results[index..].copy_from_slice(remaining_results);
159 results[0] = W::from_usize(index);
160 Some(BlockRng { results, core })
161 } else {
162 None
163 }
164 }
165}
166
167impl<W: Word, const N: usize, G: Generator<Output = [W; N]>> BlockRng<G> {
168 /// Get the index into the result buffer.
169 ///
170 /// If this is equal to or larger than the size of the result buffer then
171 /// the buffer is "empty" and `generate()` must be called to produce new
172 /// results.
173 #[inline(always)]
174 fn index(&self) -> usize {
175 self.results[0].into_usize()
176 }
177
178 #[inline(always)]
179 fn set_index(&mut self, index: usize) {
180 debug_assert!(0 < index && index <= N);
181 self.results[0] = W::from_usize(index);
182 }
183
184 /// Re-generate buffer contents, skipping the first `n` words
185 ///
186 /// Existing buffer contents are discarded. A new set of results is
187 /// generated (either immediately or when next required). The first `n`
188 /// words are skipped (this may be used to set a specific word position).
189 ///
190 /// # Panics
191 ///
192 /// This method will panic if `n >= N` where `N` is the buffer size (in
193 /// words).
194 #[inline]
195 pub fn reset_and_skip(&mut self, n: usize) {
196 if n == 0 {
197 self.set_index(N);
198 return;
199 }
200
201 assert!(n < N);
202 self.core.generate(&mut self.results);
203 self.set_index(n);
204 }
205
206 /// Get the number of words consumed since the start of the block
207 ///
208 /// The result is in the range `0..N` where `N` is the buffer size (in
209 /// words).
210 #[inline]
211 pub fn word_offset(&self) -> usize {
212 let index = self.index();
213 if index >= N { 0 } else { index }
214 }
215
216 /// Access the unused part of the results buffer
217 ///
218 /// The length of the returned slice is guaranteed to be less than the
219 /// length of `<Self as Generator>::Output` (i.e. less than `N` where
220 /// `Output = [W; N]`).
221 ///
222 /// This is a low-level interface intended for serialization.
223 /// Results are not marked as consumed.
224 #[inline]
225 pub fn remaining_results(&self) -> &[W] {
226 let index = self.index();
227 &self.results[index..]
228 }
229
230 /// Generate the next word (e.g. `u32`)
231 #[inline]
232 pub fn next_word(&mut self) -> W {
233 let mut index = self.index();
234 if index >= N {
235 self.core.generate(&mut self.results);
236 index = 0;
237 }
238
239 let value = self.results[index];
240 self.set_index(index + 1);
241 value
242 }
243}
244
245impl<const N: usize, G: Generator<Output = [u32; N]>> BlockRng<G> {
246 /// Generate a `u64` from two `u32` words
247 #[inline]
248 pub fn next_u64_from_u32(&mut self) -> u64 {
249 let index = self.index();
250 let mut new_index;
251 let (mut lo, mut hi);
252 if index < N - 1 {
253 lo = self.results[index];
254 hi = self.results[index + 1];
255 new_index = index + 2;
256 } else {
257 lo = self.results[N - 1];
258 self.core.generate(&mut self.results);
259 hi = self.results[0];
260 new_index = 1;
261 if index >= N {
262 lo = hi;
263 hi = self.results[1];
264 new_index = 2;
265 }
266 }
267 self.set_index(new_index);
268 (u64::from(hi) << 32) | u64::from(lo)
269 }
270}
271
272impl<W: Word, const N: usize, G: Generator<Output = [W; N]>> BlockRng<G> {
273 /// Fill `dest`
274 #[inline]
275 pub fn fill_bytes(&mut self, dest: &mut [u8]) {
276 let mut read_len = 0;
277 let mut index = self.index();
278 while read_len < dest.len() {
279 if index >= N {
280 self.core.generate(&mut self.results);
281 index = 0;
282 }
283
284 let size = core::mem::size_of::<W>();
285 let mut chunks = dest[read_len..].chunks_exact_mut(size);
286 let mut src = self.results[index..].iter();
287
288 let zipped = chunks.by_ref().zip(src.by_ref());
289 let num_chunks = zipped.len();
290 zipped.for_each(|(chunk, src)| chunk.copy_from_slice(src.to_le_bytes().as_ref()));
291 index += num_chunks;
292 read_len += num_chunks * size;
293
294 if let Some(src) = src.next() {
295 // We have consumed all full chunks of dest, but not src.
296 let dest_rem = chunks.into_remainder();
297 let n = dest_rem.len();
298 if n > 0 {
299 dest_rem.copy_from_slice(&src.to_le_bytes().as_ref()[..n]);
300 index += 1;
301 debug_assert_eq!(read_len + n, dest.len());
302 }
303 break;
304 }
305 }
306 self.set_index(index);
307 }
308}