diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f195af0..0780ced2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Removed dependency `getrandom` ([rand#1674]) - Removed optional dependency `serde` ([#28]) - Add `SeedableRng::fork` methods ([#17]) +- Rename trait `block::BlockRngCore` to `block::Generator` and associated type `Results` to `Output`; remove assoc. `type Item` and remove type bounds ([#26]) ### Other - Changed repository from [rust-random/rand] to [rust-random/core]. @@ -26,6 +27,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [rand#1669]: https://github.com/rust-random/rand/pull/1669 [rand#1674]: https://github.com/rust-random/rand/pull/1674 [#17]: https://github.com/rust-random/rand-core/pull/17 +[#26]: https://github.com/rust-random/rand-core/pull/28 [#28]: https://github.com/rust-random/rand-core/pull/28 [rust-random/rand]: https://github.com/rust-random/rand diff --git a/src/block.rs b/src/block.rs index 2cba57e0..c04abb61 100644 --- a/src/block.rs +++ b/src/block.rs @@ -1,6 +1,6 @@ -//! The `BlockRngCore` trait and implementation helpers +//! The `Generator` trait and implementation helpers //! -//! The [`BlockRngCore`] trait exists to assist in the implementation of RNGs +//! The [`Generator`] trait exists to assist in the implementation of RNGs //! which generate a block of data in a cache instead of returning generated //! values directly. //! @@ -15,15 +15,14 @@ //! //! ```no_run //! use rand_core::{RngCore, SeedableRng}; -//! use rand_core::block::{BlockRngCore, BlockRng}; +//! use rand_core::block::{Generator, BlockRng}; //! //! struct MyRngCore; //! -//! impl BlockRngCore for MyRngCore { -//! type Item = u32; -//! type Results = [u32; 16]; +//! impl Generator for MyRngCore { +//! type Output = [u32; 16]; //! -//! fn generate(&mut self, results: &mut Self::Results) { +//! fn generate(&mut self, output: &mut Self::Output) { //! unimplemented!() //! } //! } @@ -35,45 +34,47 @@ //! } //! } //! -//! // optionally, also implement CryptoBlockRng for MyRngCore +//! // optionally, also implement CryptoGenerator for MyRngCore //! //! // Final RNG. //! let mut rng = BlockRng::::seed_from_u64(0); //! println!("First value: {}", rng.next_u32()); //! ``` //! -//! [`BlockRngCore`]: crate::block::BlockRngCore +//! [`Generator`]: crate::block::Generator //! [`fill_bytes`]: RngCore::fill_bytes use crate::le::fill_via_chunks; use crate::{CryptoRng, RngCore, SeedableRng, TryRngCore}; use core::fmt; -/// 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. -/// -/// See the [module][crate::block] documentation for details. -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; +/// A random (block) generator +pub trait Generator { + /// The output type. + /// + /// For use with [`rand_core::block`](crate::block) code this must be `[u32; _]` or `[u64; _]`. + type Output; - /// Generate a new block of results. - fn generate(&mut self, results: &mut Self::Results); + /// Generate a new block of `output`. + /// + /// This must fill `output` with random data. + fn generate(&mut self, output: &mut Self::Output); } -/// A marker trait used to indicate that an [`RngCore`] implementation is -/// supposed to be cryptographically secure. +/// A cryptographically secure generator +/// +/// This is a marker trait used to indicate that a [`Generator`] implementation +/// is supposed to be cryptographically secure. +/// +/// Mock generators should not implement this trait *except* under a +/// `#[cfg(test)]` attribute to ensure that mock "crypto" generators cannot be +/// used in production. /// /// See [`CryptoRng`] docs for more information. -pub trait CryptoBlockRng: BlockRngCore {} +pub trait CryptoGenerator: Generator {} /// A wrapper type implementing [`RngCore`] for some type implementing -/// [`BlockRngCore`] with `u32` array buffer; i.e. this can be used to implement +/// [`Generator`] 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. @@ -86,7 +87,7 @@ pub trait CryptoBlockRng: BlockRngCore {} /// /// `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 +/// calling [`Generator::generate`] directly on the output array when /// [`fill_bytes`] is called on a large array. These methods also handle /// the bookkeeping of when to generate a new batch of values. /// @@ -106,34 +107,32 @@ pub trait CryptoBlockRng: BlockRngCore {} /// [`next_u64`]: RngCore::next_u64 /// [`fill_bytes`]: RngCore::fill_bytes #[derive(Clone)] -pub struct BlockRng { - results: R::Results, +pub struct BlockRng { + results: G::Output, index: usize, /// The *core* part of the RNG, implementing the `generate` function. - pub core: R, + pub core: G, } // Custom Debug implementation that does not expose the contents of `results`. -impl fmt::Debug for BlockRng { +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 { +impl> BlockRng { /// Create a new `BlockRng` from an existing RNG implementing - /// `BlockRngCore`. Results will be generated on first use. + /// `Generator`. Results will be generated on first use. #[inline] - pub fn new(core: R) -> BlockRng { - let results_empty = R::Results::default(); + pub fn new(core: G) -> BlockRng { BlockRng { core, - index: results_empty.as_ref().len(), - results: results_empty, + index: N, + results: [0; N], } } @@ -151,27 +150,27 @@ impl BlockRng { /// This will force a new set of results to be generated on next use. #[inline] pub fn reset(&mut self) { - self.index = self.results.as_ref().len(); + self.index = N; } /// Generate a new set of results immediately, setting the index to the /// given value. #[inline] pub fn generate_and_set(&mut self, index: usize) { - assert!(index < self.results.as_ref().len()); + assert!(index < N); self.core.generate(&mut self.results); self.index = index; } } -impl> RngCore for BlockRng { +impl> RngCore for BlockRng { #[inline] fn next_u32(&mut self) -> u32 { - if self.index >= self.results.as_ref().len() { + if self.index >= N { self.generate_and_set(0); } - let value = self.results.as_ref()[self.index]; + let value = self.results[self.index]; self.index += 1; value } @@ -183,20 +182,18 @@ impl> RngCore for BlockRng { (u64::from(data[1]) << 32) | u64::from(data[0]) }; - let len = self.results.as_ref().len(); - let index = self.index; - if index < len - 1 { + if index < N - 1 { self.index += 2; // Read an u64 from the current index - read_u64(self.results.as_ref(), index) - } else if index >= len { + read_u64(&self.results, index) + } else if index >= N { self.generate_and_set(2); - read_u64(self.results.as_ref(), 0) + read_u64(&self.results, 0) } else { - let x = u64::from(self.results.as_ref()[len - 1]); + let x = u64::from(self.results[N - 1]); self.generate_and_set(1); - let y = u64::from(self.results.as_ref()[0]); + let y = u64::from(self.results[0]); (y << 32) | x } } @@ -205,11 +202,11 @@ impl> RngCore for BlockRng { 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() { + if self.index >= N { self.generate_and_set(0); } let (consumed_u32, filled_u8) = - fill_via_chunks(&self.results.as_mut()[self.index..], &mut dest[read_len..]); + fill_via_chunks(&self.results[self.index..], &mut dest[read_len..]); self.index += consumed_u32; read_len += filled_u8; @@ -217,34 +214,34 @@ impl> RngCore for BlockRng { } } -impl SeedableRng for BlockRng { - type Seed = R::Seed; +impl + SeedableRng> SeedableRng for BlockRng { + type Seed = G::Seed; #[inline(always)] fn from_seed(seed: Self::Seed) -> Self { - Self::new(R::from_seed(seed)) + Self::new(G::from_seed(seed)) } #[inline(always)] fn seed_from_u64(seed: u64) -> Self { - Self::new(R::seed_from_u64(seed)) + Self::new(G::seed_from_u64(seed)) } #[inline(always)] fn from_rng(rng: &mut S) -> Self { - Self::new(R::from_rng(rng)) + Self::new(G::from_rng(rng)) } #[inline(always)] fn try_from_rng(rng: &mut S) -> Result { - R::try_from_rng(rng).map(Self::new) + G::try_from_rng(rng).map(Self::new) } } -impl> CryptoRng for BlockRng {} +impl> CryptoRng for BlockRng {} /// A wrapper type implementing [`RngCore`] for some type implementing -/// [`BlockRngCore`] with `u64` array buffer; i.e. this can be used to implement +/// [`Generator`] 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 @@ -264,37 +261,35 @@ impl> CryptoRng for BlockRng {} /// [`next_u64`]: RngCore::next_u64 /// [`fill_bytes`]: RngCore::fill_bytes #[derive(Clone)] -pub struct BlockRng64 { - results: R::Results, +pub struct BlockRng64 { + results: G::Output, 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, + pub core: G, } // Custom Debug implementation that does not expose the contents of `results`. -impl fmt::Debug for BlockRng64 { +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 { +impl> BlockRng64 { /// Create a new `BlockRng` from an existing RNG implementing - /// `BlockRngCore`. Results will be generated on first use. + /// `Generator`. Results will be generated on first use. #[inline] - pub fn new(core: R) -> BlockRng64 { - let results_empty = R::Results::default(); + pub fn new(core: G) -> BlockRng64 { BlockRng64 { core, - index: results_empty.as_ref().len(), + index: N, half_used: false, - results: results_empty, + results: [0; N], } } @@ -312,7 +307,7 @@ impl BlockRng64 { /// This will force a new set of results to be generated on next use. #[inline] pub fn reset(&mut self) { - self.index = self.results.as_ref().len(); + self.index = N; self.half_used = false; } @@ -320,18 +315,18 @@ impl BlockRng64 { /// given value. #[inline] pub fn generate_and_set(&mut self, index: usize) { - assert!(index < self.results.as_ref().len()); + assert!(index < N); self.core.generate(&mut self.results); self.index = index; self.half_used = false; } } -impl> RngCore for BlockRng64 { +impl> RngCore for BlockRng64 { #[inline] fn next_u32(&mut self) -> u32 { let mut index = self.index - self.half_used as usize; - if index >= self.results.as_ref().len() { + if index >= N { self.core.generate(&mut self.results); self.index = 0; index = 0; @@ -344,17 +339,17 @@ impl> RngCore for BlockRng64 { self.half_used = !self.half_used; self.index += self.half_used as usize; - (self.results.as_ref()[index] >> shift) as u32 + (self.results[index] >> shift) as u32 } #[inline] fn next_u64(&mut self) -> u64 { - if self.index >= self.results.as_ref().len() { + if self.index >= N { self.core.generate(&mut self.results); self.index = 0; } - let value = self.results.as_ref()[self.index]; + let value = self.results[self.index]; self.index += 1; self.half_used = false; value @@ -365,13 +360,13 @@ impl> RngCore for BlockRng64 { let mut read_len = 0; self.half_used = false; while read_len < dest.len() { - if self.index >= self.results.as_ref().len() { + if self.index >= N { self.core.generate(&mut self.results); self.index = 0; } let (consumed_u64, filled_u8) = - fill_via_chunks(&self.results.as_mut()[self.index..], &mut dest[read_len..]); + fill_via_chunks(&self.results[self.index..], &mut dest[read_len..]); self.index += consumed_u64; read_len += filled_u8; @@ -379,35 +374,35 @@ impl> RngCore for BlockRng64 { } } -impl SeedableRng for BlockRng64 { - type Seed = R::Seed; +impl + SeedableRng> SeedableRng for BlockRng64 { + type Seed = G::Seed; #[inline(always)] fn from_seed(seed: Self::Seed) -> Self { - Self::new(R::from_seed(seed)) + Self::new(G::from_seed(seed)) } #[inline(always)] fn seed_from_u64(seed: u64) -> Self { - Self::new(R::seed_from_u64(seed)) + Self::new(G::seed_from_u64(seed)) } #[inline(always)] fn from_rng(rng: &mut S) -> Self { - Self::new(R::from_rng(rng)) + Self::new(G::from_rng(rng)) } #[inline(always)] fn try_from_rng(rng: &mut S) -> Result { - R::try_from_rng(rng).map(Self::new) + G::try_from_rng(rng).map(Self::new) } } -impl> CryptoRng for BlockRng64 {} +impl> CryptoRng for BlockRng64 {} #[cfg(test)] mod test { - use crate::block::{BlockRng, BlockRng64, BlockRngCore}; + use crate::block::{BlockRng, BlockRng64, Generator}; use crate::{RngCore, SeedableRng}; #[derive(Debug, Clone)] @@ -415,13 +410,12 @@ mod test { counter: u32, } - impl BlockRngCore for DummyRng { - type Item = u32; - type Results = [u32; 16]; + impl Generator for DummyRng { + type Output = [u32; 16]; - fn generate(&mut self, results: &mut Self::Results) { - for r in results { - *r = self.counter; + fn generate(&mut self, output: &mut Self::Output) { + for item in output { + *item = self.counter; self.counter = self.counter.wrapping_add(3511615421); } } @@ -466,13 +460,12 @@ mod test { counter: u64, } - impl BlockRngCore for DummyRng64 { - type Item = u64; - type Results = [u64; 8]; + impl Generator for DummyRng64 { + type Output = [u64; 8]; - fn generate(&mut self, results: &mut Self::Results) { - for r in results { - *r = self.counter; + fn generate(&mut self, output: &mut Self::Output) { + for item in output { + *item = self.counter; self.counter = self.counter.wrapping_add(2781463553396133981); } } @@ -517,23 +510,23 @@ mod test { #[test] fn blockrng64_generate_and_set() { let mut rng = BlockRng64::::from_seed([1, 2, 3, 4, 5, 6, 7, 8]); - assert_eq!(rng.index(), rng.results.as_ref().len()); + assert_eq!(rng.index(), rng.results.len()); rng.generate_and_set(5); assert_eq!(rng.index(), 5); } #[test] - #[should_panic(expected = "index < self.results.as_ref().len()")] + #[should_panic(expected = "index < N")] fn blockrng64_generate_and_set_panic() { let mut rng = BlockRng64::::from_seed([1, 2, 3, 4, 5, 6, 7, 8]); - rng.generate_and_set(rng.results.as_ref().len()); + rng.generate_and_set(rng.results.len()); } #[test] fn blockrng_next_u64() { let mut rng = BlockRng::::from_seed([1, 2, 3, 4]); - let result_size = rng.results.as_ref().len(); + let result_size = rng.results.len(); for _i in 0..result_size / 2 - 1 { rng.next_u64(); }