random
Two generators and a set of distributions over them. Both generators implement RandomSource, so the whole draw surface works with either — or with a source of your own.
| Item | Import |
|---|---|
RandomSource | import std::random::source; |
Rng | import std::random::rng; |
SecureRng | import std::random::secure; |
UniformU64, Normal, WeightedIndex, ... | import std::random::distribution; |
RandomError | import std::random::error; |
Choosing a generator
Rng is xoshiro256** — excellent statistical quality, 256 bits of state, very fast. It is not suitable for cryptography.
SecureRng draws straight from the operating system's cryptographic generator. It exposes no predictable algorithm and is the right choice for keys, tokens, and nonces.
import std::random::rng;
mut r: Rng = Rng::from_seed(42); // reproducible
const roll: u64 = r.next_range(1, 7);
Rng::from_seed(seed) gives the same stream for the same seed, which is what you want for tests and simulations. Rng::from_os() seeds unpredictably, falling back to a monotonic-clock and pid mix if the kernel source is briefly unavailable, so it never hard-fails — fine for non-cryptographic use.
Rng is POD, so copying it forks the stream rather than sharing it. SecureRng is stateless, so a copy is the same source.
RandomSource
One required primitive — next_64(mut &this) -> u64 — and a substantial set of defaults built on it.
next<T>()
A uniform draw of type T, dispatched at compile time via static match (T). Select the type with a turbofish (r.next<u32>()) or let context infer it.
T | What you get |
|---|---|
Any fixed-width integer, usize, isize | The required bits, taken from the top (best-mixed) end. u128 and i128 concatenate two draws. |
boolean | The top bit. |
f64 / f32 | A uniform value in [0.0, 1.0). f64 uses the top 53 bits, so every representable value in the interval is equally likely. |
char | A uniform Unicode scalar; the surrogate range is skipped. |
Bounded draws
next_below(bound: u64) -> u64— uniform in[0, bound). Unbiased: the top partial bucket is rejected so the modulo introduces no skew. Panics whenbound == 0, since an empty range has no value to return.next_range<T>(lo: T, hi: T) -> T— uniform in[lo, hi), requiringlo < hi. Every integer width is covered; 64-bit-and-narrower spans go throughnext_below, andu128/i128use an inline 128-bit rejection sampler.next_below_wide(bound: u128) -> u128— the same top-bucket rejection over the full 128-bit range.
Bulk and collections
fill(dst: Slice<u8>)— fill a byte view.shuffle<T>(items: &Slice<T>)— an in-place uniform Fisher-Yates pass. Elements are swapped, never copied out, so there is noCopybound and owning element types work.choose<T>(items: &Slice<T>) -> Option<T*>— a uniformly chosen element, borrowed in place.Nonewhen empty.
SecureRng
import std::random::secure;
mut s: SecureRng = SecureRng::new();
s.fill(key.as_slice());
Because it satisfies RandomSource, the full draw surface above is available. Those defaults panic if the kernel cannot supply entropy — a broken system invariant rather than an expected failure. When you need to handle it, use try_fill(dst: Slice<u8>) -> Result<(), RandomError>, which reports it as EntropyUnavailable.
The backing source is per target: getrandom on Unix, RtlGenRandom on Windows. Rng::from_os routes through the same portable helper rather than binding the Linux-only symbol directly.
Distributions
A Distribution<T> turns a source of random bits into draws of a particular shape. sample(rng) is generic over R: RandomSource, so every distribution works with Rng, SecureRng, or a custom source.
| Distribution | Produces |
|---|---|
UniformU64::new(lo, hi) | u64 in [lo, hi) |
UniformI64::new(lo, hi) | i64 in [lo, hi) |
UniformF64::new(lo, hi) | f64 in [lo, hi) |
Bernoulli::new(p) | boolean — true with probability p, clamped to [0, 1] |
Normal::new(mean, std_dev) | f64 |
Exponential::new(lambda) | f64 — waiting times at rate lambda, mean 1 / lambda |
WeightedIndex::try_new(weights: Slice<f64>) | u64 — an index chosen in proportion to its weight |
import std::random::distribution;
const d: Normal = Normal::new(0.0, 1.0);
const z: f64 = d.sample(&r);
WeightedIndex is built once from a weight list and then sampled cheaply. It owns its cumulative table, so it carries a drop, and construction is fallible: InvalidWeights when the list is empty, contains a negative entry, or sums to zero.
RandomError
| Variant | Meaning |
|---|---|
EntropyUnavailable | The kernel CSPRNG could not supply bytes. Surfaced by try_fill. |
EmptyRange | A bounded draw was asked for an empty range. |
InvalidWeights | Weights were empty, negative, or summed to zero. |
It implements Eq and the usual describe() -> Str.