use std::{cell::UnsafeCell, rc::Rc};
#[cfg(feature = "csprng")]
mod blockrngbased {
use super::*;
use rand::rngs::{adapter::ReseedingRng, OsRng};
use rand::SeedableRng;
const THREAD_RNG_RESEED_THRESHOLD: u64 = 1024 * 64 * 1000;
type Core = rand_chacha::ChaCha8Core;
thread_local!(
static THREAD_RNG_KEY: Rc<UnsafeCell<ReseedingRng<Core, OsRng>>> = {
let r = Core::from_rng(OsRng).unwrap_or_else(|err|
panic!("could not initialize thread_rng: {}", err));
let rng = ReseedingRng::new(r,
THREAD_RNG_RESEED_THRESHOLD,
OsRng);
Rc::new(UnsafeCell::new(rng))
}
);
pub struct ThreadRng {
pub(super) rng: Rc<UnsafeCell<ReseedingRng<Core, OsRng>>>,
}
pub fn lpn_thread_rng() -> ThreadRng {
let rng = THREAD_RNG_KEY.with(|t| t.clone());
ThreadRng { rng }
}
}
#[cfg(feature = "csprng")]
pub use blockrngbased::{lpn_thread_rng, ThreadRng};
#[cfg(not(feature = "csprng"))]
mod xoshiro {
use super::*;
use rand::SeedableRng;
use rand_xoshiro::Xoshiro256PlusPlus;
thread_local! {
static THREAD_RNG_KEY: Rc<UnsafeCell<Xoshiro256PlusPlus>> = {
Rc::new(UnsafeCell::new(Xoshiro256PlusPlus::from_entropy()))
}
}
pub struct ThreadRng {
pub(super) rng: Rc<UnsafeCell<Xoshiro256PlusPlus>>,
}
pub fn lpn_thread_rng() -> ThreadRng {
let rng = THREAD_RNG_KEY.with(|t| t.clone());
ThreadRng { rng }
}
}
#[cfg(not(feature = "csprng"))]
pub use xoshiro::{lpn_thread_rng, ThreadRng};
impl rand::RngCore for ThreadRng {
#[inline(always)]
fn next_u32(&mut self) -> u32 {
let rng = unsafe { &mut *self.rng.get() };
rng.next_u32()
}
#[inline(always)]
fn next_u64(&mut self) -> u64 {
let rng = unsafe { &mut *self.rng.get() };
rng.next_u64()
}
#[inline(always)]
fn fill_bytes(&mut self, dest: &mut [u8]) {
let rng = unsafe { &mut *self.rng.get() };
rng.fill_bytes(dest)
}
#[inline(always)]
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand::Error> {
let rng = unsafe { &mut *self.rng.get() };
rng.try_fill_bytes(dest)
}
}
impl rand::CryptoRng for ThreadRng {}