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 ofBoxandVecserde1adds serialization support to some PRNGslogadds logging in a few places (primarily toOsRngandJitterRng)
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_f32andnext_f64; these are no longer implementable by generators; usegeninsteadgen_iter; users may instead use standard iterators with closures:::std::iter::repeat(()).map(|()| rng.gen())gen_ascii_chars; userepeatas 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 anyDistributiongen_bool(p)generates a boolean with probabilitypof being truefillandtry_fill, corresponding tofill_bytesandtry_fill_bytesrespectively (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_0_5::{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):
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_bytesRng::try_fillOsRng::newJitterRng::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:
extern crate rand; extern crate rand_chacha; use rand::prelude::*; use rand_chacha::ChaChaRng; fn main() { 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:
Standardproduces uniformly-distributed samples for many different types, and acts as a replacement forRandAlphanumericsampleschars 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, includinghighin 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);.