diff --git a/CHANGELOG.md b/CHANGELOG.md index 6792d80f..cf82dde3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Replace `le::read_u32_into` and `le::read_u64_into` with `utils::read_words` ([#38]) - Replace fn `BlockRng::index` with `word_offset` ([#44]) - Rename fn `BlockRng::generate_and_set` -> `reset_and_skip`; remove fn `reset` ([#44]) +- `RngCore` is now an extension trait of `TryRngCore` ([#45]) +- Remove `UnwrapMut` ([#45]) +- Add error handling to `utils` functions over `TryRngCore` or via closure ([#45]) ### Other - Changed repository from [rust-random/rand] to [rust-random/core]. @@ -46,6 +49,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [#36]: https://github.com/rust-random/rand-core/pull/36 [#38]: https://github.com/rust-random/rand-core/pull/38 [#44]: https://github.com/rust-random/rand-core/pull/44 +[#45]: https://github.com/rust-random/rand-core/pull/45 [rust-random/rand]: https://github.com/rust-random/rand [rust-random/core]: https://github.com/rust-random/core diff --git a/src/block.rs b/src/block.rs index 3a450fe4..624ebdd6 100644 --- a/src/block.rs +++ b/src/block.rs @@ -6,15 +6,16 @@ //! //! The struct [`BlockRng`] wraps such a [`Generator`] together with an output //! buffer and implements several methods (e.g. [`BlockRng::next_word`]) to -//! assist in the implementation of [`RngCore`]. Note that (unlike in earlier -//! versions of `rand_core`) [`BlockRng`] itself does not implement [`RngCore`] +//! assist in the implementation of [`TryRngCore`]. Note that (unlike in earlier +//! versions of `rand_core`) [`BlockRng`] itself does not implement [`TryRngCore`] //! since in practice we found it was always beneficial to use a wrapper type //! over [`BlockRng`]. //! //! # Example //! //! ``` -//! use rand_core::{RngCore, SeedableRng}; +//! use core::convert::Infallible; +//! use rand_core::{RngCore, SeedableRng, TryRngCore}; //! use rand_core::block::{Generator, BlockRng}; //! //! struct MyRngCore { @@ -45,24 +46,26 @@ //! } //! } //! -//! impl RngCore for MyRng { +//! impl TryRngCore for MyRng { +//! type Error = Infallible; +//! //! #[inline] -//! fn next_u32(&mut self) -> u32 { -//! self.0.next_word() +//! fn try_next_u32(&mut self) -> Result { +//! Ok(self.0.next_word()) //! } //! //! #[inline] -//! fn next_u64(&mut self) -> u64 { -//! self.0.next_u64_from_u32() +//! fn try_next_u64(&mut self) -> Result { +//! Ok(self.0.next_u64_from_u32()) //! } //! //! #[inline] -//! fn fill_bytes(&mut self, bytes: &mut [u8]) { -//! self.0.fill_bytes(bytes) +//! fn try_fill_bytes(&mut self, bytes: &mut [u8]) -> Result<(), Infallible> { +//! Ok(self.0.fill_bytes(bytes)) //! } //! } //! -//! // And if applicable: impl CryptoRng for MyRng {} +//! // And if applicable: impl TryCryptoRng for MyRng {} //! //! let mut rng = MyRng::seed_from_u64(0); //! println!("First value: {}", rng.next_u32()); @@ -74,10 +77,10 @@ //! The [`Generator`] trait supports usage of [`rand::rngs::ReseedingRng`]. //! This requires that [`SeedableRng`] be implemented on the "core" generator. //! Additionally, it may be useful to implement [`CryptoGenerator`]. -//! (This is in addition to any implementations on an [`RngCore`] type.) +//! (This is in addition to any implementations on an [`TryRngCore`] type.) //! //! [`Generator`]: crate::block::Generator -//! [`RngCore`]: crate::RngCore +//! [`TryRngCore`]: crate::TryRngCore //! [`SeedableRng`]: crate::SeedableRng //! [`rand::rngs::ReseedingRng`]: https://docs.rs/rand/latest/rand/rngs/struct.ReseedingRng.html @@ -115,7 +118,7 @@ pub trait Generator { /// `#[cfg(test)]` attribute to ensure that mock "crypto" generators cannot be /// used in production. /// -/// See [`CryptoRng`](crate::CryptoRng) docs for more information. +/// See [`TryCryptoRng`](crate::TryCryptoRng) docs for more information. pub trait CryptoGenerator: Generator {} /// RNG functionality for a block [`Generator`] diff --git a/src/lib.rs b/src/lib.rs index a7323bc7..b4d077b0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,70 +13,37 @@ clippy::undocumented_unsafe_blocks )] -use core::{fmt, ops::DerefMut}; +use core::{convert::Infallible, fmt, ops::DerefMut}; pub mod block; pub mod utils; mod word; -/// Implementation-level interface for RNGs +/// Trait for infallible random number generators /// -/// This trait encapsulates the low-level functionality common to all -/// generators, and is the "back end", to be implemented by generators. -/// End users should normally use the [`rand::Rng`] trait -/// which is automatically implemented for every type implementing `RngCore`. -/// -/// Three different methods for generating random data are provided since the -/// optimal implementation of each is dependent on the type of generator. There -/// is no required relationship between the output of each; e.g. many -/// implementations of [`fill_bytes`] consume a whole number of `u32` or `u64` -/// values and drop any remaining unused bytes. The same can happen with the -/// [`next_u32`] and [`next_u64`] methods, implementations may discard some -/// random bits for efficiency. -/// -/// # Properties of a generator -/// -/// Implementers should produce bits uniformly. Pathological RNGs (e.g. constant -/// or counting generators which rarely change some bits) may cause issues in -/// consumers of random data, for example dead-locks in rejection samplers and -/// obviously non-random output (e.g. a counting generator may result in -/// apparently-constant output from a uniform-ranged distribution). +/// `RngCore` is a sub-trait of [`TryRngCore`] for infallible generators. /// -/// Algorithmic generators implementing [`SeedableRng`] should normally have -/// *portable, reproducible* output, i.e. fix Endianness when converting values -/// to avoid platform differences, and avoid making any changes which affect -/// output (except by communicating that the release has breaking changes). +/// # Requirements /// -/// # Implementing `RngCore` +/// See [`TryRngCore`#Requirements] which also apply here. /// -/// Typically an RNG will implement only one of the methods available -/// in this trait directly, then use the helper functions from the -/// [`utils`] module to implement the other methods. +/// # Usage /// -/// Note that implementors of [`RngCore`] also automatically implement -/// the [`TryRngCore`] trait with the `Error` associated type being -/// equal to [`Infallible`]. +/// The [`rand`] crate provides higher level functionality, for example +/// generation of floating-point values, uniform ranged sampling and shuffling +/// sequences. In particular, [`rand::Rng`] is an extension trait over `RngCore` +/// providing many of the methods one might expect to be able to use on an RNG. /// -/// It is recommended that implementations also implement: +/// # Implementing `RngCore` /// -/// - `Debug` with a custom implementation which *does not* print any internal -/// state (at least, [`CryptoRng`]s should not risk leaking state through -/// `Debug`). -/// - `Serialize` and `Deserialize` (from Serde), preferably making Serde -/// support optional at the crate level in PRNG libs. -/// - `Clone`, if possible. -/// - *never* implement `Copy` (accidental copies may cause repeated values). -/// - *do not* implement `Default` for pseudorandom generators, but instead -/// implement [`SeedableRng`], to guide users towards proper seeding. -/// External / hardware RNGs can choose to implement `Default`. -/// - `Eq` and `PartialEq` could be implemented, but are probably not useful. +/// Implement [`TryRngCore`] with type Error = [core::convert::Infallible][]. /// +/// [`rand`]: https://docs.rs/rand/ /// [`rand::Rng`]: https://docs.rs/rand/latest/rand/trait.Rng.html /// [`fill_bytes`]: RngCore::fill_bytes /// [`next_u32`]: RngCore::next_u32 /// [`next_u64`]: RngCore::next_u64 -/// [`Infallible`]: core::convert::Infallible -pub trait RngCore { +pub trait RngCore: TryRngCore { /// Return the next random `u32`. fn next_u32(&mut self) -> u32; @@ -92,81 +59,136 @@ pub trait RngCore { fn fill_bytes(&mut self, dst: &mut [u8]); } -impl RngCore for T -where - T::Target: RngCore, -{ +impl> RngCore for R { #[inline] fn next_u32(&mut self) -> u32 { - self.deref_mut().next_u32() + match self.try_next_u32() { + Ok(x) => x, + } } #[inline] fn next_u64(&mut self) -> u64 { - self.deref_mut().next_u64() + match self.try_next_u64() { + Ok(x) => x, + } } #[inline] fn fill_bytes(&mut self, dst: &mut [u8]) { - self.deref_mut().fill_bytes(dst); + match self.try_fill_bytes(dst) { + Ok(()) => (), + } } } -/// A marker trait over [`RngCore`] for securely unpredictable RNGs +/// A marker trait for securely unpredictable infallible RNGs /// -/// This marker trait indicates that the implementing generator is intended, -/// when correctly seeded and protected from side-channel attacks such as a -/// leaking of state, to be a cryptographically secure generator. This trait is -/// provided as a tool to aid review of cryptographic code, but does not by -/// itself guarantee suitability for cryptographic applications. +/// This is a convenient trait alias for [TryCryptoRng]. +/// It is equivalent to the trait sum [RngCore] + [TryCryptoRng]. +pub trait CryptoRng: TryCryptoRng {} + +impl> CryptoRng for R {} + +/// Base trait for random number generators and random data sources /// -/// Implementors of `CryptoRng` automatically implement the [`TryCryptoRng`] -/// trait. +/// This trait provides a base interface designed to support efficient usage of +/// (`u32`, `u64`) word generators, block generators and random data sources. +/// There is no required relationship between the output of each method or any +/// requirement to use all generated random bits; for example an implementation +/// of [`try_fill_bytes`](Self::try_fill_bytes) may discard some generated bytes +/// to avoid storing a partially used word or block. /// -/// Implementors of `CryptoRng` should only implement [`Default`] if the -/// `default()` instances are themselves secure generators: for example if the -/// implementing type is a stateless interface over a secure external generator -/// (like [`OsRng`]) or if the `default()` instance uses a strong, fresh seed. +/// # Requirements /// -/// Formally, a CSPRNG (Cryptographically Secure Pseudo-Random Number Generator) -/// should satisfy an additional property over other generators: assuming that -/// the generator has been appropriately seeded and has unknown state, then -/// given the first *k* bits of an algorithm's output -/// sequence, it should not be possible using polynomial-time algorithms to -/// predict the next bit with probability significantly greater than 50%. +/// ### Quality and length /// -/// An optional property of CSPRNGs is backtracking resistance: if the CSPRNG's -/// state is revealed, it will not be computationally-feasible to reconstruct -/// prior output values. This property is not required by `CryptoRng`. +/// Implementions should produce bits uniformly: each output value should be +/// equally likely, without observable patterns in successive outputs or +/// between the output streams of multiple instances of an implementation using +/// different seeds or streams (where supported by the implementation). /// -/// [`OsRng`]: https://docs.rs/rand/latest/rand/rngs/struct.OsRng.html -pub trait CryptoRng: RngCore {} - -impl CryptoRng for T where T::Target: CryptoRng {} - -/// A potentially fallible variant of [`RngCore`] +/// Pathological implementations (e.g. constant or counting generators which +/// rarely change some bits) may cause issues in consumers of random data, for +/// example dead-locks in rejection samplers and obviously non-random output +/// (e.g. a counting generator may result in apparently-constant output from a +/// uniform-ranged distribution). +/// +/// Cryptographically unpredictable output is not a requirement of this trait, +/// but is a requirement of [`TryCryptoRng`]. +/// +/// In practice, most implementations are pseudo-random number generators with a +/// finite *period* or *cycle length*, and (among non-cryptographic PRNGs) +/// statistical anomalies may appear long before a cycle occurs. An +/// implementation should ensure its period is sufficiently long that no +/// anomalies are likely to appear in usage and/or document its limitations. +/// +/// For more on PRNG quality and period, see +/// [The Rust Rand Book: Quality](https://rust-random.github.io/book/guide-rngs.html#quality). +/// +/// ### Reproducibility +/// +/// Algorithmic generators implementing [`SeedableRng`] should normally have +/// *portable, reproducible* output, i.e. fix Endianness when converting values +/// to avoid platform differences, and avoid making any changes which affect +/// output (except by communicating that the release has breaking changes). +/// See also [The Rust Rand Book: Reproducibility](https://rust-random.github.io/book/crate-reprod.html). +/// +/// # Usage +/// +/// Often, usage of the infallible trait [`RngCore`] or its extension trait +/// [`rand::Rng`] is preferred to direct usage of `TryRngCore`. +/// +/// Many implementations of `TryRngCore` (those with +/// type Error = [Infallible][]) already implement [`RngCore`]; in +/// other cases [`Self::unwrap_err`] may be used to obtain an implementation of +/// [`RngCore`]. +/// +/// # Implementing `TryRngCore` +/// +/// Most algorithmic generators (i.e. pseudo-random number generators or PRNGs) +/// never fail; in this case type `Error` should be [`Infallible`]; in this case +/// trait `RngCore` is implemented automatically. Cycling is not considered an +/// error. +/// +/// Small PRNGs often yield either `u32` or `u64` natively. +/// Module [`crate::utils`] provides utilities to help implement other methods. /// -/// This trait is a generalization of [`RngCore`] to support potentially- -/// fallible IO-based generators such as [`OsRng`]. +/// Byte sources may implement [`try_fill_bytes`](Self::try_fill_bytes) +/// natively. +/// Module [`crate::utils`] provides utilities to help implement other methods. /// -/// All implementations of [`RngCore`] automatically support this `TryRngCore` -/// trait, using [`Infallible`][core::convert::Infallible] as the associated -/// `Error` type. +/// Block generators (which produce `[u32; N]` or `[u64; N]` for some fixed `N`) +/// should make use of the [`crate::block`] module. /// -/// An implementation of this trait may be made compatible with code requiring -/// an [`RngCore`] through [`TryRngCore::unwrap_err`]. The resulting RNG will -/// panic in case the underlying fallible RNG yields an error. +/// With regards to other traits: /// -/// [`OsRng`]: https://docs.rs/rand/latest/rand/rngs/struct.OsRng.html +/// - **Do not** implement [`Default`] for seedable pseudorandom generators, +/// though the trait may be implemented for stateless interfaces and +/// auto-seeding generators. +/// - **Do** implement [`SeedableRng`] for seedable pseudorandom generators. See +/// [Reproducibility](#reproducibility) above. +/// - Implement [`Clone`] for non-cryptographic PRNGs but consider not doing so +/// for cryptographic generators to avoid the risk of key-stream duplication. +/// - **Do not** implement [`Copy`] since accidental copies may cause repeated +/// values. +/// - Implement [`Debug`](core::fmt::Debug), except that cryptographic PRNGs +/// should use a custom implementation which avoids leaking internal state (or +/// the subset of this derived from the key). +/// - [`Eq`] and [`PartialEq`] could be implemented, but are probably not useful. +/// +/// [`rand::Rng`]: https://docs.rs/rand/latest/rand/trait.Rng.html pub trait TryRngCore { /// The type returned in the event of a RNG error. + /// + /// Use type [`core::convert::Infallible`] for infallible implementations. type Error: fmt::Debug + fmt::Display; /// Return the next random `u32`. fn try_next_u32(&mut self) -> Result; /// Return the next random `u64`. fn try_next_u64(&mut self) -> Result; - /// Fill `dest` entirely with random data. + /// Fill `dst` entirely with random data. fn try_fill_bytes(&mut self, dst: &mut [u8]) -> Result<(), Self::Error>; /// Wrap RNG with the [`UnwrapErr`] wrapper. @@ -176,119 +198,108 @@ pub trait TryRngCore { { UnwrapErr(self) } - - /// Wrap RNG with the [`UnwrapMut`] wrapper. - fn unwrap_mut(&mut self) -> UnwrapMut<'_, Self> { - UnwrapMut(self) - } } // Note that, unfortunately, this blanket impl prevents us from implementing // `TryRngCore` for types which can be dereferenced to `TryRngCore`, i.e. `TryRngCore` // will not be automatically implemented for `&mut R`, `Box`, etc. -impl TryRngCore for R { - type Error = core::convert::Infallible; +impl TryRngCore for R +where + R::Target: TryRngCore, +{ + type Error = ::Error; #[inline] fn try_next_u32(&mut self) -> Result { - Ok(self.next_u32()) + self.deref_mut().try_next_u32() } #[inline] fn try_next_u64(&mut self) -> Result { - Ok(self.next_u64()) + self.deref_mut().try_next_u64() } #[inline] fn try_fill_bytes(&mut self, dst: &mut [u8]) -> Result<(), Self::Error> { - self.fill_bytes(dst); - Ok(()) + self.deref_mut().try_fill_bytes(dst) } } /// A marker trait over [`TryRngCore`] for securely unpredictable RNGs /// -/// This trait is like [`CryptoRng`] but for the trait [`TryRngCore`]. -/// /// This marker trait indicates that the implementing generator is intended, /// when correctly seeded and protected from side-channel attacks such as a /// leaking of state, to be a cryptographically secure generator. This trait is /// provided as a tool to aid review of cryptographic code, but does not by /// itself guarantee suitability for cryptographic applications. /// -/// Implementors of `TryCryptoRng` should only implement [`Default`] if the -/// `default()` instances are themselves secure generators: for example if the -/// implementing type is a stateless interface over a secure external generator -/// (like [`OsRng`]) or if the `default()` instance uses a strong, fresh seed. +/// Formally, a CSPRNG (Cryptographically Secure Pseudo-Random Number Generator) +/// should satisfy an additional property over other generators: assuming that +/// the generator has been appropriately seeded and has unknown state, then +/// given the first *k* bits of an algorithm's output +/// sequence, it should not be possible using polynomial-time algorithms to +/// predict the next bit with probability significantly greater than 50%. +/// +/// An optional property of CSPRNGs is backtracking resistance: if the CSPRNG's +/// state is revealed, it will not be computationally-feasible to reconstruct +/// prior output values. This property is not required by `CryptoRng`. +/// +/// Implementors of `TryCryptoRng` should only implement [`Default`] if a +/// default-constructed instance is itself a secure generator, for example +/// [`getrandom::SysRng`] which is a stateless interface. /// -/// [`OsRng`]: https://docs.rs/rand/latest/rand/rngs/struct.OsRng.html +/// [`getrandom::SysRng`]: https://docs.rs/getrandom/latest/getrandom/struct.SysRng.html pub trait TryCryptoRng: TryRngCore {} -impl TryCryptoRng for R {} +impl TryCryptoRng for R where R::Target: TryCryptoRng {} /// Wrapper around [`TryRngCore`] implementation which implements [`RngCore`] /// by panicking on potential errors. #[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash)] pub struct UnwrapErr(pub R); -impl RngCore for UnwrapErr { +impl TryRngCore for UnwrapErr { + type Error = Infallible; + #[inline] - fn next_u32(&mut self) -> u32 { - self.0.try_next_u32().unwrap() + fn try_next_u32(&mut self) -> Result { + self.0 + .try_next_u32() + .map_err(|err| panic!("rand_core::UnwrapErr: failed to unwrap: {err}")) } #[inline] - fn next_u64(&mut self) -> u64 { - self.0.try_next_u64().unwrap() + fn try_next_u64(&mut self) -> Result { + self.0 + .try_next_u64() + .map_err(|err| panic!("rand_core::UnwrapErr: failed to unwrap: {err}")) } #[inline] - fn fill_bytes(&mut self, dst: &mut [u8]) { - self.0.try_fill_bytes(dst).unwrap() + fn try_fill_bytes(&mut self, dst: &mut [u8]) -> Result<(), Self::Error> { + self.0 + .try_fill_bytes(dst) + .map_err(|err| panic!("rand_core::UnwrapErr: failed to unwrap: {err}")) } } -impl CryptoRng for UnwrapErr {} +impl TryCryptoRng for UnwrapErr {} -/// Wrapper around [`TryRngCore`] implementation which implements [`RngCore`] -/// by panicking on potential errors. -#[derive(Debug, Eq, PartialEq, Hash)] -pub struct UnwrapMut<'r, R: TryRngCore + ?Sized>(pub &'r mut R); - -impl<'r, R: TryRngCore + ?Sized> UnwrapMut<'r, R> { +impl<'r, R: TryRngCore + ?Sized> UnwrapErr<&'r mut R> { /// Reborrow with a new lifetime /// /// Rust allows references like `&T` or `&mut T` to be "reborrowed" through /// coercion: essentially, the pointer is copied under a new, shorter, lifetime. /// Until rfcs#1403 lands, reborrows on user types require a method call. #[inline(always)] - pub fn re<'b>(&'b mut self) -> UnwrapMut<'b, R> + pub fn re<'b>(&'b mut self) -> UnwrapErr<&'b mut R> where 'r: 'b, { - UnwrapMut(self.0) - } -} - -impl RngCore for UnwrapMut<'_, R> { - #[inline] - fn next_u32(&mut self) -> u32 { - self.0.try_next_u32().unwrap() - } - - #[inline] - fn next_u64(&mut self) -> u64 { - self.0.try_next_u64().unwrap() - } - - #[inline] - fn fill_bytes(&mut self, dst: &mut [u8]) { - self.0.try_fill_bytes(dst).unwrap() + UnwrapErr(self.0) } } -impl CryptoRng for UnwrapMut<'_, R> {} - /// A random number generator that can be explicitly seeded. /// /// This trait encapsulates the low-level functionality common to all @@ -543,19 +554,21 @@ mod test { // A stub RNG. struct SomeRng; - impl RngCore for SomeRng { - fn next_u32(&mut self) -> u32 { + impl TryRngCore for SomeRng { + type Error = Infallible; + + fn try_next_u32(&mut self) -> Result { unimplemented!() } - fn next_u64(&mut self) -> u64 { + fn try_next_u64(&mut self) -> Result { unimplemented!() } - fn fill_bytes(&mut self, _: &mut [u8]) { + fn try_fill_bytes(&mut self, _dst: &mut [u8]) -> Result<(), Self::Error> { unimplemented!() } } - impl CryptoRng for SomeRng {} + impl TryCryptoRng for SomeRng {} #[test] fn dyn_rngcore_to_tryrngcore() { @@ -595,15 +608,14 @@ mod test { #[test] fn dyn_unwrap_mut_tryrngcore() { - // Illustrates the need for `+ ?Sized` bound in - // `impl RngCore for UnwrapMut<'_, R>`. + // Illustrates that UnwrapMut may be used over &mut R where R: TryRngCore fn third_party_api(_rng: &mut impl RngCore) -> bool { true } fn my_api(rng: &mut (impl TryRngCore + ?Sized)) -> bool { - let mut infallible_rng = rng.unwrap_mut(); + let mut infallible_rng = rng.unwrap_err(); third_party_api(&mut infallible_rng) } @@ -612,15 +624,14 @@ mod test { #[test] fn dyn_unwrap_mut_trycryptorng() { - // Illustrates the need for `+ ?Sized` bound in - // `impl CryptoRng for UnwrapMut<'_, R>`. + // Crypto variant of the above fn third_party_api(_rng: &mut impl CryptoRng) -> bool { true } fn my_api(rng: &mut (impl TryCryptoRng + ?Sized)) -> bool { - let mut infallible_rng = rng.unwrap_mut(); + let mut infallible_rng = rng.unwrap_err(); third_party_api(&mut infallible_rng) } @@ -632,7 +643,7 @@ mod test { struct FourRng; impl TryRngCore for FourRng { - type Error = core::convert::Infallible; + type Error = Infallible; fn try_next_u32(&mut self) -> Result { Ok(4) } @@ -645,7 +656,7 @@ mod test { } let mut rng = FourRng; - let mut rng = rng.unwrap_mut(); + let mut rng = (&mut rng).unwrap_err(); assert_eq!(rng.next_u32(), 4); { diff --git a/src/utils.rs b/src/utils.rs index 4fcd294c..c8504507 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -11,22 +11,22 @@ //! to/from byte sequences, and since its purpose is reproducibility, //! non-reproducible sources (e.g. `OsRng`) need not bother with it. //! -//! ## Implementing [`RngCore`] +//! ## Implementing [`TryRngCore`] //! -//! Usually an implementation of [`RngCore`] will implement one of the three +//! Usually an implementation of [`TryRngCore`] will implement one of the three //! methods over its internal source. The following helpers are provided for //! the remaining implementations. //! -//! **`fn next_u32`:** +//! **`fn try_next_u32`:** //! - `self.next_u64() as u32` //! - `(self.next_u64() >> 32) as u32` //! - [next_word_via_fill][](self) //! -//! **`fn next_u64`:** +//! **`fn try_next_u64`:** //! - [next_u64_via_u32][](self) //! - [next_word_via_fill][](self) //! -//! **`fn fill_bytes`:** +//! **`fn try_fill_bytes`:** //! - [fill_bytes_via_next_word][](self, dest) //! //! ## Implementing [`SeedableRng`] @@ -40,7 +40,8 @@ //! from M.E. O'Neill's blog post //! [Does It Beat the Minimal Standard?](https://www.pcg-random.org/posts/does-it-beat-the-minimal-standard.html). //! ``` -//! use rand_core::{RngCore, SeedableRng, utils}; +//! use core::convert::Infallible; +//! use rand_core::{RngCore, SeedableRng, TryRngCore, utils}; //! //! pub struct Mcg128(u128); //! @@ -54,21 +55,23 @@ //! } //! } //! -//! impl RngCore for Mcg128 { +//! impl TryRngCore for Mcg128 { +//! type Error = Infallible; +//! //! #[inline] -//! fn next_u32(&mut self) -> u32 { -//! (self.next_u64() >> 32) as u32 +//! fn try_next_u32(&mut self) -> Result { +//! Ok((self.next_u64() >> 32) as u32) //! } //! //! #[inline] -//! fn next_u64(&mut self) -> u64 { +//! fn try_next_u64(&mut self) -> Result { //! self.0 = self.0.wrapping_mul(0x0fc94e3bf4e9ab32866458cd56f5e605); -//! (self.0 >> 64) as u64 +//! Ok((self.0 >> 64) as u64) //! } //! //! #[inline] -//! fn fill_bytes(&mut self, dst: &mut [u8]) { -//! utils::fill_bytes_via_next_word(dst, || self.next_u64()); +//! fn try_fill_bytes(&mut self, dst: &mut [u8]) -> Result<(), Infallible> { +//! utils::fill_bytes_via_next_word(dst, || self.try_next_u64()) //! } //! } //! # @@ -80,46 +83,47 @@ //! # assert_eq!(buf, [154, 23, 43, 68, 75]); //! ``` -use crate::RngCore; -#[allow(unused)] -use crate::SeedableRng; pub use crate::word::Word; +#[allow(unused)] +use crate::{SeedableRng, TryRngCore}; -/// Implement `next_u64` via `next_u32`, little-endian order. +/// Generate a `u64` using `next_u32`, little-endian order. #[inline] -pub fn next_u64_via_u32(rng: &mut R) -> u64 { +pub fn next_u64_via_u32(rng: &mut R) -> Result { // Use LE; we explicitly generate one value before the next. - let x = u64::from(rng.next_u32()); - let y = u64::from(rng.next_u32()); - (y << 32) | x + let x = u64::from(rng.try_next_u32()?); + let y = u64::from(rng.try_next_u32()?); + Ok((y << 32) | x) } /// Fill `dst` with bytes using `next_word` /// -/// This may be used to implement [`RngCore::fill_bytes`] over `next_u32` or +/// This may be used to implement `fill_bytes` over `next_u32` or /// `next_u64`. Words are used in order of generation. The last word may be /// partially discarded. #[inline] -pub fn fill_bytes_via_next_word(dst: &mut [u8], mut next_word: impl FnMut() -> W) { +pub fn fill_bytes_via_next_word( + dst: &mut [u8], + mut next_word: impl FnMut() -> Result, +) -> Result<(), E> { let mut chunks = dst.chunks_exact_mut(size_of::()); for chunk in &mut chunks { - let val = next_word(); + let val = next_word()?; chunk.copy_from_slice(val.to_le_bytes().as_ref()); } let rem = chunks.into_remainder(); if !rem.is_empty() { - let val = next_word().to_le_bytes(); + let val = next_word()?.to_le_bytes(); rem.copy_from_slice(&val.as_ref()[..rem.len()]); } + Ok(()) } -/// Yield a word using [`RngCore::fill_bytes`] -/// -/// This may be used to implement `next_u32` or `next_u64`. -pub fn next_word_via_fill(rng: &mut R) -> W { +/// Generate a `u32` or `u64` word using `fill_bytes` +pub fn next_word_via_fill(rng: &mut R) -> Result { let mut buf: W::Bytes = Default::default(); - rng.fill_bytes(buf.as_mut()); - W::from_le_bytes(buf) + rng.try_fill_bytes(buf.as_mut())?; + Ok(W::from_le_bytes(buf)) } /// Reads an array of words from a byte slice