epoch_rng 0.1.0

Simple epoch‑based PRNG and configurable LCG PRNG.
Documentation
use std::time::{SystemTime, UNIX_EPOCH};

pub struct EpochRng {
    state: u64,
}

impl EpochRng {
    pub fn new() -> Self {
        let seed = SystemTime::now()
            .duration_since(UNIX_EPOCH)
            .expect("System time before UNIX epoch")
            .as_nanos() as u64;
        Self { state: seed }
    }

    pub fn from_seed(seed: u64) -> Self {
        Self { state: seed }
    }

    pub fn next_u64(&mut self) -> u64 {
        self.state = self.state.wrapping_mul(6364136223846793005).wrapping_add(1442695040888963407);
        self.state
    }

    pub fn next_u32(&mut self) -> u32 {
        (self.next_u64() >> 32) as u32
    }

    pub fn next_f64(&mut self) -> f64 {
        (self.next_u64() >> 11) as f64 * (1.0 / 9007199254740992.0)
    }

    pub fn gen_range(&mut self, low: f64, high: f64) -> f64 {
        assert!(low < high, "low must be less than high");
        low + (high - low) * self.next_f64()
    }

    pub fn gen_range_i32(&mut self, low: i32, high: i32) -> i32 {
        assert!(low < high, "low must be less than high");
        low + (self.next_u32() % (high - low) as u32) as i32
    }

    pub fn gen_range_usize(&mut self, low: usize, high: usize) -> usize {
        assert!(low < high, "low must be less than high");
        low + (self.next_u64() as usize % (high - low))
    }

    pub fn shuffle<T>(&mut self, slice: &mut [T]) {
        for i in (1..slice.len()).rev() {
            let j = self.gen_range_usize(0, i + 1);
            slice.swap(i, j);
        }
    }
}

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


pub struct LcgRng {
    state: u64,
    a: u64,
    b: u64,
    m: u64,
}


impl LcgRng {
    pub fn new() -> Self {
        let seed = SystemTime::now()
            .duration_since(UNIX_EPOCH)
            .expect("System time before UNIX epoch")
            .as_nanos() as u64;
        Self::from_seed(seed)
    }

    pub fn from_seed(seed: u64) -> Self {
        Self {
            state: seed,
            a: 1103515245,
            b: 12345,
            m: 1u64 << 32,
        }
    }

    pub fn with_params(seed: u64, a: u64, b: u64, m: u64) -> Self {
        Self { state: seed, a, b, m }
    }

    pub fn next_u64(&mut self) -> u64 {
        self.state = (self.a.wrapping_mul(self.state).wrapping_add(self.b)) % self.m;
        self.state
    }

    pub fn next_u32(&mut self) -> u32 {
        self.next_u64() as u32
    }

    pub fn next_f64(&mut self) -> f64 {
        self.next_u64() as f64 / self.m as f64
    }

    pub fn gen_range(&mut self, low: f64, high: f64) -> f64 {
        assert!(low < high, "low must be less than high");
        low + (high - low) * self.next_f64()
    }

    pub fn gen_range_i32(&mut self, low: i32, high: i32) -> i32 {
        assert!(low < high, "low must be less than high");
        low + (self.next_u32() % (high - low) as u32) as i32
    }

    pub fn gen_range_usize(&mut self, low: usize, high: usize) -> usize {
        assert!(low < high, "low must be less than high");
        low + (self.next_u64() as usize % (high - low))
    }
}

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