Skip to content

Commit 8121d22

Browse files
committed
random: Provide a Distribution<T> trait
This will let people make calls like random(1..=6), and 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 commits will implement it for other range types.
1 parent 4c94798 commit 8121d22

File tree

3 files changed

+20
-46
lines changed

3 files changed

+20
-46
lines changed

library/core/src/random.rs

Lines changed: 14 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
//! The [`Random`] trait allows generating a random value for a type using a
44
//! given [`RandomSource`].
55
6+
use crate::range::RangeFull;
7+
68
/// A source of randomness.
79
#[unstable(feature = "random", issue = "130703")]
810
pub trait RandomSource {
@@ -15,39 +17,27 @@ pub trait RandomSource {
1517
fn fill_bytes(&mut self, bytes: &mut [u8]);
1618
}
1719

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

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

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

library/core/src/tuple.rs

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
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};
6+
use crate::range::RangeFull;
77

88
// Recursive macro for implementing n-ary tuple functions and operations
99
//
@@ -131,16 +131,6 @@ macro_rules! tuple_impls {
131131
}
132132
}
133133

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-
144134
maybe_tuple_doc! {
145135
$($T)+ @
146136
#[stable(feature = "array_tuple_conv", since = "1.71.0")]

library/std/src/random.rs

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -68,19 +68,13 @@ impl RandomSource for DefaultRandomSource {
6868
}
6969
}
7070

71-
/// Generates a random value with the default random source.
71+
/// Generates a random value from a distribution, using the default random source.
7272
///
73-
/// This is a convenience function for `T::random(&mut DefaultRandomSource)` and
73+
/// This is a convenience function for `dist.sample(&mut DefaultRandomSource)` and
7474
/// will sample according to the same distribution as the underlying [`Random`]
7575
/// trait implementation. See [`DefaultRandomSource`] for more information about
7676
/// how randomness is sourced.
7777
///
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.
83-
///
8478
/// # Examples
8579
///
8680
/// Generating a [version 4/variant 1 UUID] represented as text:
@@ -89,7 +83,7 @@ impl RandomSource for DefaultRandomSource {
8983
///
9084
/// use std::random::random;
9185
///
92-
/// let bits: u128 = random();
86+
/// let bits: u128 = random(..);
9387
/// let g1 = (bits >> 96) as u32;
9488
/// let g2 = (bits >> 80) as u16;
9589
/// let g3 = (0x4000 | (bits >> 64) & 0x0fff) as u16;
@@ -101,6 +95,6 @@ impl RandomSource for DefaultRandomSource {
10195
///
10296
/// [version 4/variant 1 UUID]: https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_(random)
10397
#[unstable(feature = "random", issue = "130703")]
104-
pub fn random<T: Random>() -> T {
105-
T::random(&mut DefaultRandomSource)
98+
pub fn random<T>(dist: &(impl Distribution<T> + ?Sized)) -> T {
99+
dist.sample(&mut DefaultRandomSource)
106100
}

0 commit comments

Comments
 (0)