about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorHuon Wilson <dbau.pp+github@gmail.com>2013-09-29 16:49:11 +1000
committerHuon Wilson <dbau.pp+github@gmail.com>2013-10-09 22:22:42 +1100
commit0223cf65e41cc1046b306dcd0e3959a20729e0cf (patch)
treefe56fd6db779bbabcb2e8ea5f3f62ca0ff99e4c3 /src/libstd
parentf39a215f270bc8c958a19cc9f693720232340cbc (diff)
downloadrust-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.rs1
-rw-r--r--src/libstd/rand/reseeding.rs128
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;
+        }
+    }
+}