diff --git a/rand_core/CHANGELOG.md b/rand_core/CHANGELOG.md index 79603a4f438..ab9aef99231 100644 --- a/rand_core/CHANGELOG.md +++ b/rand_core/CHANGELOG.md @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [0.2.0] - Unreleased - Enable the `std` feature by default. (#409) -- Change `BlockRng64::inner` and add `BlockRng64::inner_mut` to mirror `BlockRng`. (#419) +- Remove `BlockRng{64}::inner` and `BlockRng::inner_mut`; instead making `core` public - Add `BlockRng{64}::index` and `BlockRng{64}::generate_and_set`. (#374, #419) - Change `BlockRngCore::Results` bound to also require `AsMut<[Self::Item]>`. (#419) diff --git a/rand_core/src/impls.rs b/rand_core/src/impls.rs index 54b122e07b9..f66e1e9c883 100644 --- a/rand_core/src/impls.rs +++ b/rand_core/src/impls.rs @@ -165,18 +165,28 @@ pub fn next_u64_via_fill(rng: &mut R) -> u64 { impl_uint_from_fill!(rng, u64, 8) } -/// Wrapper around PRNGs that implement [`BlockRngCore`] to keep a results -/// buffer and offer the methods from [`RngCore`]. +/// 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. +/// No generated values are ever thown away and all values are consumed +/// in-order (this may be important for reproducibility). /// -/// Currently `BlockRng` only implements `RngCore` for buffers which are slices -/// of `u32` elements; this may be extended to other types in the future. +/// 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`]. /// @@ -188,7 +198,8 @@ pub fn next_u64_via_fill(rng: &mut R) -> u64 { pub struct BlockRng { results: R::Results, index: usize, - core: R, + /// The *core* part of the RNG, implementing the `generate` function. + pub core: R, } // Custom Debug implementation that does not expose the contents of `results`. @@ -214,16 +225,6 @@ impl BlockRng { } } - /// Return a reference the wrapped `BlockRngCore`. - pub fn inner(&self) -> &R { - &self.core - } - - /// Return a mutable reference the wrapped `BlockRngCore`. - pub fn inner_mut(&mut self) -> &mut R { - &mut self.core - } - /// Get the index into the result buffer. /// /// If this is equal to or larger than the size of the result buffer then @@ -370,12 +371,20 @@ impl SeedableRng for BlockRng { -/// Wrapper around PRNGs that implement [`BlockRngCore`] to keep a results -/// buffer and offer the methods from [`RngCore`]. +/// 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 @@ -385,7 +394,8 @@ pub struct BlockRng64 { results: R::Results, index: usize, half_used: bool, // true if only half of the previous result is used - core: R, + /// The *core* part of the RNG, implementing the `generate` function. + pub core: R, } // Custom Debug implementation that does not expose the contents of `results`. @@ -413,16 +423,6 @@ impl BlockRng64 { } } - /// Return a reference the wrapped `BlockRngCore`. - pub fn inner(&self) -> &R { - &self.core - } - - /// Return a mutable reference the wrapped `BlockRngCore`. - pub fn inner_mut(&mut self) -> &mut R { - &mut self.core - } - /// Get the index into the result buffer. /// /// If this is equal to or larger than the size of the result buffer then @@ -436,6 +436,7 @@ impl BlockRng64 { /// 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 @@ -444,6 +445,7 @@ impl BlockRng64 { assert!(index < self.results.as_ref().len()); self.core.generate(&mut self.results); self.index = index; + self.half_used = false; } } diff --git a/src/prng/chacha.rs b/src/prng/chacha.rs index db45da3d914..03303238461 100644 --- a/src/prng/chacha.rs +++ b/src/prng/chacha.rs @@ -138,9 +138,8 @@ impl ChaChaRng { /// feature is enabled. In the future this will be enabled by default. #[cfg(feature = "i128_support")] pub fn get_word_pos(&self) -> u128 { - let core = self.0.inner(); - let mut c = (core.state[13] as u64) << 32 - | (core.state[12] as u64); + let mut c = (self.0.core.state[13] as u64) << 32 + | (self.0.core.state[12] as u64); let mut index = self.0.index(); // c is the end of the last block generated, unless index is at end if index >= STATE_WORDS { @@ -163,8 +162,8 @@ impl ChaChaRng { pub fn set_word_pos(&mut self, word_offset: u128) { let index = (word_offset as usize) & 0xF; let counter = (word_offset >> 4) as u64; - self.0.inner_mut().state[12] = counter as u32; - self.0.inner_mut().state[13] = (counter >> 32) as u32; + self.0.core.state[12] = counter as u32; + self.0.core.state[13] = (counter >> 32) as u32; if index != 0 { self.0.generate_and_set(index); // also increments counter } else { @@ -185,17 +184,16 @@ impl ChaChaRng { /// indirectly via `set_word_pos`), but this is not directly supported. pub fn set_stream(&mut self, stream: u64) { let index = self.0.index(); - self.0.inner_mut().state[14] = stream as u32; - self.0.inner_mut().state[15] = (stream >> 32) as u32; + self.0.core.state[14] = stream as u32; + self.0.core.state[15] = (stream >> 32) as u32; if index < STATE_WORDS { // we need to regenerate a partial result buffer { // reverse of counter adjustment in generate() - let core = self.0.inner_mut(); - if core.state[12] == 0 { - core.state[13] = core.state[13].wrapping_sub(1); + if self.0.core.state[12] == 0 { + self.0.core.state[13] = self.0.core.state[13].wrapping_sub(1); } - core.state[12] = core.state[12].wrapping_sub(1); + self.0.core.state[12] = self.0.core.state[12].wrapping_sub(1); } self.0.generate_and_set(index); } diff --git a/src/reseeding.rs b/src/reseeding.rs index c74862cbdde..4af5fa2ac2e 100644 --- a/src/reseeding.rs +++ b/src/reseeding.rs @@ -76,7 +76,7 @@ where R: BlockRngCore + SeedableRng, /// Reseed the internal PRNG. pub fn reseed(&mut self) -> Result<(), Error> { - self.0.inner_mut().reseed() + self.0.core.reseed() } } @@ -112,7 +112,7 @@ where R: BlockRngCore + SeedableRng + Clone, fn clone(&self) -> ReseedingRng { // Recreating `BlockRng` seems easier than cloning it and resetting // the index. - ReseedingRng(BlockRng::new(self.0.inner().clone())) + ReseedingRng(BlockRng::new(self.0.core.clone())) } }