diff options
| author | Huon Wilson <dbau.pp+github@gmail.com> | 2013-09-29 16:49:11 +1000 |
|---|---|---|
| committer | Huon Wilson <dbau.pp+github@gmail.com> | 2013-10-09 22:22:42 +1100 |
| commit | 0223cf65e41cc1046b306dcd0e3959a20729e0cf (patch) | |
| tree | fe56fd6db779bbabcb2e8ea5f3f62ca0ff99e4c3 /src/libstd | |
| parent | f39a215f270bc8c958a19cc9f693720232340cbc (diff) | |
| download | rust-0223cf65e41cc1046b306dcd0e3959a20729e0cf.tar.gz rust-0223cf65e41cc1046b306dcd0e3959a20729e0cf.zip | |
std::rand: Add ReseedingRng, which will reseed an RNG after it generates a certain number of bytes.
It is an "RNG adaptor" and so any RNG can be wrapped to have this behaviour.
Diffstat (limited to 'src/libstd')
| -rw-r--r-- | src/libstd/rand/mod.rs | 1 | ||||
| -rw-r--r-- | src/libstd/rand/reseeding.rs | 128 |
2 files changed, 129 insertions, 0 deletions
diff --git a/src/libstd/rand/mod.rs b/src/libstd/rand/mod.rs index 4528174a212..9fb6863692b 100644 --- a/src/libstd/rand/mod.rs +++ b/src/libstd/rand/mod.rs @@ -62,6 +62,7 @@ pub mod distributions; pub mod isaac; pub mod os; pub mod reader; +pub mod reseeding; /// A type that can be randomly generated using an Rng pub trait Rand { diff --git a/src/libstd/rand/reseeding.rs b/src/libstd/rand/reseeding.rs new file mode 100644 index 00000000000..d471a5e4e10 --- /dev/null +++ b/src/libstd/rand/reseeding.rs @@ -0,0 +1,128 @@ +// 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 rand::Rng; +use default::Default; + +/// How many bytes of entropy the underling RNG is allowed to generate +/// before it is reseeded. +static DEFAULT_GENERATION_THRESHOLD: uint = 32 * 1024; + +/// A wrapper around any RNG which reseeds the underlying RNG after it +/// has generated a certain number of random bytes. +pub struct ReseedingRng<R, Rsdr> { + priv rng: R, + priv generation_threshold: uint, + priv bytes_generated: uint, + /// Controls the behaviour when reseeding the RNG. + 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: uint, 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(); + self.fill_bytes(dest) + } +} + +/// Something that can be used to reseed an RNG via `ReseedingRng`. +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. +pub struct ReseedWithDefault; + +impl<R: Rng + Default> Reseeder<R> for ReseedWithDefault { + fn reseed(&mut self, rng: &mut R) { + *rng = Default::default(); + } +} + +#[cfg(test)] +mod test { + use super::*; + use rand::Rng; + use default::Default; + + 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 } + } + } + + #[test] + fn test_reseeding() { + let mut rs = ReseedingRng::from_options(Counter {i:0}, 100, ReseedWithDefault); + + let mut i = 0; + for _ in range(0, 1000) { + assert_eq!(rs.next_u32(), i % 100); + i += 1; + } + } +} |
