From 7c4d8a27ff8a296eb7150dc7f53624cd9b35edcd Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Sat, 13 Jan 2018 19:20:26 +0100 Subject: [PATCH] Replace ReseedWithDefault with ReseedWithNew --- src/lib.rs | 60 +++++++++++++++++------------------------------- src/reseeding.rs | 36 ++++++++++++++--------------- 2 files changed, 39 insertions(+), 57 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index ee82c5cb0a4..c67bc1aa079 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -276,6 +276,7 @@ use prng::Isaac64Rng as IsaacWordRng; use distributions::{Range, IndependentSample}; use distributions::range::SampleRange; +use reseeding::{ReseedingRng, ReseedWithNew}; // public modules pub mod distributions; @@ -933,58 +934,39 @@ pub fn weak_rng() -> XorShiftRng { XorShiftRng::new().unwrap() } -/// Controls how the thread-local RNG is reseeded. -#[cfg(feature="std")] -#[derive(Debug)] -struct ThreadRngReseeder; - -#[cfg(feature="std")] -impl reseeding::Reseeder for ThreadRngReseeder { - fn reseed(&mut self, rng: &mut StdRng) { - match StdRng::new() { - Ok(r) => *rng = r, - Err(e) => panic!("No entropy available: {}", e), - } - } -} -#[cfg(feature="std")] -const THREAD_RNG_RESEED_THRESHOLD: u64 = 32_768; -#[cfg(feature="std")] -type ThreadRngInner = reseeding::ReseedingRng; /// The thread-local RNG. #[cfg(feature="std")] #[derive(Clone, Debug)] pub struct ThreadRng { - rng: Rc>, + rng: Rc>>, } -/// Retrieve the lazily-initialized thread-local random number -/// generator, seeded by the system. Intended to be used in method -/// chaining style, e.g. `thread_rng().gen::()`. -/// -/// After generating a certain amount of randomness, the RNG will reseed itself -/// from the operating system or, if the operating system RNG returns an error, -/// a seed based on the current system time. -/// -/// The internal RNG used is platform and architecture dependent, even -/// if the operating system random number generator is rigged to give -/// the same sequence always. If absolute consistency is required, -/// explicitly select an RNG, e.g. `IsaacRng` or `Isaac64Rng`. #[cfg(feature="std")] -pub fn thread_rng() -> ThreadRng { - // used to make space in TLS for a random number generator - thread_local!(static THREAD_RNG_KEY: Rc> = { +thread_local!( + static THREAD_RNG_KEY: Rc>> = { + const THREAD_RNG_RESEED_THRESHOLD: u64 = 32_768; let r = match StdRng::new() { Ok(r) => r, - Err(e) => panic!("No entropy available: {}", e), + Err(e) => panic!("could not initialize thread_rng: {:?}", e) }; - let rng = reseeding::ReseedingRng::new(r, - THREAD_RNG_RESEED_THRESHOLD, - ThreadRngReseeder); + let rng = ReseedingRng::new(r, + THREAD_RNG_RESEED_THRESHOLD, + ReseedWithNew); Rc::new(RefCell::new(rng)) - }); + } +); +/// Retrieve the lazily-initialized thread-local random number +/// generator, seeded by the system. Intended to be used in method +/// chaining style, e.g. `thread_rng().gen::()`. +/// +/// The internal RNG used is the one defined by `StdRng`. After generating 32KiB +/// of random bytes, the RNG will reseed itself from the operating system or, if +/// the operating system RNG returns an error, the `JitterRng` entropy +/// collector. +#[cfg(feature="std")] +pub fn thread_rng() -> ThreadRng { ThreadRng { rng: THREAD_RNG_KEY.with(|t| t.clone()) } } diff --git a/src/reseeding.rs b/src/reseeding.rs index 1626d210dc1..cf389626a3c 100644 --- a/src/reseeding.rs +++ b/src/reseeding.rs @@ -11,9 +11,9 @@ //! A wrapper around another RNG that reseeds it after it //! generates a certain number of random bytes. -use core::default::Default; - use {Rng, Error}; +#[cfg(feature="std")] +use NewSeeded; /// A wrapper around any RNG which reseeds the underlying RNG after it /// has generated a certain number of random bytes. @@ -47,7 +47,7 @@ impl> ReseedingRng { /// 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.reseeder.reseed(&mut self.rng).unwrap(); self.bytes_generated = 0; } } @@ -85,30 +85,31 @@ impl> Rng for ReseedingRng { /// Note that implementations should support `Clone` only if reseeding is /// deterministic (no external entropy source). This is so that a `ReseedingRng` /// only supports `Clone` if fully deterministic. -pub trait Reseeder { +pub trait Reseeder { /// Reseed the given RNG. - fn reseed(&mut self, rng: &mut R); + /// + /// On error, this should just forward the source error; errors are handled + /// by the caller. + fn reseed(&mut self, rng: &mut R) -> Result<(), Error>; } -/// 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; +/// Reseed an RNG using `NewSeeded` to replace the current instance. +#[cfg(feature="std")] +#[derive(Debug)] +pub struct ReseedWithNew; -impl Reseeder for ReseedWithDefault { - fn reseed(&mut self, rng: &mut R) { - *rng = Default::default(); +#[cfg(feature="std")] +impl Reseeder for ReseedWithNew { + fn reseed(&mut self, rng: &mut R) -> Result<(), Error> { + R::new().map(|result| *rng = result) } } -impl Default for ReseedWithDefault { - fn default() -> ReseedWithDefault { ReseedWithDefault } -} #[cfg(test)] mod test { use {impls, le}; use core::default::Default; - use super::{ReseedingRng, ReseedWithDefault}; + use super::{ReseedingRng, ReseedWithNew}; use {SeedableRng, Rng}; struct Counter { @@ -142,11 +143,10 @@ mod test { Counter { i: seed_u32[0] } } } - type MyRng = ReseedingRng; #[test] fn test_reseeding() { - let mut rs = ReseedingRng::new(Counter {i:0}, 400, ReseedWithDefault); + let mut rs = ReseedingRng::new(Counter {i:0}, 400, ReseedWithNew); let mut i = 0; for _ in 0..1000 {