diff --git a/CHANGELOG.md b/CHANGELOG.md index 3300b9ad9fe..0454f8b6b29 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ You may also find the [Upgrade Guide](https://rust-random.github.io/book/update. - Implement `Distribution` for `Poisson` (#1498) - Limit the maximal acceptable lambda for `Poisson` to solve (#1312) (#1498) - Rename `Rng::gen_iter` to `random_iter` (#1500) +- Implement `Rng` methods as inherent methods on `StepRng`, `SmallRng`, `StdRng`, `ThreadRng` (#1492) ## [0.9.0-alpha.1] - 2024-03-18 - Add the `Slice::num_choices` method to the Slice distribution (#1402) diff --git a/rand_distr/src/triangular.rs b/rand_distr/src/triangular.rs index c1b151a576f..c1a377e145d 100644 --- a/rand_distr/src/triangular.rs +++ b/rand_distr/src/triangular.rs @@ -113,7 +113,7 @@ where #[cfg(test)] mod test { use super::*; - use rand::{rngs::mock, Rng}; + use rand::rngs::mock; #[test] fn test_triangular() { diff --git a/rand_distr/tests/pdf.rs b/rand_distr/tests/pdf.rs index 1bbbd32d55b..2acfe93fea7 100644 --- a/rand_distr/tests/pdf.rs +++ b/rand_distr/tests/pdf.rs @@ -9,7 +9,7 @@ #![allow(clippy::float_cmp)] use average::Histogram; -use rand::{Rng, SeedableRng}; +use rand::SeedableRng; use rand_distr::{Normal, SkewNormal}; const HIST_LEN: usize = 100; diff --git a/src/distr/float.rs b/src/distr/float.rs index a8cbc96bd6f..e412d541dd5 100644 --- a/src/distr/float.rs +++ b/src/distr/float.rs @@ -32,10 +32,9 @@ use serde::{Deserialize, Serialize}; /// /// # Example /// ``` -/// use rand::{thread_rng, Rng}; /// use rand::distr::OpenClosed01; /// -/// let val: f32 = thread_rng().sample(OpenClosed01); +/// let val: f32 = rand::thread_rng().sample(OpenClosed01); /// println!("f32 from (0, 1): {}", val); /// ``` /// @@ -59,10 +58,9 @@ pub struct OpenClosed01; /// /// # Example /// ``` -/// use rand::{thread_rng, Rng}; /// use rand::distr::Open01; /// -/// let val: f32 = thread_rng().sample(Open01); +/// let val: f32 = rand::thread_rng().sample(Open01); /// println!("f32 from (0, 1): {}", val); /// ``` /// diff --git a/src/distr/other.rs b/src/distr/other.rs index b2e91e53256..60bb1c6e405 100644 --- a/src/distr/other.rs +++ b/src/distr/other.rs @@ -34,10 +34,9 @@ use serde::{Deserialize, Serialize}; /// # Example /// /// ``` -/// use rand::{Rng, thread_rng}; /// use rand::distr::Alphanumeric; /// -/// let mut rng = thread_rng(); +/// let mut rng = rand::thread_rng(); /// let chars: String = (0..7).map(|_| rng.sample(Alphanumeric) as char).collect(); /// println!("Random chars: {}", chars); /// ``` diff --git a/src/distr/slice.rs b/src/distr/slice.rs index d201caa2463..302797f3098 100644 --- a/src/distr/slice.rs +++ b/src/distr/slice.rs @@ -33,7 +33,6 @@ use alloc::string::String; /// # Example /// /// ``` -/// use rand::Rng; /// use rand::distr::Slice; /// /// let vowels = ['a', 'e', 'i', 'o', 'u']; diff --git a/src/distr/uniform.rs b/src/distr/uniform.rs index 86a08fdc59f..f584ac5a14b 100644 --- a/src/distr/uniform.rs +++ b/src/distr/uniform.rs @@ -26,10 +26,9 @@ //! # Example usage //! //! ``` -//! use rand::{Rng, thread_rng}; //! use rand::distr::Uniform; //! -//! let mut rng = thread_rng(); +//! let mut rng = rand::thread_rng(); //! let side = Uniform::new(-10.0, 10.0).unwrap(); //! //! // sample between 1 and 10 points @@ -189,8 +188,6 @@ use serde::{Deserialize, Serialize}; /// For a single sample, [`Rng::gen_range`] may be preferred: /// /// ``` -/// use rand::Rng; -/// /// let mut rng = rand::thread_rng(); /// println!("{}", rng.gen_range(0..10)); /// ``` diff --git a/src/lib.rs b/src/lib.rs index 958c15d481c..e815d92cf49 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,10 +15,6 @@ //! # Quick Start //! //! ``` -//! // The prelude import enables methods we use below, specifically -//! // Rng::random, Rng::sample, SliceRandom::shuffle and IndexedRandom::choose. -//! use rand::prelude::*; -//! //! // Get an RNG: //! let mut rng = rand::thread_rng(); //! @@ -27,6 +23,9 @@ //! // Try printing a random alphanumeric value instead! //! println!("alpha: '{}'", rng.sample(rand::distr::Alphanumeric) as char); //! +//! // The prelude makes choose and shuffle available on sequences: +//! use rand::prelude::*; +//! //! // Generate and shuffle a sequence: //! let mut nums: Vec = (1..100).collect(); //! nums.shuffle(&mut rng); @@ -98,6 +97,7 @@ pub use rand_core::{CryptoRng, RngCore, SeedableRng, TryCryptoRng, TryRngCore}; // Public modules pub mod distr; pub mod prelude; +#[macro_use] mod rng; pub mod rngs; pub mod seq; @@ -135,8 +135,6 @@ use crate::distr::{Distribution, Standard}; /// following example can increase performance. /// /// ``` -/// use rand::Rng; -/// /// let mut v = vec![1, 2, 3]; /// /// for x in v.iter_mut() { diff --git a/src/rng.rs b/src/rng.rs index 7c9e887a2d7..bf30bed264f 100644 --- a/src/rng.rs +++ b/src/rng.rs @@ -22,7 +22,11 @@ use rand_core::RngCore; /// RNGs. It is implemented automatically for any `R: RngCore`. /// /// This trait must usually be brought into scope via `use rand::Rng;` or -/// `use rand::prelude::*;`. +/// `use rand::prelude::*;`. This is not necessary for +/// [`ThreadRng`](crate::rngs::ThreadRng), [`StdRng`](crate::rngs::StdRng), +/// [`SmallRng`](crate::rngs::SmallRng) and +/// [`StepRng`](crate::rngs::mock::StepRng) +/// which implement `Rng` methods as inherent methods. /// /// # Generic usage /// @@ -62,9 +66,7 @@ pub trait Rng: RngCore { /// # Example /// /// ``` - /// use rand::{thread_rng, Rng}; - /// - /// let mut rng = thread_rng(); + /// let mut rng = rand::thread_rng(); /// let x: u32 = rng.random(); /// println!("{}", x); /// println!("{:?}", rng.random::<(f64, bool)>()); @@ -81,9 +83,7 @@ pub trait Rng: RngCore { /// though note that generated values will differ. /// /// ``` - /// use rand::{thread_rng, Rng}; - /// - /// let mut rng = thread_rng(); + /// let mut rng = rand::thread_rng(); /// let tuple: (u8, i32, char) = rng.random(); // arbitrary tuple support /// /// let arr1: [f32; 32] = rng.random(); // array construction @@ -111,9 +111,7 @@ pub trait Rng: RngCore { /// # Example /// /// ``` - /// use rand::{rngs::mock::StepRng, Rng}; - /// - /// let rng = StepRng::new(1, 1); + /// let rng = rand::rngs::mock::StepRng::new(1, 1); /// let v: Vec = rng.random_iter().take(5).collect(); /// assert_eq!(&v, &[1, 2, 3, 4, 5]); /// ``` @@ -131,10 +129,9 @@ pub trait Rng: RngCore { /// ### Example /// /// ``` - /// use rand::{thread_rng, Rng}; /// use rand::distr::Uniform; /// - /// let mut rng = thread_rng(); + /// let mut rng = rand::thread_rng(); /// let x = rng.sample(Uniform::new(10u32, 15).unwrap()); /// // Type annotation requires two types, the type and distribution; the /// // distribution can be inferred. @@ -197,10 +194,8 @@ pub trait Rng: RngCore { /// # Example /// /// ``` - /// use rand::{thread_rng, Rng}; - /// /// let mut arr = [0i8; 20]; - /// thread_rng().fill(&mut arr[..]); + /// rand::thread_rng().fill(&mut arr[..]); /// ``` /// /// [`fill_bytes`]: RngCore::fill_bytes @@ -225,9 +220,7 @@ pub trait Rng: RngCore { /// # Example /// /// ``` - /// use rand::{thread_rng, Rng}; - /// - /// let mut rng = thread_rng(); + /// let mut rng = rand::thread_rng(); /// /// // Exclusive range /// let n: u32 = rng.gen_range(..10); @@ -259,9 +252,7 @@ pub trait Rng: RngCore { /// # Example /// /// ``` - /// use rand::{thread_rng, Rng}; - /// - /// let mut rng = thread_rng(); + /// let mut rng = rand::thread_rng(); /// println!("{}", rng.gen_bool(1.0 / 3.0)); /// ``` /// @@ -295,9 +286,7 @@ pub trait Rng: RngCore { /// # Example /// /// ``` - /// use rand::{thread_rng, Rng}; - /// - /// let mut rng = thread_rng(); + /// let mut rng = rand::thread_rng(); /// println!("{}", rng.gen_ratio(2, 3)); /// ``` /// @@ -330,6 +319,114 @@ pub trait Rng: RngCore { impl Rng for R {} +/// Implement [`Rng`] methods on `$target` as inherent methods +/// +/// Parameters: +/// +/// - `$target` is the type to implement for (no support for generics) +/// - `$rand` is `rand` (or `crate` within `rand`, or whatever `rand` is renamed to) +/// - `$rng` is a constructor for the RNG (used in doc examples) +macro_rules! impl_rng_methods_as_inherent { + ($target:ty, $rand:path, $rng:expr) => { + #[doc = concat!("Implement [`rand::Rng`](", stringify!($rand), "::Rng) methods as inherent methods")] + /// + /// # Example + /// + /// ``` + /// use rand::distr::{Alphanumeric, Bernoulli}; + #[doc = concat!("let mut rng = ", stringify!($rng), ";")] + /// + /// let x: u32 = rng.random(); + /// let y = rng.gen_range(1..=6); + /// let z: usize = rng.gen_range(..50); + /// println!("{x}, {y}, {z}"); + /// + /// let _ = rng.sample(Alphanumeric); + /// + /// // Simulate a Poisson process: + /// let b = Bernoulli::new(0.2).unwrap(); + #[doc = concat!("let n = ", stringify!($rng))] + /// .sample_iter(b) + /// .take(50) + /// .filter(|r| *r) + /// .count(); + /// assert!(n <= 50); + /// + /// let mut arr = [0i8; 20]; + /// rng.fill(&mut arr[..]); + /// ``` + impl $target { + #[doc = concat!("Return a random variate from the [`rand::distr::Standard`](", stringify!($rand), "::distr::Standard) distribution")] + #[inline] + pub fn random(&mut self) -> T + where + $crate::distr::Standard: $crate::distr::Distribution, + { + use $crate::distr::Distribution; + $crate::distr::Standard.sample(self) + } + + /// Return an iterator over [`random`](Self::random) variates + #[inline] + pub fn random_iter(self) -> $crate::distr::DistIter<$crate::distr::Standard, Self, T> + where + Self: Sized, + $crate::distr::Standard: $crate::distr::Distribution, + { + use $crate::distr::Distribution; + $crate::distr::Standard.sample_iter(self) + } + + /// Sample a new value, using the given distribution. + #[inline] + pub fn sample>(&mut self, distr: D) -> T { + distr.sample(self) + } + + /// Create an iterator that generates values using the given distribution. + #[inline] + pub fn sample_iter(self, distr: D) -> $crate::distr::DistIter + where + D: $crate::distr::Distribution, + Self: Sized, + { + distr.sample_iter(self) + } + + #[doc = concat!("Fill any type implementing [`rand::Fill`](", stringify!($rand), "::Fill) with random data")] + #[track_caller] + pub fn fill(&mut self, dest: &mut T) { + dest.fill(self) + } + + /// Generate a random value in the given range. + #[track_caller] + pub fn gen_range(&mut self, range: R) -> T + where + T: $crate::distr::uniform::SampleUniform, + R: $crate::distr::uniform::SampleRange, + { + assert!(!range.is_empty(), "cannot sample empty range"); + range.sample_single(self).unwrap() + } + + /// Return a bool with a probability `p` of being true. + #[inline] + #[track_caller] + pub fn gen_bool(&mut self, p: f64) -> bool { + ::gen_bool(self, p) + } + + /// Return a bool with a probability of `numerator/denominator` of being true. + #[inline] + #[track_caller] + pub fn gen_ratio(&mut self, numerator: u32, denominator: u32) -> bool { + ::gen_ratio(self, numerator, denominator) + } + } + }; +} + /// Types which may be filled with random data /// /// This trait allows arrays to be efficiently filled with random data. diff --git a/src/rngs/mock.rs b/src/rngs/mock.rs index 7238fbc8819..8af56c6b887 100644 --- a/src/rngs/mock.rs +++ b/src/rngs/mock.rs @@ -31,10 +31,7 @@ use serde::{Deserialize, Serialize}; /// # Example /// /// ``` -/// use rand::Rng; -/// use rand::rngs::mock::StepRng; -/// -/// let mut my_rng = StepRng::new(2, 1); +/// let mut my_rng = rand::rngs::mock::StepRng::new(2, 1); /// let sample: [u64; 3] = my_rng.random(); /// assert_eq!(sample, [2, 3, 4]); /// ``` @@ -77,6 +74,8 @@ impl RngCore for StepRng { rand_core::impl_try_rng_from_rng_core!(StepRng); +impl_rng_methods_as_inherent!(StepRng, crate, rand::rngs::mock::StepRng::new(1, 1)); + #[cfg(test)] mod tests { #[cfg(any(feature = "alloc", feature = "serde"))] @@ -95,7 +94,7 @@ mod tests { #[test] #[cfg(feature = "alloc")] fn test_bool() { - use crate::{distr::Standard, Rng}; + use crate::distr::Standard; // If this result ever changes, update doc on StepRng! let rng = StepRng::new(0, 1 << 31); diff --git a/src/rngs/small.rs b/src/rngs/small.rs index ea7df062842..373ef185ef2 100644 --- a/src/rngs/small.rs +++ b/src/rngs/small.rs @@ -129,3 +129,5 @@ impl SmallRng { SmallRng(Rng::from_seed(seed)) } } + +impl_rng_methods_as_inherent!(SmallRng, crate, rand::rngs::SmallRng::from_thread_rng()); diff --git a/src/rngs/std.rs b/src/rngs/std.rs index 7483becb71f..2eb30f04454 100644 --- a/src/rngs/std.rs +++ b/src/rngs/std.rs @@ -93,6 +93,12 @@ impl CryptoRng for StdRng {} rand_core::impl_try_crypto_rng_from_crypto_rng!(StdRng); +impl_rng_methods_as_inherent!( + StdRng, + crate, + ::from_os_rng() +); + #[cfg(test)] mod test { use crate::rngs::StdRng; diff --git a/src/rngs/thread.rs b/src/rngs/thread.rs index 161b5d6efcb..fae9feb4684 100644 --- a/src/rngs/thread.rs +++ b/src/rngs/thread.rs @@ -121,8 +121,6 @@ thread_local!( /// /// Example usage: /// ``` -/// use rand::Rng; -/// /// # fn main() { /// // rand::random() may be used instead of rand::thread_rng().gen(): /// println!("A random boolean: {}", rand::random::()); @@ -172,11 +170,12 @@ impl CryptoRng for ThreadRng {} rand_core::impl_try_crypto_rng_from_crypto_rng!(ThreadRng); +impl_rng_methods_as_inherent!(ThreadRng, crate, rand::thread_rng()); + #[cfg(test)] mod test { #[test] fn test_thread_rng() { - use crate::Rng; let mut r = crate::thread_rng(); r.random::(); assert_eq!(r.gen_range(0..1), 0);