Skip to content

Updates to random number generation APIs #143710

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

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
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
2 changes: 0 additions & 2 deletions library/core/src/primitive_docs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1081,13 +1081,11 @@ mod prim_str {}
/// * [`Debug`]
/// * [`Default`]
/// * [`Hash`]
/// * [`Random`]
/// * [`From<[T; N]>`][from]
///
/// [from]: convert::From
/// [`Debug`]: fmt::Debug
/// [`Hash`]: hash::Hash
/// [`Random`]: random::Random
///
/// The following traits are implemented for tuples of any length. These traits have
/// implementations that are automatically generated by the compiler, so are not limited by
Expand Down
52 changes: 25 additions & 27 deletions library/core/src/random.rs
Original file line number Diff line number Diff line change
@@ -1,48 +1,46 @@
//! Random value generation.
//!
//! The [`Random`] trait allows generating a random value for a type using a
//! given [`RandomSource`].
use crate::range::RangeFull;

/// A source of randomness.
#[unstable(feature = "random", issue = "130703")]
pub trait RandomSource {
/// Fills `bytes` with random bytes.
///
/// Note that calling `fill_bytes` multiple times is not equivalent to calling `fill_bytes` once
/// with a larger buffer. A `RandomSource` is allowed to return different bytes for those two
/// cases. For instance, this allows a `RandomSource` to generate a word at a time and throw
/// part of it away if not needed.
fn fill_bytes(&mut self, bytes: &mut [u8]);
}

