circus_simulation 0.0.1

Simulation framework inspired by FoundationDB
Documentation
//! Deterministic randomness
use std::ops::Range;

use parking_lot::Mutex;
use rand::distributions::uniform::SampleUniform;
use rand::{Rng, SeedableRng};
use std::sync::Arc;

/// A source of randomness that can be seeded to become deterministic
#[derive(Clone, Debug)]
pub struct Random {
    inner: Arc<Mutex<rand::rngs::SmallRng>>,
}

impl Default for Random {
    fn default() -> Self {
        Self::new()
    }
}

impl Random {
    /// create a non-deterministic random
    pub fn new() -> Self {
        Random {
            inner: Arc::new(Mutex::new(rand::rngs::SmallRng::from_entropy())),
        }
    }

    /// create a deterministic random given a seed
    pub fn new_with_seed(seed: u64) -> Self {
        Random {
            inner: Arc::new(Mutex::new(rand::rngs::SmallRng::seed_from_u64(seed))),
        }
    }
    /// generate a random value between the range
    pub fn random_between<T: SampleUniform + PartialOrd>(&mut self, range: Range<T>) -> T {
        let mut rng = self.inner.lock();
        (*rng).gen_range(range)
    }

    /// generate a random boolean given a probability
    pub fn random_boolean(&mut self, probability: f64) -> bool {
        let mut rng = self.inner.lock();
        (*rng).gen_bool(probability)
    }

    /// generate a float between 0 and 1
    pub fn random_01(&mut self) -> f32 {
        self.random_between(0_f32..1_f32)
    }
}

#[cfg(test)]
mod tests {
    use crate::deterministic::random::Random;

    #[test]
    fn deterministic_random() {
        for seed in 0..9999 {
            let mut a = Random::new_with_seed(seed);
            let mut b = Random::new_with_seed(seed);
            for range in vec![0.0..1.0, 0.0..42.0, 0.0..999.0] {
                for _ in 0..999 {
                    assert_eq!(
                        a.random_between(range.clone()),
                        b.random_between(range.clone())
                    );
                }
            }
        }
    }
}