challenge_prompt/
rng.rs

1use std::fmt;
2
3#[derive(Debug)]
4pub enum RngError {
5    SystemTimeError(std::time::SystemTimeError),
6    EnvVarMissing(String),
7    EnvVarParseError {
8        var_name: String,
9        var_value: String,
10        error: <u32 as std::str::FromStr>::Err,
11    },
12}
13
14impl fmt::Display for RngError {
15    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
16        write!(f, "{:?}", self)
17    }
18}
19
20impl std::error::Error for RngError {}
21
22/// A basic `xorshift` RNG. See
23/// [Wikipedia](https://en.wikipedia.org/wiki/Xorshift) for more details.
24pub struct Rng(u32);
25
26impl Rng {
27    /// Create an `Rng` with the given seed.
28    pub fn new(seed: u32) -> Rng {
29        Rng(seed)
30    }
31
32    /// Create an `Rng` seeded from the current system time.
33    pub fn new_from_time() -> Result<Rng, RngError> {
34        std::time::SystemTime::now()
35            .duration_since(std::time::UNIX_EPOCH)
36            .map(|d| Rng(d.subsec_millis()))
37            .map_err(RngError::SystemTimeError)
38    }
39
40    /// Create an `Rng` seeded from an environment variable.
41    pub fn new_from_env_var(var_name: &str) -> Result<Rng, RngError> {
42        let value = std::env::vars()
43            .find_map(|(key, value)| if key == var_name { Some(value) } else { None })
44            .ok_or_else(|| RngError::EnvVarMissing(var_name.into()))?;
45        value
46            .parse::<u32>()
47            .map(Rng)
48            .map_err(|error| RngError::EnvVarParseError {
49                var_name: var_name.into(),
50                var_value: value,
51                error,
52            })
53    }
54
55    /// Generate a fresh `u32`.
56    ///
57    /// ```
58    /// extern crate challenge_prompt;
59    /// let mut rng = challenge_prompt::Rng::new(100);
60    /// assert_eq!(rng.u32(), 27036706);
61    /// assert_eq!(rng.u32(), 2466775534);
62    ///
63    /// ```
64    pub fn u32(&mut self) -> u32 {
65        let mut x = self.0;
66        x ^= x << 13;
67        x ^= x >> 17;
68        x ^= x << 5;
69        self.0 = x;
70        x
71    }
72}