Skip to content

Commit

Permalink
Remove Rand, RandSample and gen(). Add comments and doc.
Browse files Browse the repository at this point in the history
  • Loading branch information
dhardy committed Jul 29, 2017
1 parent 9ded40c commit 92ee778
Show file tree
Hide file tree
Showing 7 changed files with 91 additions and 171 deletions.
28 changes: 1 addition & 27 deletions src/dist/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,7 @@
//!
//! TODO: is it worth exposing both submodules and re-exporting their members?

use std::marker;

use {Rng, Rand};
use Rng;

pub use self::uniform::{uniform, uniform01, open01, closed01, codepoint};
pub use self::range::Range;
Expand All @@ -42,30 +40,6 @@ pub trait Sample<T> {
}


/// A wrapper for generating types that implement `Rand` via the
/// `Sample` trait.
#[derive(Debug)]
pub struct RandSample<T> {
_marker: marker::PhantomData<fn() -> T>,
}

impl<T> Copy for RandSample<T> {}
impl<T> Clone for RandSample<T> {
fn clone(&self) -> Self { *self }
}

impl<T: Rand> Sample<T> for RandSample<T> {
fn sample<R: Rng>(&self, rng: &mut R) -> T {
rng.gen()
}
}

impl<T> RandSample<T> {
pub fn new() -> RandSample<T> {
RandSample { _marker: marker::PhantomData }
}
}

mod ziggurat_tables;

