use crate::prelude::*;
use parking_lot::Mutex;
use rand::distributions::uniform::{SampleRange, SampleUniform};
use rand::distributions::{self, Distribution};
use rand::seq::SliceRandom;
use rand::{Rng as _, SeedableRng as _};
use rand_xoshiro::Xoshiro256StarStar;
use std::cell::RefCell;
pub fn chance(probability: f64) -> bool {
THREAD_RNG.with(|rng| rng.borrow_mut().gen_chance(probability))
}
pub fn fill_bytes(bytes: &mut [u8]) {
THREAD_RNG.with(|rng| rng.borrow_mut().fill_bytes(bytes))
}
pub fn random<T: Random>() -> T {
THREAD_RNG.with(|rng| T::random_with(&mut rng.borrow_mut()))
}
pub fn range<T: SampleUniform>(range: impl SampleRange<T>) -> T {
THREAD_RNG.with(|rng| rng.borrow_mut().gen_range(range))
}
pub fn ratio<T: Number + SampleUniform>(numerator: T, denominator: T) -> bool {
THREAD_RNG.with(|rng| rng.borrow_mut().gen_ratio(numerator, denominator))
}
pub fn shuffle<T>(slice: &mut [T]) {
THREAD_RNG.with(|rng| rng.borrow_mut().shuffle(slice))
}
pub trait Random: Sized {
fn random_with(rng: &mut Rng) -> Self;
fn random() -> Self {
random()
}
}
impl<T> Random for T
where
distributions::Standard: Distribution<T>,
{
fn random_with(rng: &mut Rng) -> Self {
rng.inner.gen()
}
}
#[derive(Clone)]
pub struct Rng {
inner: Xoshiro256StarStar,
}
static GLOBAL_RNG: Lazy<Mutex<Rng>> =
Lazy::new(|| Mutex::new(Rng { inner: Xoshiro256StarStar::from_entropy() }));
thread_local! {
static THREAD_RNG: RefCell<Rng> = {
let mut global_rng = GLOBAL_RNG.lock();
let thread_rng = global_rng.clone();
global_rng.inner.long_jump();
RefCell::new(thread_rng)
};
}
impl Rng {
pub fn new() -> Rng {
THREAD_RNG.with(|rng| {
let mut thread_rng = rng.borrow_mut();
let local_rng = thread_rng.clone();
thread_rng.inner.jump();
local_rng
})
}
pub fn fill_bytes(&mut self, bytes: &mut [u8]) {
self.inner.fill(bytes);
}
pub fn gen<T: Random>(&mut self) -> T {
T::random_with(self)
}
pub fn gen_chance(&mut self, probability: f64) -> bool {
probability > self.gen()
}
pub fn gen_range<T: SampleUniform>(&mut self, range: impl SampleRange<T>) -> T {
self.inner.gen_range(range)
}
pub fn gen_ratio<T: Number + SampleUniform>(&mut self, numerator: T, denominator: T) -> bool {
debug_assert!(denominator > T::zero(), "The denominator of a ratio must be greater than zero.");
numerator > self.gen_range(T::zero()..denominator)
}
pub fn shuffle<T>(&mut self, slice: &mut [T]) {
slice.shuffle(&mut self.inner);
}
}
impl Default for Rng {
fn default() -> Self {
Self::new()
}
}