| // Copyright 2013 The Rust Project Developers. See the COPYRIGHT |
| // file at the top-level directory of this distribution and at |
| // http://rust-lang.org/COPYRIGHT. |
| // |
| // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or |
| // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license |
| // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your |
| // option. This file may not be copied, modified, or distributed |
| // except according to those terms. |
| |
| //! A wrapper around another RNG that reseeds it after it |
| //! generates a certain number of random bytes. |
| |
| use core::default::Default; |
| |
| use {Rng, SeedableRng}; |
| |
| /// How many bytes of entropy the underling RNG is allowed to generate |
| /// before it is reseeded |
| const DEFAULT_GENERATION_THRESHOLD: u64 = 32 * 1024; |
| |
| /// A wrapper around any RNG which reseeds the underlying RNG after it |
| /// has generated a certain number of random bytes. |
| #[derive(Debug)] |
| pub struct ReseedingRng<R, Rsdr> { |
| rng: R, |
| generation_threshold: u64, |
| bytes_generated: u64, |
| /// Controls the behaviour when reseeding the RNG. |
| pub reseeder: Rsdr, |
| } |
| |
| impl<R: Rng, Rsdr: Reseeder<R>> ReseedingRng<R, Rsdr> { |
| /// Create a new `ReseedingRng` with the given parameters. |
| /// |
| /// # Arguments |
| /// |
| /// * `rng`: the random number generator to use. |
| /// * `generation_threshold`: the number of bytes of entropy at which to reseed the RNG. |
| /// * `reseeder`: the reseeding object to use. |
| pub fn new(rng: R, generation_threshold: u64, reseeder: Rsdr) -> ReseedingRng<R,Rsdr> { |
| ReseedingRng { |
| rng: rng, |
| generation_threshold: generation_threshold, |
| bytes_generated: 0, |
| reseeder: reseeder |
| } |
| } |
| |
| /// Reseed the internal RNG if the number of bytes that have been |
| /// generated exceed the threshold. |
| pub fn reseed_if_necessary(&mut self) { |
| if self.bytes_generated >= self.generation_threshold { |
| self.reseeder.reseed(&mut self.rng); |
| self.bytes_generated = 0; |
| } |
| } |
| } |
| |
| |
| impl<R: Rng, Rsdr: Reseeder<R>> Rng for ReseedingRng<R, Rsdr> { |
| fn next_u32(&mut self) -> u32 { |
| self.reseed_if_necessary(); |
| self.bytes_generated += 4; |
| self.rng.next_u32() |
| } |
| |
| fn next_u64(&mut self) -> u64 { |
| self.reseed_if_necessary(); |
| self.bytes_generated += 8; |
| self.rng.next_u64() |
| } |
| |
| fn fill_bytes(&mut self, dest: &mut [u8]) { |
| self.reseed_if_necessary(); |
| self.bytes_generated += dest.len() as u64; |
| self.rng.fill_bytes(dest) |
| } |
| } |
| |
| impl<S, R: SeedableRng<S>, Rsdr: Reseeder<R> + Default> |
| SeedableRng<(Rsdr, S)> for ReseedingRng<R, Rsdr> { |
| fn reseed(&mut self, (rsdr, seed): (Rsdr, S)) { |
| self.rng.reseed(seed); |
| self.reseeder = rsdr; |
| self.bytes_generated = 0; |
| } |
| |
| /// Create a new `ReseedingRng` from the given reseeder and |
| /// seed. This uses a default value for `generation_threshold`. |
| fn from_seed((rsdr, seed): (Rsdr, S)) -> ReseedingRng<R, Rsdr> { |
| ReseedingRng { |
| rng: SeedableRng::from_seed(seed), |
| generation_threshold: DEFAULT_GENERATION_THRESHOLD, |
| bytes_generated: 0, |
| reseeder: rsdr |
| } |
| } |
| } |
| |
| /// Something that can be used to reseed an RNG via `ReseedingRng`. |
| /// |
| /// # Example |
| /// |
| /// ```rust |
| /// use rand::{Rng, SeedableRng, StdRng}; |
| /// use rand::reseeding::{Reseeder, ReseedingRng}; |
| /// |
| /// struct TickTockReseeder { tick: bool } |
| /// impl Reseeder<StdRng> for TickTockReseeder { |
| /// fn reseed(&mut self, rng: &mut StdRng) { |
| /// let val = if self.tick {0} else {1}; |
| /// rng.reseed(&[val]); |
| /// self.tick = !self.tick; |
| /// } |
| /// } |
| /// fn main() { |
| /// let rsdr = TickTockReseeder { tick: true }; |
| /// |
| /// let inner = StdRng::new().unwrap(); |
| /// let mut rng = ReseedingRng::new(inner, 10, rsdr); |
| /// |
| /// // this will repeat, because it gets reseeded very regularly. |
| /// let s: String = rng.gen_ascii_chars().take(100).collect(); |
| /// println!("{}", s); |
| /// } |
| /// |
| /// ``` |
| pub trait Reseeder<R> { |
| /// Reseed the given RNG. |
| fn reseed(&mut self, rng: &mut R); |
| } |
| |
| /// Reseed an RNG using a `Default` instance. This reseeds by |
| /// replacing the RNG with the result of a `Default::default` call. |
| #[derive(Clone, Copy, Debug)] |
| pub struct ReseedWithDefault; |
| |
| impl<R: Rng + Default> Reseeder<R> for ReseedWithDefault { |
| fn reseed(&mut self, rng: &mut R) { |
| *rng = Default::default(); |
| } |
| } |
| impl Default for ReseedWithDefault { |
| fn default() -> ReseedWithDefault { ReseedWithDefault } |
| } |
| |
| #[cfg(test)] |
| mod test { |
| use std::default::Default; |
| use std::iter::repeat; |
| use super::{ReseedingRng, ReseedWithDefault}; |
| use {SeedableRng, Rng}; |
| |
| struct Counter { |
| i: u32 |
| } |
| |
| impl Rng for Counter { |
| fn next_u32(&mut self) -> u32 { |
| self.i += 1; |
| // very random |
| self.i - 1 |
| } |
| } |
| impl Default for Counter { |
| fn default() -> Counter { |
| Counter { i: 0 } |
| } |
| } |
| impl SeedableRng<u32> for Counter { |
| fn reseed(&mut self, seed: u32) { |
| self.i = seed; |
| } |
| fn from_seed(seed: u32) -> Counter { |
| Counter { i: seed } |
| } |
| } |
| type MyRng = ReseedingRng<Counter, ReseedWithDefault>; |
| |
| #[test] |
| fn test_reseeding() { |
| let mut rs = ReseedingRng::new(Counter {i:0}, 400, ReseedWithDefault); |
| |
| let mut i = 0; |
| for _ in 0..1000 { |
| assert_eq!(rs.next_u32(), i % 100); |
| i += 1; |
| } |
| } |
| |
| #[test] |
| fn test_rng_seeded() { |
| let mut ra: MyRng = SeedableRng::from_seed((ReseedWithDefault, 2)); |
| let mut rb: MyRng = SeedableRng::from_seed((ReseedWithDefault, 2)); |
| assert!(::test::iter_eq(ra.gen_ascii_chars().take(100), |
| rb.gen_ascii_chars().take(100))); |
| } |
| |
| #[test] |
| fn test_rng_reseed() { |
| let mut r: MyRng = SeedableRng::from_seed((ReseedWithDefault, 3)); |
| let string1: String = r.gen_ascii_chars().take(100).collect(); |
| |
| r.reseed((ReseedWithDefault, 3)); |
| |
| let string2: String = r.gen_ascii_chars().take(100).collect(); |
| assert_eq!(string1, string2); |
| } |
| |
| const FILL_BYTES_V_LEN: usize = 13579; |
| #[test] |
| fn test_rng_fill_bytes() { |
| let mut v = repeat(0u8).take(FILL_BYTES_V_LEN).collect::<Vec<_>>(); |
| ::test::rng().fill_bytes(&mut v); |
| |
| // Sanity test: if we've gotten here, `fill_bytes` has not infinitely |
| // recursed. |
| assert_eq!(v.len(), FILL_BYTES_V_LEN); |
| |
| // To test that `fill_bytes` actually did something, check that the |
| // average of `v` is not 0. |
| let mut sum = 0.0; |
| for &x in v.iter() { |
| sum += x as f64; |
| } |
| assert!(sum / v.len() as f64 != 0.0); |
| } |
| } |