From 8589d2d38d0dae5b4cd1fb2cdfabd8144affa7d6 Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Wed, 9 May 2018 09:57:05 +0100 Subject: [PATCH 1/8] Move random() from thread_rng back to lib.rs --- src/lib.rs | 66 ++++++++++++++++++++++++++++++++++++++++++++- src/thread_rng.rs | 68 +---------------------------------------------- 2 files changed, 66 insertions(+), 68 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 0f49495a95b..c61a976ecf8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -209,7 +209,6 @@ pub use rand_core::{ErrorKind, Error}; #[cfg(feature="std")] pub use os::OsRng; pub use reseeding::ReseedingRng; #[cfg(feature="std")] pub use thread_rng::{ThreadRng, thread_rng}; -#[cfg(feature="std")] #[allow(deprecated)] pub use thread_rng::random; // Public modules pub mod distributions; @@ -983,6 +982,56 @@ pub fn weak_rng() -> XorShiftRng { panic!("weak_rng failed: {:?}", err)) } +/// Generates a random value using the thread-local random number generator. +/// +/// This is simply a shortcut for `thread_rng().gen()`. See [`thread_rng`] for +/// documentation of the entropy source and [`Standard`] for documentation of +/// distributions and type-specific generation. +/// +/// # Examples +/// +/// ```rust +/// let x = rand::random::(); +/// println!("{}", x); +/// +/// let y = rand::random::(); +/// println!("{}", y); +/// +/// if rand::random() { // generates a boolean +/// println!("Better lucky than good!"); +/// } +/// ``` +/// +/// If you're calling `random()` in a loop, caching the generator as in the +/// following example can increase performance. +/// +/// ```rust +/// # #![allow(deprecated)] +/// use rand::Rng; +/// +/// let mut v = vec![1, 2, 3]; +/// +/// for x in v.iter_mut() { +/// *x = rand::random() +/// } +/// +/// // can be made faster by caching thread_rng +/// +/// let mut rng = rand::thread_rng(); +/// +/// for x in v.iter_mut() { +/// *x = rng.gen(); +/// } +/// ``` +/// +/// [`thread_rng`]: fn.thread_rng.html +/// [`Standard`]: distributions/struct.Standard.html +#[cfg(feature="std")] +#[inline] +pub fn random() -> T where Standard: Distribution { + thread_rng().gen() +} + /// DEPRECATED: use `seq::sample_iter` instead. /// /// Randomly sample up to `amount` elements from a finite iterator. @@ -1210,4 +1259,19 @@ mod test { let mut rng2 = StdRng::from_rng(rng1).unwrap(); assert_eq!(rng2.next_u64(), 6766915756997287454); } + + #[test] + #[cfg(feature="std")] + fn test_random() { + // not sure how to test this aside from just getting some values + let _n : usize = random(); + let _f : f32 = random(); + let _o : Option> = random(); + let _many : ((), + (usize, + isize, + Option<(u32, (bool,))>), + (u8, i8, u16, i16, u32, i32, u64, i64), + (f32, (f64, (f64,)))) = random(); + } } diff --git a/src/thread_rng.rs b/src/thread_rng.rs index 09b5a39b690..d4b9c8cdfcd 100644 --- a/src/thread_rng.rs +++ b/src/thread_rng.rs @@ -13,9 +13,8 @@ use std::cell::UnsafeCell; use std::rc::Rc; -use {RngCore, CryptoRng, SeedableRng, EntropyRng}; +use {RngCore, CryptoRng, SeedableRng, EntropyRng, Error}; use prng::hc128::Hc128Core; -use {Distribution, Standard, Rng, Error}; use reseeding::ReseedingRng; // Rationale for using `UnsafeCell` in `ThreadRng`: @@ -120,55 +119,6 @@ impl RngCore for ThreadRng { impl CryptoRng for ThreadRng {} -/// Generates a random value using the thread-local random number generator. -/// -/// This is simply a shortcut for `thread_rng().gen()`. See [`thread_rng`] for -/// documentation of the entropy source and [`Standard`] for documentation of -/// distributions and type-specific generation. -/// -/// # Examples -/// -/// ```rust -/// let x = rand::random::(); -/// println!("{}", x); -/// -/// let y = rand::random::(); -/// println!("{}", y); -/// -/// if rand::random() { // generates a boolean -/// println!("Better lucky than good!"); -/// } -/// ``` -/// -/// If you're calling `random()` in a loop, caching the generator as in the -/// following example can increase performance. -/// -/// ```rust -/// # #![allow(deprecated)] -/// use rand::Rng; -/// -/// let mut v = vec![1, 2, 3]; -/// -/// for x in v.iter_mut() { -/// *x = rand::random() -/// } -/// -/// // can be made faster by caching thread_rng -/// -/// let mut rng = rand::thread_rng(); -/// -/// for x in v.iter_mut() { -/// *x = rng.gen(); -/// } -/// ``` -/// -/// [`thread_rng`]: fn.thread_rng.html -/// [`Standard`]: distributions/struct.Standard.html -#[inline] -pub fn random() -> T where Standard: Distribution { - thread_rng().gen() -} - #[cfg(test)] mod test { #[test] @@ -183,20 +133,4 @@ mod test { assert_eq!(v, b); assert_eq!(r.gen_range(0, 1), 0); } - - #[test] - #[allow(deprecated)] - fn test_random() { - use super::random; - // not sure how to test this aside from just getting some values - let _n : usize = random(); - let _f : f32 = random(); - let _o : Option> = random(); - let _many : ((), - (usize, - isize, - Option<(u32, (bool,))>), - (u8, i8, u16, i16, u32, i32, u64, i64), - (f32, (f64, (f64,)))) = random(); - } } From f5721f9e24c6bc2bd74f098605c30e34365de70d Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Thu, 3 May 2018 19:54:46 +0200 Subject: [PATCH 2/8] Move convenience RNGs to new rngs module --- benches/generators.rs | 3 +- benches/misc.rs | 3 +- src/distributions/exponential.rs | 3 +- src/distributions/mod.rs | 3 +- src/distributions/normal.rs | 3 +- src/lib.rs | 179 ++++---------------------- src/rngs/mod.rs | 19 +++ src/rngs/small.rs | 101 +++++++++++++++ src/rngs/std.rs | 83 ++++++++++++ src/{thread_rng.rs => rngs/thread.rs} | 5 +- 10 files changed, 238 insertions(+), 164 deletions(-) create mode 100644 src/rngs/mod.rs create mode 100644 src/rngs/small.rs create mode 100644 src/rngs/std.rs rename src/{thread_rng.rs => rngs/thread.rs} (98%) diff --git a/benches/generators.rs b/benches/generators.rs index fc93561d844..a0644d5cab8 100644 --- a/benches/generators.rs +++ b/benches/generators.rs @@ -10,9 +10,10 @@ use std::mem::size_of; use test::{black_box, Bencher}; use rand::{RngCore, Rng, SeedableRng, FromEntropy}; -use rand::{StdRng, SmallRng, OsRng, EntropyRng, ReseedingRng}; +use rand::{OsRng, EntropyRng, ReseedingRng}; use rand::prng::{XorShiftRng, Hc128Rng, IsaacRng, Isaac64Rng, ChaChaRng}; use rand::prng::hc128::Hc128Core; +use rand::rngs::{StdRng, SmallRng}; use rand::jitter::JitterRng; use rand::thread_rng; diff --git a/benches/misc.rs b/benches/misc.rs index 258f082cdf3..d6ac2189469 100644 --- a/benches/misc.rs +++ b/benches/misc.rs @@ -7,7 +7,8 @@ const RAND_BENCH_N: u64 = 1000; use test::{black_box, Bencher}; -use rand::{SeedableRng, SmallRng, Rng, thread_rng}; +use rand::{SeedableRng, Rng, thread_rng}; +use rand::rngs::SmallRng; use rand::seq::*; #[bench] diff --git a/src/distributions/exponential.rs b/src/distributions/exponential.rs index 915e02ae54c..6212f66d482 100644 --- a/src/distributions/exponential.rs +++ b/src/distributions/exponential.rs @@ -30,7 +30,8 @@ use distributions::{ziggurat, ziggurat_tables, Distribution}; /// /// # Example /// ```rust -/// use rand::{FromEntropy, SmallRng, Rng}; +/// use rand::{FromEntropy, Rng}; +/// use rand::rngs::SmallRng; /// use rand::distributions::Exp1; /// /// let val: f64 = SmallRng::from_entropy().sample(Exp1); diff --git a/src/distributions/mod.rs b/src/distributions/mod.rs index 14be4c1d91c..b96dd99f784 100644 --- a/src/distributions/mod.rs +++ b/src/distributions/mod.rs @@ -400,7 +400,8 @@ impl<'a, D, R, T> Iterator for DistIter<'a, D, R, T> /// /// # Example /// ``` -/// use rand::{FromEntropy, SmallRng, Rng}; +/// use rand::{FromEntropy, Rng}; +/// use rand::rngs::SmallRng; /// use rand::distributions::Standard; /// /// let val: f32 = SmallRng::from_entropy().sample(Standard); diff --git a/src/distributions/normal.rs b/src/distributions/normal.rs index da06cb02892..914fea15225 100644 --- a/src/distributions/normal.rs +++ b/src/distributions/normal.rs @@ -28,7 +28,8 @@ use distributions::{ziggurat, ziggurat_tables, Distribution, Open01}; /// /// # Example /// ```rust -/// use rand::{FromEntropy, SmallRng, Rng}; +/// use rand::{FromEntropy, Rng}; +/// use rand::rngs::SmallRng; /// use rand::distributions::StandardNormal; /// /// let val: f64 = SmallRng::from_entropy().sample(StandardNormal); diff --git a/src/lib.rs b/src/lib.rs index c61a976ecf8..21c09328efb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -55,12 +55,14 @@ //! ``` //! # use rand::{Rng, Error}; //! // seed with fresh entropy: -//! use rand::{StdRng, FromEntropy}; +//! use rand::FromEntropy; +//! use rand::rngs::StdRng; //! let mut rng = StdRng::from_entropy(); //! # let v: u32 = rng.gen(); //! //! // seed from thread_rng: -//! use rand::{SmallRng, SeedableRng, thread_rng}; +//! use rand::{SeedableRng, thread_rng}; +//! use rand::rngs::SmallRng; //! //! # fn try_inner() -> Result<(), Error> { //! let mut rng = SmallRng::from_rng(thread_rng())?; @@ -152,8 +154,8 @@ //! [`EntropyRng`]: struct.EntropyRng.html //! [`OsRng`]: os/struct.OsRng.html //! [`JitterRng`]: jitter/struct.JitterRng.html -//! [`StdRng`]: struct.StdRng.html -//! [`SmallRng`]: struct.SmallRng.html +//! [`StdRng`]: rngs/struct.StdRng.html +//! [`SmallRng`]: rngs/struct.SmallRng.html //! [`ReseedingRng`]: reseeding/struct.ReseedingRng.html //! [`prng`]: prng/index.html //! [`IsaacRng::new_from_u64`]: prng/isaac/struct.IsaacRng.html#method.new_from_u64 @@ -208,7 +210,7 @@ pub use rand_core::{ErrorKind, Error}; #[cfg(feature="std")] pub use entropy_rng::EntropyRng; #[cfg(feature="std")] pub use os::OsRng; pub use reseeding::ReseedingRng; -#[cfg(feature="std")] pub use thread_rng::{ThreadRng, thread_rng}; +#[cfg(feature="std")] pub use rngs::thread::thread_rng; // Public modules pub mod distributions; @@ -217,12 +219,19 @@ pub mod mock; // Public so we don't export `StepRng` directly, making it a bit // more clear it is intended for testing. pub mod prng; #[cfg(feature="std")] pub mod read; +pub mod rngs; #[cfg(feature = "alloc")] pub mod seq; +//////////////////////////////////////////////////////////////////////////////// +// Compatibility re-exports + // These modules are public to avoid API breakage, probably only temporarily. // Hidden in the documentation. #[cfg(feature="std")] #[doc(hidden)] pub mod os; + #[doc(hidden)] pub use prng::{ChaChaRng, IsaacRng, Isaac64Rng, XorShiftRng}; +#[doc(hidden)] pub use rngs::StdRng; + #[doc(hidden)] pub mod chacha { //! The ChaCha random number generator. @@ -234,17 +243,18 @@ pub mod isaac { pub use prng::{IsaacRng, Isaac64Rng}; } +#[cfg(feature="std")] #[doc(hidden)] pub use rngs::ThreadRng; + +//////////////////////////////////////////////////////////////////////////////// + // private modules #[cfg(feature="std")] mod entropy_rng; mod reseeding; -#[cfg(feature="std")] mod thread_rng; -// Normal imports just for this file use core::{marker, mem, slice}; use distributions::{Distribution, Standard, Uniform}; use distributions::uniform::SampleUniform; -use prng::hc128::Hc128Rng; /// A type that can be randomly generated using an [`Rng`]. @@ -779,7 +789,8 @@ impl Iterator for AsciiGenerator { /// ## Example /// /// ``` -/// use rand::{StdRng, Rng, FromEntropy}; +/// use rand::{Rng, FromEntropy}; +/// use rand::rngs::StdRng; /// /// let mut rng = StdRng::from_entropy(); /// println!("Random die roll: {}", rng.gen_range(1, 7)); @@ -827,141 +838,6 @@ impl FromEntropy for R { } } -/// The standard RNG. The PRNG algorithm in `StdRng` is chosen to be efficient -/// on the current platform, to be statistically strong and unpredictable -/// (meaning a cryptographically secure PRNG). -/// -/// The current algorithm used on all platforms is [HC-128]. -/// -/// Reproducibility of output from this generator is however not required, thus -/// future library versions may use a different internal generator with -/// different output. Further, this generator may not be portable and can -/// produce different output depending on the architecture. If you require -/// reproducible output, use a named RNG, for example [`ChaChaRng`]. -/// -/// [HC-128]: prng/hc128/struct.Hc128Rng.html -/// [`ChaChaRng`]: prng/chacha/struct.ChaChaRng.html -#[derive(Clone, Debug)] -pub struct StdRng(Hc128Rng); - -impl RngCore for StdRng { - #[inline(always)] - fn next_u32(&mut self) -> u32 { - self.0.next_u32() - } - - #[inline(always)] - fn next_u64(&mut self) -> u64 { - self.0.next_u64() - } - - fn fill_bytes(&mut self, dest: &mut [u8]) { - self.0.fill_bytes(dest); - } - - fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { - self.0.try_fill_bytes(dest) - } -} - -impl SeedableRng for StdRng { - type Seed = ::Seed; - - fn from_seed(seed: Self::Seed) -> Self { - StdRng(Hc128Rng::from_seed(seed)) - } - - fn from_rng(rng: R) -> Result { - Hc128Rng::from_rng(rng).map(StdRng) - } -} - -impl CryptoRng for StdRng {} - -/// An RNG recommended when small state, cheap initialization and good -/// performance are required. The PRNG algorithm in `SmallRng` is chosen to be -/// efficient on the current platform, **without consideration for cryptography -/// or security**. The size of its state is much smaller than for [`StdRng`]. -/// -/// Reproducibility of output from this generator is however not required, thus -/// future library versions may use a different internal generator with -/// different output. Further, this generator may not be portable and can -/// produce different output depending on the architecture. If you require -/// reproducible output, use a named RNG, for example [`XorShiftRng`]. -/// -/// The current algorithm used on all platforms is [Xorshift]. -/// -/// # Examples -/// -/// Initializing `SmallRng` with a random seed can be done using [`FromEntropy`]: -/// -/// ``` -/// # use rand::Rng; -/// use rand::{FromEntropy, SmallRng}; -/// -/// // Create small, cheap to initialize and fast RNG with a random seed. -/// // The randomness is supplied by the operating system. -/// let mut small_rng = SmallRng::from_entropy(); -/// # let v: u32 = small_rng.gen(); -/// ``` -/// -/// When initializing a lot of `SmallRng`'s, using [`thread_rng`] can be more -/// efficient: -/// -/// ``` -/// use std::iter; -/// use rand::{SeedableRng, SmallRng, thread_rng}; -/// -/// // Create a big, expensive to initialize and slower, but unpredictable RNG. -/// // This is cached and done only once per thread. -/// let mut thread_rng = thread_rng(); -/// // Create small, cheap to initialize and fast RNGs with random seeds. -/// // One can generally assume this won't fail. -/// let rngs: Vec = iter::repeat(()) -/// .map(|()| SmallRng::from_rng(&mut thread_rng).unwrap()) -/// .take(10) -/// .collect(); -/// ``` -/// -/// [`FromEntropy`]: trait.FromEntropy.html -/// [`StdRng`]: struct.StdRng.html -/// [`thread_rng`]: fn.thread_rng.html -/// [Xorshift]: prng/struct.XorShiftRng.html -/// [`XorShiftRng`]: prng/struct.XorShiftRng.html -#[derive(Clone, Debug)] -pub struct SmallRng(XorShiftRng); - -impl RngCore for SmallRng { - #[inline(always)] - fn next_u32(&mut self) -> u32 { - self.0.next_u32() - } - - #[inline(always)] - fn next_u64(&mut self) -> u64 { - self.0.next_u64() - } - - fn fill_bytes(&mut self, dest: &mut [u8]) { - self.0.fill_bytes(dest); - } - - fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { - self.0.try_fill_bytes(dest) - } -} - -impl SeedableRng for SmallRng { - type Seed = ::Seed; - - fn from_seed(seed: Self::Seed) -> Self { - SmallRng(XorShiftRng::from_seed(seed)) - } - - fn from_rng(rng: R) -> Result { - XorShiftRng::from_rng(rng).map(SmallRng) - } -} /// DEPRECATED: use [`SmallRng`] instead. /// @@ -974,7 +850,7 @@ impl SeedableRng for SmallRng { /// /// This will seed the generator with randomness from `thread_rng`. /// -/// [`SmallRng`]: struct.SmallRng.html +/// [`SmallRng`]: rngs/struct.SmallRng.html #[deprecated(since="0.5.0", note="removed in favor of SmallRng")] #[cfg(feature="std")] pub fn weak_rng() -> XorShiftRng { @@ -1248,18 +1124,7 @@ mod test { assert_eq!(r.gen_range(0, 1), 0); let _c: u8 = Standard.sample(&mut r); } - - #[test] - fn test_stdrng_construction() { - let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0, - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; - let mut rng1 = StdRng::from_seed(seed); - assert_eq!(rng1.next_u64(), 15759097995037006553); - - let mut rng2 = StdRng::from_rng(rng1).unwrap(); - assert_eq!(rng2.next_u64(), 6766915756997287454); - } - + #[test] #[cfg(feature="std")] fn test_random() { diff --git a/src/rngs/mod.rs b/src/rngs/mod.rs new file mode 100644 index 00000000000..b342f2134b3 --- /dev/null +++ b/src/rngs/mod.rs @@ -0,0 +1,19 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// https://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Convenience RNGs + +mod small; +mod std; +#[cfg(feature="std")] pub(crate) mod thread; + +pub use self::small::SmallRng; +pub use self::std::StdRng; +#[cfg(feature="std")] pub use self::thread::ThreadRng; diff --git a/src/rngs/small.rs b/src/rngs/small.rs new file mode 100644 index 00000000000..effdbffcbb6 --- /dev/null +++ b/src/rngs/small.rs @@ -0,0 +1,101 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// https://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A small fast RNG + +use {RngCore, SeedableRng, Error}; +use prng::XorShiftRng; + +/// An RNG recommended when small state, cheap initialization and good +/// performance are required. The PRNG algorithm in `SmallRng` is chosen to be +/// efficient on the current platform, **without consideration for cryptography +/// or security**. The size of its state is much smaller than for [`StdRng`]. +/// +/// Reproducibility of output from this generator is however not required, thus +/// future library versions may use a different internal generator with +/// different output. Further, this generator may not be portable and can +/// produce different output depending on the architecture. If you require +/// reproducible output, use a named RNG, for example [`XorShiftRng`]. +/// +/// The current algorithm used on all platforms is [Xorshift]. +/// +/// # Examples +/// +/// Initializing `SmallRng` with a random seed can be done using [`FromEntropy`]: +/// +/// ``` +/// # use rand::Rng; +/// use rand::FromEntropy; +/// use rand::rngs::SmallRng; +/// +/// // Create small, cheap to initialize and fast RNG with a random seed. +/// // The randomness is supplied by the operating system. +/// let mut small_rng = SmallRng::from_entropy(); +/// # let v: u32 = small_rng.gen(); +/// ``` +/// +/// When initializing a lot of `SmallRng`'s, using [`thread_rng`] can be more +/// efficient: +/// +/// ``` +/// use std::iter; +/// use rand::{SeedableRng, thread_rng}; +/// use rand::rngs::SmallRng; +/// +/// // Create a big, expensive to initialize and slower, but unpredictable RNG. +/// // This is cached and done only once per thread. +/// let mut thread_rng = thread_rng(); +/// // Create small, cheap to initialize and fast RNGs with random seeds. +/// // One can generally assume this won't fail. +/// let rngs: Vec = iter::repeat(()) +/// .map(|()| SmallRng::from_rng(&mut thread_rng).unwrap()) +/// .take(10) +/// .collect(); +/// ``` +/// +/// [`FromEntropy`]: ../trait.FromEntropy.html +/// [`StdRng`]: struct.StdRng.html +/// [`thread_rng`]: ../fn.thread_rng.html +/// [Xorshift]: ../prng/struct.XorShiftRng.html +/// [`XorShiftRng`]: ../prng/struct.XorShiftRng.html +#[derive(Clone, Debug)] +pub struct SmallRng(XorShiftRng); + +impl RngCore for SmallRng { + #[inline(always)] + fn next_u32(&mut self) -> u32 { + self.0.next_u32() + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + self.0.next_u64() + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.0.fill_bytes(dest); + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.0.try_fill_bytes(dest) + } +} + +impl SeedableRng for SmallRng { + type Seed = ::Seed; + + fn from_seed(seed: Self::Seed) -> Self { + SmallRng(XorShiftRng::from_seed(seed)) + } + + fn from_rng(rng: R) -> Result { + XorShiftRng::from_rng(rng).map(SmallRng) + } +} diff --git a/src/rngs/std.rs b/src/rngs/std.rs new file mode 100644 index 00000000000..1451f7636c6 --- /dev/null +++ b/src/rngs/std.rs @@ -0,0 +1,83 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// https://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The standard RNG + +use {RngCore, CryptoRng, Error, SeedableRng}; +use prng::Hc128Rng; + +/// The standard RNG. The PRNG algorithm in `StdRng` is chosen to be efficient +/// on the current platform, to be statistically strong and unpredictable +/// (meaning a cryptographically secure PRNG). +/// +/// The current algorithm used on all platforms is [HC-128]. +/// +/// Reproducibility of output from this generator is however not required, thus +/// future library versions may use a different internal generator with +/// different output. Further, this generator may not be portable and can +/// produce different output depending on the architecture. If you require +/// reproducible output, use a named RNG, for example [`ChaChaRng`]. +/// +/// [HC-128]: ../prng/hc128/struct.Hc128Rng.html +/// [`ChaChaRng`]: ../prng/chacha/struct.ChaChaRng.html +#[derive(Clone, Debug)] +pub struct StdRng(Hc128Rng); + +impl RngCore for StdRng { + #[inline(always)] + fn next_u32(&mut self) -> u32 { + self.0.next_u32() + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + self.0.next_u64() + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.0.fill_bytes(dest); + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.0.try_fill_bytes(dest) + } +} + +impl SeedableRng for StdRng { + type Seed = ::Seed; + + fn from_seed(seed: Self::Seed) -> Self { + StdRng(Hc128Rng::from_seed(seed)) + } + + fn from_rng(rng: R) -> Result { + Hc128Rng::from_rng(rng).map(StdRng) + } +} + +impl CryptoRng for StdRng {} + + +#[cfg(test)] +mod test { + use {RngCore, SeedableRng}; + use rngs::StdRng; + + #[test] + fn test_stdrng_construction() { + let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0, + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; + let mut rng1 = StdRng::from_seed(seed); + assert_eq!(rng1.next_u64(), 15759097995037006553); + + let mut rng2 = StdRng::from_rng(rng1).unwrap(); + assert_eq!(rng2.next_u64(), 6766915756997287454); + } +} diff --git a/src/thread_rng.rs b/src/rngs/thread.rs similarity index 98% rename from src/thread_rng.rs rename to src/rngs/thread.rs index d4b9c8cdfcd..860b4c85ff0 100644 --- a/src/thread_rng.rs +++ b/src/rngs/thread.rs @@ -49,7 +49,7 @@ const THREAD_RNG_RESEED_THRESHOLD: u64 = 32*1024*1024; // 32 MiB /// Cloning this handle just produces a new reference to the same thread-local /// generator. /// -/// [`thread_rng`]: fn.thread_rng.html +/// [`thread_rng`]: ../fn.thread_rng.html #[derive(Clone, Debug)] pub struct ThreadRng { rng: Rc>>, @@ -90,7 +90,7 @@ thread_local!( /// used in `ThreadRng` before rand 0.5. /// /// [`ReseedingRng`]: reseeding/struct.ReseedingRng.html -/// [`StdRng`]: struct.StdRng.html +/// [`StdRng`]: rngs/struct.StdRng.html /// [`EntropyRng`]: struct.EntropyRng.html /// [HC-128]: prng/hc128/struct.Hc128Rng.html pub fn thread_rng() -> ThreadRng { @@ -119,6 +119,7 @@ impl RngCore for ThreadRng { impl CryptoRng for ThreadRng {} + #[cfg(test)] mod test { #[test] From 16f149e2a8d20811ab9af610187db79ee5d98719 Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Wed, 9 May 2018 10:54:45 +0100 Subject: [PATCH 3/8] Move all external RNGs to the rngs module --- benches/generators.rs | 4 ++-- rand_core/src/lib.rs | 2 +- src/lib.rs | 22 +++++++++------------- src/{entropy_rng.rs => rngs/entropy.rs} | 7 +++---- src/{ => rngs}/jitter.rs | 2 +- src/rngs/mod.rs | 8 ++++++++ src/{ => rngs}/os.rs | 0 src/rngs/thread.rs | 5 +++-- 8 files changed, 27 insertions(+), 23 deletions(-) rename src/{entropy_rng.rs => rngs/entropy.rs} (98%) rename src/{ => rngs}/jitter.rs (99%) rename src/{ => rngs}/os.rs (100%) diff --git a/benches/generators.rs b/benches/generators.rs index a0644d5cab8..05a19eeccb4 100644 --- a/benches/generators.rs +++ b/benches/generators.rs @@ -10,11 +10,11 @@ use std::mem::size_of; use test::{black_box, Bencher}; use rand::{RngCore, Rng, SeedableRng, FromEntropy}; -use rand::{OsRng, EntropyRng, ReseedingRng}; +use rand::ReseedingRng; use rand::prng::{XorShiftRng, Hc128Rng, IsaacRng, Isaac64Rng, ChaChaRng}; use rand::prng::hc128::Hc128Core; +use rand::rngs::{OsRng, JitterRng, EntropyRng}; use rand::rngs::{StdRng, SmallRng}; -use rand::jitter::JitterRng; use rand::thread_rng; macro_rules! gen_bytes { diff --git a/rand_core/src/lib.rs b/rand_core/src/lib.rs index 2f87fd2b2e4..98120cbc852 100644 --- a/rand_core/src/lib.rs +++ b/rand_core/src/lib.rs @@ -381,7 +381,7 @@ pub trait SeedableRng: Sized { /// for seeding, and that it is cryptographically secure when appropriate. /// /// [`FromEntropy`]: ../rand/trait.FromEntropy.html - /// [`OsRng`]: ../rand/os/struct.OsRng.html + /// [`OsRng`]: ../rand/rngs/struct.OsRng.html fn from_rng(mut rng: R) -> Result { let mut seed = Self::Seed::default(); rng.try_fill_bytes(seed.as_mut())?; diff --git a/src/lib.rs b/src/lib.rs index 21c09328efb..b9be7a09828 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -151,9 +151,9 @@ //! [`from_rng`]: trait.SeedableRng.html#method.from_rng //! [`CryptoRng`]: trait.CryptoRng.html //! [`thread_rng`]: fn.thread_rng.html -//! [`EntropyRng`]: struct.EntropyRng.html -//! [`OsRng`]: os/struct.OsRng.html -//! [`JitterRng`]: jitter/struct.JitterRng.html +//! [`EntropyRng`]: rngs/struct.EntropyRng.html +//! [`OsRng`]: rngs/struct.OsRng.html +//! [`JitterRng`]: rngs/struct.JitterRng.html //! [`StdRng`]: rngs/struct.StdRng.html //! [`SmallRng`]: rngs/struct.SmallRng.html //! [`ReseedingRng`]: reseeding/struct.ReseedingRng.html @@ -207,14 +207,11 @@ pub use rand_core::{RngCore, BlockRngCore, CryptoRng, SeedableRng}; pub use rand_core::{ErrorKind, Error}; // Public exports -#[cfg(feature="std")] pub use entropy_rng::EntropyRng; -#[cfg(feature="std")] pub use os::OsRng; pub use reseeding::ReseedingRng; #[cfg(feature="std")] pub use rngs::thread::thread_rng; // Public modules pub mod distributions; -pub mod jitter; // Public because of the error type. pub mod mock; // Public so we don't export `StepRng` directly, making it a bit // more clear it is intended for testing. pub mod prng; @@ -223,11 +220,10 @@ pub mod rngs; #[cfg(feature = "alloc")] pub mod seq; //////////////////////////////////////////////////////////////////////////////// -// Compatibility re-exports +// Compatibility re-exports. Documentation is hidden; will be removed eventually. -// These modules are public to avoid API breakage, probably only temporarily. -// Hidden in the documentation. -#[cfg(feature="std")] #[doc(hidden)] pub mod os; +#[doc(hidden)] pub use rngs::jitter; +#[cfg(feature="std")] #[doc(hidden)] pub use rngs::{os, EntropyRng, OsRng}; #[doc(hidden)] pub use prng::{ChaChaRng, IsaacRng, Isaac64Rng, XorShiftRng}; #[doc(hidden)] pub use rngs::StdRng; @@ -248,7 +244,6 @@ pub mod isaac { //////////////////////////////////////////////////////////////////////////////// // private modules -#[cfg(feature="std")] mod entropy_rng; mod reseeding; @@ -796,7 +791,7 @@ impl Iterator for AsciiGenerator { /// println!("Random die roll: {}", rng.gen_range(1, 7)); /// ``` /// -/// [`EntropyRng`]: struct.EntropyRng.html +/// [`EntropyRng`]: rngs/struct.EntropyRng.html /// [`SeedableRng`]: trait.SeedableRng.html /// [`SeedableRng::from_seed`]: trait.SeedableRng.html#tymethod.from_seed #[cfg(feature="std")] @@ -815,7 +810,8 @@ pub trait FromEntropy: SeedableRng { /// /// ```rust /// # use rand::Error; - /// use rand::{Rng, StdRng, EntropyRng, SeedableRng}; + /// use rand::{Rng, SeedableRng}; + /// use rand::rngs::{EntropyRng, StdRng}; /// /// # fn try_inner() -> Result<(), Error> { /// // This uses StdRng, but is valid for any R: SeedableRng diff --git a/src/entropy_rng.rs b/src/rngs/entropy.rs similarity index 98% rename from src/entropy_rng.rs rename to src/rngs/entropy.rs index 6b31fc641a2..d500bc1d832 100644 --- a/src/entropy_rng.rs +++ b/src/rngs/entropy.rs @@ -11,8 +11,7 @@ //! Entropy generator, or wrapper around external generators use rand_core::{RngCore, CryptoRng, Error, impls}; -use os::OsRng; -use jitter::JitterRng; +use rngs::{OsRng, JitterRng}; /// An interface returning random data from external source(s), provided /// specifically for securely seeding algorithmic generators (PRNGs). @@ -31,9 +30,9 @@ use jitter::JitterRng; /// external entropy then primarily use the local PRNG ([`thread_rng`] is /// provided as a convenient, local, automatically-seeded CSPRNG). /// -/// [`OsRng`]: os/struct.OsRng.html +/// [`OsRng`]: struct.OsRng.html /// [`JitterRng`]: jitter/struct.JitterRng.html -/// [`thread_rng`]: fn.thread_rng.html +/// [`thread_rng`]: ../fn.thread_rng.html #[derive(Debug)] pub struct EntropyRng { rng: EntropySource, diff --git a/src/jitter.rs b/src/rngs/jitter.rs similarity index 99% rename from src/jitter.rs rename to src/rngs/jitter.rs index e633800fb5b..4524c82d454 100644 --- a/src/jitter.rs +++ b/src/rngs/jitter.rs @@ -50,7 +50,7 @@ const MEMORY_SIZE: usize = MEMORY_BLOCKS * MEMORY_BLOCKSIZE; /// This implementation is based on /// [Jitterentropy](http://www.chronox.de/jent.html) version 2.1.0. /// -/// [`OsRng`]: ../os/struct.OsRng.html +/// [`OsRng`]: struct.OsRng.html pub struct JitterRng { data: u64, // Actual random number // Number of rounds to run the entropy collector per 64 bits diff --git a/src/rngs/mod.rs b/src/rngs/mod.rs index b342f2134b3..8b1b36a4981 100644 --- a/src/rngs/mod.rs +++ b/src/rngs/mod.rs @@ -10,10 +10,18 @@ //! Convenience RNGs +#[cfg(feature="std")] mod entropy; +#[doc(hidden)] pub mod jitter; +#[cfg(feature="std")] #[doc(hidden)] pub mod os; mod small; mod std; #[cfg(feature="std")] pub(crate) mod thread; + +pub use self::jitter::{JitterRng, TimerError}; +#[cfg(feature="std")] pub use self::entropy::EntropyRng; +#[cfg(feature="std")] pub use self::os::OsRng; + pub use self::small::SmallRng; pub use self::std::StdRng; #[cfg(feature="std")] pub use self::thread::ThreadRng; diff --git a/src/os.rs b/src/rngs/os.rs similarity index 100% rename from src/os.rs rename to src/rngs/os.rs diff --git a/src/rngs/thread.rs b/src/rngs/thread.rs index 860b4c85ff0..ac492fc2efb 100644 --- a/src/rngs/thread.rs +++ b/src/rngs/thread.rs @@ -13,7 +13,8 @@ use std::cell::UnsafeCell; use std::rc::Rc; -use {RngCore, CryptoRng, SeedableRng, EntropyRng, Error}; +use {RngCore, CryptoRng, SeedableRng, Error}; +use rngs::EntropyRng; use prng::hc128::Hc128Core; use reseeding::ReseedingRng; @@ -91,7 +92,7 @@ thread_local!( /// /// [`ReseedingRng`]: reseeding/struct.ReseedingRng.html /// [`StdRng`]: rngs/struct.StdRng.html -/// [`EntropyRng`]: struct.EntropyRng.html +/// [`EntropyRng`]: rngs/struct.EntropyRng.html /// [HC-128]: prng/hc128/struct.Hc128Rng.html pub fn thread_rng() -> ThreadRng { ThreadRng { rng: THREAD_RNG_KEY.with(|t| t.clone()) } From b9b2adc867927b09a3dfb5d738248ba184258948 Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Wed, 9 May 2018 11:35:46 +0100 Subject: [PATCH 4/8] Move ReadRng and ReseedingRng to new rngs/adaptor module --- benches/generators.rs | 2 +- src/lib.rs | 11 +++++------ src/rngs/adaptor/mod.rs | 17 +++++++++++++++++ src/{ => rngs/adaptor}/read.rs | 0 src/{ => rngs/adaptor}/reseeding.rs | 0 src/rngs/mod.rs | 2 ++ src/rngs/thread.rs | 4 ++-- 7 files changed, 27 insertions(+), 9 deletions(-) create mode 100644 src/rngs/adaptor/mod.rs rename src/{ => rngs/adaptor}/read.rs (100%) rename src/{ => rngs/adaptor}/reseeding.rs (100%) diff --git a/benches/generators.rs b/benches/generators.rs index 05a19eeccb4..a5b15ddaf5d 100644 --- a/benches/generators.rs +++ b/benches/generators.rs @@ -10,9 +10,9 @@ use std::mem::size_of; use test::{black_box, Bencher}; use rand::{RngCore, Rng, SeedableRng, FromEntropy}; -use rand::ReseedingRng; use rand::prng::{XorShiftRng, Hc128Rng, IsaacRng, Isaac64Rng, ChaChaRng}; use rand::prng::hc128::Hc128Core; +use rand::rngs::adaptor::ReseedingRng; use rand::rngs::{OsRng, JitterRng, EntropyRng}; use rand::rngs::{StdRng, SmallRng}; use rand::thread_rng; diff --git a/src/lib.rs b/src/lib.rs index b9be7a09828..c2f9b5de6cc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -156,7 +156,7 @@ //! [`JitterRng`]: rngs/struct.JitterRng.html //! [`StdRng`]: rngs/struct.StdRng.html //! [`SmallRng`]: rngs/struct.SmallRng.html -//! [`ReseedingRng`]: reseeding/struct.ReseedingRng.html +//! [`ReseedingRng`]: rngs/adaptor/struct.ReseedingRng.html //! [`prng`]: prng/index.html //! [`IsaacRng::new_from_u64`]: prng/isaac/struct.IsaacRng.html#method.new_from_u64 //! [`Hc128Rng`]: prng/hc128/struct.Hc128Rng.html @@ -207,7 +207,6 @@ pub use rand_core::{RngCore, BlockRngCore, CryptoRng, SeedableRng}; pub use rand_core::{ErrorKind, Error}; // Public exports -pub use reseeding::ReseedingRng; #[cfg(feature="std")] pub use rngs::thread::thread_rng; // Public modules @@ -215,19 +214,22 @@ pub mod distributions; pub mod mock; // Public so we don't export `StepRng` directly, making it a bit // more clear it is intended for testing. pub mod prng; -#[cfg(feature="std")] pub mod read; pub mod rngs; #[cfg(feature = "alloc")] pub mod seq; //////////////////////////////////////////////////////////////////////////////// // Compatibility re-exports. Documentation is hidden; will be removed eventually. +#[cfg(feature="std")] #[doc(hidden)] pub use rngs::adaptor::read; +#[doc(hidden)] pub use rngs::adaptor::ReseedingRng; + #[doc(hidden)] pub use rngs::jitter; #[cfg(feature="std")] #[doc(hidden)] pub use rngs::{os, EntropyRng, OsRng}; #[doc(hidden)] pub use prng::{ChaChaRng, IsaacRng, Isaac64Rng, XorShiftRng}; #[doc(hidden)] pub use rngs::StdRng; + #[doc(hidden)] pub mod chacha { //! The ChaCha random number generator. @@ -243,9 +245,6 @@ pub mod isaac { //////////////////////////////////////////////////////////////////////////////// -// private modules -mod reseeding; - use core::{marker, mem, slice}; use distributions::{Distribution, Standard, Uniform}; diff --git a/src/rngs/adaptor/mod.rs b/src/rngs/adaptor/mod.rs new file mode 100644 index 00000000000..dce45731785 --- /dev/null +++ b/src/rngs/adaptor/mod.rs @@ -0,0 +1,17 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// https://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Wrappers / adaptors forming RNGs + +#[cfg(feature="std")] #[doc(hidden)] pub mod read; +mod reseeding; + +#[cfg(feature="std")] pub use self::read::ReadRng; +pub use self::reseeding::ReseedingRng; diff --git a/src/read.rs b/src/rngs/adaptor/read.rs similarity index 100% rename from src/read.rs rename to src/rngs/adaptor/read.rs diff --git a/src/reseeding.rs b/src/rngs/adaptor/reseeding.rs similarity index 100% rename from src/reseeding.rs rename to src/rngs/adaptor/reseeding.rs diff --git a/src/rngs/mod.rs b/src/rngs/mod.rs index 8b1b36a4981..ee987acae9f 100644 --- a/src/rngs/mod.rs +++ b/src/rngs/mod.rs @@ -10,6 +10,8 @@ //! Convenience RNGs +pub mod adaptor; + #[cfg(feature="std")] mod entropy; #[doc(hidden)] pub mod jitter; #[cfg(feature="std")] #[doc(hidden)] pub mod os; diff --git a/src/rngs/thread.rs b/src/rngs/thread.rs index ac492fc2efb..7b5a1225d57 100644 --- a/src/rngs/thread.rs +++ b/src/rngs/thread.rs @@ -14,9 +14,9 @@ use std::cell::UnsafeCell; use std::rc::Rc; use {RngCore, CryptoRng, SeedableRng, Error}; +use rngs::adaptor::ReseedingRng; use rngs::EntropyRng; use prng::hc128::Hc128Core; -use reseeding::ReseedingRng; // Rationale for using `UnsafeCell` in `ThreadRng`: // @@ -90,7 +90,7 @@ thread_local!( /// usage for better performance. This makes it similar to ISAAC, the algorithm /// used in `ThreadRng` before rand 0.5. /// -/// [`ReseedingRng`]: reseeding/struct.ReseedingRng.html +/// [`ReseedingRng`]: rngs/adaptor/struct.ReseedingRng.html /// [`StdRng`]: rngs/struct.StdRng.html /// [`EntropyRng`]: rngs/struct.EntropyRng.html /// [HC-128]: prng/hc128/struct.Hc128Rng.html From 4b84f489e051417504a4e4c230b24cc5be27cb74 Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Wed, 9 May 2018 12:06:37 +0100 Subject: [PATCH 5/8] Move BlockRng* to new rand_core::block module; don't export from rand These are almost exclusively for implementation of certain types of RNG, therefore exposing BlockRngCore in rand is not useful. --- rand_core/src/block.rs | 474 ++++++++++++++++++++++++++++++++++ rand_core/src/impls.rs | 410 +---------------------------- rand_core/src/lib.rs | 56 +--- src/lib.rs | 2 +- src/prng/chacha.rs | 4 +- src/prng/hc128.rs | 4 +- src/prng/isaac.rs | 4 +- src/prng/isaac64.rs | 4 +- src/rngs/adaptor/reseeding.rs | 4 +- 9 files changed, 489 insertions(+), 473 deletions(-) create mode 100644 rand_core/src/block.rs diff --git a/rand_core/src/block.rs b/rand_core/src/block.rs new file mode 100644 index 00000000000..6ed26caa3f6 --- /dev/null +++ b/rand_core/src/block.rs @@ -0,0 +1,474 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// https://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! [`BlockRng`] trait and implementation helpers + +use core::convert::AsRef; +use core::fmt; +use {RngCore, CryptoRng, SeedableRng, Error}; +use impls::{fill_via_u32_chunks, fill_via_u64_chunks}; + +/// A trait for RNGs which do not generate random numbers individually, but in +/// blocks (typically `[u32; N]`). This technique is commonly used by +/// cryptographic RNGs to improve performance. +/// +/// Usage of this trait is optional, but provides two advantages: +/// implementations only need to concern themselves with generation of the +/// block, not the various [`RngCore`] methods (especially [`fill_bytes`], where the +/// optimal implementations are not trivial), and this allows `ReseedingRng` to +/// perform periodic reseeding with very low overhead. +/// +/// # Example +/// +/// ```norun +/// use rand_core::block::{BlockRngCore, BlockRng}; +/// +/// struct MyRngCore; +/// +/// impl BlockRngCore for MyRngCore { +/// type Results = [u32; 16]; +/// +/// fn generate(&mut self, results: &mut Self::Results) { +/// unimplemented!() +/// } +/// } +/// +/// impl SeedableRng for MyRngCore { +/// type Seed = unimplemented!(); +/// fn from_seed(seed: Self::Seed) -> Self { +/// unimplemented!() +/// } +/// } +/// +/// // optionally, also implement CryptoRng for MyRngCore +/// +/// // Final RNG. +/// type MyRng = BlockRng; +/// ``` +/// +/// [`RngCore`]: ../trait.RngCore.html +/// [`fill_bytes`]: ../trait.RngCore.html#tymethod.fill_bytes +pub trait BlockRngCore { + /// Results element type, e.g. `u32`. + type Item; + + /// Results type. This is the 'block' an RNG implementing `BlockRngCore` + /// generates, which will usually be an array like `[u32; 16]`. + type Results: AsRef<[Self::Item]> + AsMut<[Self::Item]> + Default; + + /// Generate a new block of results. + fn generate(&mut self, results: &mut Self::Results); +} + + +/// A wrapper type implementing [`RngCore`] for some type implementing +/// [`BlockRngCore`] with `u32` array buffer; i.e. this can be used to implement +/// a full RNG from just a `generate` function. +/// +/// The `core` field may be accessed directly but the results buffer may not. +/// PRNG implementations can simply use a type alias +/// (`pub type MyRng = BlockRng;`) but might prefer to use a +/// wrapper type (`pub struct MyRng(BlockRng);`); the latter must +/// re-implement `RngCore` but hides the implementation details and allows +/// extra functionality to be defined on the RNG +/// (e.g. `impl MyRng { fn set_stream(...){...} }`). +/// +/// `BlockRng` has heavily optimized implementations of the [`RngCore`] methods +/// reading values from the results buffer, as well as +/// calling `BlockRngCore::generate` directly on the output array when +/// `fill_bytes` / `try_fill_bytes` is called on a large array. These methods +/// also handle the bookkeeping of when to generate a new batch of values. +/// No generated values are ever thown away and all values are consumed +/// in-order (this may be important for reproducibility). +/// +/// See also [`BlockRng64`] which uses `u64` array buffers. Currently there is +/// no direct support for other buffer types. +/// +/// For easy initialization `BlockRng` also implements [`SeedableRng`]. +/// +/// [`BlockRngCore`]: BlockRngCore.t.html +/// [`RngCore`]: ../RngCore.t.html +/// [`SeedableRng`]: ../SeedableRng.t.html +#[derive(Clone)] +#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))] +pub struct BlockRng { + results: R::Results, + index: usize, + /// The *core* part of the RNG, implementing the `generate` function. + pub core: R, +} + +// Custom Debug implementation that does not expose the contents of `results`. +impl fmt::Debug for BlockRng { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_struct("BlockRng") + .field("core", &self.core) + .field("result_len", &self.results.as_ref().len()) + .field("index", &self.index) + .finish() + } +} + +impl BlockRng { + /// Create a new `BlockRng` from an existing RNG implementing + /// `BlockRngCore`. Results will be generated on first use. + pub fn new(core: R) -> BlockRng{ + let results_empty = R::Results::default(); + BlockRng { + core, + index: results_empty.as_ref().len(), + results: results_empty, + } + } + + /// Get the index into the result buffer. + /// + /// If this is equal to or larger than the size of the result buffer then + /// the buffer is "empty" and `generate()` must be called to produce new + /// results. + pub fn index(&self) -> usize { + self.index + } + + /// Reset the number of available results. + /// This will force a new set of results to be generated on next use. + pub fn reset(&mut self) { + self.index = self.results.as_ref().len(); + } + + /// Generate a new set of results immediately, setting the index to the + /// given value. + pub fn generate_and_set(&mut self, index: usize) { + assert!(index < self.results.as_ref().len()); + self.core.generate(&mut self.results); + self.index = index; + } +} + +impl> RngCore for BlockRng +where ::Results: AsRef<[u32]> + AsMut<[u32]> +{ + #[inline(always)] + fn next_u32(&mut self) -> u32 { + if self.index >= self.results.as_ref().len() { + self.generate_and_set(0); + } + + let value = self.results.as_ref()[self.index]; + self.index += 1; + value + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + let read_u64 = |results: &[u32], index| { + if cfg!(any(target_arch = "x86", target_arch = "x86_64")) { + // requires little-endian CPU supporting unaligned reads: + unsafe { *(&results[index] as *const u32 as *const u64) } + } else { + let x = u64::from(results[index]); + let y = u64::from(results[index + 1]); + (y << 32) | x + } + }; + + let len = self.results.as_ref().len(); + + let index = self.index; + if index < len-1 { + self.index += 2; + // Read an u64 from the current index + read_u64(self.results.as_ref(), index) + } else if index >= len { + self.generate_and_set(2); + read_u64(self.results.as_ref(), 0) + } else { + let x = u64::from(self.results.as_ref()[len-1]); + self.generate_and_set(1); + let y = u64::from(self.results.as_ref()[0]); + (y << 32) | x + } + } + + // As an optimization we try to write directly into the output buffer. + // This is only enabled for little-endian platforms where unaligned writes + // are known to be safe and fast. + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + fn fill_bytes(&mut self, dest: &mut [u8]) { + let mut filled = 0; + + // Continue filling from the current set of results + if self.index < self.results.as_ref().len() { + let (consumed_u32, filled_u8) = + fill_via_u32_chunks(&self.results.as_ref()[self.index..], + dest); + + self.index += consumed_u32; + filled += filled_u8; + } + + let len_remainder = + (dest.len() - filled) % (self.results.as_ref().len() * 4); + let end_direct = dest.len() - len_remainder; + + while filled < end_direct { + let dest_u32: &mut R::Results = unsafe { + &mut *(dest[filled..].as_mut_ptr() as + *mut ::Results) + }; + self.core.generate(dest_u32); + filled += self.results.as_ref().len() * 4; + self.index = self.results.as_ref().len(); + } + + if len_remainder > 0 { + self.core.generate(&mut self.results); + let (consumed_u32, _) = + fill_via_u32_chunks(self.results.as_ref(), + &mut dest[filled..]); + + self.index = consumed_u32; + } + } + + #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] + fn fill_bytes(&mut self, dest: &mut [u8]) { + let mut read_len = 0; + while read_len < dest.len() { + if self.index >= self.results.as_ref().len() { + self.generate_and_set(0); + } + let (consumed_u32, filled_u8) = + fill_via_u32_chunks(&self.results.as_ref()[self.index..], + &mut dest[read_len..]); + + self.index += consumed_u32; + read_len += filled_u8; + } + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.fill_bytes(dest); + Ok(()) + } +} + +impl SeedableRng for BlockRng { + type Seed = R::Seed; + + fn from_seed(seed: Self::Seed) -> Self { + Self::new(R::from_seed(seed)) + } + + fn from_rng(rng: S) -> Result { + Ok(Self::new(R::from_rng(rng)?)) + } +} + + + +/// A wrapper type implementing [`RngCore`] for some type implementing +/// [`BlockRngCore`] with `u64` array buffer; i.e. this can be used to implement +/// a full RNG from just a `generate` function. +/// +/// This is similar to [`BlockRng`], but specialized for algorithms that operate +/// on `u64` values. +/// +/// Like [`BlockRng`], this wrapper does not throw away whole results and does +/// use all generated values in-order. The behaviour of `next_u32` is however +/// a bit special: half of a `u64` is consumed, leaving the other half in the +/// buffer. If the next function called is `next_u32` then the other half is +/// then consumed, however both `next_u64` and `fill_bytes` discard any +/// half-consumed `u64`s when called. +/// +/// [`BlockRngCore`]: BlockRngCore.t.html +/// [`RngCore`]: ../RngCore.t.html +/// [`BlockRng`]: struct.BlockRng.html +#[derive(Clone)] +#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))] +pub struct BlockRng64 { + results: R::Results, + index: usize, + half_used: bool, // true if only half of the previous result is used + /// The *core* part of the RNG, implementing the `generate` function. + pub core: R, +} + +// Custom Debug implementation that does not expose the contents of `results`. +impl fmt::Debug for BlockRng64 { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_struct("BlockRng64") + .field("core", &self.core) + .field("result_len", &self.results.as_ref().len()) + .field("index", &self.index) + .field("half_used", &self.half_used) + .finish() + } +} + +impl BlockRng64 { + /// Create a new `BlockRng` from an existing RNG implementing + /// `BlockRngCore`. Results will be generated on first use. + pub fn new(core: R) -> BlockRng64{ + let results_empty = R::Results::default(); + BlockRng64 { + core, + index: results_empty.as_ref().len(), + half_used: false, + results: results_empty, + } + } + + /// Get the index into the result buffer. + /// + /// If this is equal to or larger than the size of the result buffer then + /// the buffer is "empty" and `generate()` must be called to produce new + /// results. + pub fn index(&self) -> usize { + self.index + } + + /// Reset the number of available results. + /// This will force a new set of results to be generated on next use. + pub fn reset(&mut self) { + self.index = self.results.as_ref().len(); + self.half_used = false; + } + + /// Generate a new set of results immediately, setting the index to the + /// given value. + pub fn generate_and_set(&mut self, index: usize) { + assert!(index < self.results.as_ref().len()); + self.core.generate(&mut self.results); + self.index = index; + self.half_used = false; + } +} + +impl> RngCore for BlockRng64 +where ::Results: AsRef<[u64]> + AsMut<[u64]> +{ + #[inline(always)] + fn next_u32(&mut self) -> u32 { + let mut index = self.index * 2 - self.half_used as usize; + if index >= self.results.as_ref().len() * 2 { + self.core.generate(&mut self.results); + self.index = 0; + // `self.half_used` is by definition `false` + self.half_used = false; + index = 0; + } + + self.half_used = !self.half_used; + self.index += self.half_used as usize; + + // Index as if this is a u32 slice. + unsafe { + let results = + &*(self.results.as_ref() as *const [u64] as *const [u32]); + if cfg!(target_endian = "little") { + *results.get_unchecked(index) + } else { + *results.get_unchecked(index ^ 1) + } + } + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + if self.index >= self.results.as_ref().len() { + self.core.generate(&mut self.results); + self.index = 0; + } + + let value = self.results.as_ref()[self.index]; + self.index += 1; + self.half_used = false; + value + } + + // As an optimization we try to write directly into the output buffer. + // This is only enabled for little-endian platforms where unaligned writes + // are known to be safe and fast. + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + fn fill_bytes(&mut self, dest: &mut [u8]) { + let mut filled = 0; + self.half_used = false; + + // Continue filling from the current set of results + if self.index < self.results.as_ref().len() { + let (consumed_u64, filled_u8) = + fill_via_u64_chunks(&self.results.as_ref()[self.index..], + dest); + + self.index += consumed_u64; + filled += filled_u8; + } + + let len_remainder = + (dest.len() - filled) % (self.results.as_ref().len() * 8); + let end_direct = dest.len() - len_remainder; + + while filled < end_direct { + let dest_u64: &mut R::Results = unsafe { + ::core::mem::transmute(dest[filled..].as_mut_ptr()) + }; + self.core.generate(dest_u64); + filled += self.results.as_ref().len() * 8; + self.index = self.results.as_ref().len(); + } + + if len_remainder > 0 { + self.core.generate(&mut self.results); + let (consumed_u64, _) = + fill_via_u64_chunks(&mut self.results.as_ref(), + &mut dest[filled..]); + + self.index = consumed_u64; + } + } + + #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] + fn fill_bytes(&mut self, dest: &mut [u8]) { + let mut read_len = 0; + self.half_used = false; + while read_len < dest.len() { + if self.index as usize >= self.results.as_ref().len() { + self.core.generate(&mut self.results); + self.index = 0; + } + + let (consumed_u64, filled_u8) = + fill_via_u64_chunks(&self.results.as_ref()[self.index as usize..], + &mut dest[read_len..]); + + self.index += consumed_u64; + read_len += filled_u8; + } + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + Ok(self.fill_bytes(dest)) + } +} + +impl SeedableRng for BlockRng64 { + type Seed = R::Seed; + + fn from_seed(seed: Self::Seed) -> Self { + Self::new(R::from_seed(seed)) + } + + fn from_rng(rng: S) -> Result { + Ok(Self::new(R::from_rng(rng)?)) + } +} + +impl CryptoRng for BlockRng {} diff --git a/rand_core/src/impls.rs b/rand_core/src/impls.rs index f66e1e9c883..5e516d92382 100644 --- a/rand_core/src/impls.rs +++ b/rand_core/src/impls.rs @@ -19,13 +19,12 @@ //! to/from byte sequences, and since its purpose is reproducibility, //! non-reproducible sources (e.g. `OsRng`) need not bother with it. -use core::convert::AsRef; use core::intrinsics::transmute; use core::ptr::copy_nonoverlapping; -use core::{fmt, slice}; +use core::slice; use core::cmp::min; use core::mem::size_of; -use {RngCore, BlockRngCore, CryptoRng, SeedableRng, Error}; +use RngCore; /// Implement `next_u64` via `next_u32`, little-endian order. @@ -165,409 +164,4 @@ pub fn next_u64_via_fill(rng: &mut R) -> u64 { impl_uint_from_fill!(rng, u64, 8) } -/// A wrapper type implementing [`RngCore`] for some type implementing -/// [`BlockRngCore`] with `u32` array buffer; i.e. this can be used to implement -/// a full RNG from just a `generate` function. -/// -/// The `core` field may be accessed directly but the results buffer may not. -/// PRNG implementations can simply use a type alias -/// (`pub type MyRng = BlockRng;`) but might prefer to use a -/// wrapper type (`pub struct MyRng(BlockRng);`); the latter must -/// re-implement `RngCore` but hides the implementation details and allows -/// extra functionality to be defined on the RNG -/// (e.g. `impl MyRng { fn set_stream(...){...} }`). -/// -/// `BlockRng` has heavily optimized implementations of the [`RngCore`] methods -/// reading values from the results buffer, as well as -/// calling `BlockRngCore::generate` directly on the output array when -/// `fill_bytes` / `try_fill_bytes` is called on a large array. These methods -/// also handle the bookkeeping of when to generate a new batch of values. -/// No generated values are ever thown away and all values are consumed -/// in-order (this may be important for reproducibility). -/// -/// See also [`BlockRng64`] which uses `u64` array buffers. Currently there is -/// no direct support for other buffer types. -/// -/// For easy initialization `BlockRng` also implements [`SeedableRng`]. -/// -/// [`BlockRngCore`]: ../BlockRngCore.t.html -/// [`RngCore`]: ../RngCore.t.html -/// [`SeedableRng`]: ../SeedableRng.t.html -#[derive(Clone)] -#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))] -pub struct BlockRng { - results: R::Results, - index: usize, - /// The *core* part of the RNG, implementing the `generate` function. - pub core: R, -} - -// Custom Debug implementation that does not expose the contents of `results`. -impl fmt::Debug for BlockRng { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - fmt.debug_struct("BlockRng") - .field("core", &self.core) - .field("result_len", &self.results.as_ref().len()) - .field("index", &self.index) - .finish() - } -} - -impl BlockRng { - /// Create a new `BlockRng` from an existing RNG implementing - /// `BlockRngCore`. Results will be generated on first use. - pub fn new(core: R) -> BlockRng{ - let results_empty = R::Results::default(); - BlockRng { - core, - index: results_empty.as_ref().len(), - results: results_empty, - } - } - - /// Get the index into the result buffer. - /// - /// If this is equal to or larger than the size of the result buffer then - /// the buffer is "empty" and `generate()` must be called to produce new - /// results. - pub fn index(&self) -> usize { - self.index - } - - /// Reset the number of available results. - /// This will force a new set of results to be generated on next use. - pub fn reset(&mut self) { - self.index = self.results.as_ref().len(); - } - - /// Generate a new set of results immediately, setting the index to the - /// given value. - pub fn generate_and_set(&mut self, index: usize) { - assert!(index < self.results.as_ref().len()); - self.core.generate(&mut self.results); - self.index = index; - } -} - -impl> RngCore for BlockRng -where ::Results: AsRef<[u32]> + AsMut<[u32]> -{ - #[inline(always)] - fn next_u32(&mut self) -> u32 { - if self.index >= self.results.as_ref().len() { - self.generate_and_set(0); - } - - let value = self.results.as_ref()[self.index]; - self.index += 1; - value - } - - #[inline(always)] - fn next_u64(&mut self) -> u64 { - let read_u64 = |results: &[u32], index| { - if cfg!(any(target_arch = "x86", target_arch = "x86_64")) { - // requires little-endian CPU supporting unaligned reads: - unsafe { *(&results[index] as *const u32 as *const u64) } - } else { - let x = u64::from(results[index]); - let y = u64::from(results[index + 1]); - (y << 32) | x - } - }; - - let len = self.results.as_ref().len(); - - let index = self.index; - if index < len-1 { - self.index += 2; - // Read an u64 from the current index - read_u64(self.results.as_ref(), index) - } else if index >= len { - self.generate_and_set(2); - read_u64(self.results.as_ref(), 0) - } else { - let x = u64::from(self.results.as_ref()[len-1]); - self.generate_and_set(1); - let y = u64::from(self.results.as_ref()[0]); - (y << 32) | x - } - } - - // As an optimization we try to write directly into the output buffer. - // This is only enabled for little-endian platforms where unaligned writes - // are known to be safe and fast. - #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - fn fill_bytes(&mut self, dest: &mut [u8]) { - let mut filled = 0; - - // Continue filling from the current set of results - if self.index < self.results.as_ref().len() { - let (consumed_u32, filled_u8) = - fill_via_u32_chunks(&self.results.as_ref()[self.index..], - dest); - - self.index += consumed_u32; - filled += filled_u8; - } - - let len_remainder = - (dest.len() - filled) % (self.results.as_ref().len() * 4); - let end_direct = dest.len() - len_remainder; - - while filled < end_direct { - let dest_u32: &mut R::Results = unsafe { - &mut *(dest[filled..].as_mut_ptr() as - *mut ::Results) - }; - self.core.generate(dest_u32); - filled += self.results.as_ref().len() * 4; - self.index = self.results.as_ref().len(); - } - - if len_remainder > 0 { - self.core.generate(&mut self.results); - let (consumed_u32, _) = - fill_via_u32_chunks(self.results.as_ref(), - &mut dest[filled..]); - - self.index = consumed_u32; - } - } - - #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] - fn fill_bytes(&mut self, dest: &mut [u8]) { - let mut read_len = 0; - while read_len < dest.len() { - if self.index >= self.results.as_ref().len() { - self.generate_and_set(0); - } - let (consumed_u32, filled_u8) = - fill_via_u32_chunks(&self.results.as_ref()[self.index..], - &mut dest[read_len..]); - - self.index += consumed_u32; - read_len += filled_u8; - } - } - - fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { - self.fill_bytes(dest); - Ok(()) - } -} - -impl SeedableRng for BlockRng { - type Seed = R::Seed; - - fn from_seed(seed: Self::Seed) -> Self { - Self::new(R::from_seed(seed)) - } - - fn from_rng(rng: S) -> Result { - Ok(Self::new(R::from_rng(rng)?)) - } -} - - - -/// A wrapper type implementing [`RngCore`] for some type implementing -/// [`BlockRngCore`] with `u64` array buffer; i.e. this can be used to implement -/// a full RNG from just a `generate` function. -/// -/// This is similar to [`BlockRng`], but specialized for algorithms that operate -/// on `u64` values. -/// -/// Like [`BlockRng`], this wrapper does not throw away whole results and does -/// use all generated values in-order. The behaviour of `next_u32` is however -/// a bit special: half of a `u64` is consumed, leaving the other half in the -/// buffer. If the next function called is `next_u32` then the other half is -/// then consumed, however both `next_u64` and `fill_bytes` discard any -/// half-consumed `u64`s when called. -/// -/// [`BlockRngCore`]: ../BlockRngCore.t.html -/// [`RngCore`]: ../RngCore.t.html -/// [`BlockRng`]: struct.BlockRng.html -#[derive(Clone)] -#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))] -pub struct BlockRng64 { - results: R::Results, - index: usize, - half_used: bool, // true if only half of the previous result is used - /// The *core* part of the RNG, implementing the `generate` function. - pub core: R, -} - -// Custom Debug implementation that does not expose the contents of `results`. -impl fmt::Debug for BlockRng64 { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - fmt.debug_struct("BlockRng64") - .field("core", &self.core) - .field("result_len", &self.results.as_ref().len()) - .field("index", &self.index) - .field("half_used", &self.half_used) - .finish() - } -} - -impl BlockRng64 { - /// Create a new `BlockRng` from an existing RNG implementing - /// `BlockRngCore`. Results will be generated on first use. - pub fn new(core: R) -> BlockRng64{ - let results_empty = R::Results::default(); - BlockRng64 { - core, - index: results_empty.as_ref().len(), - half_used: false, - results: results_empty, - } - } - - /// Get the index into the result buffer. - /// - /// If this is equal to or larger than the size of the result buffer then - /// the buffer is "empty" and `generate()` must be called to produce new - /// results. - pub fn index(&self) -> usize { - self.index - } - - /// Reset the number of available results. - /// This will force a new set of results to be generated on next use. - pub fn reset(&mut self) { - self.index = self.results.as_ref().len(); - self.half_used = false; - } - - /// Generate a new set of results immediately, setting the index to the - /// given value. - pub fn generate_and_set(&mut self, index: usize) { - assert!(index < self.results.as_ref().len()); - self.core.generate(&mut self.results); - self.index = index; - self.half_used = false; - } -} - -impl> RngCore for BlockRng64 -where ::Results: AsRef<[u64]> + AsMut<[u64]> -{ - #[inline(always)] - fn next_u32(&mut self) -> u32 { - let mut index = self.index * 2 - self.half_used as usize; - if index >= self.results.as_ref().len() * 2 { - self.core.generate(&mut self.results); - self.index = 0; - // `self.half_used` is by definition `false` - self.half_used = false; - index = 0; - } - - self.half_used = !self.half_used; - self.index += self.half_used as usize; - - // Index as if this is a u32 slice. - unsafe { - let results = - &*(self.results.as_ref() as *const [u64] as *const [u32]); - if cfg!(target_endian = "little") { - *results.get_unchecked(index) - } else { - *results.get_unchecked(index ^ 1) - } - } - } - - #[inline(always)] - fn next_u64(&mut self) -> u64 { - if self.index >= self.results.as_ref().len() { - self.core.generate(&mut self.results); - self.index = 0; - } - - let value = self.results.as_ref()[self.index]; - self.index += 1; - self.half_used = false; - value - } - - // As an optimization we try to write directly into the output buffer. - // This is only enabled for little-endian platforms where unaligned writes - // are known to be safe and fast. - #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - fn fill_bytes(&mut self, dest: &mut [u8]) { - let mut filled = 0; - self.half_used = false; - - // Continue filling from the current set of results - if self.index < self.results.as_ref().len() { - let (consumed_u64, filled_u8) = - fill_via_u64_chunks(&self.results.as_ref()[self.index..], - dest); - - self.index += consumed_u64; - filled += filled_u8; - } - - let len_remainder = - (dest.len() - filled) % (self.results.as_ref().len() * 8); - let end_direct = dest.len() - len_remainder; - - while filled < end_direct { - let dest_u64: &mut R::Results = unsafe { - ::core::mem::transmute(dest[filled..].as_mut_ptr()) - }; - self.core.generate(dest_u64); - filled += self.results.as_ref().len() * 8; - self.index = self.results.as_ref().len(); - } - - if len_remainder > 0 { - self.core.generate(&mut self.results); - let (consumed_u64, _) = - fill_via_u64_chunks(&mut self.results.as_ref(), - &mut dest[filled..]); - - self.index = consumed_u64; - } - } - - #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] - fn fill_bytes(&mut self, dest: &mut [u8]) { - let mut read_len = 0; - self.half_used = false; - while read_len < dest.len() { - if self.index as usize >= self.results.as_ref().len() { - self.core.generate(&mut self.results); - self.index = 0; - } - - let (consumed_u64, filled_u8) = - fill_via_u64_chunks(&self.results.as_ref()[self.index as usize..], - &mut dest[read_len..]); - - self.index += consumed_u64; - read_len += filled_u8; - } - } - - fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { - Ok(self.fill_bytes(dest)) - } -} - -impl SeedableRng for BlockRng64 { - type Seed = R::Seed; - - fn from_seed(seed: Self::Seed) -> Self { - Self::new(R::from_seed(seed)) - } - - fn from_rng(rng: S) -> Result { - Ok(Self::new(R::from_rng(rng)?)) - } -} - -impl CryptoRng for BlockRng {} - // TODO: implement tests for the above diff --git a/rand_core/src/lib.rs b/rand_core/src/lib.rs index 98120cbc852..1fa79bf7b10 100644 --- a/rand_core/src/lib.rs +++ b/rand_core/src/lib.rs @@ -59,6 +59,7 @@ pub use error::{ErrorKind, Error}; mod error; +pub mod block; pub mod impls; pub mod le; @@ -191,59 +192,6 @@ pub trait RngCore { fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error>; } -/// A trait for RNGs which do not generate random numbers individually, but in -/// blocks (typically `[u32; N]`). This technique is commonly used by -/// cryptographic RNGs to improve performance. -/// -/// Usage of this trait is optional, but provides two advantages: -/// implementations only need to concern themselves with generation of the -/// block, not the various [`RngCore`] methods (especially [`fill_bytes`], where the -/// optimal implementations are not trivial), and this allows `ReseedingRng` to -/// perform periodic reseeding with very low overhead. -/// -/// # Example -/// -/// ```norun -/// use rand_core::BlockRngCore; -/// use rand_core::impls::BlockRng; -/// -/// struct MyRngCore; -/// -/// impl BlockRngCore for MyRngCore { -/// type Results = [u32; 16]; -/// -/// fn generate(&mut self, results: &mut Self::Results) { -/// unimplemented!() -/// } -/// } -/// -/// impl SeedableRng for MyRngCore { -/// type Seed = unimplemented!(); -/// fn from_seed(seed: Self::Seed) -> Self { -/// unimplemented!() -/// } -/// } -/// -/// // optionally, also implement CryptoRng for MyRngCore -/// -/// // Final RNG. -/// type MyRng = BlockRng; -/// ``` -/// -/// [`RngCore`]: trait.RngCore.html -/// [`fill_bytes`]: trait.RngCore.html#tymethod.fill_bytes -pub trait BlockRngCore { - /// Results element type, e.g. `u32`. - type Item; - - /// Results type. This is the 'block' an RNG implementing `BlockRngCore` - /// generates, which will usually be an array like `[u32; 16]`. - type Results: AsRef<[Self::Item]> + AsMut<[Self::Item]> + Default; - - /// Generate a new block of results. - fn generate(&mut self, results: &mut Self::Results); -} - /// A marker trait used to indicate that an [`RngCore`] or [`BlockRngCore`] /// implementation is supposed to be cryptographically secure. /// @@ -266,7 +214,7 @@ pub trait BlockRngCore { /// weaknesses such as seeding from a weak entropy source or leaking state. /// /// [`RngCore`]: trait.RngCore.html -/// [`BlockRngCore`]: trait.BlockRngCore.html +/// [`BlockRngCore`]: ../rand_core/block/trait.BlockRngCore.html pub trait CryptoRng {} /// A random number generator that can be explicitly seeded. diff --git a/src/lib.rs b/src/lib.rs index c2f9b5de6cc..2d984448b33 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -203,7 +203,7 @@ extern crate rand_core; // Re-exports from rand_core -pub use rand_core::{RngCore, BlockRngCore, CryptoRng, SeedableRng}; +pub use rand_core::{RngCore, CryptoRng, SeedableRng}; pub use rand_core::{ErrorKind, Error}; // Public exports diff --git a/src/prng/chacha.rs b/src/prng/chacha.rs index 03303238461..e0a0cc599cf 100644 --- a/src/prng/chacha.rs +++ b/src/prng/chacha.rs @@ -11,8 +11,8 @@ //! The ChaCha random number generator. use core::fmt; -use rand_core::{BlockRngCore, CryptoRng, RngCore, SeedableRng, Error, le}; -use rand_core::impls::BlockRng; +use rand_core::{CryptoRng, RngCore, SeedableRng, Error, le}; +use rand_core::block::{BlockRngCore, BlockRng}; const SEED_WORDS: usize = 8; // 8 words for the 256-bit key const STATE_WORDS: usize = 16; diff --git a/src/prng/hc128.rs b/src/prng/hc128.rs index bd7fa46ef4d..3bff4ded7cc 100644 --- a/src/prng/hc128.rs +++ b/src/prng/hc128.rs @@ -11,8 +11,8 @@ //! The HC-128 random number generator. use core::fmt; -use rand_core::{BlockRngCore, CryptoRng, RngCore, SeedableRng, Error, le}; -use rand_core::impls::BlockRng; +use rand_core::{CryptoRng, RngCore, SeedableRng, Error, le}; +use rand_core::block::{BlockRngCore, BlockRng}; const SEED_WORDS: usize = 8; // 128 bit key followed by 128 bit iv diff --git a/src/prng/isaac.rs b/src/prng/isaac.rs index 5bf739d9422..6207472de7b 100644 --- a/src/prng/isaac.rs +++ b/src/prng/isaac.rs @@ -12,8 +12,8 @@ use core::{fmt, slice}; use core::num::Wrapping as w; -use rand_core::{BlockRngCore, RngCore, SeedableRng, Error, le}; -use rand_core::impls::BlockRng; +use rand_core::{RngCore, SeedableRng, Error, le}; +use rand_core::block::{BlockRngCore, BlockRng}; use prng::isaac_array::IsaacArray; #[allow(non_camel_case_types)] diff --git a/src/prng/isaac64.rs b/src/prng/isaac64.rs index 35376fbb73f..8a3ed9eee8f 100644 --- a/src/prng/isaac64.rs +++ b/src/prng/isaac64.rs @@ -12,8 +12,8 @@ use core::{fmt, slice}; use core::num::Wrapping as w; -use rand_core::{BlockRngCore, RngCore, SeedableRng, Error, le}; -use rand_core::impls::BlockRng64; +use rand_core::{RngCore, SeedableRng, Error, le}; +use rand_core::block::{BlockRngCore, BlockRng64}; use prng::isaac_array::IsaacArray; #[allow(non_camel_case_types)] diff --git a/src/rngs/adaptor/reseeding.rs b/src/rngs/adaptor/reseeding.rs index 4af5fa2ac2e..af85da38a5f 100644 --- a/src/rngs/adaptor/reseeding.rs +++ b/src/rngs/adaptor/reseeding.rs @@ -13,8 +13,8 @@ use core::mem::size_of; -use rand_core::{RngCore, BlockRngCore, CryptoRng, SeedableRng, Error, ErrorKind}; -use rand_core::impls::BlockRng; +use rand_core::{RngCore, CryptoRng, SeedableRng, Error, ErrorKind}; +use rand_core::block::{BlockRngCore, BlockRng}; /// A wrapper around any PRNG which reseeds the underlying PRNG after it has /// generated a certain number of random bytes. From 45136b30227d885cb5d0fd8df2039b112c11dec6 Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Wed, 9 May 2018 12:17:15 +0100 Subject: [PATCH 6/8] Improve BlockRngCore doc --- rand_core/src/block.rs | 82 +++++++++++++++++++++++------------------- 1 file changed, 45 insertions(+), 37 deletions(-) diff --git a/rand_core/src/block.rs b/rand_core/src/block.rs index 6ed26caa3f6..0b587113fb4 100644 --- a/rand_core/src/block.rs +++ b/rand_core/src/block.rs @@ -8,7 +8,50 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! [`BlockRng`] trait and implementation helpers +//! The `BlockRngCore` trait and implementation helpers +//! +//! The [`BlockRngCore`] trait exists to assist in the implementation of RNGs +//! which generate a block of data in a cache instead of returning generated +//! values directly. +//! +//! Usage of this trait is optional, but provides two advantages: +//! implementations only need to concern themselves with generation of the +//! block, not the various [`RngCore`] methods (especially [`fill_bytes`], where +//! the optimal implementations are not trivial), and this allows +//! [`ReseedingRng`] perform periodic reseeding with very low overhead. +//! +//! # Example +//! +//! ```norun +//! use rand_core::block::{BlockRngCore, BlockRng}; +//! +//! struct MyRngCore; +//! +//! impl BlockRngCore for MyRngCore { +//! type Results = [u32; 16]; +//! +//! fn generate(&mut self, results: &mut Self::Results) { +//! unimplemented!() +//! } +//! } +//! +//! impl SeedableRng for MyRngCore { +//! type Seed = unimplemented!(); +//! fn from_seed(seed: Self::Seed) -> Self { +//! unimplemented!() +//! } +//! } +//! +//! // optionally, also implement CryptoRng for MyRngCore +//! +//! // Final RNG. +//! type MyRng = BlockRng; +//! ``` +//! +//! [`BlockRngCore`]: trait.BlockRngCore.html +//! [`RngCore`]: ../trait.RngCore.html +//! [`fill_bytes`]: ../trait.RngCore.html#tymethod.fill_bytes +//! [`ReseedingRng`]: ../../rand/rngs/adaptor/struct.ReseedingRng.html use core::convert::AsRef; use core::fmt; @@ -19,42 +62,7 @@ use impls::{fill_via_u32_chunks, fill_via_u64_chunks}; /// blocks (typically `[u32; N]`). This technique is commonly used by /// cryptographic RNGs to improve performance. /// -/// Usage of this trait is optional, but provides two advantages: -/// implementations only need to concern themselves with generation of the -/// block, not the various [`RngCore`] methods (especially [`fill_bytes`], where the -/// optimal implementations are not trivial), and this allows `ReseedingRng` to -/// perform periodic reseeding with very low overhead. -/// -/// # Example -/// -/// ```norun -/// use rand_core::block::{BlockRngCore, BlockRng}; -/// -/// struct MyRngCore; -/// -/// impl BlockRngCore for MyRngCore { -/// type Results = [u32; 16]; -/// -/// fn generate(&mut self, results: &mut Self::Results) { -/// unimplemented!() -/// } -/// } -/// -/// impl SeedableRng for MyRngCore { -/// type Seed = unimplemented!(); -/// fn from_seed(seed: Self::Seed) -> Self { -/// unimplemented!() -/// } -/// } -/// -/// // optionally, also implement CryptoRng for MyRngCore -/// -/// // Final RNG. -/// type MyRng = BlockRng; -/// ``` -/// -/// [`RngCore`]: ../trait.RngCore.html -/// [`fill_bytes`]: ../trait.RngCore.html#tymethod.fill_bytes +/// See the [module documentation](index.html) for details. pub trait BlockRngCore { /// Results element type, e.g. `u32`. type Item; From f4de8629446fbb444e35256aa410190ba735f893 Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Wed, 9 May 2018 12:47:38 +0100 Subject: [PATCH 7/8] Add prelude module --- benches/generators.rs | 4 +--- benches/misc.rs | 3 +-- src/distributions/exponential.rs | 3 +-- src/distributions/mod.rs | 3 +-- src/distributions/normal.rs | 3 +-- src/distributions/uniform.rs | 7 +++---- src/lib.rs | 5 +++-- src/prelude.rs | 28 ++++++++++++++++++++++++++++ 8 files changed, 39 insertions(+), 17 deletions(-) create mode 100644 src/prelude.rs diff --git a/benches/generators.rs b/benches/generators.rs index a5b15ddaf5d..3a70c209890 100644 --- a/benches/generators.rs +++ b/benches/generators.rs @@ -9,13 +9,11 @@ const BYTES_LEN: usize = 1024; use std::mem::size_of; use test::{black_box, Bencher}; -use rand::{RngCore, Rng, SeedableRng, FromEntropy}; +use rand::prelude::*; use rand::prng::{XorShiftRng, Hc128Rng, IsaacRng, Isaac64Rng, ChaChaRng}; use rand::prng::hc128::Hc128Core; use rand::rngs::adaptor::ReseedingRng; use rand::rngs::{OsRng, JitterRng, EntropyRng}; -use rand::rngs::{StdRng, SmallRng}; -use rand::thread_rng; macro_rules! gen_bytes { ($fnn:ident, $gen:expr) => { diff --git a/benches/misc.rs b/benches/misc.rs index d6ac2189469..4eb910c9d2d 100644 --- a/benches/misc.rs +++ b/benches/misc.rs @@ -7,8 +7,7 @@ const RAND_BENCH_N: u64 = 1000; use test::{black_box, Bencher}; -use rand::{SeedableRng, Rng, thread_rng}; -use rand::rngs::SmallRng; +use rand::prelude::*; use rand::seq::*; #[bench] diff --git a/src/distributions/exponential.rs b/src/distributions/exponential.rs index 6212f66d482..8c55f804c5b 100644 --- a/src/distributions/exponential.rs +++ b/src/distributions/exponential.rs @@ -30,8 +30,7 @@ use distributions::{ziggurat, ziggurat_tables, Distribution}; /// /// # Example /// ```rust -/// use rand::{FromEntropy, Rng}; -/// use rand::rngs::SmallRng; +/// use rand::prelude::*; /// use rand::distributions::Exp1; /// /// let val: f64 = SmallRng::from_entropy().sample(Exp1); diff --git a/src/distributions/mod.rs b/src/distributions/mod.rs index b96dd99f784..fbe09d07ba0 100644 --- a/src/distributions/mod.rs +++ b/src/distributions/mod.rs @@ -400,8 +400,7 @@ impl<'a, D, R, T> Iterator for DistIter<'a, D, R, T> /// /// # Example /// ``` -/// use rand::{FromEntropy, Rng}; -/// use rand::rngs::SmallRng; +/// use rand::prelude::*; /// use rand::distributions::Standard; /// /// let val: f32 = SmallRng::from_entropy().sample(Standard); diff --git a/src/distributions/normal.rs b/src/distributions/normal.rs index 914fea15225..ac24b018c58 100644 --- a/src/distributions/normal.rs +++ b/src/distributions/normal.rs @@ -28,8 +28,7 @@ use distributions::{ziggurat, ziggurat_tables, Distribution, Open01}; /// /// # Example /// ```rust -/// use rand::{FromEntropy, Rng}; -/// use rand::rngs::SmallRng; +/// use rand::prelude::*; /// use rand::distributions::StandardNormal; /// /// let val: f64 = SmallRng::from_entropy().sample(StandardNormal); diff --git a/src/distributions/uniform.rs b/src/distributions/uniform.rs index 0dffb0d5b00..f5b40bfddc5 100644 --- a/src/distributions/uniform.rs +++ b/src/distributions/uniform.rs @@ -53,10 +53,9 @@ //! The example below merely wraps another back-end. //! //! ``` -//! use rand::{Rng, thread_rng}; -//! use rand::distributions::Distribution; -//! use rand::distributions::uniform::{Uniform, SampleUniform}; -//! use rand::distributions::uniform::{UniformSampler, UniformFloat}; +//! use rand::prelude::*; +//! use rand::distributions::uniform::{Uniform, SampleUniform, +//! UniformSampler, UniformFloat}; //! //! #[derive(Clone, Copy, PartialEq, PartialOrd)] //! struct MyF32(f32); diff --git a/src/lib.rs b/src/lib.rs index 2d984448b33..5a19a1ccdc4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -213,6 +213,7 @@ pub use rand_core::{ErrorKind, Error}; pub mod distributions; pub mod mock; // Public so we don't export `StepRng` directly, making it a bit // more clear it is intended for testing. +pub mod prelude; pub mod prng; pub mod rngs; #[cfg(feature = "alloc")] pub mod seq; @@ -809,8 +810,8 @@ pub trait FromEntropy: SeedableRng { /// /// ```rust /// # use rand::Error; - /// use rand::{Rng, SeedableRng}; - /// use rand::rngs::{EntropyRng, StdRng}; + /// use rand::prelude::*; + /// use rand::rngs::EntropyRng; /// /// # fn try_inner() -> Result<(), Error> { /// // This uses StdRng, but is valid for any R: SeedableRng diff --git a/src/prelude.rs b/src/prelude.rs new file mode 100644 index 00000000000..358c2370823 --- /dev/null +++ b/src/prelude.rs @@ -0,0 +1,28 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// https://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Convenience re-export of common members +//! +//! Like the standard library's prelude, this module simplifies importing of +//! common items. Unlike the standard prelude, the contents of this module must +//! be imported manually: +//! +//! ``` +//! use rand::prelude::*; +//! # let _ = StdRng::from_entropy(); +//! # let mut r = SmallRng::from_rng(thread_rng()).unwrap(); +//! # let _: f32 = r.gen(); +//! ``` + +#[doc(no_inline)] pub use distributions::Distribution; +#[doc(no_inline)] pub use rngs::{SmallRng, StdRng}; +#[doc(no_inline)] #[cfg(feature="std")] pub use rngs::ThreadRng; +#[doc(no_inline)] pub use {Rng, RngCore, CryptoRng, SeedableRng}; +#[doc(no_inline)] #[cfg(feature="std")] pub use {FromEntropy, random, thread_rng}; From f1f544a700f797e20fe4d7edb07ba425b59a5401 Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Thu, 10 May 2018 10:55:12 +0100 Subject: [PATCH 8/8] Mock mock module to rngs/mock --- src/distributions/float.rs | 2 +- src/distributions/mod.rs | 2 +- src/lib.rs | 4 +--- src/rngs/adaptor/reseeding.rs | 2 +- src/{ => rngs}/mock.rs | 2 +- src/rngs/mod.rs | 2 ++ 6 files changed, 7 insertions(+), 7 deletions(-) rename src/{ => rngs}/mock.rs (98%) diff --git a/src/distributions/float.rs b/src/distributions/float.rs index 6db9b6d2aed..83af82984b4 100644 --- a/src/distributions/float.rs +++ b/src/distributions/float.rs @@ -148,7 +148,7 @@ float_impls! { f64, u64, 52, 1023 } mod tests { use Rng; use distributions::{Open01, OpenClosed01}; - use mock::StepRng; + use rngs::mock::StepRng; const EPSILON32: f32 = ::core::f32::EPSILON; const EPSILON64: f64 = ::core::f64::EPSILON; diff --git a/src/distributions/mod.rs b/src/distributions/mod.rs index fbe09d07ba0..7be8749dd95 100644 --- a/src/distributions/mod.rs +++ b/src/distributions/mod.rs @@ -622,7 +622,7 @@ fn ziggurat( #[cfg(test)] mod tests { use Rng; - use mock::StepRng; + use rngs::mock::StepRng; use super::{WeightedChoice, Weighted, Distribution}; #[test] diff --git a/src/lib.rs b/src/lib.rs index 5a19a1ccdc4..01cc15dd0bf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -211,8 +211,6 @@ pub use rand_core::{ErrorKind, Error}; // Public modules pub mod distributions; -pub mod mock; // Public so we don't export `StepRng` directly, making it a bit - // more clear it is intended for testing. pub mod prelude; pub mod prng; pub mod rngs; @@ -933,7 +931,7 @@ pub fn sample(rng: &mut R, iterable: I, amount: usize) -> Vec #[cfg(test)] mod test { - use mock::StepRng; + use rngs::mock::StepRng; use super::*; #[cfg(all(not(feature="std"), feature="alloc"))] use alloc::boxed::Box; diff --git a/src/rngs/adaptor/reseeding.rs b/src/rngs/adaptor/reseeding.rs index af85da38a5f..7ec8de51675 100644 --- a/src/rngs/adaptor/reseeding.rs +++ b/src/rngs/adaptor/reseeding.rs @@ -224,7 +224,7 @@ where R: BlockRngCore + SeedableRng + CryptoRng, mod test { use {Rng, SeedableRng}; use prng::chacha::ChaChaCore; - use mock::StepRng; + use rngs::mock::StepRng; use super::ReseedingRng; #[test] diff --git a/src/mock.rs b/src/rngs/mock.rs similarity index 98% rename from src/mock.rs rename to src/rngs/mock.rs index 090258ef8b2..3651e04776b 100644 --- a/src/mock.rs +++ b/src/rngs/mock.rs @@ -20,7 +20,7 @@ use rand_core::{RngCore, Error, impls}; /// /// ```rust /// use rand::Rng; -/// use rand::mock::StepRng; +/// use rand::rngs::mock::StepRng; /// /// let mut my_rng = StepRng::new(2, 1); /// let sample: [u64; 3] = my_rng.gen(); diff --git a/src/rngs/mod.rs b/src/rngs/mod.rs index ee987acae9f..aa204ecc757 100644 --- a/src/rngs/mod.rs +++ b/src/rngs/mod.rs @@ -14,6 +14,8 @@ pub mod adaptor; #[cfg(feature="std")] mod entropy; #[doc(hidden)] pub mod jitter; +pub mod mock; // Public so we don't export `StepRng` directly, making it a bit + // more clear it is intended for testing. #[cfg(feature="std")] #[doc(hidden)] pub mod os; mod small; mod std;