Skip to content

Commit

Permalink
Replace ReseedWithDefault with ReseedWithNew
Browse files Browse the repository at this point in the history
  • Loading branch information
pitdicker committed Jan 13, 2018
1 parent 603bb37 commit 7c4d8a2
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 57 deletions.
60 changes: 21 additions & 39 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<StdRng> 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<StdRng, ThreadRngReseeder>;

/// The thread-local RNG.
#[cfg(feature="std")]
#[derive(Clone, Debug)]
pub struct ThreadRng {
rng: Rc<RefCell<ThreadRngInner>>,
rng: Rc<RefCell<ReseedingRng<StdRng, ReseedWithNew>>>,
}

/// 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::<i32>()`.
///
/// 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<RefCell<ThreadRngInner>> = {
thread_local!(
static THREAD_RNG_KEY: Rc<RefCell<ReseedingRng<StdRng, ReseedWithNew>>> = {
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::<i32>()`.
///
/// 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()) }
}

Expand Down
36 changes: 18 additions & 18 deletions src/reseeding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -47,7 +47,7 @@ impl<R: Rng, Rsdr: Reseeder<R>> ReseedingRng<R, Rsdr> {
/// 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;
}
}
Expand Down Expand Up @@ -85,30 +85,31 @@ impl<R: Rng, Rsdr: Reseeder<R>> Rng for ReseedingRng<R, Rsdr> {
/// 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<R> {
pub trait Reseeder<R: ?Sized> {
/// 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<R: Rng + Default> Reseeder<R> for ReseedWithDefault {
fn reseed(&mut self, rng: &mut R) {
*rng = Default::default();
#[cfg(feature="std")]
impl<R: Rng + NewSeeded> Reseeder<R> 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 {
Expand Down Expand Up @@ -142,11 +143,10 @@ mod test {
Counter { i: seed_u32[0] }
}
}
type MyRng = ReseedingRng<Counter, ReseedWithDefault>;

#[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 {
Expand Down

0 comments on commit 7c4d8a2

Please sign in to comment.