/// A trait for getting a random value for a type.
///
/// **Warning:** Be careful when manipulating random values! The
/// [`random`](Random::random) method on integers samples them with a uniform
/// distribution, so a value of 1 is just as likely as [`i32::MAX`]. By using
/// modulo operations, some of the resulting values can become more likely than
/// others. Use audited crates when in doubt.
/// A trait representing a distribution of random values for a type.
#[unstable(feature = "random", issue = "130703")]
pub trait Random: Sized {
/// Generates a random value.
fn random(source: &mut (impl RandomSource + ?Sized)) -> Self;
pub trait Distribution<T> {
/// Samples a random value from the distribution, using the specified random source.
fn sample(&self, source: &mut (impl RandomSource + ?Sized)) -> T;
}

impl<T, DT: Distribution<T>> Distribution<T> for &DT {
fn sample(&self, source: &mut (impl RandomSource + ?Sized)) -> T {
(*self).sample(source)
}
}

impl Random for bool {
fn random(source: &mut (impl RandomSource + ?Sized)) -> Self {
u8::random(source) & 1 == 1
impl Distribution<bool> for RangeFull {
fn sample(&self, source: &mut (impl RandomSource + ?Sized)) -> bool {
let byte: u8 = RangeFull.sample(source);
byte & 1 == 1
}
}

macro_rules! impl_primitive {
($t:ty) => {
impl Random for $t {
/// Generates a random value.
///
/// **Warning:** Be careful when manipulating the resulting value! This
/// method samples according to a uniform distribution, so a value of 1 is
/// just as likely as [`MAX`](Self::MAX). By using modulo operations, some
/// values can become more likely than others. Use audited crates when in
/// doubt.
fn random(source: &mut (impl RandomSource + ?Sized)) -> Self {
let mut bytes = (0 as Self).to_ne_bytes();
impl Distribution<$t> for RangeFull {
fn sample(&self, source: &mut (impl RandomSource + ?Sized)) -> $t {
let mut bytes = (0 as $t).to_ne_bytes();
source.fill_bytes(&mut bytes);
Self::from_ne_bytes(bytes)
<$t>::from_ne_bytes(bytes)
}
}
};
Expand Down
11 changes: 0 additions & 11 deletions library/core/src/tuple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
use crate::cmp::Ordering::{self, *};
use crate::marker::{ConstParamTy_, StructuralPartialEq, UnsizedConstParamTy};
use crate::ops::ControlFlow::{self, Break, Continue};
use crate::random::{Random, RandomSource};

// Recursive macro for implementing n-ary tuple functions and operations
//
Expand Down Expand Up @@ -131,16 +130,6 @@ macro_rules! tuple_impls {
}
}

maybe_tuple_doc! {
$($T)+ @
#[unstable(feature = "random", issue = "130703")]
impl<$($T: Random),+> Random for ($($T,)+) {
fn random(source: &mut (impl RandomSource + ?Sized)) -> Self {
($({ let x: $T = Random::random(source); x},)+)
}
}
}

maybe_tuple_doc! {
$($T)+ @
#[stable(feature = "array_tuple_conv", since = "1.71.0")]
Expand Down
24 changes: 7 additions & 17 deletions library/std/src/random.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
//! Random value generation.
//!
//! The [`Random`] trait allows generating a random value for a type using a
//! given [`RandomSource`].
#[unstable(feature = "random", issue = "130703")]
pub use core::random::*;
Expand Down Expand Up @@ -68,18 +65,11 @@ impl RandomSource for DefaultRandomSource {
}
}

/// Generates a random value with the default random source.
/// Generates a random value from a distribution, using the default random source.
///
/// This is a convenience function for `T::random(&mut DefaultRandomSource)` and
/// will sample according to the same distribution as the underlying [`Random`]
/// trait implementation. See [`DefaultRandomSource`] for more information about
/// how randomness is sourced.
///
/// **Warning:** Be careful when manipulating random values! The
/// [`random`](Random::random) method on integers samples them with a uniform
/// distribution, so a value of 1 is just as likely as [`i32::MAX`]. By using
/// modulo operations, some of the resulting values can become more likely than
/// others. Use audited crates when in doubt.
/// This is a convenience function for `dist.sample(&mut DefaultRandomSource)` and will sample
/// according to the same distribution as the underlying [`Distribution`] trait implementation. See
/// [`DefaultRandomSource`] for more information about how randomness is sourced.
///
/// # Examples
///
Expand All @@ -89,7 +79,7 @@ impl RandomSource for DefaultRandomSource {
///
/// use std::random::random;
///
/// let bits: u128 = random();
/// let bits: u128 = random(..);
/// let g1 = (bits >> 96) as u32;
/// let g2 = (bits >> 80) as u16;
/// let g3 = (0x4000 | (bits >> 64) & 0x0fff) as u16;
Expand All @@ -101,6 +91,6 @@ impl RandomSource for DefaultRandomSource {
///
/// [version 4/variant 1 UUID]: https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_(random)
#[unstable(feature = "random", issue = "130703")]
pub fn random<T: Random>() -> T {
T::random(&mut DefaultRandomSource)
pub fn random<T>(dist: impl Distribution<T>) -> T {
dist.sample(&mut DefaultRandomSource)
}
4 changes: 2 additions & 2 deletions library/std/src/sys/pal/sgx/abi/usercalls/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::cmp;
use crate::io::{
BorrowedCursor, Error as IoError, ErrorKind, IoSlice, IoSliceMut, Result as IoResult,
};
use crate::random::{DefaultRandomSource, Random};
use crate::random::random;
use crate::time::{Duration, Instant};

pub(crate) mod alloc;
Expand Down Expand Up @@ -179,7 +179,7 @@ pub fn wait(event_mask: u64, mut timeout: u64) -> IoResult<u64> {
// trusted to ensure accurate timeouts.
if let Ok(timeout_signed) = i64::try_from(timeout) {
let tenth = timeout_signed / 10;
let deviation = i64::random(&mut DefaultRandomSource).checked_rem(tenth).unwrap_or(0);
let deviation = random::<i64>(..).checked_rem(tenth).unwrap_or(0);
timeout = timeout_signed.saturating_add(deviation) as _;
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/tools/miri/tests/pass/shims/random.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#![feature(random)]

fn main() {
let _x: i32 = std::random::random();
let _x: i32 = std::random::random(..);
}
Loading