This guide gives a few more details than the changelog, in particular giving guidance on how to use new features and migrate away from old ones.
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.
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
.
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
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.
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()
A new trait has been added: FromEntropy
. This is automatically implemented for
any type supporting SeedableRng
, and provides construction from fresh, strong
entropy:
use rand::{ChaChaRng, FromEntropy};
let mut rng = ChaChaRng::from_entropy();
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.
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.
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.
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):
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
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.
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; dependending on usage
this may or may not be the fastest algorithm, but will always be fast.)
The ReseedingRng
wrapper has been signficantly altered to reduce overhead.
Unfortunately the new ReseedingRng
is not compatible with all RNGs, but only
those using BlockRngCore
.
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 superceeded by
a method to construct any PRNG from any hashable object in the future.
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()
.
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.
The random()
function has been removed; users may simply use
thread_rng().gen()
instead or may choose to cache
let mut rng = thread_rng();
locally, or even use a different generator.
weak_rng()
has been deprecated; use SmallRng::from_entropy()
instead.
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 existance 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 Open01
and Closed01
wrappers have been removed. Rng::gen()
(via
Standard
) now yields samples from (0, 1)
for floats; i.e. the same as the
old Open01
. This is considered sufficient for most uses.
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
The Range
distribution has been heavily adapted, while remaining largely
backwards compatible:
Range::new(low, high)
remains (half open[low, high)
)Range::new_inclusive(low, high)
has been added, includinghigh
in the sample rangeRange::sample_single(low, high, rng)
is a faster variant for single usage sampling from[low, high)
Range
can now be implemented for user-defined types; see the RangeImpl
type.
SampleRange
has been adapted to suit the new Range
model.
Two distributions have been added:
- Poisson, modelling the number of events expected from a constant-rate source within a fixed time interval (e.g. nuclear decay)
- Binomial, modelling the outcome of a fixed number of yes-no trials
The sampling methods are based on those in "Numerical Recipes in C".
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);
.