humphrey_server/server/
rand.rs

1//! Provides a simple LCG implementation for generating random numbers.
2
3use std::time::SystemTime;
4
5/// Represents a linear congruential generator, used to generate random `u32` numbers.
6#[derive(Clone, Debug, PartialEq, Eq)]
7pub struct Lcg {
8    modulus: usize,
9    multiplier: usize,
10    increment: usize,
11    seed: usize,
12}
13
14/// Allows random sampling on an object.
15pub trait Choose {
16    /// The type of the object.
17    type Item;
18
19    /// Selects a random item from the collection.
20    fn choose(&self, lcg: &mut Lcg) -> Option<&Self::Item>;
21}
22
23impl Lcg {
24    /// Creates a new linear congruential generator with default parameters.
25    /// Default parameters are taken from [glibc](https://sourceware.org/git/?p=glibc.git;a=blob;f=stdlib/random_r.c;hb=glibc-2.26#l362).
26    /// Modulus has been reduced by one so as to not be a direct power of two, reducing patterns.
27    pub fn new() -> Self {
28        Lcg {
29            modulus: 2_usize.pow(31) - 1,
30            multiplier: 1103515245,
31            increment: 12345,
32            seed: SystemTime::now()
33                .duration_since(SystemTime::UNIX_EPOCH)
34                .unwrap()
35                .as_secs() as usize,
36        }
37    }
38
39    /// Creates a new linear congruential generator with the specified parameters.
40    #[allow(dead_code)]
41    pub fn with_parameters(
42        modulus: usize,
43        multiplier: usize,
44        increment: usize,
45        seed: usize,
46    ) -> Self {
47        Lcg {
48            modulus,
49            multiplier,
50            increment,
51            seed,
52        }
53    }
54}
55
56impl Default for Lcg {
57    fn default() -> Self {
58        Self::new()
59    }
60}
61
62impl Iterator for Lcg {
63    type Item = u32;
64
65    fn next(&mut self) -> Option<Self::Item> {
66        let value = (self.multiplier * self.seed + self.increment) % self.modulus;
67        self.seed = value;
68
69        Some(value as u32)
70    }
71}
72
73impl<T> Choose for [T] {
74    type Item = T;
75
76    fn choose(&self, lcg: &mut Lcg) -> Option<&Self::Item> {
77        let value = lcg.next().unwrap();
78        self.get((value % self.len() as u32) as usize)
79    }
80}