1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
use std::cell::UnsafeCell;
use std::mem::MaybeUninit;
use std::rc::Rc;
use std::thread_local;

use rand::rngs::SmallRng;
use rand::{RngCore, SeedableRng};

thread_local!(
    static THREAD_RNG_KEY: Rc<UnsafeCell<SmallRng>> = {
        Rc::new(UnsafeCell::new(SmallRng::from_rng(&mut rand::thread_rng()).unwrap()))
    }
);

pub fn fast_thread_rng() -> SmallThreadRng {
    let rng = THREAD_RNG_KEY.with(|t| t.clone());
    SmallThreadRng { rng }
}

pub fn gen_fast_bytes<const N: usize>() -> [u8; N] {
    THREAD_RNG_KEY.with(|t| {
        unsafe {
            // SAFETY: We must make sure to stop using `rng` before anyone else
            // creates another mutable reference
            let rng = &mut *t.get();

            let mut id = MaybeUninit::<[u8; N]>::uninit();
            rng.fill_bytes(&mut *id.as_mut_ptr() as &mut [u8; N]);

            id.assume_init()
        }
    })
}

pub struct SmallThreadRng {
    rng: Rc<UnsafeCell<SmallRng>>,
}

impl RngCore for SmallThreadRng {
    #[inline(always)]
    fn next_u32(&mut self) -> u32 {
        // SAFETY: We must make sure to stop using `rng` before anyone else
        // creates another mutable reference
        let rng = unsafe { &mut *self.rng.get() };
        rng.next_u32()
    }

    #[inline(always)]
    fn next_u64(&mut self) -> u64 {
        // SAFETY: We must make sure to stop using `rng` before anyone else
        // creates another mutable reference
        let rng = unsafe { &mut *self.rng.get() };
        rng.next_u64()
    }

    fn fill_bytes(&mut self, dest: &mut [u8]) {
        // SAFETY: We must make sure to stop using `rng` before anyone else
        // creates another mutable reference
        let rng = unsafe { &mut *self.rng.get() };
        rng.fill_bytes(dest)
    }

    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand::Error> {
        // SAFETY: We must make sure to stop using `rng` before anyone else
        // creates another mutable reference
        let rng = unsafe { &mut *self.rng.get() };
        rng.try_fill_bytes(dest)
    }
}