use rand::{rngs::StdRng, Rng, SeedableRng};
use std::{
marker::PhantomData,
sync::{Arc, Mutex},
};
pub trait WithRng {
type Rng: Rng;
type Output;
fn with_rng(&mut self, fun: &mut dyn FnMut(&mut Self::Rng) -> Self::Output) -> Self::Output;
}
#[derive(Debug, Clone, PartialEq)]
pub struct RngBox<R = StdRng, O = usize>(R, PhantomData<*const O>);
impl<R: Rng, O> RngBox<R, O> {
pub fn new(rng: R) -> Self {
Self(rng, PhantomData::default())
}
}
impl<R: SeedableRng + Rng, O> RngBox<R, O> {
pub fn new_seedable(seed: Option<u64>) -> Self {
Self::new(seed.map_or_else(R::from_entropy, R::seed_from_u64))
}
}
impl<R: SeedableRng + Rng, O> Default for RngBox<R, O> {
fn default() -> Self {
Self::new_seedable(None)
}
}
impl<R: Rng, O> WithRng for RngBox<R, O> {
type Rng = R;
type Output = O;
fn with_rng(&mut self, fun: &mut dyn FnMut(&mut R) -> Self::Output) -> Self::Output {
fun(&mut self.0)
}
}
unsafe impl<R: Send, O: Send> Send for RngBox<R, O> {}
unsafe impl<R: Sync, O: Sync> Sync for RngBox<R, O> {}
#[derive(Debug, Clone)]
pub struct SyncRngBox<R = StdRng, O = usize>(Arc<Mutex<R>>, PhantomData<*const O>);
impl<R: Rng, O> SyncRngBox<R, O> {
pub fn new(rng: R) -> Self {
Self(Arc::new(Mutex::new(rng)), PhantomData::default())
}
}
impl<R: SeedableRng + Rng, O> SyncRngBox<R, O> {
pub fn new_seedable(seed: Option<u64>) -> Self {
Self::new(seed.map_or_else(R::from_entropy, R::seed_from_u64))
}
}
impl<R: SeedableRng + Rng, O> Default for SyncRngBox<R, O> {
fn default() -> Self {
Self::new_seedable(None)
}
}
impl<R: Rng, O> WithRng for SyncRngBox<R, O> {
type Rng = R;
type Output = O;
fn with_rng(&mut self, fun: &mut dyn FnMut(&mut R) -> Self::Output) -> Self::Output {
fun(&mut self.0.lock().expect("Mutex fail"))
}
}
unsafe impl<R: Send, O: Send> Send for SyncRngBox<R, O> {}
unsafe impl<R: Sync, O: Sync> Sync for SyncRngBox<R, O> {}