rand_dev/
lib.rs

1#![doc = include_str!("../README.md")]
2
3#[cfg(feature = "rand-v09")]
4pub use rand;
5
6use rand_chacha::ChaCha8Rng;
7use rand_core::{CryptoRng, OsRng, RngCore, SeedableRng, TryRngCore};
8
9/// Reproducible random generator for tests
10#[derive(Debug, Clone)]
11pub struct DevRng(ChaCha8Rng);
12
13impl DevRng {
14    const VAR_NAME: &'static str = "RUST_TESTS_SEED";
15
16    /// Constructs randomness generator
17    ///
18    /// Reads a seed from env variable `RUST_TESTS_SEED` or generates a random seed if env variable is not set.
19    /// Prints seed to stderr.
20    ///
21    /// Panics if `RUST_TESTS_SEED` contains invalid value.
22    #[track_caller]
23    pub fn new() -> Self {
24        let mut seed = [0u8; 32];
25        match std::env::var(Self::VAR_NAME) {
26            Ok(provided_seed) => const_hex::decode_to_slice(provided_seed, &mut seed)
27                .expect("provided seed is not valid"),
28            Err(std::env::VarError::NotUnicode(_)) => {
29                panic!("provided seed is not a valid unicode")
30            }
31            Err(std::env::VarError::NotPresent) => OsRng
32                .try_fill_bytes(&mut seed)
33                .expect("system randomness unavailable"),
34        }
35        eprintln!("RUST_TESTS_SEED={}", const_hex::encode(seed));
36
37        DevRng(ChaCha8Rng::from_seed(seed))
38    }
39
40    /// Derives another randomness generator from this instance
41    ///
42    /// Uses `self` to generate a seed and constructs a new instance of `DevRng` from the seed.
43    ///
44    /// May be useful when you have several threads/futures/places where you need access the
45    /// randomness generation, but you don't want to mess with ownership system.
46    pub fn fork(&mut self) -> Self {
47        let mut seed = [0u8; 32];
48        self.fill_bytes(&mut seed);
49        Self::from_seed(seed)
50    }
51
52    /// Retrieves generator seed
53    pub fn get_seed(&self) -> [u8; 32] {
54        self.0.get_seed()
55    }
56}
57
58impl Default for DevRng {
59    fn default() -> Self {
60        Self::new()
61    }
62}
63
64impl RngCore for DevRng {
65    fn next_u32(&mut self) -> u32 {
66        self.0.next_u32()
67    }
68
69    fn next_u64(&mut self) -> u64 {
70        self.0.next_u64()
71    }
72
73    fn fill_bytes(&mut self, dest: &mut [u8]) {
74        self.0.fill_bytes(dest)
75    }
76}
77
78impl SeedableRng for DevRng {
79    type Seed = <ChaCha8Rng as SeedableRng>::Seed;
80
81    fn from_seed(seed: Self::Seed) -> Self {
82        DevRng(ChaCha8Rng::from_seed(seed))
83    }
84
85    fn seed_from_u64(state: u64) -> Self {
86        DevRng(ChaCha8Rng::seed_from_u64(state))
87    }
88
89    fn from_rng(rng: &mut impl RngCore) -> Self {
90        Self(ChaCha8Rng::from_rng(rng))
91    }
92
93    fn try_from_rng<R: TryRngCore>(rng: &mut R) -> Result<Self, R::Error> {
94        ChaCha8Rng::try_from_rng(rng).map(Self)
95    }
96
97    fn from_os_rng() -> Self {
98        Self(ChaCha8Rng::from_os_rng())
99    }
100
101    fn try_from_os_rng() -> Result<Self, getrandom::Error> {
102        ChaCha8Rng::try_from_os_rng().map(Self)
103    }
104}
105
106impl CryptoRng for DevRng {}