diff --git a/benches/generators.rs b/benches/generators.rs index 044d7b24e89..088a94da2fe 100644 --- a/benches/generators.rs +++ b/benches/generators.rs @@ -9,7 +9,7 @@ const BYTES_LEN: usize = 1024; use std::mem::size_of; use test::{black_box, Bencher}; -use rand::{Rng, NewRng, StdRng, OsRng, JitterRng}; +use rand::{Rng, SampleRng, NewRng, StdRng, OsRng, JitterRng}; use rand::{XorShiftRng, Hc128Rng, IsaacRng, Isaac64Rng, ChaChaRng}; macro_rules! gen_bytes { diff --git a/benches/misc.rs b/benches/misc.rs index 42517617662..41d518c0283 100644 --- a/benches/misc.rs +++ b/benches/misc.rs @@ -5,7 +5,7 @@ extern crate rand; use test::{black_box, Bencher}; -use rand::{Rng, weak_rng}; +use rand::{SampleRng, weak_rng}; use rand::seq::*; #[bench] diff --git a/rand-derive/src/lib.rs b/rand-derive/src/lib.rs index 80c803af29c..71eecf1461b 100644 --- a/rand-derive/src/lib.rs +++ b/rand-derive/src/lib.rs @@ -108,7 +108,7 @@ fn impl_rand_derive(ast: &syn::MacroInput) -> quote::Tokens { quote! { impl #impl_generics ::rand::Rand for #name #ty_generics #where_clause { #[inline] - fn rand<__R: ::rand::Rng>(__rng: &mut __R) -> Self { + fn rand<__R: ::rand::SampleRng>(__rng: &mut __R) -> Self { #rand } } diff --git a/rand-derive/tests/rand_macros.rs b/rand-derive/tests/rand_macros.rs index 938f2b06a79..f0d0c3aa70d 100644 --- a/rand-derive/tests/rand_macros.rs +++ b/rand-derive/tests/rand_macros.rs @@ -4,7 +4,7 @@ extern crate rand; #[macro_use] extern crate rand_derive; -use rand::Rng; +use rand::SampleRng; #[derive(Rand)] struct Struct { diff --git a/src/distributions/exponential.rs b/src/distributions/exponential.rs index d3e48fc84f8..afb076905b1 100644 --- a/src/distributions/exponential.rs +++ b/src/distributions/exponential.rs @@ -10,7 +10,7 @@ //! The exponential distribution. -use {Rng, Rand}; +use {Rng, SampleRng, Rand}; use distributions::{ziggurat, ziggurat_tables, Sample, IndependentSample}; /// A wrapper around an `f64` to generate Exp(1) random numbers. diff --git a/src/distributions/gamma.rs b/src/distributions/gamma.rs index 9c4ac45aa44..787e8482e10 100644 --- a/src/distributions/gamma.rs +++ b/src/distributions/gamma.rs @@ -15,7 +15,7 @@ use self::GammaRepr::*; use self::ChiSquaredRepr::*; -use {Rng, Open01}; +use {Rng, SampleRng, Open01}; use super::normal::StandardNormal; use super::{IndependentSample, Sample, Exp}; diff --git a/src/distributions/mod.rs b/src/distributions/mod.rs index 9eb2e464baf..2a0817efbc1 100644 --- a/src/distributions/mod.rs +++ b/src/distributions/mod.rs @@ -19,7 +19,7 @@ use core::marker; -use {Rng, Rand}; +use {Rng, SampleRng, Rand}; pub use self::range::Range; #[cfg(feature="std")] diff --git a/src/distributions/normal.rs b/src/distributions/normal.rs index 71d498b573a..4aaf4355377 100644 --- a/src/distributions/normal.rs +++ b/src/distributions/normal.rs @@ -10,7 +10,7 @@ //! The normal and derived distributions. -use {Rng, Rand, Open01}; +use {Rng, SampleRng, Rand, Open01}; use distributions::{ziggurat, ziggurat_tables, Sample, IndependentSample}; /// A wrapper around an `f64` to generate N(0, 1) random numbers diff --git a/src/distributions/range.rs b/src/distributions/range.rs index 051fb7a85ab..f8f7119e4c6 100644 --- a/src/distributions/range.rs +++ b/src/distributions/range.rs @@ -14,7 +14,7 @@ use core::num::Wrapping as w; -use Rng; +use {Rng, SampleRng}; use distributions::{Sample, IndependentSample}; /// Sample values uniformly between two bounds. diff --git a/src/lib.rs b/src/lib.rs index 48c4acf8d3d..161e84cd7b6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -79,7 +79,7 @@ //! # Examples //! //! ```rust -//! use rand::Rng; +//! use rand::SampleRng; //! //! let mut rng = rand::thread_rng(); //! if rng.gen() { // random bool @@ -152,7 +152,7 @@ //! [Monty Hall Problem]: https://en.wikipedia.org/wiki/Monty_Hall_problem //! //! ``` -//! use rand::Rng; +//! use rand::SampleRng; //! use rand::distributions::{IndependentSample, Range}; //! //! struct SimulationResult { @@ -161,7 +161,7 @@ //! } //! //! // Run a single simulation of the Monty Hall problem. -//! fn simulate(random_door: &Range, rng: &mut R) +//! fn simulate(random_door: &Range, rng: &mut R) //! -> SimulationResult { //! let car = random_door.ind_sample(rng); //! @@ -182,7 +182,7 @@ //! //! // Returns the door the game host opens given our choice and knowledge of //! // where the car is. The game host will never open the door with the car. -//! fn game_host_open(car: u32, choice: u32, rng: &mut R) -> u32 { +//! fn game_host_open(car: u32, choice: u32, rng: &mut R) -> u32 { //! let choices = free_doors(&[car, choice]); //! rand::seq::sample_slice(rng, &choices, 1)[0] //! } @@ -346,6 +346,21 @@ pub trait Rand : Sized { } /// A random number generator. +/// +/// This trait encapsulates the low-level functionality common to all +/// generators, and is the "back end", to be implemented by generators. +/// Several extension traits exist: +/// +/// * [`SampleRng`] provides high-level generic functionality built on top of +/// `Rng` +/// * [`SeedableRng`] is another "back end" trait covering creation and +/// seeding of algorithmic RNGs (PRNGs) +/// * [`NewRng`] is a high-level trait providing a convenient way to create +/// freshly-seeded PRNGs +/// +/// [`SampleRng`]: trait.SampleRng.html +/// [`SeedableRng`]: trait.SeedableRng.html +/// [`NewRng`]: trait.NewRng.html pub trait Rng { /// Return the next random `u32`. /// @@ -473,13 +488,28 @@ pub trait Rng { fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { Ok(self.fill_bytes(dest)) } +} +/// An automatically-implemented extension trait on [`Rng`] providing high-level +/// generic methods for sampling values and other convenience methods. +/// +/// Users should "use" this trait to enable its extension methods on [`Rng`] +/// or require this type directly (i.e. ``). Since `SampleRng` +/// extends `Rng` and every `Rng` implements `SampleRng`, usage of the two +/// traits is somewhat interchangeable. +/// +/// This functionality is provided as an extension trait to allow separation +/// between the backend (the [`Rng`] providing randomness) and the front-end +/// (converting that randomness to the desired type and distribution). +/// +/// [`Rng`]: trait.Rng.html +pub trait SampleRng: Rng + Sized { /// Return a random value of a `Rand` type. /// /// # Example /// /// ```rust - /// use rand::{thread_rng, Rng}; + /// use rand::{thread_rng, SampleRng}; /// /// let mut rng = thread_rng(); /// let x: u32 = rng.gen(); @@ -487,7 +517,7 @@ pub trait Rng { /// println!("{:?}", rng.gen::<(f64, bool)>()); /// ``` #[inline(always)] - fn gen(&mut self) -> T where Self: Sized { + fn gen(&mut self) -> T { Rand::rand(self) } @@ -497,7 +527,7 @@ pub trait Rng { /// # Example /// /// ``` - /// use rand::{thread_rng, Rng}; + /// use rand::{thread_rng, SampleRng}; /// /// let mut rng = thread_rng(); /// let x = rng.gen_iter::().take(10).collect::>(); @@ -505,7 +535,7 @@ pub trait Rng { /// println!("{:?}", rng.gen_iter::<(f64, bool)>().take(5) /// .collect::>()); /// ``` - fn gen_iter<'a, T: Rand>(&'a mut self) -> Generator<'a, T, Self> where Self: Sized { + fn gen_iter<'a, T: Rand>(&'a mut self) -> Generator<'a, T, Self> { Generator { rng: self, _marker: marker::PhantomData } } @@ -524,7 +554,7 @@ pub trait Rng { /// # Example /// /// ```rust - /// use rand::{thread_rng, Rng}; + /// use rand::{thread_rng, SampleRng}; /// /// let mut rng = thread_rng(); /// let n: u32 = rng.gen_range(0, 10); @@ -532,8 +562,8 @@ pub trait Rng { /// let m: f64 = rng.gen_range(-40.0f64, 1.3e5f64); /// println!("{}", m); /// ``` - fn gen_range(&mut self, low: T, high: T) -> T where Self: Sized { - assert!(low < high, "Rng.gen_range called with low >= high"); + fn gen_range(&mut self, low: T, high: T) -> T { + assert!(low < high, "SampleRng::gen_range called with low >= high"); Range::new(low, high).ind_sample(self) } @@ -542,12 +572,12 @@ pub trait Rng { /// # Example /// /// ```rust - /// use rand::{thread_rng, Rng}; + /// use rand::{thread_rng, SampleRng}; /// /// let mut rng = thread_rng(); /// println!("{}", rng.gen_weighted_bool(3)); /// ``` - fn gen_weighted_bool(&mut self, n: u32) -> bool where Self: Sized { + fn gen_weighted_bool(&mut self, n: u32) -> bool { n <= 1 || self.gen_range(0, n) == 0 } @@ -556,12 +586,12 @@ pub trait Rng { /// # Example /// /// ```rust - /// use rand::{thread_rng, Rng}; + /// use rand::{thread_rng, SampleRng}; /// /// let s: String = thread_rng().gen_ascii_chars().take(10).collect(); /// println!("{}", s); /// ``` - fn gen_ascii_chars<'a>(&'a mut self) -> AsciiGenerator<'a, Self> where Self: Sized { + fn gen_ascii_chars<'a>(&'a mut self) -> AsciiGenerator<'a, Self> { AsciiGenerator { rng: self } } @@ -572,14 +602,14 @@ pub trait Rng { /// # Example /// /// ``` - /// use rand::{thread_rng, Rng}; + /// use rand::{thread_rng, SampleRng}; /// /// let choices = [1, 2, 4, 8, 16, 32]; /// let mut rng = thread_rng(); /// println!("{:?}", rng.choose(&choices)); /// assert_eq!(rng.choose(&choices[..0]), None); /// ``` - fn choose<'a, T>(&mut self, values: &'a [T]) -> Option<&'a T> where Self: Sized { + fn choose<'a, T>(&mut self, values: &'a [T]) -> Option<&'a T> { if values.is_empty() { None } else { @@ -590,7 +620,7 @@ pub trait Rng { /// Return a mutable pointer to a random element from `values`. /// /// Return `None` if `values` is empty. - fn choose_mut<'a, T>(&mut self, values: &'a mut [T]) -> Option<&'a mut T> where Self: Sized { + fn choose_mut<'a, T>(&mut self, values: &'a mut [T]) -> Option<&'a mut T> { if values.is_empty() { None } else { @@ -607,7 +637,7 @@ pub trait Rng { /// # Example /// /// ```rust - /// use rand::{thread_rng, Rng}; + /// use rand::{thread_rng, SampleRng}; /// /// let mut rng = thread_rng(); /// let mut y = [1, 2, 3]; @@ -616,7 +646,7 @@ pub trait Rng { /// rng.shuffle(&mut y); /// println!("{:?}", y); /// ``` - fn shuffle(&mut self, values: &mut [T]) where Self: Sized { + fn shuffle(&mut self, values: &mut [T]) { let mut i = values.len(); while i >= 2 { // invariant: elements with index >= i have been locked in place. @@ -627,6 +657,8 @@ pub trait Rng { } } +impl SampleRng for R {} + impl<'a, R: ?Sized> Rng for &'a mut R where R: Rng { #[inline] fn next_u32(&mut self) -> u32 { @@ -737,7 +769,15 @@ impl<'a, R: Rng> Iterator for AsciiGenerator<'a, R> { /// A random number generator that can be explicitly seeded. /// -/// Each pseudo-random number generator (PRNG) should implement this. +/// This trait encapsulates the low-level functionality common to all +/// pseudo-random number generators (PRNGs, or algorithmic generators). +/// +/// Normally users should use the [`NewRng`] extension trait, excepting when a +/// fixed seed must be used, in which case usage of [`SeedableRng::from_seed`] +/// is recommended. +/// +/// [`NewRng`]: trait.NewRng.html +/// [`SeedableRng::from_seed`]: #tymethod.from_seed pub trait SeedableRng: Sized { /// Seed type, which is restricted to types mutably-dereferencable as `u8` /// arrays (we recommend `[u8; N]` for some `N`). @@ -767,8 +807,12 @@ pub trait SeedableRng: Sized { /// Create a new PRNG seeded from another `Rng`. /// - /// This is the recommended way to initialize PRNGs. The [`NewRng`] trait - /// provides a convenient new method based on `from_rng`. + /// This is the recommended way to initialize PRNGs with fresh entropy. The + /// [`NewRng`] trait provides a convenient new method based on `from_rng`. + /// + /// Usage of this method is not recommended when reproducibility is required + /// since implementing PRNGs are not required to fix Endianness and are + /// allowed to modify implementations in new releases. /// /// It is important to use a good source of randomness to initialize the /// PRNG. Cryptographic PRNG may be rendered insecure when seeded from a @@ -789,7 +833,6 @@ pub trait SeedableRng: Sized { /// /// PRNG implementations are allowed to assume that a good RNG is provided /// for seeding, and that it is cryptographically secure when appropriate. - /// There are no reproducibility requirements like endianness conversion. /// /// [`NewRng`]: trait.NewRng.html /// [`OsRng`]: os/struct.OsRng.html @@ -806,7 +849,7 @@ pub trait SeedableRng: Sized { /// pseudo-random number generators (PRNGs). /// /// This is the recommended way to create PRNGs, unless a deterministic seed is -/// desired (in which case `SeedableRng::from_seed` should be used). +/// desired (in which case [`SeedableRng::from_seed`] should be used). /// /// Note: this trait is automatically implemented for any PRNG implementing /// [`SeedableRng`] and is not intended to be implemented by users. @@ -814,13 +857,14 @@ pub trait SeedableRng: Sized { /// ## Example /// /// ``` -/// use rand::{StdRng, Rng, NewRng}; +/// use rand::{StdRng, SampleRng, NewRng}; /// /// let mut rng = StdRng::new().unwrap(); /// println!("Random die roll: {}", rng.gen_range(1, 7)); /// ``` /// /// [`SeedableRng`]: trait.SeedableRng.html +/// [`SeedableRng::from_seed`]: trait.SeedableRng.html#tymethod.from_seed #[cfg(feature="std")] pub trait NewRng: SeedableRng { /// Creates a new instance, automatically seeded with fresh entropy. @@ -1032,7 +1076,7 @@ impl Rng for ThreadRng { /// Caching the thread local random number generator: /// /// ``` -/// use rand::Rng; +/// use rand::SampleRng; /// /// let mut v = vec![1, 2, 3]; /// @@ -1085,7 +1129,7 @@ mod test { use impls; #[cfg(feature="std")] use super::{random, thread_rng}; - use super::{Rng, SeedableRng, StdRng}; + use super::{Rng, SampleRng, SeedableRng, StdRng}; #[cfg(feature="alloc")] use alloc::boxed::Box; diff --git a/src/rand_impls.rs b/src/rand_impls.rs index e8c70f523d4..307a683ff3d 100644 --- a/src/rand_impls.rs +++ b/src/rand_impls.rs @@ -12,7 +12,7 @@ use core::{char, mem}; -use {Rand, Rng, SeedableRng}; +use {Rand, Rng, SampleRng, SeedableRng}; impl Rand for isize { #[inline] @@ -255,7 +255,7 @@ impl Rand for T { #[cfg(test)] mod tests { use impls; - use {Rng, Open01, Closed01}; + use {Rng, SampleRng, Open01, Closed01}; struct ConstantRng(u64); impl Rng for ConstantRng { diff --git a/src/read.rs b/src/read.rs index 0590d6fe35e..a9c10ddf775 100644 --- a/src/read.rs +++ b/src/read.rs @@ -25,7 +25,7 @@ use {Rng, Error, ErrorKind, impls}; /// # Example /// /// ```rust -/// use rand::{read, Rng}; +/// use rand::{read, SampleRng}; /// /// let data = vec![1, 2, 3, 4, 5, 6, 7, 8]; /// let mut rng = read::ReadRng::new(&data[..]); diff --git a/src/seq.rs b/src/seq.rs index 7c071afb500..279fd1d966b 100644 --- a/src/seq.rs +++ b/src/seq.rs @@ -10,7 +10,7 @@ //! Functions for randomly accessing and sampling sequences. -use super::Rng; +use super::{Rng, SampleRng}; // This crate is only enabled when either std or alloc is available. // BTreeMap is not as fast in tests, but better than nothing. @@ -227,7 +227,7 @@ fn sample_indices_cache( #[cfg(test)] mod test { use super::*; - use {XorShiftRng, SeedableRng}; + use {XorShiftRng, Rng, SeedableRng}; #[cfg(not(feature="std"))] use alloc::Vec;