Skip to content

Commit 4c36374

Browse files
authored
Rollup merge of rust-lang#143710 - joshtriplett:random-updates, r=Amanieu
Updates to random number generation APIs Updates based on discussions about random number generation. - Add comment on `RandomSource::fill_bytes` about multiple calls, to allow efficient implementations for random sources that generate a word at a time. - Drop the `Random` trait in favor of `Distribution<T>`, which will let people make calls like random(1..=6), and which allows for future expansion to non-uniform distributions, as well as floating-point. (For now, this is only implemented for `RangeFull`, to get the interface in place. Subsequent PRs will implement it for other range types.)
2 parents bf22a09 + 900aa00 commit 4c36374

File tree

5 files changed

+33
-58
lines changed

5 files changed

+33
-58
lines changed

library/core/src/primitive_docs.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1081,13 +1081,11 @@ mod prim_str {}
10811081
/// * [`Debug`]
10821082
/// * [`Default`]
10831083
/// * [`Hash`]
1084-
/// * [`Random`]
10851084
/// * [`From<[T; N]>`][from]
10861085
///
10871086
/// [from]: convert::From
10881087
/// [`Debug`]: fmt::Debug
10891088
/// [`Hash`]: hash::Hash
1090-
/// [`Random`]: random::Random
10911089
///
10921090
/// The following traits are implemented for tuples of any length. These traits have
10931091
/// implementations that are automatically generated by the compiler, so are not limited by

library/core/src/random.rs

Lines changed: 25 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,46 @@
11
//! Random value generation.
2-
//!
3-
//! The [`Random`] trait allows generating a random value for a type using a
4-
//! given [`RandomSource`].
2+
3+
use crate::range::RangeFull;
54

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

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

26-
impl Random for bool {
27-
fn random(source: &mut (impl RandomSource + ?Sized)) -> Self {
28-
u8::random(source) & 1 == 1
30+
impl Distribution<bool> for RangeFull {
31+
fn sample(&self, source: &mut (impl RandomSource + ?Sized)) -> bool {
32+
let byte: u8 = RangeFull.sample(source);
33+
byte & 1 == 1
2934
}
3035
}
3136

3237
macro_rules! impl_primitive {
3338
($t:ty) => {
34-
impl Random for $t {
35-
/// Generates a random value.
36-
///
37-
/// **Warning:** Be careful when manipulating the resulting value! This
38-
/// method samples according to a uniform distribution, so a value of 1 is
39-
/// just as likely as [`MAX`](Self::MAX). By using modulo operations, some
40-
/// values can become more likely than others. Use audited crates when in
41-
/// doubt.
42-
fn random(source: &mut (impl RandomSource + ?Sized)) -> Self {
43-
let mut bytes = (0 as Self).to_ne_bytes();
39+
impl Distribution<$t> for RangeFull {
40+
fn sample(&self, source: &mut (impl RandomSource + ?Sized)) -> $t {
41+
let mut bytes = (0 as $t).to_ne_bytes();
4442
source.fill_bytes(&mut bytes);
45-
Self::from_ne_bytes(bytes)
43+
<$t>::from_ne_bytes(bytes)
4644
}
4745
}
4846
};

library/core/src/tuple.rs

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
use crate::cmp::Ordering::{self, *};
44
use crate::marker::{ConstParamTy_, StructuralPartialEq, UnsizedConstParamTy};
55
use crate::ops::ControlFlow::{self, Break, Continue};
6-
use crate::random::{Random, RandomSource};
76

87
// Recursive macro for implementing n-ary tuple functions and operations
98
//
@@ -131,16 +130,6 @@ macro_rules! tuple_impls {
131130
}
132131
}
133132

134-
maybe_tuple_doc! {
135-
$($T)+ @
136-
#[unstable(feature = "random", issue = "130703")]
137-
impl<$($T: Random),+> Random for ($($T,)+) {
138-
fn random(source: &mut (impl RandomSource + ?Sized)) -> Self {
139-
($({ let x: $T = Random::random(source); x},)+)
140-
}
141-
}
142-
}
143-
144133
maybe_tuple_doc! {
145134
$($T)+ @
146135
#[stable(feature = "array_tuple_conv", since = "1.71.0")]

library/std/src/random.rs

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
11
//! Random value generation.
2-
//!
3-
//! The [`Random`] trait allows generating a random value for a type using a
4-
//! given [`RandomSource`].
52
63
#[unstable(feature = "random", issue = "130703")]
74
pub use core::random::*;
@@ -68,18 +65,11 @@ impl RandomSource for DefaultRandomSource {
6865
}
6966
}
7067

71-
/// Generates a random value with the default random source.
68+
/// Generates a random value from a distribution, using the default random source.
7269
///
73-
/// This is a convenience function for `T::random(&mut DefaultRandomSource)` and
74-
/// will sample according to the same distribution as the underlying [`Random`]
75-
/// trait implementation. See [`DefaultRandomSource`] for more information about
76-
/// how randomness is sourced.
77-
///
78-
/// **Warning:** Be careful when manipulating random values! The
79-
/// [`random`](Random::random) method on integers samples them with a uniform
80-
/// distribution, so a value of 1 is just as likely as [`i32::MAX`]. By using
81-
/// modulo operations, some of the resulting values can become more likely than
82-
/// others. Use audited crates when in doubt.
70+
/// This is a convenience function for `dist.sample(&mut DefaultRandomSource)` and will sample
71+
/// according to the same distribution as the underlying [`Distribution`] trait implementation. See
72+
/// [`DefaultRandomSource`] for more information about how randomness is sourced.
8373
///
8474
/// # Examples
8575
///
@@ -89,7 +79,7 @@ impl RandomSource for DefaultRandomSource {
8979
///
9080
/// use std::random::random;
9181
///
92-
/// let bits: u128 = random();
82+
/// let bits: u128 = random(..);
9383
/// let g1 = (bits >> 96) as u32;
9484
/// let g2 = (bits >> 80) as u16;
9585
/// let g3 = (0x4000 | (bits >> 64) & 0x0fff) as u16;
@@ -101,6 +91,6 @@ impl RandomSource for DefaultRandomSource {
10191
///
10292
/// [version 4/variant 1 UUID]: https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_(random)
10393
#[unstable(feature = "random", issue = "130703")]
104-
pub fn random<T: Random>() -> T {
105-
T::random(&mut DefaultRandomSource)
94+
pub fn random<T>(dist: impl Distribution<T>) -> T {
95+
dist.sample(&mut DefaultRandomSource)
10696
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#![feature(random)]
22

33
fn main() {
4-
let _x: i32 = std::random::random();
4+
let _x: i32 = std::random::random(..);
55
}

0 commit comments

Comments
 (0)