From 7409873031deb4b79ad546908c1640b7167289f4 Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Thu, 25 Jan 2018 17:34:28 +0000 Subject: [PATCH 1/3] Split Rng into RngCore and extension Rng: RngCore --- benches/bench.rs | 2 +- benches/generators.rs | 2 +- src/distributions/mod.rs | 4 +- src/impls.rs | 14 +++---- src/jitter.rs | 4 +- src/lib.rs | 88 ++++++++++++++++++++++++++++++---------- src/os.rs | 7 ++-- src/prng/chacha.rs | 12 +++--- src/prng/hc128.rs | 6 +-- src/prng/isaac.rs | 8 ++-- src/prng/isaac64.rs | 8 ++-- src/prng/xorshift.rs | 8 ++-- src/rand_impls.rs | 4 +- src/read.rs | 6 +-- src/reseeding.rs | 12 +++--- src/seq.rs | 2 +- 16 files changed, 115 insertions(+), 72 deletions(-) diff --git a/benches/bench.rs b/benches/bench.rs index bb9f54d92d8..4aa06511e1a 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -9,7 +9,7 @@ mod distributions; use std::mem::size_of; use test::{black_box, Bencher}; -use rand::{StdRng, Rng, NewRng}; +use rand::{StdRng, RngCore, NewRng}; #[bench] fn rand_f32(b: &mut Bencher) { diff --git a/benches/generators.rs b/benches/generators.rs index 0298f5ed65f..d747b2484c2 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, EntropyRng}; +use rand::{RngCore, Rng, NewRng, StdRng, OsRng, JitterRng, EntropyRng}; use rand::{XorShiftRng, Hc128Rng, IsaacRng, Isaac64Rng, ChaChaRng}; use rand::reseeding::ReseedingRng; diff --git a/src/distributions/mod.rs b/src/distributions/mod.rs index 9eb2e464baf..552bf930fd0 100644 --- a/src/distributions/mod.rs +++ b/src/distributions/mod.rs @@ -279,7 +279,7 @@ fn ziggurat( #[cfg(test)] mod tests { - use {Rng, Rand}; + use {Rng, RngCore, Rand}; use impls; use super::{RandSample, WeightedChoice, Weighted, Sample, IndependentSample}; @@ -293,7 +293,7 @@ mod tests { // 0, 1, 2, 3, ... struct CountingRng { i: u32 } - impl Rng for CountingRng { + impl RngCore for CountingRng { fn next_u32(&mut self) -> u32 { self.i += 1; self.i - 1 diff --git a/src/impls.rs b/src/impls.rs index f645044b18f..7c00def6f25 100644 --- a/src/impls.rs +++ b/src/impls.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Helper functions for implementing `Rng` functions. +//! Helper functions for implementing `RngCore` functions. //! //! For cross-platform reproducibility, these functions all use Little Endian: //! least-significant part first. For example, `next_u64_via_u32` takes `u32` @@ -27,10 +27,10 @@ use core::ptr::copy_nonoverlapping; use core::slice; use core::cmp::min; use core::mem::size_of; -use Rng; +use RngCore; /// Implement `next_u64` via `next_u32`, little-endian order. -pub fn next_u64_via_u32(rng: &mut R) -> u64 { +pub fn next_u64_via_u32(rng: &mut R) -> u64 { // Use LE; we explicitly generate one value before the next. let x = rng.next_u32() as u64; let y = rng.next_u32() as u64; @@ -59,12 +59,12 @@ macro_rules! fill_bytes_via { } /// Implement `fill_bytes` via `next_u32`, little-endian order. -pub fn fill_bytes_via_u32(rng: &mut R, dest: &mut [u8]) { +pub fn fill_bytes_via_u32(rng: &mut R, dest: &mut [u8]) { fill_bytes_via!(rng, next_u32, 4, dest) } /// Implement `fill_bytes` via `next_u64`, little-endian order. -pub fn fill_bytes_via_u64(rng: &mut R, dest: &mut [u8]) { +pub fn fill_bytes_via_u64(rng: &mut R, dest: &mut [u8]) { fill_bytes_via!(rng, next_u64, 8, dest) } @@ -158,12 +158,12 @@ pub fn fill_via_u64_chunks(src: &[u64], dest: &mut [u8]) -> (usize, usize) { } /// Implement `next_u32` via `fill_bytes`, little-endian order. -pub fn next_u32_via_fill(rng: &mut R) -> u32 { +pub fn next_u32_via_fill(rng: &mut R) -> u32 { impl_uint_from_fill!(rng, u32, 4) } /// Implement `next_u64` via `fill_bytes`, little-endian order. -pub fn next_u64_via_fill(rng: &mut R) -> u64 { +pub fn next_u64_via_fill(rng: &mut R) -> u64 { impl_uint_from_fill!(rng, u64, 8) } diff --git a/src/jitter.rs b/src/jitter.rs index 060d1624cb1..5fdcf1c6765 100644 --- a/src/jitter.rs +++ b/src/jitter.rs @@ -16,7 +16,7 @@ //! Non-physical true random number generator based on timing jitter. -use {Rng, Error, ErrorKind, impls}; +use {RngCore, Error, ErrorKind, impls}; use core::{fmt, mem, ptr}; #[cfg(feature="std")] @@ -746,7 +746,7 @@ fn black_box(dummy: T) -> T { } } -impl Rng for JitterRng { +impl RngCore for JitterRng { fn next_u32(&mut self) -> u32 { // We want to use both parts of the generated entropy if self.data_half_used { diff --git a/src/lib.rs b/src/lib.rs index e0d0a68dcf3..be2c3caf9ea 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -355,7 +355,22 @@ pub trait Rand : Sized { } /// A random number generator. -pub trait Rng { +/// +/// 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: +/// +/// * [`Rng`] provides high-level generic functionality built on top of +/// `RngCore` +/// * [`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 +/// +/// [`Rng`]: trait.Rng.html +/// [`SeedableRng`]: trait.SeedableRng.html +/// [`NewRng`]: trait.NewRng.html +pub trait RngCore { /// Return the next random `u32`. /// /// Implementations of this trait must implement at least one of @@ -457,7 +472,7 @@ pub trait Rng { /// # Example /// /// ```rust - /// use rand::{thread_rng, Rng}; + /// use rand::{thread_rng, RngCore}; /// /// let mut v = [0u8; 13579]; /// thread_rng().fill_bytes(&mut v); @@ -478,11 +493,26 @@ pub trait Rng { /// Other than error handling, this method is identical to [`fill_bytes`], and /// has a default implementation simply wrapping [`fill_bytes`]. /// - /// [`fill_bytes`]: trait.Rng.html#method.fill_bytes + /// [`fill_bytes`]: trait.RngCore.html#method.fill_bytes fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { Ok(self.fill_bytes(dest)) } +} +/// An automatically-implemented extension trait on [`RngCore`] providing high-level +/// generic methods for sampling values and other convenience methods. +/// +/// Users should "use" this trait to enable its extension methods on [`RngCore`] +/// or require this type directly (i.e. ``). Since `Rng` +/// extends `RngCore` and every `RngCore` implements `Rng`, usage of the two +/// traits is somewhat interchangeable. +/// +/// This functionality is provided as an extension trait to allow separation +/// between the backend (the [`RngCore`] providing randomness) and the front-end +/// (converting that randomness to the desired type and distribution). +/// +/// [`RngCore`]: trait.RngCore.html +pub trait Rng: RngCore { /// Return a random value of a `Rand` type. /// /// # Example @@ -543,7 +573,7 @@ pub trait Rng { /// 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"); + assert!(low < high, "Rng::gen_range called with low >= high"); Range::new(low, high).ind_sample(self) } @@ -637,7 +667,9 @@ pub trait Rng { } } -impl<'a, R: Rng + ?Sized> Rng for &'a mut R { +impl Rng for R {} + +impl<'a, R: RngCore + ?Sized> RngCore for &'a mut R { #[inline] fn next_u32(&mut self) -> u32 { (**self).next_u32() @@ -670,7 +702,7 @@ impl<'a, R: Rng + ?Sized> Rng for &'a mut R { } #[cfg(any(feature="std", feature="alloc"))] -impl Rng for Box { +impl RngCore for Box { #[inline] fn next_u32(&mut self) -> u32 { (**self).next_u32() @@ -714,7 +746,7 @@ pub struct Generator<'a, T, R:'a> { _marker: marker::PhantomData T>, } -impl<'a, T: Rand, R: Rng> Iterator for Generator<'a, T, R> { +impl<'a, T: Rand, R: RngCore> Iterator for Generator<'a, T, R> { type Item = T; fn next(&mut self) -> Option { @@ -733,7 +765,7 @@ pub struct AsciiGenerator<'a, R:'a> { rng: &'a mut R, } -impl<'a, R: Rng> Iterator for AsciiGenerator<'a, R> { +impl<'a, R: RngCore> Iterator for AsciiGenerator<'a, R> { type Item = char; fn next(&mut self) -> Option { @@ -747,7 +779,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`). @@ -777,8 +817,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 @@ -799,12 +843,11 @@ 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 /// [`XorShiftRng`]: prng/xorshift/struct.XorShiftRng.html - fn from_rng(rng: &mut R) -> Result { + fn from_rng(rng: &mut R) -> Result { let mut seed = Self::Seed::default(); rng.try_fill_bytes(seed.as_mut())?; Ok(Self::from_seed(seed)) @@ -816,7 +859,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. @@ -831,6 +874,7 @@ pub trait SeedableRng: Sized { /// ``` /// /// [`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. @@ -894,7 +938,7 @@ pub struct Closed01(pub F); #[derive(Clone, Debug)] pub struct StdRng(IsaacWordRng); -impl Rng for StdRng { +impl RngCore for StdRng { fn next_u32(&mut self) -> u32 { self.0.next_u32() } @@ -989,7 +1033,7 @@ pub fn thread_rng() -> ThreadRng { } #[cfg(feature="std")] -impl Rng for ThreadRng { +impl RngCore for ThreadRng { #[inline] fn next_u32(&mut self) -> u32 { self.rng.borrow_mut().next_u32() @@ -1053,7 +1097,7 @@ impl EntropyRng { } #[cfg(feature="std")] -impl Rng for EntropyRng { +impl RngCore for EntropyRng { fn next_u32(&mut self) -> u32 { impls::next_u32_via_fill(self) } @@ -1222,13 +1266,13 @@ mod test { use impls; #[cfg(feature="std")] use super::{random, thread_rng, EntropyRng}; - use super::{Rng, SeedableRng, StdRng}; + use super::{RngCore, Rng, SeedableRng, StdRng}; #[cfg(feature="alloc")] use alloc::boxed::Box; pub struct TestRng { inner: R } - impl Rng for TestRng { + impl RngCore for TestRng { fn next_u32(&mut self) -> u32 { self.inner.next_u32() } @@ -1259,7 +1303,7 @@ mod test { } struct ConstRng { i: u64 } - impl Rng for ConstRng { + impl RngCore for ConstRng { fn next_u32(&mut self) -> u32 { self.i as u32 } fn next_u64(&mut self) -> u64 { self.i } @@ -1398,7 +1442,7 @@ mod test { fn test_rng_trait_object() { let mut rng = rng(109); { - let mut r = &mut rng as &mut Rng; + let mut r = &mut rng as &mut RngCore; r.next_u32(); let r2 = &mut r; r2.gen::(); @@ -1409,7 +1453,7 @@ mod test { assert_eq!(r2.gen_range(0, 1), 0); } { - let mut r = Box::new(rng) as Box; + let mut r = Box::new(rng) as Box; r.next_u32(); r.gen::(); let mut v = [1, 1, 1]; diff --git a/src/os.rs b/src/os.rs index 168b6295755..a7c10509e92 100644 --- a/src/os.rs +++ b/src/os.rs @@ -17,7 +17,7 @@ use std::io::Read; #[allow(unused)] use std::path::Path; #[allow(unused)] use std::sync::{Once, Mutex, ONCE_INIT}; -use {Rng, Error, ErrorKind, impls}; +use {RngCore, Error, ErrorKind, impls}; /// A random number generator that retrieves randomness straight from /// the operating system. @@ -54,7 +54,7 @@ impl OsRng { } } -impl Rng for OsRng { +impl RngCore for OsRng { fn next_u32(&mut self) -> u32 { impls::next_u32_via_fill(self) } @@ -577,7 +577,6 @@ mod imp { #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))] mod imp { use std::io; - use Rng; #[derive(Debug)] pub struct OsRng; @@ -595,7 +594,7 @@ mod imp { #[cfg(test)] mod test { use std::sync::mpsc::channel; - use Rng; + use RngCore; use OsRng; use std::thread; diff --git a/src/prng/chacha.rs b/src/prng/chacha.rs index 04a4e57fc43..12311382469 100644 --- a/src/prng/chacha.rs +++ b/src/prng/chacha.rs @@ -11,7 +11,7 @@ //! The ChaCha random number generator. use core::fmt; -use {Rng, SeedableRng}; +use {RngCore, SeedableRng}; use {impls, le}; const SEED_WORDS: usize = 8; // 8 words for the 256-bit key @@ -108,7 +108,7 @@ impl ChaChaRng { /// # Examples /// /// ```rust - /// use rand::{Rng, ChaChaRng}; + /// use rand::{RngCore, ChaChaRng}; /// /// let mut ra = ChaChaRng::new_unseeded(); /// println!("{:?}", ra.next_u32()); @@ -139,7 +139,7 @@ impl ChaChaRng { /// # Examples /// /// ```rust - /// use rand::{Rng, ChaChaRng}; + /// use rand::{RngCore, ChaChaRng}; /// /// let mut rng1 = ChaChaRng::new_unseeded(); // Use `ChaChaRng::new()` or /// // `ChaChaRng::from_rng()` @@ -170,7 +170,7 @@ impl ChaChaRng { /// # Examples /// /// ```rust - /// use rand::{Rng, ChaChaRng}; + /// use rand::{RngCore, ChaChaRng}; /// /// let mut rng = ChaChaRng::new_unseeded(); // Use `ChaChaRng::new()` or /// // `ChaChaRng::from_rng()` @@ -215,7 +215,7 @@ impl ChaChaRng { } } -impl Rng for ChaChaRng { +impl RngCore for ChaChaRng { #[inline] fn next_u32(&mut self) -> u32 { // Using a local variable for `index`, and checking the size avoids a @@ -272,7 +272,7 @@ impl SeedableRng for ChaChaRng { #[cfg(test)] mod test { - use {Rng, SeedableRng}; + use {RngCore, SeedableRng}; use super::ChaChaRng; #[test] diff --git a/src/prng/hc128.rs b/src/prng/hc128.rs index 0e8f97e71db..0377f64c029 100644 --- a/src/prng/hc128.rs +++ b/src/prng/hc128.rs @@ -11,7 +11,7 @@ //! The HC-128 random number generator. use core::{fmt, slice}; -use {Rng, SeedableRng}; +use {RngCore, SeedableRng}; use {impls, le}; const SEED_WORDS: usize = 8; // 128 bit key followed by 128 bit iv @@ -290,7 +290,7 @@ impl Hc128 { } } -impl Rng for Hc128Rng { +impl RngCore for Hc128Rng { #[inline] fn next_u32(&mut self) -> u32 { if self.index >= 16 { @@ -408,7 +408,7 @@ impl SeedableRng for Hc128Rng { #[cfg(test)] mod test { - use {Rng, SeedableRng}; + use {RngCore, SeedableRng}; use super::Hc128Rng; #[test] diff --git a/src/prng/isaac.rs b/src/prng/isaac.rs index de5336aeed0..9cd91b81bbd 100644 --- a/src/prng/isaac.rs +++ b/src/prng/isaac.rs @@ -13,7 +13,7 @@ use core::{fmt, slice}; use core::num::Wrapping as w; -use {Rng, SeedableRng, Error}; +use {RngCore, SeedableRng, Error}; use {impls, le}; #[allow(non_camel_case_types)] @@ -213,7 +213,7 @@ impl IsaacRng { } } -impl Rng for IsaacRng { +impl RngCore for IsaacRng { #[inline] fn next_u32(&mut self) -> u32 { // Using a local variable for `index`, and checking the size avoids a @@ -347,7 +347,7 @@ impl SeedableRng for IsaacRng { init(seed_extended, 2) } - fn from_rng(rng: &mut R) -> Result { + fn from_rng(rng: &mut R) -> Result { // Custom `from_rng` implementation that fills a seed with the same size // as the entire state. let mut seed = [w(0u32); RAND_SIZE]; @@ -367,7 +367,7 @@ impl SeedableRng for IsaacRng { #[cfg(test)] mod test { - use {Rng, SeedableRng}; + use {RngCore, SeedableRng}; use super::IsaacRng; #[test] diff --git a/src/prng/isaac64.rs b/src/prng/isaac64.rs index 8a3cd0f30d7..696a8489044 100644 --- a/src/prng/isaac64.rs +++ b/src/prng/isaac64.rs @@ -13,7 +13,7 @@ use core::{fmt, slice}; use core::num::Wrapping as w; -use {Rng, SeedableRng, Error}; +use {RngCore, SeedableRng, Error}; use {impls, le}; #[allow(non_camel_case_types)] @@ -199,7 +199,7 @@ impl Isaac64Rng { } } -impl Rng for Isaac64Rng { +impl RngCore for Isaac64Rng { #[inline] fn next_u32(&mut self) -> u32 { // Using a local variable for `index`, and checking the size avoids a @@ -322,7 +322,7 @@ impl SeedableRng for Isaac64Rng { init(seed_extended, 2) } - fn from_rng(rng: &mut R) -> Result { + fn from_rng(rng: &mut R) -> Result { // Custom `from_rng` implementation that fills a seed with the same size // as the entire state. let mut seed = [w(0u64); RAND_SIZE]; @@ -342,7 +342,7 @@ impl SeedableRng for Isaac64Rng { #[cfg(test)] mod test { - use {Rng, SeedableRng}; + use {RngCore, SeedableRng}; use super::Isaac64Rng; #[test] diff --git a/src/prng/xorshift.rs b/src/prng/xorshift.rs index e4e37a100e4..81c6dbe1b7e 100644 --- a/src/prng/xorshift.rs +++ b/src/prng/xorshift.rs @@ -12,7 +12,7 @@ use core::num::Wrapping as w; use core::{fmt, slice}; -use {Rng, SeedableRng, Error}; +use {RngCore, SeedableRng, Error}; use {impls, le}; /// An Xorshift[1] random number @@ -58,7 +58,7 @@ impl XorShiftRng { } } -impl Rng for XorShiftRng { +impl RngCore for XorShiftRng { #[inline] fn next_u32(&mut self) -> u32 { let x = self.x; @@ -102,7 +102,7 @@ impl SeedableRng for XorShiftRng { } } - fn from_rng(rng: &mut R) -> Result { + fn from_rng(rng: &mut R) -> Result { let mut seed_u32 = [0u32; 4]; loop { unsafe { @@ -125,7 +125,7 @@ impl SeedableRng for XorShiftRng { #[cfg(test)] mod tests { - use {Rng, SeedableRng}; + use {RngCore, SeedableRng}; use super::XorShiftRng; #[test] diff --git a/src/rand_impls.rs b/src/rand_impls.rs index 9b84358c47f..59b0edd0f67 100644 --- a/src/rand_impls.rs +++ b/src/rand_impls.rs @@ -255,13 +255,13 @@ impl Rand for T { #[cfg(test)] mod tests { use impls; - use {Rng, Open01, Closed01}; + use {RngCore, Rng, Open01, Closed01}; const EPSILON32: f32 = ::core::f32::EPSILON; const EPSILON64: f64 = ::core::f64::EPSILON; struct ConstantRng(u64); - impl Rng for ConstantRng { + impl RngCore for ConstantRng { fn next_u32(&mut self) -> u32 { let ConstantRng(v) = *self; v as u32 diff --git a/src/read.rs b/src/read.rs index 0590d6fe35e..9eec5bec2fc 100644 --- a/src/read.rs +++ b/src/read.rs @@ -12,7 +12,7 @@ use std::io::Read; -use {Rng, Error, ErrorKind, impls}; +use {RngCore, Error, ErrorKind, impls}; /// An RNG that reads random bytes straight from a `Read`. This will @@ -45,7 +45,7 @@ impl ReadRng { } } -impl Rng for ReadRng { +impl RngCore for ReadRng { fn next_u32(&mut self) -> u32 { impls::next_u32_via_fill(self) } @@ -70,7 +70,7 @@ impl Rng for ReadRng { #[cfg(test)] mod test { use super::ReadRng; - use Rng; + use RngCore; #[test] fn test_reader_rng_u64() { diff --git a/src/reseeding.rs b/src/reseeding.rs index 0fe85e4028f..2beb3e5bd6c 100644 --- a/src/reseeding.rs +++ b/src/reseeding.rs @@ -11,7 +11,7 @@ //! A wrapper around another PRNG that reseeds it after it //! generates a certain number of random bytes. -use {Rng, SeedableRng, Error, ErrorKind}; +use {RngCore, SeedableRng, Error, ErrorKind}; /// A wrapper around any PRNG which reseeds the underlying PRNG after it has /// generated a certain number of random bytes. @@ -62,7 +62,7 @@ pub struct ReseedingRng { bytes_until_reseed: i64, } -impl ReseedingRng { +impl ReseedingRng { /// Create a new `ReseedingRng` with the given parameters. /// /// # Arguments @@ -143,7 +143,7 @@ impl ReseedingRng { } } -impl Rng for ReseedingRng { +impl RngCore for ReseedingRng { fn next_u32(&mut self) -> u32 { let value = self.rng.next_u32(); self.bytes_until_reseed -= 4; @@ -184,13 +184,13 @@ impl Rng for ReseedingRng { mod test { use {impls, le}; use super::{ReseedingRng}; - use {SeedableRng, Rng, Error}; + use {SeedableRng, RngCore, Error}; struct Counter { i: u32 } - impl Rng for Counter { + impl RngCore for Counter { fn next_u32(&mut self) -> u32 { self.i += 1; // very random @@ -215,7 +215,7 @@ mod test { #[derive(Debug, Clone)] struct ResetCounter; - impl Rng for ResetCounter { + impl RngCore for ResetCounter { fn next_u32(&mut self) -> u32 { unimplemented!() } fn next_u64(&mut self) -> u64 { unimplemented!() } fn fill_bytes(&mut self, _dest: &mut [u8]) { unimplemented!() } diff --git a/src/seq.rs b/src/seq.rs index 7c071afb500..9bb328dc209 100644 --- a/src/seq.rs +++ b/src/seq.rs @@ -227,7 +227,7 @@ fn sample_indices_cache( #[cfg(test)] mod test { use super::*; - use {XorShiftRng, SeedableRng}; + use {XorShiftRng, RngCore, SeedableRng}; #[cfg(not(feature="std"))] use alloc::Vec; From 6508ae2fab23755e684b934f433121bc54fae647 Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Mon, 29 Jan 2018 19:04:29 +0000 Subject: [PATCH 2/3] Make SampleRng extension trait require Sized All methods already require the bound --- src/lib.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index be2c3caf9ea..f6c568d69bc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -512,7 +512,7 @@ pub trait RngCore { /// (converting that randomness to the desired type and distribution). /// /// [`RngCore`]: trait.RngCore.html -pub trait Rng: RngCore { +pub trait Rng: RngCore + Sized { /// Return a random value of a `Rand` type. /// /// # Example @@ -526,7 +526,7 @@ pub trait Rng: RngCore { /// println!("{:?}", rng.gen::<(f64, bool)>()); /// ``` #[inline(always)] - fn gen(&mut self) -> T where Self: Sized { + fn gen(&mut self) -> T { Rand::rand(self) } @@ -544,7 +544,7 @@ pub trait Rng: RngCore { /// 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 } } @@ -572,7 +572,7 @@ pub trait Rng: RngCore { /// 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 { + fn gen_range(&mut self, low: T, high: T) -> T { assert!(low < high, "Rng::gen_range called with low >= high"); Range::new(low, high).ind_sample(self) } @@ -587,7 +587,7 @@ pub trait Rng: RngCore { /// 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 } @@ -601,7 +601,7 @@ pub trait Rng: RngCore { /// 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 } } @@ -619,7 +619,7 @@ pub trait Rng: RngCore { /// 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 { @@ -630,7 +630,7 @@ pub trait Rng: RngCore { /// 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 { @@ -656,7 +656,7 @@ pub trait Rng: RngCore { /// 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. From 301105d908f70a6b9c1da0d0155e68422814de52 Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Sun, 18 Feb 2018 09:43:11 +0000 Subject: [PATCH 3/3] Update documentation on Rng and RngCore --- src/lib.rs | 53 +++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 39 insertions(+), 14 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index f6c568d69bc..a1a4f0a5962 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -354,18 +354,37 @@ pub trait Rand : Sized { fn rand(rng: &mut R) -> Self; } -/// A random number generator. +/// The core of 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. +/// End users should normally use [`Rng`] instead. +/// +/// Unlike [`Rng`], this trait is object-safe. To use a type-erased [`Rng`] — +/// i.e. dynamic dispatch — this trait must be used, along with [`Rng`] to +/// use its generic functions: +/// +/// ``` +/// use rand::{Rng, RngCore}; +/// +/// fn use_rng(mut rng: &mut RngCore) -> u32 { +/// rng.gen_range(1, 7) +/// } +/// +/// // or: +/// fn use_any_rng(rng: &mut R) -> char { +/// // TODO: generating a single char should be easier than this +/// rng.gen_ascii_chars().next().unwrap() +/// } +/// ``` +/// /// Several extension traits exist: /// -/// * [`Rng`] provides high-level generic functionality built on top of -/// `RngCore` -/// * [`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 +/// * [`Rng`] provides high-level functionality using generic functions +/// * [`SeedableRng`] is another low-level trait to be implemented by PRNGs +/// (algorithmic RNGs), concerning creation and seeding +/// * [`NewRng`] is a high-level trait providing a `new()` function, allowing +/// easy construction of freshly-seeded PRNGs /// /// [`Rng`]: trait.Rng.html /// [`SeedableRng`]: trait.SeedableRng.html @@ -502,14 +521,20 @@ pub trait RngCore { /// An automatically-implemented extension trait on [`RngCore`] providing high-level /// generic methods for sampling values and other convenience methods. /// -/// Users should "use" this trait to enable its extension methods on [`RngCore`] -/// or require this type directly (i.e. ``). Since `Rng` -/// extends `RngCore` and every `RngCore` implements `Rng`, usage of the two -/// traits is somewhat interchangeable. +/// This is the primary trait to use when generating random values. Example: +/// +/// ``` +/// use rand::Rng; +/// +/// fn use_rng(rng: &mut R) -> f32 { +/// rng.gen() +/// } +/// ``` /// -/// This functionality is provided as an extension trait to allow separation -/// between the backend (the [`RngCore`] providing randomness) and the front-end -/// (converting that randomness to the desired type and distribution). +/// Since this trait exclusively uses generic methods, it is marked `Sized`. +/// Should it be necessary to support trait objects, use [`RngCore`]. +/// Since `Rng` extends `RngCore` and every `RngCore` implements `Rng`, usage +/// of the two traits is somewhat interchangeable. /// /// [`RngCore`]: trait.RngCore.html pub trait Rng: RngCore + Sized {