1// Copyright 2018 Developers of the Rand project.
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9//! A small fast RNG
10
11use rand_core::{Error, RngCore, SeedableRng};
12
13#[cfg(target_pointer_width = "64")]
14type Rng = super::xoshiro256plusplus::Xoshiro256PlusPlus;
15#[cfg(not(target_pointer_width = "64"))]
16type Rng = super::xoshiro128plusplus::Xoshiro128PlusPlus;
17
18/// A small-state, fast non-crypto PRNG
19///
20/// `SmallRng` may be a good choice when a PRNG with small state, cheap
21/// initialization, good statistical quality and good performance are required.
22/// Note that depending on the application, [`StdRng`] may be faster on many
23/// modern platforms while providing higher-quality randomness. Furthermore,
24/// `SmallRng` is **not** a good choice when:
25/// - Security against prediction is important. Use [`StdRng`] instead.
26/// - Seeds with many zeros are provided. In such cases, it takes `SmallRng`
27/// about 10 samples to produce 0 and 1 bits with equal probability. Either
28/// provide seeds with an approximately equal number of 0 and 1 (for example
29/// by using [`SeedableRng::from_entropy`] or [`SeedableRng::seed_from_u64`]),
30/// or use [`StdRng`] instead.
31///
32/// The algorithm is deterministic but should not be considered reproducible
33/// due to dependence on platform and possible replacement in future
34/// library versions. For a reproducible generator, use a named PRNG from an
35/// external crate, e.g. [rand_xoshiro] or [rand_chacha].
36/// Refer also to [The Book](https://rust-random.github.io/book/guide-rngs.html).
37///
38/// The PRNG algorithm in `SmallRng` is chosen to be efficient on the current
39/// platform, without consideration for cryptography or security. The size of
40/// its state is much smaller than [`StdRng`]. The current algorithm is
41/// `Xoshiro256PlusPlus` on 64-bit platforms and `Xoshiro128PlusPlus` on 32-bit
42/// platforms. Both are also implemented by the [rand_xoshiro] crate.
43///
44/// # Examples
45///
46/// Initializing `SmallRng` with a random seed can be done using [`SeedableRng::from_entropy`]:
47///
48/// ```
49/// use rand::{Rng, SeedableRng};
50/// use rand::rngs::SmallRng;
51///
52/// // Create small, cheap to initialize and fast RNG with a random seed.
53/// // The randomness is supplied by the operating system.
54/// let mut small_rng = SmallRng::from_entropy();
55/// # let v: u32 = small_rng.gen();
56/// ```
57///
58/// When initializing a lot of `SmallRng`'s, using [`thread_rng`] can be more
59/// efficient:
60///
61/// ```
62/// use rand::{SeedableRng, thread_rng};
63/// use rand::rngs::SmallRng;
64///
65/// // Create a big, expensive to initialize and slower, but unpredictable RNG.
66/// // This is cached and done only once per thread.
67/// let mut thread_rng = thread_rng();
68/// // Create small, cheap to initialize and fast RNGs with random seeds.
69/// // One can generally assume this won't fail.
70/// let rngs: Vec<SmallRng> = (0..10)
71/// .map(|_| SmallRng::from_rng(&mut thread_rng).unwrap())
72/// .collect();
73/// ```
74///
75/// [`StdRng`]: crate::rngs::StdRng
76/// [`thread_rng`]: crate::thread_rng
77/// [rand_chacha]: https://crates.io/crates/rand_chacha
78/// [rand_xoshiro]: https://crates.io/crates/rand_xoshiro
79#[cfg_attr(doc_cfg, doc(cfg(feature = "small_rng")))]
80#[derive(Clone, Debug, PartialEq, Eq)]
81pub struct SmallRng(Rng);
82
83impl RngCore for SmallRng {
84 #[inline(always)]
85 fn next_u32(&mut self) -> u32 {
86 self.0.next_u32()
87 }
88
89 #[inline(always)]
90 fn next_u64(&mut self) -> u64 {
91 self.0.next_u64()
92 }
93
94 #[inline(always)]
95 fn fill_bytes(&mut self, dest: &mut [u8]) {
96 self.0.fill_bytes(dest);
97 }
98
99 #[inline(always)]
100 fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
101 self.0.try_fill_bytes(dest)
102 }
103}
104
105impl SeedableRng for SmallRng {
106 type Seed = <Rng as SeedableRng>::Seed;
107
108 #[inline(always)]
109 fn from_seed(seed: Self::Seed) -> Self {
110 SmallRng(Rng::from_seed(seed))
111 }
112
113 #[inline(always)]
114 fn from_rng<R: RngCore>(rng: R) -> Result<Self, Error> {
115 Rng::from_rng(rng).map(op:SmallRng)
116 }
117}
118