seeded_random/
rng.rs

1use std::sync::Arc;
2
3use parking_lot::RwLock;
4use rand::distributions::{Alphanumeric, Standard};
5use rand::prelude::Distribution;
6use rand::{Rng, SeedableRng};
7use rand_chacha::ChaCha12Rng;
8
9use crate::Seed;
10
11#[derive(Debug)]
12#[must_use]
13/// The main RNG data structure.
14pub struct Random {
15  rng: Arc<RwLock<ChaCha12Rng>>,
16}
17
18#[must_use]
19#[cfg(feature = "std")]
20pub(crate) fn new_seed() -> Seed {
21  let mut rng = rand::thread_rng();
22  Seed(rng.gen())
23}
24
25impl Random {
26  /// Create a new RNG from a new, random seed.
27  #[cfg(feature = "std")]
28  pub fn new() -> Self {
29    Self::from_seed(new_seed())
30  }
31
32  // Need to allow this lint so we can write an API that consumes the Seed even
33  // though it's not technically necessary.
34  #[allow(clippy::needless_pass_by_value)]
35  /// Create a new [Random] RNG from a seed.
36  pub fn from_seed(seed: Seed) -> Self {
37    let rng = ChaCha12Rng::seed_from_u64(seed.0);
38    Self {
39      rng: Arc::new(RwLock::new(rng)),
40    }
41  }
42
43  /// Generated a new seed from this RNG.
44  pub fn seed(&self) -> Seed {
45    Seed(self.gen())
46  }
47
48  #[must_use]
49  /// Function that delegates to [rand::Rng::gen()]
50  pub fn gen<T>(&self) -> T
51  where
52    Standard: Distribution<T>,
53  {
54    let mut rng = self.rng.write();
55    rng.gen()
56  }
57
58  /// Utility function to generate a new [u32]
59  pub fn u32(&self) -> u32 {
60    self.gen()
61  }
62
63  /// Utility function to generate a new [i32]
64  pub fn i32(&self) -> i32 {
65    self.gen()
66  }
67
68  /// Utility function to generate a new [Vec] of bytes.
69  pub fn bytes(&self, length: usize) -> Vec<u8> {
70    let mut bytes: Vec<u8> = Vec::with_capacity(length);
71    let mut rng = self.rng.write();
72    for _ in 0..length {
73      bytes.push(rng.gen());
74    }
75    bytes
76  }
77
78  /// Utility function to generate a new [String]
79  pub fn string(&self, length: usize) -> String {
80    let mut string: String = String::with_capacity(length);
81    let mut rng = self.rng.write();
82
83    for _ in 0..length {
84      string.push(rng.gen());
85    }
86    string
87  }
88
89  /// Utility function to generate a new [String] consisting only of numbers and letters.
90  pub fn alphanumeric(&self, length: usize) -> String {
91    let mut rng = self.rng.write();
92    let chars: String = std::iter::repeat(())
93      .map(|()| rng.sample(Alphanumeric))
94      .map(char::from)
95      .take(length)
96      .collect();
97    chars
98  }
99
100  /// Utility function to generate a new [uuid::Uuid]
101  #[cfg(feature = "uuid")]
102  pub fn uuid(&self) -> uuid::Uuid {
103    let mut raw_bytes: [u8; 16] = [0; 16];
104    let mut rng = self.rng.write();
105    rng.fill(&mut raw_bytes);
106    let bytes: uuid::Bytes = raw_bytes;
107    let builder = uuid::Builder::from_bytes(bytes);
108    builder.into_uuid()
109  }
110
111  /// Utility function that delegates to [rand::Rng::gen_range()]
112  pub fn range(&self, min: u32, max: u32) -> u32 {
113    let mut rng = self.rng.write();
114    rng.gen_range(min..max)
115  }
116}
117
118#[cfg(feature = "std")]
119impl Default for Random {
120  fn default() -> Self {
121    Self::new()
122  }
123}
124
125#[cfg(test)]
126mod tests {
127  use super::*;
128
129  #[test]
130  fn bytes() {
131    let rng = Random::from_seed(Seed(100000));
132    let bytes1 = rng.bytes(10);
133    let bytes2 = rng.bytes(10);
134    assert_ne!(bytes1, bytes2);
135    let rng = Random::from_seed(Seed(100000));
136    let bytes2 = rng.bytes(10);
137    assert_eq!(bytes1, bytes2);
138  }
139  #[test]
140  fn string() {
141    let rng = Random::from_seed(Seed(100000));
142    let v1 = rng.string(10);
143    let v2 = rng.string(10);
144    assert_ne!(v1, v2);
145    let rng = Random::from_seed(Seed(100000));
146    let v2 = rng.string(10);
147    assert_eq!(v1, v2);
148  }
149
150  #[test]
151  fn alphanum() {
152    let rng = Random::from_seed(Seed(100000));
153    let v1 = rng.alphanumeric(10);
154    let v2 = rng.alphanumeric(10);
155    assert_ne!(v1, v2);
156    let rng = Random::from_seed(Seed(100000));
157    let v2 = rng.alphanumeric(10);
158    assert_eq!(v1, v2);
159  }
160
161  #[test]
162  #[cfg(feature = "uuid")]
163  fn uuid() {
164    let rng = Random::from_seed(Seed(100000));
165    let v1 = rng.uuid();
166    let v2 = rng.uuid();
167    assert_ne!(v1, v2);
168    let rng = Random::from_seed(Seed(100000));
169    let v2 = rng.uuid();
170    assert_eq!(v1, v2);
171  }
172}