use std::any::type_name;
use better_any::{Tid, TidAble};
use rand::{RngCore, SeedableRng};
use rand_chacha::ChaCha12Rng;
use serde::Serialize;
use crate::state::CustomState;
#[derive(Tid)]
pub struct Random {
config: RandomConfig,
constructor: fn(u64) -> Random,
inner: Box<dyn RngCore + Send>,
}
impl CustomState<'_> for Random {}
#[derive(Debug, Clone, Serialize)]
pub struct RandomConfig {
pub name: &'static str,
pub seed: u64,
}
impl Random {
pub fn new(seed: u64) -> Self {
Random::with_rng::<ChaCha12Rng>(seed)
}
pub fn with_rng<RNG>(seed: u64) -> Self
where
RNG: RngCore + SeedableRng + Send + 'static,
{
Random {
config: RandomConfig {
name: type_name::<RNG>(),
seed,
},
constructor: |seed: u64| Random::with_rng::<RNG>(seed),
inner: Box::new(RNG::seed_from_u64(seed)),
}
}
pub fn testing() -> Self {
Random::new(0)
}
pub fn config(&self) -> &RandomConfig {
&self.config
}
pub fn iter_children(&mut self) -> RandomIter {
RandomIter { rng: self }
}
}
impl RngCore for Random {
fn next_u32(&mut self) -> u32 {
self.inner.next_u32()
}
fn next_u64(&mut self) -> u64 {
self.inner.next_u64()
}
fn fill_bytes(&mut self, dest: &mut [u8]) {
self.inner.fill_bytes(dest)
}
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand::Error> {
self.inner.try_fill_bytes(dest)
}
}
impl Default for Random {
fn default() -> Self {
Random::new(rand::thread_rng().next_u64())
}
}
pub struct RandomIter<'a> {
rng: &'a mut Random,
}
impl<'a> Iterator for RandomIter<'a> {
type Item = Random;
fn next(&mut self) -> Option<Self::Item> {
let seed = self.rng.next_u64();
Some((self.rng.constructor)(seed))
}
}
impl<'a> IntoIterator for &'a mut Random {
type Item = Random;
type IntoIter = RandomIter<'a>;
fn into_iter(self) -> Self::IntoIter {
self.iter_children()
}
}