diff --git a/CHANGELOG.md b/CHANGELOG.md index c80cb36a631..891db26a9f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ A [separate changelog is kept for rand_core](rand_core/CHANGELOG.md). You may also find the [Upgrade Guide](https://rust-random.github.io/book/update.html) useful. +## [Unreleased] +### Deprecated +- Deprecate `rand::rngs::mock` module and `StepRng` generator (#1634) + ## [0.9.1] - 2025-04-17 ### Security and unsafe - Revise "not a crypto library" policy again (#1565) diff --git a/README.md b/README.md index 8dde999050c..e8b6fe3d337 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ With broad support for random value generation and random processes: and [more](https://docs.rs/rand/latest/rand/distr/index.html) - Samplers for a large number of non-uniform random number distributions via our own [`rand_distr`](https://docs.rs/rand_distr) and via - the [`statrs`](https://docs.rs/statrs/0.13.0/statrs/) + the [`statrs`](https://docs.rs/statrs) - Random processes (mostly choose and shuffle) via [`rand::seq`](https://docs.rs/rand/latest/rand/seq/index.html) traits All with: diff --git a/benches/benches/generators.rs b/benches/benches/generators.rs index 64325ceb9ee..31f08a02408 100644 --- a/benches/benches/generators.rs +++ b/benches/benches/generators.rs @@ -10,8 +10,8 @@ use core::time::Duration; use criterion::measurement::WallTime; use criterion::{black_box, criterion_group, criterion_main, BenchmarkGroup, Criterion}; use rand::prelude::*; +use rand::rngs::OsRng; use rand::rngs::ReseedingRng; -use rand::rngs::{mock::StepRng, OsRng}; use rand_chacha::rand_core::UnwrapErr; use rand_chacha::{ChaCha12Rng, ChaCha20Core, ChaCha20Rng, ChaCha8Rng}; use rand_pcg::{Pcg32, Pcg64, Pcg64Dxsm, Pcg64Mcg}; @@ -39,7 +39,6 @@ pub fn random_bytes(c: &mut Criterion) { }); } - bench(&mut g, "step", StepRng::new(0, 1)); bench(&mut g, "pcg32", Pcg32::from_rng(&mut rand::rng())); bench(&mut g, "pcg64", Pcg64::from_rng(&mut rand::rng())); bench(&mut g, "pcg64mcg", Pcg64Mcg::from_rng(&mut rand::rng())); @@ -68,7 +67,6 @@ pub fn random_u32(c: &mut Criterion) { }); } - bench(&mut g, "step", StepRng::new(0, 1)); bench(&mut g, "pcg32", Pcg32::from_rng(&mut rand::rng())); bench(&mut g, "pcg64", Pcg64::from_rng(&mut rand::rng())); bench(&mut g, "pcg64mcg", Pcg64Mcg::from_rng(&mut rand::rng())); @@ -97,7 +95,6 @@ pub fn random_u64(c: &mut Criterion) { }); } - bench(&mut g, "step", StepRng::new(0, 1)); bench(&mut g, "pcg32", Pcg32::from_rng(&mut rand::rng())); bench(&mut g, "pcg64", Pcg64::from_rng(&mut rand::rng())); bench(&mut g, "pcg64mcg", Pcg64Mcg::from_rng(&mut rand::rng())); diff --git a/src/distr/float.rs b/src/distr/float.rs index ec380b4bd4d..44c33e99268 100644 --- a/src/distr/float.rs +++ b/src/distr/float.rs @@ -175,7 +175,7 @@ float_impls! { feature = "simd_support", f64x8, u64x8, f64, u64, 52, 1023 } #[cfg(test)] mod tests { use super::*; - use crate::rngs::mock::StepRng; + use crate::test::const_rng; const EPSILON32: f32 = f32::EPSILON; const EPSILON64: f64 = f64::EPSILON; @@ -187,30 +187,30 @@ mod tests { let two = $ty::splat(2.0); // StandardUniform - let mut zeros = StepRng::new(0, 0); + let mut zeros = const_rng(0); assert_eq!(zeros.random::<$ty>(), $ZERO); - let mut one = StepRng::new(1 << 8 | 1 << (8 + 32), 0); + let mut one = const_rng(1 << 8 | 1 << (8 + 32)); assert_eq!(one.random::<$ty>(), $EPSILON / two); - let mut max = StepRng::new(!0, 0); + let mut max = const_rng(!0); assert_eq!(max.random::<$ty>(), $ty::splat(1.0) - $EPSILON / two); // OpenClosed01 - let mut zeros = StepRng::new(0, 0); + let mut zeros = const_rng(0); assert_eq!(zeros.sample::<$ty, _>(OpenClosed01), $ZERO + $EPSILON / two); - let mut one = StepRng::new(1 << 8 | 1 << (8 + 32), 0); + let mut one = const_rng(1 << 8 | 1 << (8 + 32)); assert_eq!(one.sample::<$ty, _>(OpenClosed01), $EPSILON); - let mut max = StepRng::new(!0, 0); + let mut max = const_rng(!0); assert_eq!(max.sample::<$ty, _>(OpenClosed01), $ZERO + $ty::splat(1.0)); // Open01 - let mut zeros = StepRng::new(0, 0); + let mut zeros = const_rng(0); assert_eq!(zeros.sample::<$ty, _>(Open01), $ZERO + $EPSILON / two); - let mut one = StepRng::new(1 << 9 | 1 << (9 + 32), 0); + let mut one = const_rng(1 << 9 | 1 << (9 + 32)); assert_eq!( one.sample::<$ty, _>(Open01), $EPSILON / two * $ty::splat(3.0) ); - let mut max = StepRng::new(!0, 0); + let mut max = const_rng(!0); assert_eq!( max.sample::<$ty, _>(Open01), $ty::splat(1.0) - $EPSILON / two @@ -235,30 +235,30 @@ mod tests { let two = $ty::splat(2.0); // StandardUniform - let mut zeros = StepRng::new(0, 0); + let mut zeros = const_rng(0); assert_eq!(zeros.random::<$ty>(), $ZERO); - let mut one = StepRng::new(1 << 11, 0); + let mut one = const_rng(1 << 11); assert_eq!(one.random::<$ty>(), $EPSILON / two); - let mut max = StepRng::new(!0, 0); + let mut max = const_rng(!0); assert_eq!(max.random::<$ty>(), $ty::splat(1.0) - $EPSILON / two); // OpenClosed01 - let mut zeros = StepRng::new(0, 0); + let mut zeros = const_rng(0); assert_eq!(zeros.sample::<$ty, _>(OpenClosed01), $ZERO + $EPSILON / two); - let mut one = StepRng::new(1 << 11, 0); + let mut one = const_rng(1 << 11); assert_eq!(one.sample::<$ty, _>(OpenClosed01), $EPSILON); - let mut max = StepRng::new(!0, 0); + let mut max = const_rng(!0); assert_eq!(max.sample::<$ty, _>(OpenClosed01), $ZERO + $ty::splat(1.0)); // Open01 - let mut zeros = StepRng::new(0, 0); + let mut zeros = const_rng(0); assert_eq!(zeros.sample::<$ty, _>(Open01), $ZERO + $EPSILON / two); - let mut one = StepRng::new(1 << 12, 0); + let mut one = const_rng(1 << 12); assert_eq!( one.sample::<$ty, _>(Open01), $EPSILON / two * $ty::splat(3.0) ); - let mut max = StepRng::new(!0, 0); + let mut max = const_rng(!0); assert_eq!( max.sample::<$ty, _>(Open01), $ty::splat(1.0) - $EPSILON / two diff --git a/src/distr/uniform_float.rs b/src/distr/uniform_float.rs index ccc1c39c2e4..e9b0421aaf0 100644 --- a/src/distr/uniform_float.rs +++ b/src/distr/uniform_float.rs @@ -219,14 +219,14 @@ uniform_float_impl! { feature = "simd_support", f64x8, u64x8, f64, u64, 64 - 52 mod tests { use super::*; use crate::distr::{utils::FloatSIMDScalarUtils, Uniform}; - use crate::rngs::mock::StepRng; + use crate::test::{const_rng, step_rng}; #[test] #[cfg_attr(miri, ignore)] // Miri is too slow fn test_floats() { let mut rng = crate::test::rng(252); - let mut zero_rng = StepRng::new(0, 0); - let mut max_rng = StepRng::new(0xffff_ffff_ffff_ffff, 0); + let mut zero_rng = const_rng(0); + let mut max_rng = const_rng(0xffff_ffff_ffff_ffff); macro_rules! t { ($ty:ty, $f_scalar:ident, $bits_shifted:expr) => {{ let v: &[($f_scalar, $f_scalar)] = &[ @@ -318,10 +318,8 @@ mod tests { // since for those rounding might result in selecting high for a very // long time. if (high_scalar - low_scalar) > 0.0001 { - let mut lowering_max_rng = StepRng::new( - 0xffff_ffff_ffff_ffff, - (-1i64 << $bits_shifted) as u64, - ); + let mut lowering_max_rng = + step_rng(0xffff_ffff_ffff_ffff, (-1i64 << $bits_shifted) as u64); assert!( <$ty as SampleUniform>::Sampler::sample_single( low, diff --git a/src/lib.rs b/src/lib.rs index 6f2af2fc147..9187c9cc16a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -309,6 +309,34 @@ mod test { rand_pcg::Pcg32::new(seed, INC) } + /// Construct a generator yielding a constant value + pub fn const_rng(x: u64) -> StepRng { + StepRng(x, 0) + } + + /// Construct a generator yielding an arithmetic sequence + pub fn step_rng(x: u64, increment: u64) -> StepRng { + StepRng(x, increment) + } + + #[derive(Clone)] + pub struct StepRng(u64, u64); + impl RngCore for StepRng { + fn next_u32(&mut self) -> u32 { + self.next_u64() as u32 + } + + fn next_u64(&mut self) -> u64 { + let res = self.0; + self.0 = self.0.wrapping_add(self.1); + res + } + + fn fill_bytes(&mut self, dst: &mut [u8]) { + rand_core::impls::fill_bytes_via_next(self, dst) + } + } + #[test] #[cfg(feature = "thread_rng")] fn test_random() { diff --git a/src/rng.rs b/src/rng.rs index b0891a97217..c502e1ba476 100644 --- a/src/rng.rs +++ b/src/rng.rs @@ -110,11 +110,11 @@ pub trait Rng: RngCore { /// # Example /// /// ``` - /// use rand::{rngs::mock::StepRng, Rng}; + /// use rand::{rngs::SmallRng, Rng, SeedableRng}; /// - /// let rng = StepRng::new(1, 1); + /// let rng = SmallRng::seed_from_u64(0); /// let v: Vec = rng.random_iter().take(5).collect(); - /// assert_eq!(&v, &[1, 2, 3, 4, 5]); + /// assert_eq!(v.len(), 5); /// ``` #[inline] fn random_iter(self) -> distr::Iter @@ -479,14 +479,13 @@ where #[cfg(test)] mod test { use super::*; - use crate::rngs::mock::StepRng; - use crate::test::rng; + use crate::test::{const_rng, rng}; #[cfg(feature = "alloc")] use alloc::boxed::Box; #[test] fn test_fill_bytes_default() { - let mut r = StepRng::new(0x11_22_33_44_55_66_77_88, 0); + let mut r = const_rng(0x11_22_33_44_55_66_77_88); // check every remainder mod 8, both in small and big vectors. let lengths = [0, 1, 2, 3, 4, 5, 6, 7, 80, 81, 82, 83, 84, 85, 86, 87]; @@ -507,7 +506,7 @@ mod test { #[test] fn test_fill() { let x = 9041086907909331047; // a random u64 - let mut rng = StepRng::new(x, 0); + let mut rng = const_rng(x); // Convert to byte sequence and back to u64; byte-swap twice if BE. let mut array = [0u64; 2]; @@ -537,7 +536,7 @@ mod test { #[test] fn test_fill_empty() { let mut array = [0u32; 0]; - let mut rng = StepRng::new(0, 1); + let mut rng = rng(1); rng.fill(&mut array); rng.fill(&mut array[..]); } diff --git a/src/rngs/mock.rs b/src/rngs/mock.rs index b6da66a8565..5b6a2253b18 100644 --- a/src/rngs/mock.rs +++ b/src/rngs/mock.rs @@ -8,6 +8,8 @@ //! Mock random number generator +#![allow(deprecated)] + use rand_core::{impls, RngCore}; #[cfg(feature = "serde")] @@ -31,6 +33,7 @@ use serde::{Deserialize, Serialize}; /// # Example /// /// ``` +/// # #![allow(deprecated)] /// use rand::Rng; /// use rand::rngs::mock::StepRng; /// @@ -40,6 +43,7 @@ use serde::{Deserialize, Serialize}; /// ``` #[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[deprecated(since = "0.9.2", note = "Deprecated without replacement")] pub struct StepRng { v: u64, a: u64, @@ -74,30 +78,3 @@ impl RngCore for StepRng { impls::fill_bytes_via_next(self, dst) } } - -#[cfg(test)] -mod tests { - #[cfg(any(feature = "alloc", feature = "serde"))] - use super::StepRng; - - #[test] - #[cfg(feature = "serde")] - fn test_serialization_step_rng() { - let some_rng = StepRng::new(42, 7); - let de_some_rng: StepRng = - bincode::deserialize(&bincode::serialize(&some_rng).unwrap()).unwrap(); - assert_eq!(some_rng.v, de_some_rng.v); - assert_eq!(some_rng.a, de_some_rng.a); - } - - #[test] - #[cfg(feature = "alloc")] - fn test_bool() { - use crate::{distr::StandardUniform, Rng}; - - // If this result ever changes, update doc on StepRng! - let rng = StepRng::new(0, 1 << 31); - let result: alloc::vec::Vec = rng.sample_iter(StandardUniform).take(6).collect(); - assert_eq!(&result, &[false, true, false, true, false, true]); - } -} diff --git a/src/rngs/mod.rs b/src/rngs/mod.rs index cb7ed57f33e..8ce25759a26 100644 --- a/src/rngs/mod.rs +++ b/src/rngs/mod.rs @@ -80,6 +80,7 @@ mod reseeding; pub use reseeding::ReseedingRng; +#[deprecated(since = "0.9.2")] pub mod mock; // Public so we don't export `StepRng` directly, making it a bit // more clear it is intended for testing. diff --git a/src/rngs/reseeding.rs b/src/rngs/reseeding.rs index 570d04eeba4..69b9045e0de 100644 --- a/src/rngs/reseeding.rs +++ b/src/rngs/reseeding.rs @@ -253,15 +253,15 @@ where #[cfg(feature = "std_rng")] #[cfg(test)] mod test { - use crate::rngs::mock::StepRng; use crate::rngs::std::Core; + use crate::test::const_rng; use crate::Rng; use super::ReseedingRng; #[test] fn test_reseeding() { - let zero = StepRng::new(0, 0); + let zero = const_rng(0); let thresh = 1; // reseed every time the buffer is exhausted let mut reseeding = ReseedingRng::::new(thresh, zero).unwrap(); @@ -281,7 +281,7 @@ mod test { #[test] #[allow(clippy::redundant_clone)] fn test_clone_reseeding() { - let zero = StepRng::new(0, 0); + let zero = const_rng(0); let mut rng1 = ReseedingRng::::new(32 * 4, zero).unwrap(); let first: u32 = rng1.random();