| 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::{RngCore, SeedableRng}; |
| 12 | |
| 13 | #[cfg (any(target_pointer_width = "32" , target_pointer_width = "16" ))] |
| 14 | type Rng = super::xoshiro128plusplus::Xoshiro128PlusPlus; |
| 15 | #[cfg (target_pointer_width = "64" )] |
| 16 | type Rng = super::xoshiro256plusplus::Xoshiro256PlusPlus; |
| 17 | |
| 18 | /// A small-state, fast, non-crypto, non-portable PRNG |
| 19 | /// |
| 20 | /// This is the "standard small" RNG, a generator with the following properties: |
| 21 | /// |
| 22 | /// - Non-[portable]: any future library version may replace the algorithm |
| 23 | /// and results may be platform-dependent. |
| 24 | /// (For a small portable generator, use the [rand_pcg] or [rand_xoshiro] crate.) |
| 25 | /// - Non-cryptographic: output is easy to predict (insecure) |
| 26 | /// - [Quality]: statistically good quality |
| 27 | /// - Fast: the RNG is fast for both bulk generation and single values, with |
| 28 | /// consistent cost of method calls |
| 29 | /// - Fast initialization |
| 30 | /// - Small state: little memory usage (current state size is 16-32 bytes |
| 31 | /// depending on platform) |
| 32 | /// |
| 33 | /// The current algorithm is |
| 34 | /// `Xoshiro256PlusPlus` on 64-bit platforms and `Xoshiro128PlusPlus` on 32-bit |
| 35 | /// platforms. Both are also implemented by the [rand_xoshiro] crate. |
| 36 | /// |
| 37 | /// ## Seeding (construction) |
| 38 | /// |
| 39 | /// This generator implements the [`SeedableRng`] trait. All methods are |
| 40 | /// suitable for seeding, but note that, even with a fixed seed, output is not |
| 41 | /// [portable]. Some suggestions: |
| 42 | /// |
| 43 | /// 1. To automatically seed with a unique seed, use [`SeedableRng::from_rng`]: |
| 44 | /// ``` |
| 45 | /// use rand::SeedableRng; |
| 46 | /// use rand::rngs::SmallRng; |
| 47 | /// let rng = SmallRng::from_rng(&mut rand::rng()); |
| 48 | /// # let _: SmallRng = rng; |
| 49 | /// ``` |
| 50 | /// or [`SeedableRng::from_os_rng`]: |
| 51 | /// ``` |
| 52 | /// # use rand::SeedableRng; |
| 53 | /// # use rand::rngs::SmallRng; |
| 54 | /// let rng = SmallRng::from_os_rng(); |
| 55 | /// # let _: SmallRng = rng; |
| 56 | /// ``` |
| 57 | /// 2. To use a deterministic integral seed, use `seed_from_u64`. This uses a |
| 58 | /// hash function internally to yield a (typically) good seed from any |
| 59 | /// input. |
| 60 | /// ``` |
| 61 | /// # use rand::{SeedableRng, rngs::SmallRng}; |
| 62 | /// let rng = SmallRng::seed_from_u64(1); |
| 63 | /// # let _: SmallRng = rng; |
| 64 | /// ``` |
| 65 | /// 3. To seed deterministically from text or other input, use [`rand_seeder`]. |
| 66 | /// |
| 67 | /// See also [Seeding RNGs] in the book. |
| 68 | /// |
| 69 | /// ## Generation |
| 70 | /// |
| 71 | /// The generators implements [`RngCore`] and thus also [`Rng`][crate::Rng]. |
| 72 | /// See also the [Random Values] chapter in the book. |
| 73 | /// |
| 74 | /// [portable]: https://rust-random.github.io/book/crate-reprod.html |
| 75 | /// [Seeding RNGs]: https://rust-random.github.io/book/guide-seeding.html |
| 76 | /// [Random Values]: https://rust-random.github.io/book/guide-values.html |
| 77 | /// [Quality]: https://rust-random.github.io/book/guide-rngs.html#quality |
| 78 | /// [`StdRng`]: crate::rngs::StdRng |
| 79 | /// [rand_pcg]: https://crates.io/crates/rand_pcg |
| 80 | /// [rand_xoshiro]: https://crates.io/crates/rand_xoshiro |
| 81 | /// [`rand_chacha::ChaCha8Rng`]: https://docs.rs/rand_chacha/latest/rand_chacha/struct.ChaCha8Rng.html |
| 82 | /// [`rand_seeder`]: https://docs.rs/rand_seeder/latest/rand_seeder/ |
| 83 | #[derive (Clone, Debug, PartialEq, Eq)] |
| 84 | pub struct SmallRng(Rng); |
| 85 | |
| 86 | impl SeedableRng for SmallRng { |
| 87 | // Fix to 256 bits. Changing this is a breaking change! |
| 88 | type Seed = [u8; 32]; |
| 89 | |
| 90 | #[inline (always)] |
| 91 | fn from_seed(seed: Self::Seed) -> Self { |
| 92 | // This is for compatibility with 32-bit platforms where Rng::Seed has a different seed size |
| 93 | // With MSRV >= 1.77: let seed = *seed.first_chunk().unwrap() |
| 94 | const LEN: usize = core::mem::size_of::<<Rng as SeedableRng>::Seed>(); |
| 95 | let seed: [u8; 32] = (&seed[..LEN]).try_into().unwrap(); |
| 96 | SmallRng(Rng::from_seed(seed)) |
| 97 | } |
| 98 | |
| 99 | #[inline (always)] |
| 100 | fn seed_from_u64(state: u64) -> Self { |
| 101 | SmallRng(Rng::seed_from_u64(state)) |
| 102 | } |
| 103 | } |
| 104 | |
| 105 | impl RngCore for SmallRng { |
| 106 | #[inline (always)] |
| 107 | fn next_u32(&mut self) -> u32 { |
| 108 | self.0.next_u32() |
| 109 | } |
| 110 | |
| 111 | #[inline (always)] |
| 112 | fn next_u64(&mut self) -> u64 { |
| 113 | self.0.next_u64() |
| 114 | } |
| 115 | |
| 116 | #[inline (always)] |
| 117 | fn fill_bytes(&mut self, dest: &mut [u8]) { |
| 118 | self.0.fill_bytes(dst:dest) |
| 119 | } |
| 120 | } |
| 121 | |