rng.rs

1.9 kB · rust · 73 lines

1use crate::chacha::ChaCha8;23/// A seeded, seekable ChaCha8 random stream.4#[derive(Clone)]5pub struct Rng {6    inner: ChaCha8,7}89impl Rng {10    /// Builds the stream from a seed.11    pub fn new(seed: u64) -> Rng {12        Rng {13            inner: ChaCha8::from_u64(seed),14        }15    }16    /// Draws an integer between lo and hi inclusive, or lo when hi is not above lo.17    pub fn range(&mut self, lo: i64, hi: i64) -> i64 {18        if hi <= lo {19            lo20        } else {21            self.inner.range_i64(lo, hi)22        }23    }24    /// Draws an integer below n, or zero when n is zero.25    pub fn below(&mut self, n: usize) -> usize {26        if n == 0 {27            028        } else {29            self.inner.below_u64(n as u64) as usize30        }31    }32    /// Draws a float at or above zero and below one.33    pub fn unit(&mut self) -> f64 {34        self.inner.unit()35    }36    /// Draws a fair coin flip.37    pub fn boolean(&mut self) -> bool {38        self.inner.boolean()39    }40    /// Returns true with probability p.41    pub fn chance(&mut self, p: f64) -> bool {42        self.unit() < p43    }44    /// Draws one element of the slice.45    pub fn choice<'a, T>(&mut self, items: &'a [T]) -> &'a T {46        &items[self.below(items.len())]47    }48    /// Returns the stream's current word position.49    pub fn pos(&self) -> u128 {50        self.inner.word_pos()51    }52    /// Moves the stream to a word position so later draws replay from there.53    pub fn seek(&mut self, pos: u128) {54        self.inner.set_word_pos(pos);55    }56}5758#[cfg(test)]59mod tests {60    use super::*;61    #[test]62    fn seek_resumes_the_stream() {63        let mut a = Rng::new(7);64        a.below(100);65        a.unit();66        let pos = a.pos();67        let next: Vec<usize> = (0..5).map(|_| a.below(1000)).collect();68        let mut b = Rng::new(7);69        b.seek(pos);70        let again: Vec<usize> = (0..5).map(|_| b.below(1000)).collect();71        assert_eq!(next, again);72    }73}