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 11 use rand_core::{Error, RngCore, SeedableRng}; 12 13 #[cfg(target_pointer_width = "64")] 14 type Rng = super::xoshiro256plusplus::Xoshiro256PlusPlus; 15 #[cfg(not(target_pointer_width = "64"))] 16 type 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)] 81 pub struct SmallRng(Rng); 82 83 impl RngCore for SmallRng { 84 #[inline(always)] next_u32(&mut self) -> u3285 fn next_u32(&mut self) -> u32 { 86 self.0.next_u32() 87 } 88 89 #[inline(always)] next_u64(&mut self) -> u6490 fn next_u64(&mut self) -> u64 { 91 self.0.next_u64() 92 } 93 94 #[inline(always)] fill_bytes(&mut self, dest: &mut [u8])95 fn fill_bytes(&mut self, dest: &mut [u8]) { 96 self.0.fill_bytes(dest); 97 } 98 99 #[inline(always)] try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error>100 fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { 101 self.0.try_fill_bytes(dest) 102 } 103 } 104 105 impl SeedableRng for SmallRng { 106 type Seed = <Rng as SeedableRng>::Seed; 107 108 #[inline(always)] from_seed(seed: Self::Seed) -> Self109 fn from_seed(seed: Self::Seed) -> Self { 110 SmallRng(Rng::from_seed(seed)) 111 } 112 113 #[inline(always)] from_rng<R: RngCore>(rng: R) -> Result<Self, Error>114 fn from_rng<R: RngCore>(rng: R) -> Result<Self, Error> { 115 Rng::from_rng(rng).map(SmallRng) 116 } 117 } 118