Updating to 0.5
The 0.5 release has quite significant changes over the 0.4 release; as such, it may be worth reading through the following coverage of breaking changes. This release also contains many optimisations, which are not detailed below.
Crates
We have a new crate: rand_core
! This crate houses some important traits,
RngCore
, BlockRngCore
, SeedableRng
and CryptoRng
, the error types, as
well as two modules with helpers for implementations: le
and impls
. It is
recommended that implementations of generators use the rand_core
crate while
other users use only the rand
crate, which re-exports most parts of rand_core
.
The rand_derive
crate has been deprecated due to very low usage and
deprecation of Rand
.
Features
Several new Cargo feature flags have been added:
alloc
, used withoutstd
, allows use ofBox
andVec
serde1
adds serialization support to some PRNGslog
adds logging in a few places (primarily toOsRng
andJitterRng
)
Rng
and friends (core traits)
Rng
trait has been split into two traits, a "back end" RngCore
(implemented
by generators) and a "front end" Rng
implementing all the convenient extension
methods.
Implementations of generators must impl RngCore
instead. Usage of rand_core
for implementations is encouraged; the rand_core::{le, impls}
modules may
prove useful.
Users of Rng
who don't need to implement it won't need to make so many
changes; often users can forget about RngCore
and only import Rng
. Instead
of RngCore::next_u32()
/ next_u64()
users should prefer Rng::gen()
, and
instead of RngCore::fill_bytes(dest)
, Rng::fill(dest)
can be used.
Rng
/ RngCore
methods
To allow error handling from fallible sources (e.g. OsRng
), a new
RngCore::try_fill_bytes
method has been added; for example EntropyRng
uses
this mechanism to fall back to JitterRng
if OsRng
fails, and various
handlers produce better error messages.
As before, the other methods will panic on failure, but since these are usually
used with algorithmic generators which are usually infallible, this is
considered an appropriate compromise.
A few methods from the old Rng
have been removed or deprecated:
next_f32
andnext_f64
; these are no longer implementable by generators; usegen
insteadgen_iter
; users may instead use standard iterators with closures:::std::iter::repeat(()).map(|()| rng.gen())
gen_ascii_chars
; userepeat
as above andrng.sample(Alphanumeric)
gen_weighted_bool(n)
; usegen_bool(1.0 / n)
instead
Rng
has a few new methods:
sample(distr)
is a shortcut fordistr.sample(rng)
for anyDistribution
gen_bool(p)
generates a boolean with probabilityp
of being truefill
andtry_fill
, corresponding tofill_bytes
andtry_fill_bytes
respectively (i.e. the only difference is error handling); these can fill and integer slice / array directly, and provide better performance thangen()
Constructing PRNGs
New randomly-initialised PRNGs
A new trait has been added: FromEntropy
. This is automatically implemented for
any type supporting SeedableRng
, and provides construction from fresh, strong
entropy:
#![allow(unused)] fn main() { use rand::{ChaChaRng, FromEntropy}; let mut rng = ChaChaRng::from_entropy(); }
Seeding PRNGs
The SeedableRng
trait has been modified to include the seed type via an
associated type (SeedableRng::Seed
) instead of a template parameter
(SeedableRng<Seed>
). Additionally, all PRNGs now seed from a byte-array
([u8; N]
for some fixed N). This allows generic handling of PRNG seeding
which was not previously possible.
PRNGs are no longer constructed from other PRNGs via Rand
support / gen()
,
but through SeedableRng::from_rng
, which allows error handling and is
intentionally explicit.
SeedableRng::reseed
has been removed since it has no utility over from_seed
and its performance advantage is questionable.
Implementations of SeedableRng
may need to change their Seed
type to a
byte-array; this restriction has been made to ensure portable handling of
Endianness. Helper functions are available in rand_core::le
to read u32
and
u64
values from byte arrays.
Block-based PRNGs
rand_core has a new helper trait, BlockRngCore
, and implementation,
BlockRng
. These are for use by generators which generate a block of random
data at a time instead of word-sized values. Using this trait and implementation
has two advantages: optimised RngCore
methods are provided, and the PRNG can
be used with ReseedingRng
with very low overhead.
Cryptographic RNGs
A new trait has been added: CryptoRng
. This is purely a marker trait to
indicate which generators should be suitable for cryptography, e.g.
fn foo<R: Rng + CryptoRng>(rng: &mut R)
. Suitability for cryptographic
use cannot be guaranteed.
Error handling
A new Error
type has been added, designed explicitly for no-std compatibility,
simplicity, and enough flexibility for our uses (carrying a cause
when
possible):
#![allow(unused)] fn main() { pub struct Error { pub kind: ErrorKind, pub msg: &'static str, // some fields omitted } }
The associated ErrorKind
allows broad classification of errors into permanent,
unexpected, transient and not-yet-ready kinds.
The following use the new error type:
RngCore::try_fill_bytes
Rng::try_fill
OsRng::new
JitterRng::new
External generators
We have a new generator, EntropyRng
, which wraps OsRng
and JitterRng
(preferring to use the former, but falling back to the latter if necessary).
This allows easy construction with fallback via SeedableRng::from_rng
,
e.g. IsaacRng::from_rng(EntropyRng::new())?
. This is equivalent to using
FromEntropy
except for error handling.
It is recommended to use EntropyRng
over OsRng
to avoid errors on platforms
with broken system generator, but it should be noted that the JitterRng
fallback is very slow.
PRNGs
Pseudo-Random Number Generators (i.e. deterministic algorithmic generators)
have had a few changes since 0.4, and are now housed in the prng
module
(old names remain temporarily available for compatibility; eventually these
generators will likely be housed outside the rand
crate).
All PRNGs now do not implement Copy
to prevent accidental copying of the
generator's state (and thus repetitions of generated values). Explicit cloning
via Clone
is still available. All PRNGs now have a custom implementation of
Debug
which does not print any internal state; this helps avoid accidentally
leaking cryptographic generator state in log files. External PRNG
implementations are advised to follow this pattern (see also doc on RngCore
).
SmallRng
has been added as a wrapper, currently around XorShiftRng
(but
likely another algorithm soon). This is for uses where small state and fast
initialisation are important but cryptographic strength is not required.
(Actual performance of generation varies by benchmark; depending on usage
this may or may not be the fastest algorithm, but will always be fast.)
ReseedingRng
The ReseedingRng
wrapper has been significantly altered to reduce overhead.
Unfortunately the new ReseedingRng
is not compatible with all RNGs, but only
those using BlockRngCore
.
ChaCha
The method ChaChaRng::set_counter
has been replaced by two new methods,
set_word_pos
and set_stream
. Where necessary, the behaviour of the old
method may be emulated as follows:
#![allow(unused)] fn main() { use rand::prelude::*; use rand_chacha::ChaChaRng; let lower = 88293; let higher = 9300932; // previously: // let mut rng = rand::ChaChaRng::new_unseeded(); // rng.set_counter(lower, higher); // now: let mut rng = ChaChaRng::from_seed([0u8; 32]); rng.set_word_pos(lower << 4); rng.set_stream(higher); assert_eq!(4060232610, rng.next_u32()); assert_eq!(2786236710, rng.next_u32()); }
ISAAC PRNGs
The IsaacRng
and Isaac64Rng
PRNGs now have an additional construction
method: new_from_u64(seed)
. 64 bits of state is insufficient for cryptography
but may be of use in simulations and games. This will likely be superseded by
a method to construct any PRNG from any hashable object in the future.
HC-128
This is a new cryptographic generator, selected as one of the "stream ciphers
suitable for widespread adoption" by eSTREAM. This is now the default
cryptographic generator, used by StdRng
and thread_rng()
.
Helper functions/traits
The Rand
trait has been deprecated. Instead, users are encouraged to use
Standard
which is a real distribution and supports the same sampling as
Rand
. Rng::gen()
now uses Standard
and should work exactly as before.
See the documentation of the distributions
module on how to implement
Distribution<T>
for Standard
for user types T
weak_rng()
has been deprecated; use SmallRng::from_entropy()
instead.
Distributions
The Sample
and IndependentSample
traits have been replaced by a single
trait, Distribution
. This is largely equivalent to IndependentSample
, but
with ind_sample
replaced by just sample
. Support for mutable distributions
has been dropped; although it appears there may be a few genuine uses, these
are not used widely enough to justify the existence of two independent traits
or of having to provide mutable access to a distribution object. Both Sample
and IndependentSample
are still available, but deprecated; they will be
removed in a future release.
Distribution::sample
(as well as several other functions) can now be called
directly on type-erased (unsized) RNGs.
RandSample
has been removed (see Rand
deprecation and new Standard
distribution).
The Closed01
wrapper has been removed, but OpenClosed01
has been added.
Uniform distributions
Two new distributions are available:
Standard
produces uniformly-distributed samples for many different types, and acts as a replacement forRand
Alphanumeric
sampleschar
s from the rangesa-z A-Z 0-9
Ranges
The Range
distribution has been heavily adapted, and renamed to Uniform
:
Uniform::new(low, high)
remains (half open[low, high)
)Uniform::new_inclusive(low, high)
has been added, includinghigh
in the sample rangeUniform::sample_single(low, high, rng)
is a faster variant for single usage sampling from[low, high)
Uniform
can now be implemented for user-defined types; see the uniform
module.
Non-uniform distributions
Two distributions have been added:
- Poisson, modeling the number of events expected from a constant-rate source within a fixed time interval (e.g. nuclear decay)
- Binomial, modeling the outcome of a fixed number of yes-no trials
The sampling methods are based on those in "Numerical Recipes in C".
Exponential and Normal distributions
The main Exp
and Normal
distributions are unchanged, however the
"standard" versions, Exp1
and StandardNormal
are no longer wrapper types,
but full distributions. Instead of writing let Exp1(x) = rng.gen();
you now
write let x = rng.sample(Exp1);
.