Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inherent rng methods #1492

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ You may also find the [Upgrade Guide](https://rust-random.github.io/book/update.
- Implement `Distribution<u64>` for `Poisson<f64>` (#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)
Expand Down
2 changes: 1 addition & 1 deletion rand_distr/src/triangular.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ where
#[cfg(test)]
mod test {
use super::*;
use rand::{rngs::mock, Rng};
use rand::rngs::mock;

#[test]
fn test_triangular() {
Expand Down
2 changes: 1 addition & 1 deletion rand_distr/tests/pdf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
6 changes: 2 additions & 4 deletions src/distr/float.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
/// ```
///
Expand All @@ -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);
/// ```
///
Expand Down
3 changes: 1 addition & 2 deletions src/distr/other.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
/// ```
Expand Down
1 change: 0 additions & 1 deletion src/distr/slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ use alloc::string::String;
/// # Example
///
/// ```
/// use rand::Rng;
/// use rand::distr::Slice;
///
/// let vowels = ['a', 'e', 'i', 'o', 'u'];
Expand Down
5 changes: 1 addition & 4 deletions src/distr/uniform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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));
/// ```
Expand Down
10 changes: 4 additions & 6 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
//!
Expand All @@ -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<i32> = (1..100).collect();
//! nums.shuffle(&mut rng);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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() {
Expand Down
145 changes: 121 additions & 24 deletions src/rng.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
///
Expand Down Expand Up @@ -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)>());
Expand All @@ -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
Expand Down Expand Up @@ -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<i32> = rng.random_iter().take(5).collect();
/// assert_eq!(&v, &[1, 2, 3, 4, 5]);
/// ```
Expand All @@ -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.
Expand Down Expand Up @@ -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
Expand All @@ -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);
Expand Down Expand Up @@ -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));
/// ```
///
Expand Down Expand Up @@ -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));
/// ```
///
Expand Down Expand Up @@ -330,6 +319,114 @@ pub trait Rng: RngCore {

impl<R: RngCore + ?Sized> 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<T>(&mut self) -> T
where
$crate::distr::Standard: $crate::distr::Distribution<T>,
{
use $crate::distr::Distribution;
$crate::distr::Standard.sample(self)
}

/// Return an iterator over [`random`](Self::random) variates
#[inline]
pub fn random_iter<T>(self) -> $crate::distr::DistIter<$crate::distr::Standard, Self, T>
where
Self: Sized,
$crate::distr::Standard: $crate::distr::Distribution<T>,
{
use $crate::distr::Distribution;
$crate::distr::Standard.sample_iter(self)
}

/// Sample a new value, using the given distribution.
#[inline]
pub fn sample<T, D: $crate::distr::Distribution<T>>(&mut self, distr: D) -> T {
distr.sample(self)
}

/// Create an iterator that generates values using the given distribution.
#[inline]
pub fn sample_iter<T, D>(self, distr: D) -> $crate::distr::DistIter<D, Self, T>
where
D: $crate::distr::Distribution<T>,
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<T: $crate::Fill + ?Sized>(&mut self, dest: &mut T) {
dest.fill(self)
}

/// Generate a random value in the given range.
#[track_caller]
pub fn gen_range<T, R>(&mut self, range: R) -> T
where
T: $crate::distr::uniform::SampleUniform,
R: $crate::distr::uniform::SampleRange<T>,
{
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 {
<Self as $crate::Rng>::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 {
<Self as $crate::Rng>::gen_ratio(self, numerator, denominator)
}
}
};
}

/// Types which may be filled with random data
///
/// This trait allows arrays to be efficiently filled with random data.
Expand Down
9 changes: 4 additions & 5 deletions src/rngs/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]);
/// ```
Expand Down Expand Up @@ -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"))]
Expand All @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions src/rngs/small.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,3 +129,5 @@ impl SmallRng {
SmallRng(Rng::from_seed(seed))
}
}

impl_rng_methods_as_inherent!(SmallRng, crate, rand::rngs::SmallRng::from_thread_rng());
6 changes: 6 additions & 0 deletions src/rngs/std.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
<rand::rngs::StdRng as rand::SeedableRng>::from_os_rng()
);

#[cfg(test)]
mod test {
use crate::rngs::StdRng;
Expand Down
Loading