use rand::{Error, Rng, RngCore, SeedableRng};
use rand_core::impls;
use rand_xorshift::XorShiftRng;
use std::{cell::RefCell, fmt};
pub trait RngDebug: RngCore + fmt::Debug {}
impl RngDebug for XorShiftRng {}
#[derive(Clone, Copy, Debug)]
pub enum RngChoice {
Random,
Seeded([u32; 4]),
}
pub fn new_common_rng(seed: RngChoice) -> XorShiftRng {
let seed = match seed {
RngChoice::Random => rand::thread_rng().gen(),
RngChoice::Seeded(seed) => seed,
};
println!("Seed: {:?}", seed);
let mut rng = XorShiftRng::from_seed(convert_seed(seed));
RNG.with(|thread_rng| *thread_rng.borrow_mut() = new_rng(&mut rng));
rng
}
pub fn new_rng<R: RngCore>(rng: &mut R) -> XorShiftRng {
let new_seed = [
rng.next_u32().wrapping_add(rng.next_u32()),
rng.next_u32().wrapping_add(rng.next_u32()),
rng.next_u32().wrapping_add(rng.next_u32()),
rng.next_u32().wrapping_add(rng.next_u32()),
];
XorShiftRng::from_seed(convert_seed(new_seed))
}
pub fn thread_rng() -> XorShiftRng {
RNG.with(|rng| new_rng(&mut *rng.borrow_mut()))
}
thread_local! {
static RNG: RefCell<XorShiftRng> = RefCell::new(XorShiftRng::from_seed(rand::thread_rng().gen()));
}
pub struct ReplayRng {
values: Vec<u32>,
index: usize,
}
impl ReplayRng {
pub fn new(values: Vec<u32>) -> Self {
Self { values, index: 0 }
}
}
impl RngCore for ReplayRng {
fn next_u32(&mut self) -> u32 {
let value = unwrap!(self.values.get(self.index));
self.index += 1;
*value
}
fn next_u64(&mut self) -> u64 {
impls::next_u64_via_u32(self)
}
fn fill_bytes(&mut self, dest: &mut [u8]) {
impls::fill_bytes_via_next(self, dest)
}
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
self.fill_bytes(dest);
Ok(())
}
}
fn convert_seed(src: [u32; 4]) -> [u8; 16] {
let mut bytes = [0; 16];
let mut index = 0;
for num in src.iter() {
for num_byte in &num.to_le_bytes() {
bytes[index] = *num_byte;
index += 1;
}
}
bytes
}