Skip to content

Commit 766c7ec

Browse files
authored
Doc: improve random, thread_rng, ThreadRng docs (#1257)
* Use a custom Debug impl for ThreadRng * Adjust documentation of random, thread_rng, ThreadRng * Fix no-std build * Compatibility with older rustc
1 parent 2b4f00a commit 766c7ec

File tree

4 files changed

+55
-49
lines changed

4 files changed

+55
-49
lines changed

rand_core/src/os.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,9 @@ use getrandom::getrandom;
1919
/// The implementation is provided by the [getrandom] crate. Refer to
2020
/// [getrandom] documentation for details.
2121
///
22-
/// This struct is only available when specifying the crate feature `getrandom`
23-
/// or `std`. When using the `rand` lib, it is also available as `rand::rngs::OsRng`.
22+
/// This struct is available as `rand_core::OsRng` and as `rand::rngs::OsRng`.
23+
/// In both cases, this requires the crate feature `getrandom` or `std`
24+
/// (enabled by default in `rand` but not in `rand_core`).
2425
///
2526
/// # Blocking and error handling
2627
///

src/lib.rs

Lines changed: 4 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -110,36 +110,10 @@ use crate::distributions::{Distribution, Standard};
110110

111111
/// Generates a random value using the thread-local random number generator.
112112
///
113-
/// This is simply a shortcut for `thread_rng().gen()`. See [`thread_rng`] for
114-
/// documentation of the entropy source and [`Standard`] for documentation of
115-
/// distributions and type-specific generation.
113+
/// This function is simply a shortcut for `thread_rng().gen()`:
116114
///
117-
/// # Provided implementations
118-
///
119-
/// The following types have provided implementations that
120-
/// generate values with the following ranges and distributions:
121-
///
122-
/// * Integers (`i32`, `u32`, `isize`, `usize`, etc.): Uniformly distributed
123-
/// over all values of the type.
124-
/// * `char`: Uniformly distributed over all Unicode scalar values, i.e. all
125-
/// code points in the range `0...0x10_FFFF`, except for the range
126-
/// `0xD800...0xDFFF` (the surrogate code points). This includes
127-
/// unassigned/reserved code points.
128-
/// * `bool`: Generates `false` or `true`, each with probability 0.5.
129-
/// * Floating point types (`f32` and `f64`): Uniformly distributed in the
130-
/// half-open range `[0, 1)`. See notes below.
131-
/// * Wrapping integers (`Wrapping<T>`), besides the type identical to their
132-
/// normal integer variants.
133-
///
134-
/// Also supported is the generation of the following
135-
/// compound types where all component types are supported:
136-
///
137-
/// * Tuples (up to 12 elements): each element is generated sequentially.
138-
/// * Arrays (up to 32 elements): each element is generated sequentially;
139-
/// see also [`Rng::fill`] which supports arbitrary array length for integer
140-
/// types and tends to be faster for `u32` and smaller types.
141-
/// * `Option<T>` first generates a `bool`, and if true generates and returns
142-
/// `Some(value)` where `value: T`, otherwise returning `None`.
115+
/// - See [`ThreadRng`] for documentation of the generator and security
116+
/// - See [`Standard`] for documentation of supported types and distributions
143117
///
144118
/// # Examples
145119
///
@@ -177,6 +151,7 @@ use crate::distributions::{Distribution, Standard};
177151
/// ```
178152
///
179153
/// [`Standard`]: distributions::Standard
154+
/// [`ThreadRng`]: rngs::ThreadRng
180155
#[cfg(all(feature = "std", feature = "std_rng"))]
181156
#[cfg_attr(doc_cfg, doc(cfg(all(feature = "std", feature = "std_rng"))))]
182157
#[inline]

src/rng.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ use core::{mem, slice};
5353
/// # let v = foo(&mut thread_rng());
5454
/// ```
5555
pub trait Rng: RngCore {
56-
/// Return a random value supporting the [`Standard`] distribution.
56+
/// Return a random value via the [`Standard`] distribution.
5757
///
5858
/// # Example
5959
///

src/rngs/thread.rs

Lines changed: 47 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use core::cell::UnsafeCell;
1212
use std::rc::Rc;
1313
use std::thread_local;
14+
use std::fmt;
1415

1516
use super::std::Core;
1617
use crate::rngs::adapter::ReseedingRng;
@@ -39,31 +40,43 @@ const THREAD_RNG_RESEED_THRESHOLD: u64 = 1024 * 64;
3940

4041
/// A reference to the thread-local generator
4142
///
43+
/// This type is a reference to a lazily-initialized thread-local generator.
4244
/// An instance can be obtained via [`thread_rng`] or via `ThreadRng::default()`.
4345
/// This handle is safe to use everywhere (including thread-local destructors),
4446
/// though it is recommended not to use inside a fork handler.
4547
/// The handle cannot be passed between threads (is not `Send` or `Sync`).
4648
///
47-
/// `ThreadRng` uses the same PRNG as [`StdRng`] for security and performance
48-
/// and is automatically seeded from [`OsRng`].
49+
/// `ThreadRng` uses the same CSPRNG as [`StdRng`], ChaCha12. As with
50+
/// [`StdRng`], the algorithm may be changed, subject to reasonable expectations
51+
/// of security and performance.
4952
///
50-
/// Unlike `StdRng`, `ThreadRng` uses the [`ReseedingRng`] wrapper to reseed
51-
/// the PRNG from fresh entropy every 64 kiB of random data as well as after a
52-
/// fork on Unix (though not quite immediately; see documentation of
53-
/// [`ReseedingRng`]).
54-
/// Note that the reseeding is done as an extra precaution against side-channel
55-
/// attacks and mis-use (e.g. if somehow weak entropy were supplied initially).
56-
/// The PRNG algorithms used are assumed to be secure.
53+
/// `ThreadRng` is automatically seeded from [`OsRng`] with periodic reseeding
54+
/// (every 64 kiB, as well as "soon" after a fork on Unix — see [`ReseedingRng`]
55+
/// documentation for details).
56+
///
57+
/// Security must be considered relative to a thread model and validation
58+
/// requirements. `ThreadRng` attempts to meet basic security considerations
59+
/// for producing unpredictable random numbers: use a CSPRNG, use a
60+
/// recommended platform-specific seed ([`OsRng`]), and avoid
61+
/// leaking internal secrets e.g. via [`Debug`] implementation or serialization.
62+
/// Memory is not zeroized on drop.
5763
///
5864
/// [`ReseedingRng`]: crate::rngs::adapter::ReseedingRng
5965
/// [`StdRng`]: crate::rngs::StdRng
6066
#[cfg_attr(doc_cfg, doc(cfg(all(feature = "std", feature = "std_rng"))))]
61-
#[derive(Clone, Debug)]
67+
#[derive(Clone)]
6268
pub struct ThreadRng {
6369
// Rc is explicitly !Send and !Sync
6470
rng: Rc<UnsafeCell<ReseedingRng<Core, OsRng>>>,
6571
}
6672

73+
/// Debug implementation does not leak internal state
74+
impl fmt::Debug for ThreadRng {
75+
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
76+
write!(fmt, "ThreadRng {{ .. }}")
77+
}
78+
}
79+
6780
thread_local!(
6881
// We require Rc<..> to avoid premature freeing when thread_rng is used
6982
// within thread-local destructors. See #968.
@@ -77,13 +90,23 @@ thread_local!(
7790
}
7891
);
7992

80-
/// Retrieve the lazily-initialized thread-local random number generator,
81-
/// seeded by the system. Intended to be used in method chaining style,
82-
/// e.g. `thread_rng().gen::<i32>()`, or cached locally, e.g.
83-
/// `let mut rng = thread_rng();`. Invoked by the `Default` trait, making
84-
/// `ThreadRng::default()` equivalent.
93+
/// Access the thread-local generator
94+
///
95+
/// Returns a reference to the local [`ThreadRng`], initializing the generator
96+
/// on the first call on each thread.
8597
///
86-
/// For more information see [`ThreadRng`].
98+
/// Example usage:
99+
/// ```
100+
/// use rand::Rng;
101+
///
102+
/// # fn main() {
103+
/// // rand::random() may be used instead of rand::thread_rng().gen():
104+
/// println!("A random boolean: {}", rand::random::<bool>());
105+
///
106+
/// let mut rng = rand::thread_rng();
107+
/// println!("A simulated die roll: {}", rng.gen_range(1..=6));
108+
/// # }
109+
/// ```
87110
#[cfg_attr(doc_cfg, doc(cfg(all(feature = "std", feature = "std_rng"))))]
88111
pub fn thread_rng() -> ThreadRng {
89112
let rng = THREAD_RNG_KEY.with(|t| t.clone());
@@ -92,7 +115,7 @@ pub fn thread_rng() -> ThreadRng {
92115

93116
impl Default for ThreadRng {
94117
fn default() -> ThreadRng {
95-
crate::prelude::thread_rng()
118+
thread_rng()
96119
}
97120
}
98121

@@ -140,4 +163,11 @@ mod test {
140163
r.gen::<i32>();
141164
assert_eq!(r.gen_range(0..1), 0);
142165
}
166+
167+
#[test]
168+
fn test_debug_output() {
169+
// We don't care about the exact output here, but it must not include
170+
// private CSPRNG state or the cache stored by BlockRng!
171+
assert_eq!(std::format!("{:?}", crate::thread_rng()), "ThreadRng { .. }");
172+
}
143173
}

0 commit comments

Comments
 (0)