/// Sample a random number using the Ziggurat method (specifically the
Expand Down
16 changes: 2 additions & 14 deletions src/dist/weighted.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,18 +138,12 @@ impl<'a, T: Clone> Sample<T> for WeightedChoice<'a, T> {

#[cfg(test)]
mod tests {

use {Rng, Rand};
use dist::{RandSample, Sample};
use Rng;
use dist::Sample;
use super::{WeightedChoice, Weighted};

#[derive(PartialEq, Debug)]
struct ConstRand(usize);
impl Rand for ConstRand {
fn rand<R: Rng>(_: &mut R) -> ConstRand {
ConstRand(0)
}
}

// 0, 1, 2, 3, ...
struct CountingRng { i: u32 }
Expand All @@ -163,12 +157,6 @@ mod tests {
}
}

#[test]
fn test_rand_sample() {
let rand_sample = RandSample::<ConstRand>::new();

assert_eq!(rand_sample.sample(&mut ::test::rng()), ConstRand(0));
}
#[test]
fn test_weighted_choice() {
// this makes assumptions about the internal implementation of
Expand Down
66 changes: 4 additions & 62 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -269,45 +269,6 @@ pub mod reseeding;
mod read;
mod os;

/// A type that can be randomly generated using an `Rng`.
///
/// ## Built-in Implementations
///
/// This crate implements `Rand` for various primitive types. Assuming the
/// provided `Rng` is well-behaved, these implementations generate values with
/// the following ranges and distributions:
///
/// * Integers (`i32`, `u32`, `isize`, `usize`, etc.): Uniformly distributed
/// over all values of the type.
/// * `char`: Uniformly distributed over all Unicode scalar values, i.e. all
/// code points in the range `0...0x10_FFFF`, except for the range
/// `0xD800...0xDFFF` (the surrogate code points). This includes
/// unassigned/reserved code points.
/// * `bool`: Generates `false` or `true`, each with probability 0.5.
/// * Floating point types (`f32` and `f64`): Uniformly distributed in the
/// half-open range `[0, 1)`. (The [`Open01`], [`Closed01`], [`Exp1`], and
/// [`StandardNormal`] wrapper types produce floating point numbers with
/// alternative ranges or distributions.)
///
/// [`Open01`]: struct.Open01.html
/// [`Closed01`]: struct.Closed01.html
/// [`Exp1`]: struct.Exp1.html
/// [`StandardNormal`]: struct.StandardNormal.html
///
/// The following aggregate types also implement `Rand` as long as their
/// component types implement it:
///
/// * Tuples and arrays: Each element of the tuple or array is generated
/// independently, using its own `Rand` implementation.
/// * `Option<T>`: Returns `None` with probability 0.5; otherwise generates a
/// random `T` and returns `Some(T)`.

pub trait Rand : Sized {
/// Generates a random instance of this type using the specified source of
/// randomness.
fn rand<R: Rng>(rng: &mut R) -> Self;
}

/// A random number generator.
pub trait Rng {
/// Return the next random u32.
Expand Down Expand Up @@ -429,27 +390,6 @@ pub trait Rng {
}
}

/// Return a random value of a `Rand` type.
///
/// # Example
///
/// ```rust
/// use rand::{thread_rng, Rng};
/// use rand::dist::{uniform, uniform01};
///
/// let mut rng = thread_rng();
/// let x: u32 = uniform(&mut rng);
/// let y: f64 = uniform01(&mut rng);
/// let z: bool = uniform(&mut rng);
/// println!("{}", x);
/// println!("{}", y);
/// println!("{}", z);
/// ```
#[inline(always)]
fn gen<T: Rand>(&mut self) -> T where Self: Sized {
Rand::rand(self)
}

/// Yield an iterator applying some function to self.
///
/// Unfortunately this is only possible with static dispatch (i.e. where
Expand Down Expand Up @@ -737,7 +677,7 @@ impl StdRng {
/// Reading the randomness from the OS may fail, and any error is
/// propagated via the `io::Result` return value.
pub fn new() -> io::Result<StdRng> {
OsRng::new().map(|mut r| StdRng { rng: r.gen() })
OsRng::new().map(|mut r| StdRng { rng: IsaacWordRng::new_from_rng(&mut r) })
}
}

Expand Down Expand Up @@ -774,9 +714,11 @@ impl<'a> SeedableRng<&'a [usize]> for StdRng {
///
/// This will read randomness from the operating system to seed the
/// generator.
// TODO: is this method useful?
pub fn weak_rng() -> XorShiftRng {
// TODO: should this seed from `thread_rng()`?
match OsRng::new() {
Ok(mut r) => r.gen(),
Ok(mut r) => XorShiftRng::new_from_rng(&mut r),
Err(e) => panic!("weak_rng: failed to create seeded RNG: {:?}", e)
}
}
Expand Down
28 changes: 15 additions & 13 deletions src/prng/chacha.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
//! The ChaCha random number generator.

use std::num::Wrapping as w;
use {Rng, SeedableRng, Rand};
use {Rng, SeedableRng};

#[allow(bad_style)]
type w32 = w<u32>;
Expand Down Expand Up @@ -81,7 +81,6 @@ fn core(output: &mut [w32; STATE_WORDS], input: &[w32; STATE_WORDS]) {
}

impl ChaChaRng {

/// Create an ChaCha random number generator using the default
/// fixed key of 8 zero words.
///
Expand All @@ -108,6 +107,20 @@ impl ChaChaRng {
rng
}

/// Create an ChaCha random number generator, seeding from another generator.
///
/// Care should be taken when seeding one RNG from another. There is no
/// free entropy gained. In some cases where the parent and child RNGs use
/// the same algorithm, both generate the same output sequences (possibly
/// with a small lag).
pub fn new_from_rng<R: Rng>(other: &mut R) -> ChaChaRng {
let mut key : [u32; KEY_WORDS] = [0; KEY_WORDS];
for word in key.iter_mut() {
*word = other.next_u32();
}
SeedableRng::from_seed(&key[..])
}

/// Sets the internal 128-bit ChaCha counter to
/// a user-provided value. This permits jumping
/// arbitrarily ahead (or backwards) in the pseudorandom stream.
Expand Down Expand Up @@ -201,7 +214,6 @@ impl Rng for ChaChaRng {
}

impl<'a> SeedableRng<&'a [u32]> for ChaChaRng {

fn reseed(&mut self, seed: &'a [u32]) {
// reset state
self.init(&[0u32; KEY_WORDS]);
Expand All @@ -223,16 +235,6 @@ impl<'a> SeedableRng<&'a [u32]> for ChaChaRng {
}
}

impl Rand for ChaChaRng {
fn rand<R: Rng>(other: &mut R) -> ChaChaRng {
let mut key : [u32; KEY_WORDS] = [0; KEY_WORDS];
for word in key.iter_mut() {
*word = other.next_u32();
}
SeedableRng::from_seed(&key[..])
}
}


#[cfg(test)]
mod test {
Expand Down
87 changes: 47 additions & 40 deletions src/prng/isaac.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use std::iter::repeat;
use std::num::Wrapping as w;
use std::fmt;

use {Rng, SeedableRng, Rand};
use {Rng, SeedableRng};

/// Select 32- or 64-bit variant dependent on pointer size.
#[cfg(target_pointer_width = "32")]
Expand Down Expand Up @@ -61,7 +61,6 @@ static EMPTY: IsaacRng = IsaacRng {
};

impl IsaacRng {

/// Create an ISAAC random number generator using the default
/// fixed seed.
pub fn new_unseeded() -> IsaacRng {
Expand All @@ -70,6 +69,29 @@ impl IsaacRng {
rng
}

/// Create an ISAAC random number generator, seeding from another generator.
///
/// Care should be taken when seeding one RNG from another. There is no
/// free entropy gained. In some cases where the parent and child RNGs use
/// the same algorithm, both generate the same output sequences (possibly
/// with a small lag).
pub fn new_from_rng<R: Rng>(other: &mut R) -> IsaacRng {
let mut ret = EMPTY;
unsafe {
let ptr = ret.rsl.as_mut_ptr() as *mut u8;

let slice = slice::from_raw_parts_mut(ptr, RAND_SIZE_USIZE * 4);
other.fill_bytes(slice);
}
ret.cnt = 0;
ret.a = w(0);
ret.b = w(0);
ret.c = w(0);

ret.init(true);
return ret;
}

/// Initialises `self`. If `use_rsl` is true, then use the current value
/// of `rsl` as a seed, otherwise construct one algorithmically (not
/// randomly).
Expand Down Expand Up @@ -253,25 +275,6 @@ impl<'a> SeedableRng<&'a [u32]> for IsaacRng {
}
}

impl Rand for IsaacRng {
fn rand<R: Rng>(other: &mut R) -> IsaacRng {
let mut ret = EMPTY;
unsafe {
let ptr = ret.rsl.as_mut_ptr() as *mut u8;

let slice = slice::from_raw_parts_mut(ptr, RAND_SIZE_USIZE * 4);
other.fill_bytes(slice);
}
ret.cnt = 0;
ret.a = w(0);
ret.b = w(0);
ret.c = w(0);

ret.init(true);
return ret;
}
}

impl fmt::Debug for IsaacRng {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "IsaacRng {{}}")
Expand Down Expand Up @@ -317,6 +320,29 @@ impl Isaac64Rng {
rng
}

/// Create an ISAAC random number generator, seeding from another generator.
///
/// Care should be taken when seeding one RNG from another. There is no
/// free entropy gained. In some cases where the parent and child RNGs use
/// the same algorithm, both generate the same output sequences (possibly
/// with a small lag).
pub fn new_from_rng<R: Rng>(other: &mut R) -> Isaac64Rng {
let mut ret = EMPTY_64;
unsafe {
let ptr = ret.rsl.as_mut_ptr() as *mut u8;

let slice = slice::from_raw_parts_mut(ptr, RAND_SIZE_64 * 8);
other.fill_bytes(slice);
}
ret.cnt = 0;
ret.a = w(0);
ret.b = w(0);
ret.c = w(0);

ret.init(true);
return ret;
}

/// Initialises `self`. If `use_rsl` is true, then use the current value
/// of `rsl` as a seed, otherwise construct one algorithmically (not
/// randomly).
Expand Down Expand Up @@ -501,25 +527,6 @@ impl<'a> SeedableRng<&'a [u64]> for Isaac64Rng {
}
}

impl Rand for Isaac64Rng {
fn rand<R: Rng>(other: &mut R) -> Isaac64Rng {
let mut ret = EMPTY_64;
unsafe {
let ptr = ret.rsl.as_mut_ptr() as *mut u8;

let slice = slice::from_raw_parts_mut(ptr, RAND_SIZE_64 * 8);
other.fill_bytes(slice);
}
ret.cnt = 0;
ret.a = w(0);
ret.b = w(0);
ret.c = w(0);

ret.init(true);
return ret;
}
}

impl fmt::Debug for Isaac64Rng {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Isaac64Rng {{}}")
Expand Down
3 changes: 3 additions & 0 deletions src/prng/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@
//! short periods for some seeds. If one PRNG is seeded from another using the
//! same algorithm, it is possible that both will yield the same sequence of
//! values (with some lag).
//!
//! TODO: add some guidance on selection of a PRNG: cryptographic approval,
//! statistical properties, performance.

mod chacha;
mod isaac;
Expand Down
Loading

0 comments on commit 92ee778

Please sign in to comment.