use rand::{Rng, Rand, SeedableRng, XorShiftRng};
use rand::distributions::range::SampleRange;
use std::fmt;
pub type GASeed = [u32; 4];
pub struct GARandomCtx
{
seed: GASeed,
rng: XorShiftRng,
name: String,
seeded: bool,
values_generated: u32
}
impl GARandomCtx
{
pub fn new_unseeded(name: String) -> GARandomCtx
{
let std_rng = XorShiftRng::new_unseeded();
GARandomCtx
{
seed: [0; 4],
rng: std_rng,
name: name,
seeded: false,
values_generated: 0
}
}
pub fn from_seed(seed: GASeed, name: String) -> GARandomCtx
{
let std_rng = SeedableRng::from_seed(seed);
GARandomCtx
{
seed: seed,
rng: std_rng,
name: name,
seeded: true,
values_generated: 0
}
}
pub fn gen<T: Rand>(&mut self) -> T where Self: Sized
{
self.values_generated += 1;
self.rng.gen()
}
pub fn gen_range<T: PartialOrd + SampleRange>(&mut self, low: T, high: T) -> T
{
self.values_generated += 1;
self.rng.gen_range(low, high)
}
pub fn next_u32(&mut self) -> u32 { self.gen::<u32>() }
pub fn next_u64(&mut self) -> u64 { self.gen::<u64>() }
pub fn next_f32(&mut self) -> f32 { self.gen::<f32>() }
pub fn next_f64(&mut self) -> f64 { self.gen::<f64>() }
pub fn test_value<T: PartialOrd + Rand>(&mut self, value: T) -> bool
{
self.gen::<T>() < value
}
pub fn reseed(&mut self, seed: GASeed)
{
self.seed = seed;
self.seeded = true;
self.reset();
}
pub fn reset(&mut self)
{
self.values_generated = 0;
if self.seeded
{
self.rng.reseed(self.seed);
}
else
{
self.rng = XorShiftRng::new_unseeded();
}
}
}
impl fmt::Debug for GARandomCtx
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
{
let seeded_str = if self.seeded
{
"Seeded"
}
else
{
"Not Seeded"
};
write!(f, "GARandomCtx {} - {} {{ seed: {:?}, values_generated: {:?} }}",
self.name,
seeded_str,
self.seed,
self.values_generated)
}
}
#[cfg(test)]
mod test
{
extern crate env_logger;
use super::{GASeed, GARandomCtx};
#[test]
fn same_seed()
{
let _ = env_logger::init();
let seed : GASeed = [1,2,3,4];
let mut ga_ctx = GARandomCtx::from_seed(seed, String::from("TestRandomCtx"));
let mut ga_ctx_2 = GARandomCtx::from_seed(seed, String::from("TestRandomCtx2"));
debug!("{:?}", ga_ctx);
debug!("{:?}", ga_ctx_2);
for _ in 0..100
{
assert_eq!(ga_ctx.gen::<f64>(), ga_ctx_2.gen::<f64>());
}
debug!("{:?}", ga_ctx);
debug!("{:?}", ga_ctx_2);
for _ in 0..100
{
assert_eq!(ga_ctx.gen::<u32>(), ga_ctx_2.gen::<u32>());
}
debug!("{:?}", ga_ctx);
debug!("{:?}", ga_ctx_2);
}
#[test]
fn diff_seed()
{
let _ = env_logger::init();
let seed_1 : GASeed = [1,2,3,4];
let seed_2 : GASeed = [4,3,2,1];
let mut ga_ctx = GARandomCtx::from_seed(seed_1, String::from("TestRandomCtx"));
let mut ga_ctx_2 = GARandomCtx::from_seed(seed_2, String::from("TestRandomCtx2"));
debug!("{:?}", ga_ctx);
debug!("{:?}", ga_ctx_2);
for _ in 0..100
{
assert!(ga_ctx.gen::<f32>() != ga_ctx_2.gen::<f32>());
}
debug!("{:?}", ga_ctx);
debug!("{:?}", ga_ctx_2);
for _ in 0..100
{
assert!(ga_ctx.gen::<u64>() != ga_ctx_2.gen::<u64>());
}
debug!("{:?}", ga_ctx);
debug!("{:?}", ga_ctx_2);
}
#[test]
fn same_seed_different_types()
{
let _ = env_logger::init();
let seed_1 = [1; 4];
let mut ga_ctx = GARandomCtx::from_seed(seed_1, String::from("TestRandomCtx"));
let mut ga_ctx_2 = GARandomCtx::from_seed(seed_1, String::from("TestRandomCtx"));
debug!("{:?}", ga_ctx.gen::<f32>());
debug!("{:?}", ga_ctx_2.gen::<i8>());
assert_eq!(ga_ctx.gen::<f32>(), ga_ctx_2.gen::<f32>());
}
}