blob: 1f24e2006fd20dad1cf6e60f447b36b472ddb9ec [file] [log] [blame]
// 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);
}
}