Skip to content

Commit

Permalink
Merge pull request #49 from rust-random/work
Browse files Browse the repository at this point in the history
Add test harness
  • Loading branch information
dhardy authored Feb 23, 2022
2 parents 66724c2 + 56ed9ab commit e92deb4
Show file tree
Hide file tree
Showing 23 changed files with 269 additions and 136 deletions.
25 changes: 25 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: Tests

on:
push:
branches: [ master, '0.[0-9]+' ]
pull_request:
branches: [ master, '0.[0-9]+' ]

jobs:
code-samples:
name: Test code samples
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
- name: Generate harness
working-directory: ./tests
run: ./generate.sh
- name: Test code samples
working-directory: ./tests
run: cargo test
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
book
tests/src/*
Cargo.lock
4 changes: 2 additions & 2 deletions src/contrib-doc.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ When referring to an item from within another crate,

Examples:

```
```ignore
// We depend on rand_core, therefore can use the Rust path:
/// [`BlockRngCore`]: rand_core::block::BlockRngCore
Expand All @@ -95,7 +95,7 @@ example.
For the most part these files do not have any continuous testing.
Where examples are included (currently only for the `rand_jitter` crate),
we enable continuous testing via `doc_comment` (see
[lib.rs:62 onwards](https://github.com/rust-random/rand/blob/master/rand_jitter/src/lib.rs#L62)).
[lib.rs:62 onwards](https://github.com/rust-random/rngs/blob/master/rand_jitter/src/lib.rs#L62)).

### CHANGELOG files

Expand Down
2 changes: 1 addition & 1 deletion src/contrib-test.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ Often test code needs some RNG to test with, but does not need any particular
RNG. In this case, we prefer use of `::test::rng` which is simple, fast to
initialise and deterministic:

```rust
```rust,ignore
let mut rng = ::test::rng(528); // just pick some number
```

Expand Down
2 changes: 1 addition & 1 deletion src/contributing.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,5 +47,5 @@ thus we may take considerable time to get back to you.

Our works are attributed to "The Rand Project Developers". This is not a
formal entity but merely the collection of all contributors to this project.
For more, see the [COPYRIGHT](COPYRIGHT) file.
For more, see the `COPYRIGHT` file.
- **Thank you!**
2 changes: 1 addition & 1 deletion src/crates-gen.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ The following crates implement pseudo-random number generators


[`rand_chacha`]: https://rust-random.github.io/rand/rand_chacha/index.html
[`rand_hc`]: https://rust-random.github.io/rand/rand_hc/index.html
[`rand_hc`]: https://docs.rs/rand_hc/
[`rand_isaac`]: https://docs.rs/rand_isaac/
[`rand_pcg`]: https://rust-random.github.io/rand/rand_pcg/index.html
[`rand_xoshiro`]: https://docs.rs/rand_xoshiro/
Expand Down
2 changes: 1 addition & 1 deletion src/crates.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ platform-dependent random number source, [`rand_core`] defines the API that
generators must implement, and a number of crates like [`rand_chacha`] and
[`rand_xoshiro`] provide pseudo-random generators.

```
```plain
getrandom ┐
└ rand_core ┐
├ rand_chacha ┐
Expand Down
5 changes: 4 additions & 1 deletion src/guide-data.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@
```rust
# extern crate rand;
# use rand::RngCore;
# fn main() {
// get some random data:
let mut data = [0u8; 32];
let mut data = [0u8; 8];
rand::thread_rng().fill_bytes(&mut data);
println!("{:?}", data)
# }
```

## What is randomness?
Expand Down
84 changes: 27 additions & 57 deletions src/guide-dist.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ For maximum flexibility when producing random values, we define the
[`Distribution`] trait:

```rust
# use rand::{Rng, distributions::DistIter};
// a producer of data of type T:
pub trait Distribution<T> {
// the key function:
Expand All @@ -14,7 +15,10 @@ pub trait Distribution<T> {
where
Self: Sized,
R: Rng,
{ ... }
{
// [has a default implementation]
# todo!()
}
}
```

Expand Down Expand Up @@ -86,10 +90,11 @@ Lets go over the distributions by type:
- For SIMD types, each element is sampled as above, for [`Standard`] and
[`Uniform`] (for the latter, `low` and `high` parameters are *also* SIMD
types, effectively sampling from multiple ranges simultaneously). SIMD
support is gated behind a [feature flag](../features.html#simd-support).
support requires using the `simd_support` feature flag and nightly `rustc`.
- For enums, you have to implement uniform sampling yourself. For example, you
could use the following approach:
```rust
# use rand::{Rng, distributions::{Distribution, Standard}};
pub enum Food {
Burger,
Pizza,
Expand All @@ -111,29 +116,15 @@ Lets go over the distributions by type:

# Non-uniform distributions

Non-uniform distributions can be divided into two categories, as follows.
Some of these discrete and all of the continuous distributions have been moved
from the main [`rand`] crate to a dedicated [`rand_distr`] crate.

## Discrete non-uniform distributions

Discrete distributions sample from boolean or integer types. As above, these
can be sampled uniformly, or, as below, via a non-uniform distribution.

Potentially a discrete distribution could sample directly from a set of discrete
values such as a slice or an `enum`. See the section on [Sequences] regarding
Rand's traits for slice and iterator types. Rand does not provide direct
sampling from `enum`s, with the exception of `Option` (see above).

### Booleans
The [`rand`] crate provides only two non-uniform distributions:

The [`Bernoulli`] distribution is a fancy name for generating a boolean
with a given a probability `p` of being `true`, or defined via a
`success : failure` ratio. Often this is described as a *trial* with
probability `p` of *success* (`true`).
- The [`Bernoulli`] distribution simply generates a boolean where the
probability of sampling `true` is some constant (`Bernoulli::new(0.5)`) or
ratio (`Bernoulli::from_ratio(1, 6)`).
- The [`WeightedIndex`] distribution may be used to sample from a sequence of
weighted values. See the [Sequences] section.

The methods [`Rng::gen_bool`] and [`Rng::gen_ratio`] are short-cuts to this
distribution.
Many more non-uniform distributions are provided by the [`rand_distr`] crate.

### Integers

Expand All @@ -154,26 +145,6 @@ For example, `u64` values can be attained with `rng.sample(Poisson) as u64`.
Note that out of range float to int conversions with `as` result in undefined
behavior for Rust <1.45 and a saturating conversion for Rust >=1.45.

### Weighted sequences

The [`WeightedIndex`] distribution samples an index from sequence of weights.
See the [Sequences] section for convenience wrappers directly sampling a slice
element.

For example, weighted sampling could be used to model the colour of a marble
sampled from a bucket containing 5 green, 15 red and 80 blue marbles.

Currently the Rand lib only implements *sampling with replacement*, i.e.
repeated sampling assumes the same distribution (that any sampled marble
has been replaced). An alternative distribution implementing
*sampling without replacement* has been
[requested](https://github.com/rust-random/rand/issues/596).

Note also that two implementations of [`WeightedIndex`] are available; the
first is optimised for a small number of samples while
[`alias_method::WeightedIndex`] is optimised for a large number of samples
(where "large" may mean "> 1000"; benchmarks recommended).

## Continuous non-uniform distributions

Continuous distributions model samples drawn from the real number line ℝ, or in
Expand All @@ -190,7 +161,7 @@ deviation. The [`LogNormal`] is related: for sample `X` from the log-normal
distribution, `log(X)` is normally distributed; this "skews" the normal
distribution to avoid negative values and to have a long positive tail.

The [`UnitCircle`] and [`UnitSphereSurface`] distributions simulate uniform
The [`UnitCircle`] and [`UnitSphere`] distributions simulate uniform
sampling from the edge of a circle or surface of a sphere.

The [`Cauchy`] distribution (also known as the Lorentz distribution) is the
Expand All @@ -201,7 +172,7 @@ The [`Beta`] distribution is a two-parameter probability distribution, whose
output values lie between 0 and 1. The [`Dirichlet`] distribution is a
generalisation to any positive number of parameters.

[Sequences]: ../guide-seq.html
[Sequences]: guide-seq.html
[`Distribution`]: ../rand/rand/distributions/trait.Distribution.html
[`distributions`]: ../rand/rand/distributions/index.html
[`rand`]: ../rand/rand/index.html
Expand All @@ -219,16 +190,15 @@ generalisation to any positive number of parameters.
[`Open01`]: ../rand/rand/distributions/struct.Open01.html
[`OpenClosed01`]: ../rand/rand/distributions/struct.OpenClosed01.html
[`Bernoulli`]: ../rand/rand/distributions/struct.Bernoulli.html
[`Binomial`]: ../rand/rand/distributions/struct.Binomial.html
[`Exp`]: ../rand/rand/distributions/struct.Exp.html
[`Normal`]: ../rand/rand/distributions/struct.Normal.html
[`LogNormal`]: ../rand/rand/distributions/struct.LogNormal.html
[`UnitCircle`]: ../rand/rand/distributions/struct.UnitCircle.html
[`UnitSphereSurface`]: ../rand/rand/distributions/struct.UnitSphereSurface.html
[`Cauchy`]: ../rand/rand/distributions/struct.Cauchy.html
[`Poisson`]: ../rand/rand/distributions/struct.Poisson.html
[`Beta`]: ../rand/rand/distributions/struct.Beta.html
[`Dirichlet`]: ../rand/rand/distributions/struct.Dirichlet.html
[`WeightedIndex`]: ../rand/rand/distributions/weighted/struct.WeightedIndex.html
[`alias_method::WeightedIndex`]: ../rand/rand/distributions/weighted/alias_method/struct.WeightedIndex.html
[`Binomial`]: ../rand/rand_distr/struct.Binomial.html
[`Exp`]: ../rand/rand_distr/struct.Exp.html
[`Normal`]: ../rand/rand_distr/struct.Normal.html
[`LogNormal`]: ../rand/rand_distr/struct.LogNormal.html
[`UnitCircle`]: ../rand/rand_distr/struct.UnitCircle.html
[`UnitSphere`]: ../rand/rand_distr/struct.UnitSphere.html
[`Cauchy`]: ../rand/rand_distr/struct.Cauchy.html
[`Poisson`]: ../rand/rand_distr/struct.Poisson.html
[`Beta`]: ../rand/rand_distr/struct.Beta.html
[`Dirichlet`]: ../rand/rand_distr/struct.Dirichlet.html
[`statrs`]: https://github.com/statrs-dev/statrs/
[`WeightedIndex`]: ../rand/rand/distributions/struct.WeightedIndex.html
24 changes: 10 additions & 14 deletions src/guide-err.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,24 +19,20 @@ reduce to calls to [`RngCore`]'s "infallible" methods. Since most RNGs cannot
fail anyway this is usually not a problem, but the few generators which can may
be forced to fail in this case:

- [`OsRng`] interfaces with the Operating System's generator; in rare cases
this may fail as "not ready" or simply "unavailable".
- [`JitterRng`] is a generator based on timer jitter; if the timer does not
appear to be capable of sufficient precision or is too predictable, this
will fail.
- [`EntropyRng`] is an abstraction over the above, falling back to the next
option when the first fails but ultimately failing if all sources fail
- [`thread_rng`] seeds itself via [`EntropyRng`], thus can potentially fail
on its first use on each thread (though it never fails after the first use)
- [`ReadRng`] tries to read data from its source but fails when the stream
ends or errors (though it retries on interrupt).
- [`OsRng`] is a wrapper over [`getrandom`]. From the latter's documentation:
"In general, on supported platforms, failure is highly unlikely, though not
impossible." [`OsRng`] will forward errors through
[`RngCore::try_fill_bytes`] while other methods panic on error.
- [`thread_rng`] seeds itself via [`OsRng`] on first use and periodically
thereafter, thus can potentially fail, though unlikely. If initial seeding
fails, a panic will result. If a failure happens during reseeding (less
likely) then the RNG continues without reseeding; a log message (warning)
is emitted if logging is enabled.

[`Rng::try_fill`]: ../rand/rand/trait.Rng.html#method.try_fill
[`RngCore::try_fill_bytes`]: ../rand/rand_core/trait.RngCore.html#tymethod.try_fill_bytes
[`SeedableRng::from_rng`]: ../rand/rand_core/trait.SeedableRng.html#method.from_rng
[`RngCore`]: ../rand/rand_core/trait.RngCore.html
[`thread_rng`]: ../rand/rand/fn.thread_rng.html
[`OsRng`]: ../rand/rand/rngs/struct.OsRng.html
[`JitterRng`]: ../rand/rand/rngs/struct.JitterRng.html
[`EntropyRng`]: ../rand/rand/rngs/struct.EntropyRng.html
[`ReadRng`]: ../rand/rand/rngs/adapter/struct.ReadRng.html
[`getrandom`]: https://docs.rs/getrandom/latest/getrandom/
9 changes: 7 additions & 2 deletions src/guide-gen.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,17 @@ This section concerns theory; see also the chapter on
```rust
# extern crate rand;
# extern crate rand_pcg;
use rand::{Rng, SeedableRng};

# fn main() {
// prepare a non-deterministic random number generator:
let mut rng = rand::thread_rng();
println!("{}", rng.gen::<i32>());

// prepare a deterministic generator:
use rand::SeedableRng;
let mut rng = rand_pcg::Pcg32::seed_from_u64(123);
println!("{}", rng.gen::<i32>());
# }
```

## True random number generators
Expand Down Expand Up @@ -125,4 +130,4 @@ couple of bits entropy is available per time-stamp, after running several tests
on the timer's quality).

[`RngCore`]: ../rand/rand_core/trait.RngCore.html
[`JitterRng`]: ../rand/rand/rngs/jitter/struct.JitterRng.html
[`JitterRng`]: https://docs.rs/rand_jitter/latest/rand_jitter/struct.JitterRng.html
16 changes: 9 additions & 7 deletions src/guide-rngs.md
Original file line number Diff line number Diff line change
Expand Up @@ -245,11 +245,11 @@ for recommendations.
It is worth noting that a CSPRNG's security relies absolutely on being
seeded with a secure random key. Should the key be known or guessable, all
output of the CSPRNG is easy to guess. This implies that the seed should
come from a trusted source; usually either the OS or another CSPRNG. Our
seeding helper trait, [`FromEntropy`], and the source it uses
([`EntropyRng`]), should be secure. Additionally, [`ThreadRng`] is a CSPRNG,
thus it is acceptable to seed from this (although for security applications
fresh/external entropy should be preferred).
come from a trusted source; usually either the OS or another CSPRNG. For this
purpose, we recommend using the [`getrandom`] crate which interfaces the OS's
secure random interface. [`SeedableRng::from_entropy`] is a wrapper around
[`getrandom`] for convenience. Alternatively, using a user-space CSPRNG such as
[`ThreadRng`] for seeding should be sufficient.

Further, it should be obvious that the internal state of a CSPRNG must be
kept secret. With that in mind, our implementations do not provide direct
Expand Down Expand Up @@ -305,10 +305,10 @@ by P. Hellekalek.
[`Xoshiro256PlusPlus`]: https://docs.rs/rand_xoshiro/latest/rand_xoshiro/struct.Xoshiro256PlusPlus.html
[`Xoshiro256Plus`]: https://docs.rs/rand_xoshiro/latest/rand_xoshiro/struct.Xoshiro256Plus.html
[`SplitMix64`]: https://docs.rs/rand_xoshiro/latest/rand_xoshiro/struct.SplitMix64.html
[`ChaChaRng`]: ../rand/rand_chacha/struct.ChaChaRng.html
[`ChaChaRng`]: ../rand/rand_chacha/type.ChaChaRng.html
[`ChaCha20Rng`]: ../rand/rand_chacha/struct.ChaCha20Rng.html
[`ChaCha8Rng`]: ../rand/rand_chacha/struct.ChaCha8Rng.html
[`Hc128Rng`]: ../rand/rand_hc/struct.Hc128Rng.html
[`Hc128Rng`]: https://docs.rs/rand_hc/latest/rand_hc/struct.Hc128Rng.html
[`IsaacRng`]: https://docs.rs/rand_isaac/latest/rand_isaac/isaac/struct.IsaacRng.html
[`Isaac64Rng`]: https://docs.rs/rand_isaac/latest/rand_isaac/isaac64/struct.Isaac64Rng.html
[`ThreadRng`]: ../rand/rand/rngs/struct.ThreadRng.html
Expand All @@ -325,3 +325,5 @@ by P. Hellekalek.
[next-bit test]: https://en.wikipedia.org/wiki/Next-bit_test
[NIST]: https://www.nist.gov/
[ECRYPT]: http://www.ecrypt.eu.org/
[`getrandom`]: https://docs.rs/getrandom/
[`SeedableRng::from_entropy`]: ../rand/rand/trait.SeedableRng.html#method.from_entropy
Loading

0 comments on commit e92deb4

Please sign in to comment.