Skip to main content

lgp/utils/
random.rs

1use std::{cell::UnsafeCell, rc::Rc};
2
3use rand::{RngCore, SeedableRng};
4use rand_xoshiro::Xoshiro256PlusPlus;
5
6type InternalGenerator = Rc<UnsafeCell<Xoshiro256PlusPlus>>;
7
8#[derive(Clone, Debug)]
9pub struct Random {
10    rng: InternalGenerator,
11}
12
13thread_local! {
14    static GENERATOR: InternalGenerator = {
15        let prng = Xoshiro256PlusPlus::from_entropy();
16
17        Rc::new(UnsafeCell::new(prng))
18    }
19}
20
21/// This function should only be called once and at the top level of a program.
22pub fn update_seed(seed: Option<u64>) {
23    let prng = match seed {
24        Some(internal_seed) => Xoshiro256PlusPlus::seed_from_u64(internal_seed),
25        None => Xoshiro256PlusPlus::from_entropy(),
26    };
27
28    GENERATOR.with(|t| {
29        let generator = unsafe { &mut *t.get() };
30        *generator = prng;
31    });
32}
33
34pub fn generator() -> Random {
35    let rng = GENERATOR.with(|t| t.clone());
36    Random { rng }
37}
38
39impl Default for Random {
40    fn default() -> Self {
41        generator()
42    }
43}
44
45impl RngCore for Random {
46    fn next_u32(&mut self) -> u32 {
47        let rng = unsafe { &mut *self.rng.get() };
48        rng.next_u32()
49    }
50
51    fn next_u64(&mut self) -> u64 {
52        let rng = unsafe { &mut *self.rng.get() };
53        rng.next_u64()
54    }
55
56    fn fill_bytes(&mut self, dest: &mut [u8]) {
57        let rng = unsafe { &mut *self.rng.get() };
58        rng.fill_bytes(dest)
59    }
60
61    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand::Error> {
62        let rng = unsafe { &mut *self.rng.get() };
63        rng.try_fill_bytes(dest)
64    }
65}