rand_core/utils.rs
1//! Utilties to aid trait implementations
2//!
3//! ## Portability
4//!
5//! For cross-platform reproducibility, Little-Endian order (least-significant
6//! part first) has been chosen as the standard for inter-type conversion.
7//! For example, [`next_u64_via_u32`] generates two `u32` values `x, y`,
8//! then outputs `(y << 32) | x`.
9//!
10//! Byte-swapping (like the std `to_le` functions) is only needed to convert
11//! to/from byte sequences, and since its purpose is reproducibility,
12//! non-reproducible sources (e.g. `OsRng`) need not bother with it.
13//!
14//! ## Implementing [`TryRng`]
15//!
16//! Usually an implementation of [`TryRng`] will implement one of the three
17//! methods over its internal source. The following helpers are provided for
18//! the remaining implementations.
19//!
20//! **`fn try_next_u32`:**
21//! - `self.next_u64() as u32`
22//! - `(self.next_u64() >> 32) as u32`
23//! - <code>[next_word_via_fill][](self)</code>
24//!
25//! **`fn try_next_u64`:**
26//! - <code>[next_u64_via_u32][](self)</code>
27//! - <code>[next_word_via_fill][](self)</code>
28//!
29//! **`fn try_fill_bytes`:**
30//! - <code>[fill_bytes_via_next_word][](self, dest)</code>
31//!
32//! ## Implementing [`SeedableRng`]
33//!
34//! In many cases, [`SeedableRng::Seed`] must be converted to `[u32; _]` or
35//! `[u64; _]`. [`read_words`] may be used for this.
36//!
37//! [`SeedableRng`]: crate::SeedableRng
38//! [`SeedableRng::Seed`]: crate::SeedableRng::Seed
39//!
40//! ## Example
41//!
42//! We demonstrate a simple multiplicative congruential generator (MCG), taken
43//! from M.E. O'Neill's blog post [Does It Beat the Minimal Standard?][0].
44//!
45//! [0]: https://www.pcg-random.org/posts/does-it-beat-the-minimal-standard.html
46//!
47//! ```
48//! use core::convert::Infallible;
49//! use rand_core::{Rng, SeedableRng, TryRng, utils};
50//!
51//! pub struct Mcg128(u128);
52//!
53//! impl SeedableRng for Mcg128 {
54//! type Seed = [u8; 16];
55//!
56//! #[inline]
57//! fn from_seed(seed: Self::Seed) -> Self {
58//! // Always use little-endian byte order to ensure portable results
59//! Self(u128::from_le_bytes(seed))
60//! }
61//! }
62//!
63//! impl TryRng for Mcg128 {
64//! type Error = Infallible;
65//!
66//! #[inline]
67//! fn try_next_u32(&mut self) -> Result<u32, Infallible> {
68//! Ok((self.next_u64() >> 32) as u32)
69//! }
70//!
71//! #[inline]
72//! fn try_next_u64(&mut self) -> Result<u64, Infallible> {
73//! self.0 = self.0.wrapping_mul(0x0fc94e3bf4e9ab32866458cd56f5e605);
74//! Ok((self.0 >> 64) as u64)
75//! }
76//!
77//! #[inline]
78//! fn try_fill_bytes(&mut self, dst: &mut [u8]) -> Result<(), Infallible> {
79//! utils::fill_bytes_via_next_word(dst, || self.try_next_u64())
80//! }
81//! }
82//! #
83//! # let mut rng = Mcg128::seed_from_u64(42);
84//! # assert_eq!(rng.next_u32(), 3443086493);
85//! # assert_eq!(rng.next_u64(), 3462997187007721903);
86//! # let mut buf = [0u8; 5];
87//! # rng.fill_bytes(&mut buf);
88//! # assert_eq!(buf, [154, 23, 43, 68, 75]);
89//! ```
90
91use crate::TryRng;
92pub use crate::word::Word;
93
94/// Generate a `u64` using `next_u32`, little-endian order.
95#[inline]
96pub fn next_u64_via_u32<R: TryRng + ?Sized>(rng: &mut R) -> Result<u64, R::Error> {
97 // Use LE; we explicitly generate one value before the next.
98 let x = u64::from(rng.try_next_u32()?);
99 let y = u64::from(rng.try_next_u32()?);
100 Ok((y << 32) | x)
101}
102
103/// Fill `dst` with bytes using `next_word`
104///
105/// This may be used to implement `fill_bytes` over `next_u32` or
106/// `next_u64`. Words are used in order of generation. The last word may be
107/// partially discarded.
108#[inline]
109pub fn fill_bytes_via_next_word<E, W: Word>(
110 dst: &mut [u8],
111 mut next_word: impl FnMut() -> Result<W, E>,
112) -> Result<(), E> {
113 let mut chunks = dst.chunks_exact_mut(size_of::<W>());
114 for chunk in &mut chunks {
115 let val = next_word()?;
116 chunk.copy_from_slice(val.to_le_bytes().as_ref());
117 }
118 let rem = chunks.into_remainder();
119 if !rem.is_empty() {
120 let val = next_word()?.to_le_bytes();
121 rem.copy_from_slice(&val.as_ref()[..rem.len()]);
122 }
123 Ok(())
124}
125
126/// Generate a `u32` or `u64` word using `fill_bytes`
127pub fn next_word_via_fill<W: Word, R: TryRng>(rng: &mut R) -> Result<W, R::Error> {
128 let mut buf: W::Bytes = Default::default();
129 rng.try_fill_bytes(buf.as_mut())?;
130 Ok(W::from_le_bytes(buf))
131}
132
133/// Reads an array of words from a byte slice
134///
135/// Words are read from `src` in order, using LE conversion from bytes.
136///
137/// # Panics
138///
139/// Panics if `size_of_val(src) != size_of::<[W; N]>()`.
140#[inline(always)]
141pub fn read_words<W: Word, const N: usize>(src: &[u8]) -> [W; N] {
142 assert_eq!(size_of_val(src), size_of::<[W; N]>());
143 let mut dst = [W::from_usize(0); N];
144 let chunks = src.chunks_exact(size_of::<W>());
145 for (out, chunk) in dst.iter_mut().zip(chunks) {
146 let mut buf: W::Bytes = Default::default();
147 buf.as_mut().copy_from_slice(chunk);
148 *out = W::from_le_bytes(buf);
149 }
150 dst
151}