use std::cell::RefCell;
use std::sync::Mutex;
use once_cell::sync::Lazy;
use rand::rngs::StdRng;
use rand::{Rng, SeedableRng};
pub fn with_thread_rng<F, T>(f: F) -> T
where
F: FnMut(&mut StdRng) -> T,
{
thread_local! {
static THREAD_RNG: RefCell<StdRng> = RefCell::new(seeded_std_rng());
}
THREAD_RNG.with_borrow_mut(f)
}
pub fn random<T>() -> T
where
rand::distributions::Standard: rand::distributions::Distribution<T>,
{
with_thread_rng(|rng| rng.gen())
}
fn seeded_std_rng() -> StdRng {
let seed = {
let mut rng = SEED_RNG.lock().unwrap();
rng.gen()
};
StdRng::from_seed(seed)
}
static SEED_RNG: Lazy<Mutex<StdRng>> = Lazy::new(|| {
let env_seed: Option<u64> = {
match std::env::var("JUNCTION_SEED") {
Ok(seed_str) => seed_str.parse().ok(),
_ => None,
}
};
let rng = match env_seed {
Some(seed) => StdRng::seed_from_u64(seed),
None => StdRng::from_entropy(),
};
Mutex::new(rng)
});