aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--nitrocli/CHANGELOG.md4
-rw-r--r--nitrocli/Cargo.lock111
-rw-r--r--nitrocli/Cargo.toml5
-rw-r--r--nitrokey/CHANGELOG.md13
-rw-r--r--nitrokey/Cargo.toml6
-rw-r--r--nitrokey/README.md15
-rw-r--r--nitrokey/src/auth.rs14
-rw-r--r--nitrokey/src/config.rs2
-rw-r--r--nitrokey/src/device.rs99
-rw-r--r--nitrokey/src/lib.rs22
-rw-r--r--nitrokey/src/otp.rs8
-rw-r--r--nitrokey/src/pws.rs19
-rw-r--r--nitrokey/src/tests/mod.rs4
-rw-r--r--nitrokey/src/tests/util.rs11
-rw-r--r--nitrokey/src/util.rs19
-rw-r--r--nitrokey/tests/device.rs (renamed from nitrokey/src/tests/device.rs)109
-rw-r--r--nitrokey/tests/otp.rs (renamed from nitrokey/src/tests/otp.rs)10
-rw-r--r--nitrokey/tests/pws.rs (renamed from nitrokey/src/tests/pws.rs)45
-rw-r--r--nitrokey/tests/util/mod.rs8
-rw-r--r--rand/.travis.yml200
-rw-r--r--rand/CHANGELOG.md227
-rw-r--r--rand/COPYRIGHT12
-rw-r--r--rand/Cargo.toml73
-rw-r--r--rand/LICENSE-APACHE4
-rw-r--r--rand/LICENSE-MIT1
-rw-r--r--rand/README.md192
-rw-r--r--rand/appveyor.yml22
-rw-r--r--rand/benches/bench.rs34
-rw-r--r--rand/benches/distributions.rs237
-rw-r--r--rand/benches/distributions/exponential.rs18
-rw-r--r--rand/benches/distributions/gamma.rs31
-rw-r--r--rand/benches/distributions/mod.rs3
-rw-r--r--rand/benches/distributions/normal.rs18
-rw-r--r--rand/benches/generators.rs197
-rw-r--r--rand/benches/misc.rs152
-rw-r--r--rand/benches/seq.rs174
-rw-r--r--rand/build.rs14
-rw-r--r--rand/examples/monte-carlo.rs51
-rw-r--r--rand/examples/monty-hall.rs116
-rw-r--r--rand/rand-derive/Cargo.toml23
-rw-r--r--rand/rand-derive/README.md51
-rw-r--r--rand/rand-derive/src/lib.rs116
-rw-r--r--rand/rand-derive/tests/rand_macros.rs58
-rw-r--r--rand/rand_chacha/CHANGELOG.md8
-rw-r--r--rand/rand_chacha/COPYRIGHT12
-rw-r--r--rand/rand_chacha/Cargo.toml25
-rw-r--r--rand/rand_chacha/LICENSE-APACHE201
-rw-r--r--rand/rand_chacha/LICENSE-MIT26
-rw-r--r--rand/rand_chacha/README.md45
-rw-r--r--rand/rand_chacha/build.rs8
-rw-r--r--rand/rand_chacha/src/chacha.rs449
-rw-r--r--rand/rand_chacha/src/lib.rs25
-rw-r--r--rand/rand_core/CHANGELOG.md33
-rw-r--r--rand/rand_core/COPYRIGHT12
-rw-r--r--rand/rand_core/Cargo.toml28
-rw-r--r--rand/rand_core/LICENSE-APACHE201
-rw-r--r--rand/rand_core/LICENSE-MIT26
-rw-r--r--rand/rand_core/README.md65
-rw-r--r--rand/rand_core/src/block.rs508
-rw-r--r--rand/rand_core/src/error.rs177
-rw-r--r--rand/rand_core/src/impls.rs165
-rw-r--r--rand/rand_core/src/le.rs68
-rw-r--r--rand/rand_core/src/lib.rs486
-rw-r--r--rand/rand_hc/CHANGELOG.md8
-rw-r--r--rand/rand_hc/COPYRIGHT12
-rw-r--r--rand/rand_hc/Cargo.toml21
-rw-r--r--rand/rand_hc/LICENSE-APACHE201
-rw-r--r--rand/rand_hc/LICENSE-MIT25
-rw-r--r--rand/rand_hc/README.md45
-rw-r--r--rand/rand_hc/src/hc128.rs462
-rw-r--r--rand/rand_hc/src/lib.rs25
-rw-r--r--rand/rand_isaac/CHANGELOG.md8
-rw-r--r--rand/rand_isaac/COPYRIGHT12
-rw-r--r--rand/rand_isaac/Cargo.toml31
-rw-r--r--rand/rand_isaac/LICENSE-APACHE201
-rw-r--r--rand/rand_isaac/LICENSE-MIT26
-rw-r--r--rand/rand_isaac/README.md47
-rw-r--r--rand/rand_isaac/src/isaac.rs484
-rw-r--r--rand/rand_isaac/src/isaac64.rs481
-rw-r--r--rand/rand_isaac/src/isaac_array.rs136
-rw-r--r--rand/rand_isaac/src/lib.rs36
-rw-r--r--rand/rand_pcg/CHANGELOG.md14
-rw-r--r--rand/rand_pcg/COPYRIGHT12
-rw-r--r--rand/rand_pcg/Cargo.toml37
-rw-r--r--rand/rand_pcg/LICENSE-APACHE201
-rw-r--r--rand/rand_pcg/LICENSE-MIT26
-rw-r--r--rand/rand_pcg/README.md51
-rw-r--r--rand/rand_pcg/build.rs8
-rw-r--r--rand/rand_pcg/src/lib.rs48
-rw-r--r--rand/rand_pcg/src/pcg128.rs122
-rw-r--r--rand/rand_pcg/src/pcg64.rs141
-rw-r--r--rand/rand_pcg/tests/lcg64xsh32.rs58
-rw-r--r--rand/rand_pcg/tests/mcg128xsl64.rs59
-rw-r--r--rand/rand_xorshift/CHANGELOG.md8
-rw-r--r--rand/rand_xorshift/COPYRIGHT12
-rw-r--r--rand/rand_xorshift/Cargo.toml31
-rw-r--r--rand/rand_xorshift/LICENSE-APACHE201
-rw-r--r--rand/rand_xorshift/LICENSE-MIT26
-rw-r--r--rand/rand_xorshift/README.md45
-rw-r--r--rand/rand_xorshift/src/lib.rs123
-rw-r--r--rand/rand_xorshift/tests/mod.rs92
-rw-r--r--rand/src/deprecated.rs611
-rw-r--r--rand/src/distributions/bernoulli.rs165
-rw-r--r--rand/src/distributions/binomial.rs177
-rw-r--r--rand/src/distributions/cauchy.rs115
-rw-r--r--rand/src/distributions/dirichlet.rs137
-rw-r--r--rand/src/distributions/exponential.rs86
-rw-r--r--rand/src/distributions/float.rs259
-rw-r--r--rand/src/distributions/gamma.rs209
-rw-r--r--rand/src/distributions/integer.rs161
-rw-r--r--rand/src/distributions/mod.rs666
-rw-r--r--rand/src/distributions/normal.rs120
-rw-r--r--rand/src/distributions/other.rs219
-rw-r--r--rand/src/distributions/pareto.rs74
-rw-r--r--rand/src/distributions/poisson.rs157
-rw-r--r--rand/src/distributions/range.rs241
-rw-r--r--rand/src/distributions/triangular.rs86
-rw-r--r--rand/src/distributions/uniform.rs1297
-rw-r--r--rand/src/distributions/unit_circle.rs102
-rw-r--r--rand/src/distributions/unit_sphere.rs100
-rw-r--r--rand/src/distributions/utils.rs504
-rw-r--r--rand/src/distributions/weibull.rs71
-rw-r--r--rand/src/distributions/weighted.rs232
-rw-r--r--rand/src/distributions/ziggurat_tables.rs9
-rw-r--r--rand/src/lib.rs1604
-rw-r--r--rand/src/os.rs617
-rw-r--r--rand/src/prelude.rs27
-rw-r--r--rand/src/prng/chacha.rs321
-rw-r--r--rand/src/prng/isaac.rs328
-rw-r--r--rand/src/prng/isaac64.rs340
-rw-r--r--rand/src/prng/mod.rs74
-rw-r--r--rand/src/prng/xorshift.rs101
-rw-r--r--rand/src/rand_impls.rs299
-rw-r--r--rand/src/read.rs123
-rw-r--r--rand/src/reseeding.rs229
-rw-r--r--rand/src/rngs/adapter/mod.rs15
-rw-r--r--rand/src/rngs/adapter/read.rs137
-rw-r--r--rand/src/rngs/adapter/reseeding.rs370
-rw-r--r--rand/src/rngs/entropy.rs297
-rw-r--r--rand/src/rngs/jitter.rs (renamed from rand/src/jitter.rs)605
-rw-r--r--rand/src/rngs/mock.rs59
-rw-r--r--rand/src/rngs/mod.rs217
-rw-r--r--rand/src/rngs/os.rs1275
-rw-r--r--rand/src/rngs/small.rs105
-rw-r--r--rand/src/rngs/std.rs81
-rw-r--r--rand/src/rngs/thread.rs135
-rw-r--r--rand/src/seq.rs337
-rw-r--r--rand/src/seq/index.rs378
-rw-r--r--rand/src/seq/mod.rs836
-rw-r--r--rand/tests/uniformity.rs67
-rw-r--r--rand/utils/ci/install.sh49
-rw-r--r--rand/utils/ci/script.sh22
-rwxr-xr-xrand/utils/ziggurat_tables.py18
-rw-r--r--rustc_version/.gitignore2
-rw-r--r--rustc_version/.travis.yml21
-rw-r--r--rustc_version/Cargo.toml18
-rw-r--r--rustc_version/LICENSE-APACHE201
-rw-r--r--rustc_version/LICENSE-MIT25
-rw-r--r--rustc_version/README.md75
-rw-r--r--rustc_version/src/errors.rs79
-rw-r--r--rustc_version/src/lib.rs347
-rw-r--r--semver-parser/.gitignore2
-rw-r--r--semver-parser/Cargo.toml11
-rw-r--r--semver-parser/LICENSE-APACHE201
-rw-r--r--semver-parser/LICENSE-MIT25
-rw-r--r--semver-parser/src/common.rs66
-rw-r--r--semver-parser/src/lib.rs8
-rw-r--r--semver-parser/src/range.rs696
-rw-r--r--semver-parser/src/recognize.rs154
-rw-r--r--semver-parser/src/version.rs365
-rw-r--r--semver/.gitignore3
-rw-r--r--semver/.travis.yml18
-rw-r--r--semver/Cargo.toml32
-rw-r--r--semver/LICENSE-APACHE201
-rw-r--r--semver/LICENSE-MIT25
-rw-r--r--semver/README.md103
-rw-r--r--semver/src/lib.rs182
-rw-r--r--semver/src/version.rs759
-rw-r--r--semver/src/version_req.rs895
-rw-r--r--semver/tests/deprecation.rs22
-rw-r--r--semver/tests/regression.rs25
-rw-r--r--semver/tests/serde.rs90
182 files changed, 22875 insertions, 5332 deletions
diff --git a/nitrocli/CHANGELOG.md b/nitrocli/CHANGELOG.md
index da08209..c6ad543 100644
--- a/nitrocli/CHANGELOG.md
+++ b/nitrocli/CHANGELOG.md
@@ -3,6 +3,10 @@ Unreleased
- Added the `pws` command for accessing the password safe
- Added the `lock` command for locking the Nitrokey device
- Adjusted release build compile options to optimize binary for size
+- Bumped `nitrokey` dependency to `0.2.3`
+ - Bumped `rand` dependency to `0.6.1`
+ - Added `rustc_version` version `0.2.3`, `semver` version `0.9.0`, and
+ `semver-parser` version `0.7.0` as indirect dependencies
- Bumped `cc` dependency to `1.0.28`
diff --git a/nitrocli/Cargo.lock b/nitrocli/Cargo.lock
index 09775f8..abbf84d 100644
--- a/nitrocli/Cargo.lock
+++ b/nitrocli/Cargo.lock
@@ -18,6 +18,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
replace = "cc 1.0.28"
[[package]]
+name = "cloudabi"
+version = "0.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "fuchsia-zircon"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -46,16 +54,16 @@ name = "nitrocli"
version = "0.2.0"
dependencies = [
"argparse 0.2.2",
- "nitrokey 0.2.1",
+ "nitrokey 0.2.3",
]
[[package]]
name = "nitrokey"
-version = "0.2.1"
+version = "0.2.3"
dependencies = [
"libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)",
"nitrokey-sys 3.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -73,18 +81,103 @@ replace = "nitrokey-sys 3.4.1"
[[package]]
name = "rand"
-version = "0.4.3"
+version = "0.6.1"
dependencies = [
+ "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_chacha 0.1.0",
+ "rand_core 0.3.0",
+ "rand_hc 0.1.0",
+ "rand_isaac 0.1.0",
+ "rand_pcg 0.1.1",
+ "rand_xorshift 0.1.0",
+ "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand"
-version = "0.4.3"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+replace = "rand 0.6.1"
+
+[[package]]
+name = "rand_chacha"
+version = "0.1.0"
+dependencies = [
+ "rand_core 0.3.0",
+ "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.3.0"
+
+[[package]]
+name = "rand_hc"
+version = "0.1.0"
+dependencies = [
+ "rand_core 0.3.0",
+]
+
+[[package]]
+name = "rand_isaac"
+version = "0.1.0"
+dependencies = [
+ "rand_core 0.3.0",
+]
+
+[[package]]
+name = "rand_pcg"
+version = "0.1.1"
+dependencies = [
+ "rand_core 0.3.0",
+ "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rand_xorshift"
+version = "0.1.0"
+dependencies = [
+ "rand_core 0.3.0",
+]
+
+[[package]]
+name = "rustc_version"
+version = "0.2.3"
+dependencies = [
+ "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rustc_version"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+replace = "rustc_version 0.2.3"
+
+[[package]]
+name = "semver"
+version = "0.9.0"
+dependencies = [
+ "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "semver"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+replace = "semver 0.9.0"
+
+[[package]]
+name = "semver-parser"
+version = "0.7.0"
+
+[[package]]
+name = "semver-parser"
+version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-replace = "rand 0.4.3"
+replace = "semver-parser 0.7.0"
[[package]]
name = "winapi"
@@ -108,11 +201,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
"checksum cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4a8b715cb4597106ea87c7c84b2f1d452c7492033765df7f32651e66fcf749"
+"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
"checksum libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)" = "2d2857ec59fadc0773853c664d2d18e7198e83883e7060b63c924cb077bd5c74"
"checksum nitrokey-sys 3.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "34794d630d40a093a3f0e31b821b38ee1c16e6909dc42064feff28f4798484f4"
-"checksum rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8356f47b32624fef5b3301c1be97e5944ecdd595409cc5da11d05f211db6cfbd"
+"checksum rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ae9d223d52ae411a33cf7e54ec6034ec165df296ccd23533d671a28252b6f66a"
+"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
+"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
+"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
diff --git a/nitrocli/Cargo.toml b/nitrocli/Cargo.toml
index fc97e20..1fd4f3d 100644
--- a/nitrocli/Cargo.toml
+++ b/nitrocli/Cargo.toml
@@ -54,4 +54,7 @@ path = "../nitrokey"
"cc:1.0.28" = { path = "../cc" }
"libc:0.2.45" = { path = "../libc" }
"nitrokey-sys:3.4.1" = { path = "../nitrokey-sys" }
-"rand:0.4.3" = { path = "../rand" }
+"rand:0.6.1" = { path = "../rand" }
+"rustc_version:0.2.3" = { path = "../rustc_version" }
+"semver:0.9.0" = { path = "../semver" }
+"semver-parser:0.7.0" = { path = "../semver-parser" }
diff --git a/nitrokey/CHANGELOG.md b/nitrokey/CHANGELOG.md
index a60d6a7..5064d4f 100644
--- a/nitrokey/CHANGELOG.md
+++ b/nitrokey/CHANGELOG.md
@@ -1,3 +1,16 @@
+# v0.2.3 (2018-12-31)
+
+- Dummy release to fix an issue with the crates.io tarball.
+
+# v0.2.2 (2018-12-30)
+
+- Update to Rust edition 2018.
+- Remove the `test-no-device` feature.
+- Update the rand dependency to version 0.6.
+- Add function `Device::get_model` that returns the connected model.
+- Derive the `Copy` and `Clone` traits for the enums `CommandError`, `LogLevel`
+ and `OtpMode`
+
# v0.2.1 (2018-12-10)
- Re-export `device::{StorageStatus, VolumeStatus}` in `lib.rs`.
diff --git a/nitrokey/Cargo.toml b/nitrokey/Cargo.toml
index dad751b..6369fba 100644
--- a/nitrokey/Cargo.toml
+++ b/nitrokey/Cargo.toml
@@ -1,7 +1,8 @@
[package]
name = "nitrokey"
-version = "0.2.1"
+version = "0.2.3"
authors = ["Robin Krahl <robin.krahl@ireas.org>"]
+edition = "2018"
homepage = "https://code.ireas.org/nitrokey-rs/"
repository = "https://git.ireas.org/nitrokey-rs/"
documentation = "https://docs.rs/nitrokey"
@@ -12,11 +13,10 @@ readme = "README.md"
license = "MIT"
[features]
-test-no-device = []
test-pro = []
test-storage = []
[dependencies]
libc = "0.2"
nitrokey-sys = "3.4.1"
-rand = "0.4"
+rand = "0.6"
diff --git a/nitrokey/README.md b/nitrokey/README.md
index 6039943..568b1d4 100644
--- a/nitrokey/README.md
+++ b/nitrokey/README.md
@@ -4,11 +4,6 @@ A libnitrokey wrapper for Rust providing access to Nitrokey devices.
[Documentation][]
-```toml
-[dependencies]
-nitrokey = "0.2.1"
-```
-
## Compatibility
The required [`libnitrokey`][] version is built from source. The host system
@@ -35,12 +30,12 @@ supported by `nitrokey-rs`:
## Tests
This crate has three test suites that can be selected using features. One test
-suite (feature `test-no-device`) assumes that no Nitrokey device is connected.
-The two other test suites require a Nitrokey Pro (feature `test-pro`) or a
-Nitrokey Storage (feature `test-storage`) to be connected.
+suite assumes that no Nitrokey device is connected. It is run if no other test
+suite is selected. The two other test suites require a Nitrokey Pro (feature
+`test-pro`) or a Nitrokey Storage (feature `test-storage`) to be connected.
Use the `--features` option for Cargo to select one of the test suites. You
-cannot select more than one of the test suites at the same time. Note that the
+should select more than one of the test suites at the same time. Note that the
test suites that require a Nitrokey device assume that the device’s passwords
are the factory defaults (admin password `12345678` and user password
`123456`). Running the test suite with a device with different passwords might
@@ -54,7 +49,7 @@ the test executable.
In conclusion, you can use these commands to run the test suites:
```
-$ cargo test --features test-no-device -- --test-threads 1
+$ cargo test
$ cargo test --features test-pro -- --test-threads 1
$ cargo test --features test-storage -- --test-threads 1
```
diff --git a/nitrokey/src/auth.rs b/nitrokey/src/auth.rs
index 0918222..017cdbb 100644
--- a/nitrokey/src/auth.rs
+++ b/nitrokey/src/auth.rs
@@ -1,10 +1,14 @@
-use config::{Config, RawConfig};
-use device::{Device, DeviceWrapper, Pro, Storage};
-use nitrokey_sys;
-use otp::{ConfigureOtp, GenerateOtp, OtpMode, OtpSlotData, RawOtpSlotData};
use std::ops::Deref;
use std::os::raw::c_int;
-use util::{generate_password, get_command_result, get_cstring, result_from_string, CommandError};
+
+use nitrokey_sys;
+
+use crate::config::{Config, RawConfig};
+use crate::device::{Device, DeviceWrapper, Pro, Storage};
+use crate::otp::{ConfigureOtp, GenerateOtp, OtpMode, OtpSlotData, RawOtpSlotData};
+use crate::util::{
+ generate_password, get_command_result, get_cstring, result_from_string, CommandError,
+};
static TEMPORARY_PASSWORD_LENGTH: usize = 25;
diff --git a/nitrokey/src/config.rs b/nitrokey/src/config.rs
index 33bf256..2ce6f77 100644
--- a/nitrokey/src/config.rs
+++ b/nitrokey/src/config.rs
@@ -1,4 +1,4 @@
-use util::CommandError;
+use crate::util::CommandError;
/// The configuration for a Nitrokey.
#[derive(Clone, Copy, Debug, PartialEq)]
diff --git a/nitrokey/src/device.rs b/nitrokey/src/device.rs
index f135261..9c6608d 100644
--- a/nitrokey/src/device.rs
+++ b/nitrokey/src/device.rs
@@ -1,20 +1,38 @@
-use auth::Authenticate;
-use config::{Config, RawConfig};
+use std::fmt;
+
use libc;
use nitrokey_sys;
-use otp::GenerateOtp;
-use pws::GetPasswordSafe;
-use util::{get_command_result, get_cstring, get_last_error, result_from_string, CommandError};
+
+use crate::auth::Authenticate;
+use crate::config::{Config, RawConfig};
+use crate::otp::GenerateOtp;
+use crate::pws::GetPasswordSafe;
+use crate::util::{
+ get_command_result, get_cstring, get_last_error, result_from_string, CommandError,
+};
/// Available Nitrokey models.
-#[derive(Debug, PartialEq)]
-enum Model {
+#[derive(Clone, Copy, Debug, PartialEq)]
+pub enum Model {
/// The Nitrokey Storage.
Storage,
/// The Nitrokey Pro.
Pro,
}
+impl fmt::Display for Model {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(
+ f,
+ "{}",
+ match *self {
+ Model::Pro => "Pro",
+ Model::Storage => "Storage",
+ }
+ )
+ }
+}
+
/// A wrapper for a Nitrokey device of unknown type.
///
/// Use the function [`connect`][] to obtain a wrapped instance. The wrapper implements all traits
@@ -210,6 +228,21 @@ pub struct StorageStatus {
/// This trait provides the commands that can be executed without authentication and that are
/// present on all supported Nitrokey devices.
pub trait Device: Authenticate + GetPasswordSafe + GenerateOtp {
+ /// Returns the model of the connected Nitrokey device.
+ ///
+ /// # Example
+ ///
+ /// ```no_run
+ /// use nitrokey::Device;
+ /// # use nitrokey::CommandError;
+ ///
+ /// # fn try_main() -> Result<(), CommandError> {
+ /// let device = nitrokey::connect()?;
+ /// println!("Connected to a Nitrokey {}", device.get_model());
+ /// # Ok(())
+ /// # }
+ fn get_model(&self) -> Model;
+
/// Returns the serial number of the Nitrokey device. The serial number is the string
/// representation of a hex number.
///
@@ -536,7 +569,7 @@ fn connect_model(model: Model) -> bool {
}
impl DeviceWrapper {
- fn device(&self) -> &Device {
+ fn device(&self) -> &dyn Device {
match *self {
DeviceWrapper::Storage(ref storage) => storage,
DeviceWrapper::Pro(ref pro) => pro,
@@ -562,9 +595,30 @@ impl GenerateOtp for DeviceWrapper {
}
}
-impl Device for DeviceWrapper {}
+impl Device for DeviceWrapper {
+ fn get_model(&self) -> Model {
+ match *self {
+ DeviceWrapper::Pro(_) => Model::Pro,
+ DeviceWrapper::Storage(_) => Model::Storage,
+ }
+ }
+}
impl Pro {
+ /// Connects to a Nitrokey Pro.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use nitrokey::Pro;
+ ///
+ /// fn use_pro(device: Pro) {}
+ ///
+ /// match nitrokey::Pro::connect() {
+ /// Ok(device) => use_pro(device),
+ /// Err(err) => println!("Could not connect to the Nitrokey Pro: {}", err),
+ /// }
+ /// ```
pub fn connect() -> Result<Pro, CommandError> {
// TODO: maybe Option instead of Result?
match connect_model(Model::Pro) {
@@ -582,11 +636,29 @@ impl Drop for Pro {
}
}
-impl Device for Pro {}
+impl Device for Pro {
+ fn get_model(&self) -> Model {
+ Model::Pro
+ }
+}
impl GenerateOtp for Pro {}
impl Storage {
+ /// Connects to a Nitrokey Storage.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use nitrokey::Storage;
+ ///
+ /// fn use_storage(device: Storage) {}
+ ///
+ /// match nitrokey::Storage::connect() {
+ /// Ok(device) => use_storage(device),
+ /// Err(err) => println!("Could not connect to the Nitrokey Storage: {}", err),
+ /// }
+ /// ```
pub fn connect() -> Result<Storage, CommandError> {
// TODO: maybe Option instead of Result?
match connect_model(Model::Storage) {
@@ -661,7 +733,6 @@ impl Storage {
unsafe { get_command_result(nitrokey_sys::NK_lock_encrypted_volume()) }
}
-
/// Returns the status of the connected storage device.
///
/// # Example
@@ -715,7 +786,11 @@ impl Drop for Storage {
}
}
-impl Device for Storage {}
+impl Device for Storage {
+ fn get_model(&self) -> Model {
+ Model::Storage
+ }
+}
impl GenerateOtp for Storage {}
diff --git a/nitrokey/src/lib.rs b/nitrokey/src/lib.rs
index e70aa73..9f21518 100644
--- a/nitrokey/src/lib.rs
+++ b/nitrokey/src/lib.rs
@@ -84,25 +84,25 @@
//! [`DeviceWrapper`]: enum.DeviceWrapper.html
//! [`User`]: struct.User.html
-extern crate libc;
-extern crate nitrokey_sys;
-extern crate rand;
+#![warn(missing_docs, rust_2018_compatibility, rust_2018_idioms, unused)]
mod auth;
mod config;
mod device;
mod otp;
mod pws;
-#[cfg(test)]
-mod tests;
mod util;
-pub use auth::{Admin, Authenticate, User};
-pub use config::Config;
-pub use device::{connect, Device, DeviceWrapper, Pro, Storage, StorageStatus, VolumeStatus};
-pub use otp::{ConfigureOtp, GenerateOtp, OtpMode, OtpSlotData};
-pub use pws::{GetPasswordSafe, PasswordSafe, SLOT_COUNT};
-pub use util::{CommandError, LogLevel};
+use nitrokey_sys;
+
+pub use crate::auth::{Admin, Authenticate, User};
+pub use crate::config::Config;
+pub use crate::device::{
+ connect, Device, DeviceWrapper, Model, Pro, Storage, StorageStatus, VolumeStatus,
+};
+pub use crate::otp::{ConfigureOtp, GenerateOtp, OtpMode, OtpSlotData};
+pub use crate::pws::{GetPasswordSafe, PasswordSafe, SLOT_COUNT};
+pub use crate::util::{CommandError, LogLevel};
/// Enables or disables debug output. Calling this method with `true` is equivalent to setting the
/// log level to `Debug`; calling it with `false` is equivalent to the log level `Error` (see
diff --git a/nitrokey/src/otp.rs b/nitrokey/src/otp.rs
index 00a5e5e..6f6bd80 100644
--- a/nitrokey/src/otp.rs
+++ b/nitrokey/src/otp.rs
@@ -1,9 +1,11 @@
-use nitrokey_sys;
use std::ffi::CString;
-use util::{get_command_result, get_cstring, result_from_string, CommandError};
+
+use nitrokey_sys;
+
+use crate::util::{get_command_result, get_cstring, result_from_string, CommandError};
/// Modes for one-time password generation.
-#[derive(Debug, PartialEq)]
+#[derive(Clone, Copy, Debug, PartialEq)]
pub enum OtpMode {
/// Generate one-time passwords with six digits.
SixDigits,
diff --git a/nitrokey/src/pws.rs b/nitrokey/src/pws.rs
index c20fe9d..08ac365 100644
--- a/nitrokey/src/pws.rs
+++ b/nitrokey/src/pws.rs
@@ -1,7 +1,10 @@
-use device::{Device, DeviceWrapper, Pro, Storage};
use libc;
use nitrokey_sys;
-use util::{get_command_result, get_cstring, get_last_error, result_from_string, CommandError};
+
+use crate::device::{Device, DeviceWrapper, Pro, Storage};
+use crate::util::{
+ get_command_result, get_cstring, get_last_error, result_from_string, CommandError,
+};
/// The number of slots in a [`PasswordSafe`][].
///
@@ -51,7 +54,7 @@ pub const SLOT_COUNT: u8 = 16;
/// [`lock`]: trait.Device.html#method.lock
/// [`GetPasswordSafe`]: trait.GetPasswordSafe.html
pub struct PasswordSafe<'a> {
- _device: &'a Device,
+ _device: &'a dyn Device,
}
/// Provides access to a [`PasswordSafe`][].
@@ -98,11 +101,11 @@ pub trait GetPasswordSafe {
/// [`lock`]: trait.Device.html#method.lock
/// [`InvalidString`]: enum.CommandError.html#variant.InvalidString
/// [`WrongPassword`]: enum.CommandError.html#variant.WrongPassword
- fn get_password_safe(&self, user_pin: &str) -> Result<PasswordSafe, CommandError>;
+ fn get_password_safe(&self, user_pin: &str) -> Result<PasswordSafe<'_>, CommandError>;
}
fn get_password_safe<'a>(
- device: &'a Device,
+ device: &'a dyn Device,
user_pin: &str,
) -> Result<PasswordSafe<'a>, CommandError> {
let user_pin_string = get_cstring(user_pin)?;
@@ -333,19 +336,19 @@ impl<'a> Drop for PasswordSafe<'a> {
}
impl GetPasswordSafe for Pro {
- fn get_password_safe(&self, user_pin: &str) -> Result<PasswordSafe, CommandError> {
+ fn get_password_safe(&self, user_pin: &str) -> Result<PasswordSafe<'_>, CommandError> {
get_password_safe(self, user_pin)
}
}
impl GetPasswordSafe for Storage {
- fn get_password_safe(&self, user_pin: &str) -> Result<PasswordSafe, CommandError> {
+ fn get_password_safe(&self, user_pin: &str) -> Result<PasswordSafe<'_>, CommandError> {
get_password_safe(self, user_pin)
}
}
impl GetPasswordSafe for DeviceWrapper {
- fn get_password_safe(&self, user_pin: &str) -> Result<PasswordSafe, CommandError> {
+ fn get_password_safe(&self, user_pin: &str) -> Result<PasswordSafe<'_>, CommandError> {
get_password_safe(self, user_pin)
}
}
diff --git a/nitrokey/src/tests/mod.rs b/nitrokey/src/tests/mod.rs
deleted file mode 100644
index 34ca0aa..0000000
--- a/nitrokey/src/tests/mod.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-mod device;
-mod otp;
-mod pws;
-mod util;
diff --git a/nitrokey/src/tests/util.rs b/nitrokey/src/tests/util.rs
deleted file mode 100644
index c6fbb8f..0000000
--- a/nitrokey/src/tests/util.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-pub static ADMIN_PASSWORD: &str = "12345678";
-pub static USER_PASSWORD: &str = "123456";
-
-#[cfg(feature = "test-no-device")]
-pub type Target = ::Pro;
-
-#[cfg(feature = "test-pro")]
-pub type Target = ::Pro;
-
-#[cfg(feature = "test-storage")]
-pub type Target = ::Storage;
diff --git a/nitrokey/src/util.rs b/nitrokey/src/util.rs
index 6f4fbb0..a2e957e 100644
--- a/nitrokey/src/util.rs
+++ b/nitrokey/src/util.rs
@@ -1,13 +1,12 @@
-use libc::{c_void, free};
-use nitrokey_sys;
-use rand::{OsRng, Rng};
-use std;
use std::ffi::{CStr, CString};
use std::fmt;
use std::os::raw::{c_char, c_int};
+use libc::{c_void, free};
+use rand::Rng;
+
/// Error types returned by Nitrokey device or by the library.
-#[derive(Debug, PartialEq)]
+#[derive(Clone, Copy, Debug, PartialEq)]
pub enum CommandError {
/// A packet with a wrong checksum has been sent or received.
WrongCrc,
@@ -44,7 +43,7 @@ pub enum CommandError {
///
/// Setting the log level to a lower level enables all output from higher levels too. Currently,
/// only the log levels `Warning`, `DebugL1`, `Debug` and `DebugL2` are actually used.
-#[derive(Debug, PartialEq)]
+#[derive(Clone, Copy, Debug, PartialEq)]
pub enum LogLevel {
/// Error messages. Currently not used.
Error,
@@ -101,12 +100,8 @@ pub fn get_last_error() -> CommandError {
}
pub fn generate_password(length: usize) -> std::io::Result<Vec<u8>> {
- let mut rng = match OsRng::new() {
- Ok(rng) => rng,
- Err(err) => return Err(err),
- };
let mut data = vec![0u8; length];
- rng.fill_bytes(&mut data[..]);
+ rand::thread_rng().fill(&mut data[..]);
return Ok(data);
}
@@ -115,7 +110,7 @@ pub fn get_cstring<T: Into<Vec<u8>>>(s: T) -> Result<CString, CommandError> {
}
impl fmt::Display for CommandError {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let msg = match *self {
CommandError::WrongCrc => "A packet with a wrong checksum has been sent or received",
CommandError::WrongSlot => "The given OTP slot does not exist",
diff --git a/nitrokey/src/tests/device.rs b/nitrokey/tests/device.rs
index fed465d..26afa62 100644
--- a/nitrokey/src/tests/device.rs
+++ b/nitrokey/tests/device.rs
@@ -1,8 +1,12 @@
+mod util;
+
use std::ffi::CStr;
use std::process::Command;
use std::{thread, time};
-use tests::util::{Target, ADMIN_PASSWORD, USER_PASSWORD};
-use {Authenticate, CommandError, Config, Device, Storage};
+
+use nitrokey::{Authenticate, CommandError, Config, Device, Storage};
+
+use crate::util::{Target, ADMIN_PASSWORD, USER_PASSWORD};
static ADMIN_NEW_PASSWORD: &str = "1234567890";
static USER_NEW_PASSWORD: &str = "abcdefghij";
@@ -15,45 +19,45 @@ fn count_nitrokey_block_devices() -> usize {
.expect("Could not list block devices");
String::from_utf8_lossy(&output.stdout)
.split("\n")
- .filter(|&s| s == "Nitrokey Storage")
+ .filter(|&s| s.replace("_", " ") == "Nitrokey Storage")
.count()
}
#[test]
-#[cfg_attr(not(feature = "test-no-device"), ignore)]
+#[cfg_attr(any(feature = "test-pro", feature = "test-storage"), ignore)]
fn connect_no_device() {
- assert!(::connect().is_err());
- assert!(::Pro::connect().is_err());
- assert!(::Storage::connect().is_err());
+ assert!(nitrokey::connect().is_err());
+ assert!(nitrokey::Pro::connect().is_err());
+ assert!(nitrokey::Storage::connect().is_err());
}
#[test]
#[cfg_attr(not(feature = "test-pro"), ignore)]
fn connect_pro() {
- assert!(::connect().is_ok());
- assert!(::Pro::connect().is_ok());
- assert!(::Storage::connect().is_err());
- match ::connect().unwrap() {
- ::DeviceWrapper::Pro(_) => assert!(true),
- ::DeviceWrapper::Storage(_) => assert!(false),
+ assert!(nitrokey::connect().is_ok());
+ assert!(nitrokey::Pro::connect().is_ok());
+ assert!(nitrokey::Storage::connect().is_err());
+ match nitrokey::connect().unwrap() {
+ nitrokey::DeviceWrapper::Pro(_) => assert!(true),
+ nitrokey::DeviceWrapper::Storage(_) => assert!(false),
};
}
#[test]
#[cfg_attr(not(feature = "test-storage"), ignore)]
fn connect_storage() {
- assert!(::connect().is_ok());
- assert!(::Pro::connect().is_err());
- assert!(::Storage::connect().is_ok());
- match ::connect().unwrap() {
- ::DeviceWrapper::Pro(_) => assert!(false),
- ::DeviceWrapper::Storage(_) => assert!(true),
+ assert!(nitrokey::connect().is_ok());
+ assert!(nitrokey::Pro::connect().is_err());
+ assert!(nitrokey::Storage::connect().is_ok());
+ match nitrokey::connect().unwrap() {
+ nitrokey::DeviceWrapper::Pro(_) => assert!(false),
+ nitrokey::DeviceWrapper::Storage(_) => assert!(true),
};
}
fn assert_empty_serial_number() {
unsafe {
- let ptr = ::nitrokey_sys::NK_device_serial_number();
+ let ptr = nitrokey_sys::NK_device_serial_number();
assert!(!ptr.is_null());
let cstr = CStr::from_ptr(ptr);
assert_eq!(cstr.to_string_lossy(), "");
@@ -77,6 +81,23 @@ fn disconnect() {
assert_empty_serial_number();
}
+fn require_model(model: nitrokey::Model) {
+ assert_eq!(model, nitrokey::connect().unwrap().get_model());
+ assert_eq!(model, Target::connect().unwrap().get_model());
+}
+
+#[test]
+#[cfg_attr(not(feature = "test-pro"), ignore)]
+fn get_model_pro() {
+ require_model(nitrokey::Model::Pro);
+}
+
+#[test]
+#[cfg_attr(not(feature = "test-storage"), ignore)]
+fn get_model_storage() {
+ require_model(nitrokey::Model::Storage);
+}
+
#[test]
#[cfg_attr(not(any(feature = "test-pro", feature = "test-storage")), ignore)]
fn get_serial_number() {
@@ -163,11 +184,9 @@ fn change_user_pin() {
let device = device.authenticate_user(USER_PASSWORD).unwrap().device();
let device = device.authenticate_user(USER_NEW_PASSWORD).unwrap_err().0;
- assert!(
- device
- .change_user_pin(USER_PASSWORD, USER_NEW_PASSWORD)
- .is_ok()
- );
+ assert!(device
+ .change_user_pin(USER_PASSWORD, USER_NEW_PASSWORD)
+ .is_ok());
let device = device.authenticate_user(USER_PASSWORD).unwrap_err().0;
let device = device
@@ -178,11 +197,9 @@ fn change_user_pin() {
let result = device.change_user_pin(USER_PASSWORD, USER_PASSWORD);
assert_eq!(Err(CommandError::WrongPassword), result);
- assert!(
- device
- .change_user_pin(USER_NEW_PASSWORD, USER_PASSWORD)
- .is_ok()
- );
+ assert!(device
+ .change_user_pin(USER_NEW_PASSWORD, USER_PASSWORD)
+ .is_ok());
let device = device.authenticate_user(USER_PASSWORD).unwrap().device();
assert!(device.authenticate_user(USER_NEW_PASSWORD).is_err());
@@ -195,11 +212,9 @@ fn change_admin_pin() {
let device = device.authenticate_admin(ADMIN_PASSWORD).unwrap().device();
let device = device.authenticate_admin(ADMIN_NEW_PASSWORD).unwrap_err().0;
- assert!(
- device
- .change_admin_pin(ADMIN_PASSWORD, ADMIN_NEW_PASSWORD)
- .is_ok()
- );
+ assert!(device
+ .change_admin_pin(ADMIN_PASSWORD, ADMIN_NEW_PASSWORD)
+ .is_ok());
let device = device.authenticate_admin(ADMIN_PASSWORD).unwrap_err().0;
let device = device
@@ -212,11 +227,9 @@ fn change_admin_pin() {
device.change_admin_pin(ADMIN_PASSWORD, ADMIN_PASSWORD)
);
- assert!(
- device
- .change_admin_pin(ADMIN_NEW_PASSWORD, ADMIN_PASSWORD)
- .is_ok()
- );
+ assert!(device
+ .change_admin_pin(ADMIN_NEW_PASSWORD, ADMIN_PASSWORD)
+ .is_ok());
let device = device.authenticate_admin(ADMIN_PASSWORD).unwrap().device();
device.authenticate_admin(ADMIN_NEW_PASSWORD).unwrap_err();
@@ -235,11 +248,9 @@ fn require_failed_user_login(device: Target, password: &str, error: CommandError
fn unlock_user_pin() {
let device = Target::connect().unwrap();
let device = device.authenticate_user(USER_PASSWORD).unwrap().device();
- assert!(
- device
- .unlock_user_pin(ADMIN_PASSWORD, USER_PASSWORD)
- .is_ok()
- );
+ assert!(device
+ .unlock_user_pin(ADMIN_PASSWORD, USER_PASSWORD)
+ .is_ok());
assert_eq!(
Err(CommandError::WrongPassword),
device.unlock_user_pin(USER_PASSWORD, USER_PASSWORD)
@@ -255,11 +266,9 @@ fn unlock_user_pin() {
Err(CommandError::WrongPassword),
device.unlock_user_pin(USER_PASSWORD, USER_PASSWORD)
);
- assert!(
- device
- .unlock_user_pin(ADMIN_PASSWORD, USER_PASSWORD)
- .is_ok()
- );
+ assert!(device
+ .unlock_user_pin(ADMIN_PASSWORD, USER_PASSWORD)
+ .is_ok());
device.authenticate_user(USER_PASSWORD).unwrap();
}
diff --git a/nitrokey/src/tests/otp.rs b/nitrokey/tests/otp.rs
index cf71d9d..8e7ae08 100644
--- a/nitrokey/src/tests/otp.rs
+++ b/nitrokey/tests/otp.rs
@@ -1,6 +1,12 @@
+mod util;
+
use std::ops::Deref;
-use tests::util::{Target, ADMIN_PASSWORD, USER_PASSWORD};
-use {Admin, Authenticate, CommandError, Config, ConfigureOtp, GenerateOtp, OtpMode, OtpSlotData};
+
+use nitrokey::{
+ Admin, Authenticate, CommandError, Config, ConfigureOtp, GenerateOtp, OtpMode, OtpSlotData,
+};
+
+use crate::util::{Target, ADMIN_PASSWORD, USER_PASSWORD};
// test suite according to RFC 4226, Appendix D
static HOTP_SECRET: &str = "3132333435363738393031323334353637383930";
diff --git a/nitrokey/src/tests/pws.rs b/nitrokey/tests/pws.rs
index f581515..875324b 100644
--- a/nitrokey/src/tests/pws.rs
+++ b/nitrokey/tests/pws.rs
@@ -1,8 +1,31 @@
-use device::Device;
+mod util;
+
+use std::ffi::CStr;
+
+use libc::{c_int, c_void, free};
+use nitrokey::{CommandError, Device, GetPasswordSafe, PasswordSafe, SLOT_COUNT};
use nitrokey_sys;
-use pws::{GetPasswordSafe, PasswordSafe, SLOT_COUNT};
-use tests::util::{Target, ADMIN_PASSWORD, USER_PASSWORD};
-use util::{result_from_string, CommandError};
+
+use crate::util::{Target, ADMIN_PASSWORD, USER_PASSWORD};
+
+fn get_slot_name_direct(slot: u8) -> Result<String, CommandError> {
+ let ptr = unsafe { nitrokey_sys::NK_get_password_safe_slot_name(slot) };
+ if ptr.is_null() {
+ return Err(CommandError::Unknown);
+ }
+ let s = unsafe { CStr::from_ptr(ptr).to_string_lossy().into_owned() };
+ unsafe { free(ptr as *mut c_void) };
+ match s.is_empty() {
+ true => {
+ let error = unsafe { nitrokey_sys::NK_get_last_command_status() } as c_int;
+ match error {
+ 0 => Err(CommandError::Unknown),
+ other => Err(CommandError::from(other)),
+ }
+ }
+ false => Ok(s),
+ }
+}
fn get_pws(device: &Target) -> PasswordSafe {
device.get_password_safe(USER_PASSWORD).unwrap()
@@ -12,11 +35,9 @@ fn get_pws(device: &Target) -> PasswordSafe {
#[cfg_attr(not(any(feature = "test-pro", feature = "test-storage")), ignore)]
fn enable() {
let device = Target::connect().unwrap();
- assert!(
- device
- .get_password_safe(&(USER_PASSWORD.to_owned() + "123"))
- .is_err()
- );
+ assert!(device
+ .get_password_safe(&(USER_PASSWORD.to_owned() + "123"))
+ .is_err());
assert!(device.get_password_safe(USER_PASSWORD).is_ok());
assert!(device.get_password_safe(ADMIN_PASSWORD).is_err());
assert!(device.get_password_safe(USER_PASSWORD).is_ok());
@@ -30,13 +51,13 @@ fn drop() {
let pws = get_pws(&device);
assert!(pws.write_slot(1, "name", "login", "password").is_ok());
assert_eq!("name", pws.get_slot_name(1).unwrap());
- let result = result_from_string(unsafe { nitrokey_sys::NK_get_password_safe_slot_name(1) });
+ let result = get_slot_name_direct(1);
assert_eq!(Ok(String::from("name")), result);
}
- let result = result_from_string(unsafe { nitrokey_sys::NK_get_password_safe_slot_name(1) });
+ let result = get_slot_name_direct(1);
assert_eq!(Ok(String::from("name")), result);
assert!(device.lock().is_ok());
- let result = result_from_string(unsafe { nitrokey_sys::NK_get_password_safe_slot_name(1) });
+ let result = get_slot_name_direct(1);
assert_eq!(Err(CommandError::NotAuthorized), result);
}
diff --git a/nitrokey/tests/util/mod.rs b/nitrokey/tests/util/mod.rs
new file mode 100644
index 0000000..c2c94e2
--- /dev/null
+++ b/nitrokey/tests/util/mod.rs
@@ -0,0 +1,8 @@
+pub static ADMIN_PASSWORD: &str = "12345678";
+pub static USER_PASSWORD: &str = "123456";
+
+#[cfg(not(feature = "test-storage"))]
+pub type Target = nitrokey::Pro;
+
+#[cfg(feature = "test-storage")]
+pub type Target = nitrokey::Storage;
diff --git a/rand/.travis.yml b/rand/.travis.yml
index f3d7688..2f0bb79 100644
--- a/rand/.travis.yml
+++ b/rand/.travis.yml
@@ -1,28 +1,212 @@
language: rust
sudo: false
+# We support too many combinations of Rust releases, crate features, operating
+# systems, and architectures to even remotely test all combinations.
+# Yet it turns out we can test most of these independent of each other, because
+# they serve different goals or test different pieces of code.
+#
+# RUST RELEASES
+# Goal: make sure we don't use language features unavailable on a certain
+# version, and build without warnings.
+# We have different builders use 4 Rust releases, a pinned stable release,
+# the latest stable, beta and nightly.
+#
+# ARCHITECTURES
+# Goal: test against issues caused by differences in endianness, pointer sizes,
+# etc.
+# We run tests on 4 different architectures.
+# - x64_84, default on Travis (Linux) and AppVeyor (Windows)
+# - i686, second AppVeyor (Windows) configuration
+# - MIPS, big-endian Linux emulated with QEMU (thanks to Trust)
+# - ARMv7, Android emulated with QEMU (thanks to Trust)
+#
+# OPERATING SYSTEMS
+# Goal: test on many operating systems, to verify the OsRng code, which is
+# mostly architecture-independent.
+# We run tests on Linux, OS X, Windows, Android (emulated), and Node.js (using
+# cargo-web).
+# One builder cross-compiles for many of the remaining OSes, which ensures we
+# keep building, but doesn't run tests.
+# OSes supported by Rand but which we can't cross-compile because there
+# is no pre-built standard library available: Dragonfly BSD, Haiku, OpenBSD.
+#
+# CRATE FEATURES, TESTS, AND SUB-CRATES
+# Goal: Run unit tests, doctests, examples, and test benchmarks for all crates,
+# in configurations that cover all interesting combinations of features.
+# (`--lib` only runs unit tests just like `--tests`, but the latter is not
+# available in Rust 1.22.0)
+# Tests run on rand:
+# - test no_std support, but only the unit tests:
+# `cargo test --lib --no-default-features`
+# - run unit tests and doctests with all features which are available on stable:
+# `cargo test --features=serde1,log`
+# - test examples:
+# `cargo test --examples`
+# Additional tests on nightly:
+# - run unit tests and doctests with all features which are available on nightly:
+# `cargo test --all-features`
+# - test no_std support, including the nightly alloc feature:
+# cargo test --lib --no-default-features --features=alloc
+# - run benchmarks as tests:
+# `cargo test --benches --features=nightly`
+# Tests on subcrates:
+# - select crates via --manifest-path (more reliable than --package)
+# - test appropriate feature matrix
+#
+# TODO: SIMD support on stable releases
+# NOTE: SIMD support is unreliable on nightly; we track the latest release
matrix:
include:
- - rust: 1.15.0
- - rust: stable
+ - rust: 1.22.0
+ env: DESCRIPTION="pinned stable Rust release"
+ script:
+ # Differs from standard script: rand_pcg features
+ - cargo test --lib --no-default-features
+ # TODO: add simd_support feature:
+ - cargo test --features=serde1,log
+ - cargo test --examples
+ - cargo test --manifest-path rand_core/Cargo.toml
+ - cargo test --manifest-path rand_core/Cargo.toml --no-default-features
+ - cargo test --manifest-path rand_isaac/Cargo.toml --features=serde1
+ # TODO: cannot test rand_pcg due to explicit dependency on i128
+ - cargo test --manifest-path rand_xorshift/Cargo.toml --features=serde1
+ - cargo test --manifest-path rand_chacha/Cargo.toml
+ - cargo test --manifest-path rand_hc/Cargo.toml
+
- rust: stable
+ env: DESCRIPTION="stable Rust release, macOS, iOS (cross-compile only)"
os: osx
+ install:
+ - rustup target add aarch64-apple-ios
+ script:
+ # Differs from standard script: includes aarch64-apple-ios cross-build
+ - cargo test --lib --no-default-features
+ # TODO: add simd_support feature:
+ - cargo test --features=serde1,log
+ - cargo test --examples
+ - cargo test --manifest-path rand_core/Cargo.toml
+ - cargo test --manifest-path rand_core/Cargo.toml --no-default-features
+ - cargo test --manifest-path rand_isaac/Cargo.toml --features=serde1
+ - cargo test --manifest-path rand_pcg/Cargo.toml --features=serde1
+ - cargo test --manifest-path rand_xorshift/Cargo.toml --features=serde1
+ - cargo test --manifest-path rand_chacha/Cargo.toml
+ - cargo test --manifest-path rand_hc/Cargo.toml
+ - cargo build --target=aarch64-apple-ios
+
- rust: beta
- - rust: nightly
+ env: DESCRIPTION="beta Rust release"
- rust: nightly
+ env: DESCRIPTION="nightly features, benchmarks, documentation"
+ install:
+ - cargo --list | egrep "^\s*deadlinks$" -q || cargo install cargo-deadlinks
+ - cargo deadlinks -V
before_script:
- pip install 'travis-cargo<0.2' --user && export PATH=$HOME/.local/bin:$PATH
script:
- - cargo doc --no-deps --all-features
- - cargo test --benches
- - cargo test --features nightly
+ # Differs from standard script: alloc feature, all features, doc build
+ - cargo test --lib --no-default-features --features=alloc
+ - cargo test --all-features
+ - cargo test --benches --features=nightly
+ - cargo test --examples
+ - cargo test --manifest-path rand_core/Cargo.toml
+ - cargo test --manifest-path rand_core/Cargo.toml --no-default-features --features=alloc
+ - cargo test --manifest-path rand_isaac/Cargo.toml --features=serde1
+ - cargo test --manifest-path rand_pcg/Cargo.toml --features=serde1
+ - cargo test --manifest-path rand_xorshift/Cargo.toml --features=serde1
+ - cargo test --manifest-path rand_chacha/Cargo.toml
+ - cargo test --manifest-path rand_hc/Cargo.toml
+ # remove cached documentation, otherwise files from previous PRs can get included
+ - rm -rf target/doc
+ - cargo doc --no-deps --all --all-features
+ - cargo deadlinks --dir target/doc
after_success:
- travis-cargo --only nightly doc-upload
+ - rust: nightly
+ env: DESCRIPTION="WASM via emscripten, stdweb and wasm-bindgen"
+ install:
+ - rustup target add wasm32-unknown-unknown
+ - rustup target add wasm32-unknown-emscripten
+ # cargo-web takes ±10 min. to install, and cargo and cargo-update offer
+ # no reliable update-or-install command. We ignore updating for now
+ # (just drop the Travis' caches when necessary)
+ - cargo --list | egrep "^\s*web$" -q || cargo install cargo-web
+ - cargo web -V
+ addons:
+ chrome: stable
+ script:
+ # testing wasm32-unknown-emscripten fails because of rust-lang/rust#49877
+ - cargo build --target wasm32-unknown-emscripten
+ #- cargo web test --target wasm32-unknown-emscripten
+ #- cargo web test --nodejs --target wasm32-unknown-emscripten
+ - cargo build --target wasm32-unknown-unknown # without any features
+ - cargo web test --nodejs --target wasm32-unknown-unknown --features=stdweb
+ - cargo build --target wasm32-unknown-unknown --features=wasm-bindgen
+
+ - rust: nightly
+ env: DESCRIPTION="cross-platform builder (doesn't run tests)"
+ install:
+ - rustup target add x86_64-sun-solaris
+ - rustup target add x86_64-unknown-cloudabi
+ - rustup target add x86_64-unknown-freebsd
+ #- rustup target add x86_64-unknown-fuchsia
+ - rustup target add x86_64-unknown-netbsd
+ - rustup target add x86_64-unknown-redox
+ script:
+ - cargo build --target=x86_64-sun-solaris --all-features
+ - cargo build --target=x86_64-unknown-cloudabi --all-features
+ - cargo build --target=x86_64-unknown-freebsd --all-features
+ #- cargo build --target=x86_64-unknown-fuchsia --all-features
+ - cargo build --target=x86_64-unknown-netbsd --all-features
+ - cargo build --target=x86_64-unknown-redox --all-features
+
+ # Trust cross-built/emulated targets. We must repeat all non-default values.
+ - rust: stable
+ sudo: required
+ dist: trusty
+ services: docker
+ env: DESCRIPTION="Linux (MIPS, big-endian)" TARGET=mips-unknown-linux-gnu
+ install:
+ - sh utils/ci/install.sh
+ - source ~/.cargo/env || true
+ script:
+ - bash utils/ci/script.sh
+ - rust: stable
+ sudo: required
+ dist: trusty
+ services: docker
+ env: DESCRIPTION="Android (ARMv7)" TARGET=armv7-linux-androideabi
+ install:
+ - sh utils/ci/install.sh
+ - source ~/.cargo/env || true
+ script:
+ - bash utils/ci/script.sh
+
+before_install:
+ - set -e
+ - rustup self update
+
script:
- - cargo test
- - cargo test --manifest-path rand-derive/Cargo.toml
+ - cargo test --lib --no-default-features
+ # TODO: add simd_support feature:
+ - cargo test --features=serde1,log
+ - cargo test --examples
+ - cargo test --manifest-path rand_core/Cargo.toml
+ - cargo test --manifest-path rand_core/Cargo.toml --no-default-features
+ - cargo test --manifest-path rand_isaac/Cargo.toml --features=serde1
+ - cargo test --manifest-path rand_pcg/Cargo.toml --features=serde1
+ - cargo test --manifest-path rand_xorshift/Cargo.toml --features=serde1
+ - cargo test --manifest-path rand_chacha/Cargo.toml
+ - cargo test --manifest-path rand_hc/Cargo.toml
+
+after_script: set +e
+
+cache: cargo
+before_cache:
+ # Travis can't cache files that are not readable by "others"
+ - chmod -R a+r $HOME/.cargo
env:
global:
diff --git a/rand/CHANGELOG.md b/rand/CHANGELOG.md
index 1811b45..489df48 100644
--- a/rand/CHANGELOG.md
+++ b/rand/CHANGELOG.md
@@ -2,22 +2,224 @@
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
-and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+A [separate changelog is kept for rand_core](rand_core/CHANGELOG.md).
+
+You may also find the [Upgrade Guide](https://rust-random.github.io/book/update.html) useful.
+
+
+## [0.6.1] - 2018-11-22
+- Support sampling `Duration` also for `no_std` (only since Rust 1.25) (#649)
+- Disable default features of `libc` (#647)
+
+## [0.6.0] - 2018-11-14
+
+### Project organisation
+- Rand has moved from [rust-lang-nursery](https://github.com/rust-lang-nursery/rand)
+ to [rust-random](https://github.com/rust-random/rand)! (#578)
+- Created [The Rust Random Book](https://rust-random.github.io/book/)
+ ([source](https://github.com/rust-random/book))
+- Update copyright and licence notices (#591, #611)
+- Migrate policy documentation from the wiki (#544)
+
+### Platforms
+- Add fork protection on Unix (#466)
+- Added support for wasm-bindgen. (#541, #559, #562, #600)
+- Enable `OsRng` for powerpc64, sparc and sparc64 (#609)
+- Use `syscall` from `libc` on Linux instead of redefining it (#629)
+
+### RNGs
+- Switch `SmallRng` to use PCG (#623)
+- Implement `Pcg32` and `Pcg64Mcg` generators (#632)
+- Move ISAAC RNGs to a dedicated crate (#551)
+- Move Xorshift RNG to its own crate (#557)
+- Move ChaCha and HC128 RNGs to dedicated crates (#607, #636)
+- Remove usage of `Rc` from `ThreadRng` (#615)
+
+### Sampling and distributions
+- Implement `Rng.gen_ratio()` and `Bernoulli::new_ratio()` (#491)
+- Make `Uniform` strictly respect `f32` / `f64` high/low bounds (#477)
+- Allow `gen_range` and `Uniform` to work on non-`Copy` types (#506)
+- `Uniform` supports inclusive ranges: `Uniform::from(a..=b)`. This is
+ automatically enabled for Rust >= 1.27. (#566)
+- Implement `TrustedLen` and `FusedIterator` for `DistIter` (#620)
+
+#### New distributions
+- Add the `Dirichlet` distribution (#485)
+- Added sampling from the unit sphere and circle. (#567)
+- Implement the triangular distribution (#575)
+- Implement the Weibull distribution (#576)
+- Implement the Beta distribution (#574)
+
+#### Optimisations
+
+- Optimise `Bernoulli::new` (#500)
+- Optimise `char` sampling (#519)
+- Optimise sampling of `std::time::Duration` (#583)
+
+### Sequences
+- Redesign the `seq` module (#483, #515)
+- Add `WeightedIndex` and `choose_weighted` (#518, #547)
+- Optimised and changed return type of the `sample_indices` function. (#479)
+- Use `Iterator::size_hint()` to speed up `IteratorRandom::choose` (#593)
+
+### SIMD
+- Support for generating SIMD types (#523, #542, #561, #630)
+
+### Other
+- Revise CI scripts (#632, #635)
+- Remove functionality already deprecated in 0.5 (#499)
+- Support for `i128` and `u128` is automatically enabled for Rust >= 1.26. This
+ renders the `i128_support` feature obsolete. It still exists for backwards
+ compatibility but does not have any effect. This breaks programs using Rand
+ with `i128_support` on nightlies older than Rust 1.26. (#571)
+
+
+## [0.5.5] - 2018-08-07
+### Documentation
+- Fix links in documentation (#582)
+
+
+## [0.5.4] - 2018-07-11
+### Platform support
+- Make `OsRng` work via WASM/stdweb for WebWorkers
+
+
+## [0.5.3] - 2018-06-26
+### Platform support
+- OpenBSD, Bitrig: fix compilation (broken in 0.5.1) (#530)
+
+
+## [0.5.2] - 2018-06-18
+### Platform support
+- Hide `OsRng` and `JitterRng` on unsupported platforms (#512; fixes #503).
+
+
+## [0.5.1] - 2018-06-08
+
+### New distributions
+- Added Cauchy distribution. (#474, #486)
+- Added Pareto distribution. (#495)
+
+### Platform support and `OsRng`
+- Remove blanket Unix implementation. (#484)
+- Remove Wasm unimplemented stub. (#484)
+- Dragonfly BSD: read from `/dev/random`. (#484)
+- Bitrig: use `getentropy` like OpenBSD. (#484)
+- Solaris: (untested) use `getrandom` if available, otherwise `/dev/random`. (#484)
+- Emscripten, `stdweb`: split the read up in chunks. (#484)
+- Emscripten, Haiku: don't do an extra blocking read from `/dev/random`. (#484)
+- Linux, NetBSD, Solaris: read in blocking mode on first use in `fill_bytes`. (#484)
+- Fuchsia, CloudABI: fix compilation (broken in Rand 0.5). (#484)
+
+
+## [0.5.0] - 2018-05-21
+
+### Crate features and organisation
+- Minimum Rust version update: 1.22.0. (#239)
+- Create a separate `rand_core` crate. (#288)
+- Deprecate `rand_derive`. (#256)
+- Add `prelude` (and module reorganisation). (#435)
+- Add `log` feature. Logging is now available in `JitterRng`, `OsRng`, `EntropyRng` and `ReseedingRng`. (#246)
+- Add `serde1` feature for some PRNGs. (#189)
+- `stdweb` feature for `OsRng` support on WASM via stdweb. (#272, #336)
+
+### `Rng` trait
+- Split `Rng` in `RngCore` and `Rng` extension trait.
+ `next_u32`, `next_u64` and `fill_bytes` are now part of `RngCore`. (#265)
+- Add `Rng::sample`. (#256)
+- Deprecate `Rng::gen_weighted_bool`. (#308)
+- Add `Rng::gen_bool`. (#308)
+- Remove `Rng::next_f32` and `Rng::next_f64`. (#273)
+- Add optimized `Rng::fill` and `Rng::try_fill` methods. (#247)
+- Deprecate `Rng::gen_iter`. (#286)
+- Deprecate `Rng::gen_ascii_chars`. (#279)
+
+### `rand_core` crate
+- `rand` now depends on new `rand_core` crate (#288)
+- `RngCore` and `SeedableRng` are now part of `rand_core`. (#288)
+- Add modules to help implementing RNGs `impl` and `le`. (#209, #228)
+- Add `Error` and `ErrorKind`. (#225)
+- Add `CryptoRng` marker trait. (#273)
+- Add `BlockRngCore` trait. (#281)
+- Add `BlockRng` and `BlockRng64` wrappers to help implementations. (#281, #325)
+- Revise the `SeedableRng` trait. (#233)
+- Remove default implementations for `RngCore::next_u64` and `RngCore::fill_bytes`. (#288)
+- Add `RngCore::try_fill_bytes`. (#225)
+
+### Other traits and types
+- Add `FromEntropy` trait. (#233, #375)
+- Add `SmallRng` wrapper. (#296)
+- Rewrite `ReseedingRng` to only work with `BlockRngCore` (substantial performance improvement). (#281)
+- Deprecate `weak_rng`. Use `SmallRng` instead. (#296)
+- Deprecate `AsciiGenerator`. (#279)
+
+### Random number generators
+- Switch `StdRng` and `thread_rng` to HC-128. (#277)
+- `StdRng` must now be created with `from_entropy` instead of `new`
+- Change `thread_rng` reseeding threshold to 32 MiB. (#277)
+- PRNGs no longer implement `Copy`. (#209)
+- `Debug` implementations no longer show internals. (#209)
+- Implement `Clone` for `ReseedingRng`, `JitterRng`, OsRng`. (#383, #384)
+- Implement serialization for `XorShiftRng`, `IsaacRng` and `Isaac64Rng` under the `serde1` feature. (#189)
+- Implement `BlockRngCore` for `ChaChaCore` and `Hc128Core`. (#281)
+- All PRNGs are now portable across big- and little-endian architectures. (#209)
+- `Isaac64Rng::next_u32` no longer throws away half the results. (#209)
+- Add `IsaacRng::new_from_u64` and `Isaac64Rng::new_from_u64`. (#209)
+- Add the HC-128 CSPRNG `Hc128Rng`. (#210)
+- Change ChaCha20 to have 64-bit counter and 64-bit stream. (#349)
+- Changes to `JitterRng` to get its size down from 2112 to 24 bytes. (#251)
+- Various performance improvements to all PRNGs.
+
+### Platform support and `OsRng`
+- Add support for CloudABI. (#224)
+- Remove support for NaCl. (#225)
+- WASM support for `OsRng` via stdweb, behind the `stdweb` feature. (#272, #336)
+- Use `getrandom` on more platforms for Linux, and on Android. (#338)
+- Use the `SecRandomCopyBytes` interface on macOS. (#322)
+- On systems that do not have a syscall interface, only keep a single file descriptor open for `OsRng`. (#239)
+- On Unix, first try a single read from `/dev/random`, then `/dev/urandom`. (#338)
+- Better error handling and reporting in `OsRng` (using new error type). (#225)
+- `OsRng` now uses non-blocking when available. (#225)
+- Add `EntropyRng`, which provides `OsRng`, but has `JitterRng` as a fallback. (#235)
+
+### Distributions
+- New `Distribution` trait. (#256)
+- Add `Distribution::sample_iter` and `Rng::::sample_iter`. (#361)
+- Deprecate `Rand`, `Sample` and `IndependentSample` traits. (#256)
+- Add a `Standard` distribution (replaces most `Rand` implementations). (#256)
+- Add `Binomial` and `Poisson` distributions. (#96)
+- Add `Bernoulli` dsitribution. (#411)
+- Add `Alphanumeric` distribution. (#279)
+- Remove `Closed01` distribution, add `OpenClosed01`. (#274, #420)
+- Rework `Range` type, making it possible to implement it for user types. (#274)
+- Rename `Range` to `Uniform`. (#395)
+- Add `Uniform::new_inclusive` for inclusive ranges. (#274)
+- Use widening multiply method for much faster integer range reduction. (#274)
+- `Standard` distribution for `char` uses `Uniform` internally. (#274)
+- `Standard` distribution for `bool` uses sign test. (#274)
+- Implement `Standard` distribution for `Wrapping<T>`. (#436)
+- Implement `Uniform` distribution for `Duration`. (#427)
+
## [0.4.3] - 2018-08-16
### Fixed
- Use correct syscall number for PowerPC (#589)
-## [0.4.2] - 2018-01-05
+
+## [0.4.2] - 2018-01-06
### Changed
-- Use winapi on Windows
+- Use `winapi` on Windows
- Update for Fuchsia OS
- Remove dev-dependency on `log`
+
## [0.4.1] - 2017-12-17
### Added
- `no_std` support
+
## [0.4.0-pre.0] - 2017-12-11
### Added
- `JitterRng` added as a high-quality alternative entropy source using the
@@ -33,6 +235,20 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
### Deprecated
- `sample` function deprecated (replaced by `sample_iter`)
+
+## [0.3.20] - 2018-01-06
+### Changed
+- Remove dev-dependency on `log`
+- Update `fuchsia-zircon` dependency to 0.3.2
+
+
+## [0.3.19] - 2017-12-27
+### Changed
+- Require `log <= 0.3.8` for dev builds
+- Update `fuchsia-zircon` dependency to 0.3
+- Fix broken links in docs (to unblock compiler docs testing CI)
+
+
## [0.3.18] - 2017-11-06
### Changed
- `thread_rng` is seeded from the system time if `OsRng` fails
@@ -181,7 +397,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- Compatible with Rust master
### Removed
-- Removed Copy inplementaions from RNGs
+- Removed Copy implementations from RNGs
## [0.1.2] - 2015-02-03
@@ -227,7 +443,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- `Rng::gen_ascii_chars()` which will return an infinite stream of random ascii characters
### Changed
-- Now only depends on libcore! 2adf5363f88ffe06f6d2ea5c338d1b186d47f4a1
+- Now only depends on libcore!
- Remove `Rng.choose()`, rename `Rng.choose_option()` to `.choose()`
- Rename OSRng to OsRng
- The WeightedChoice structure is no longer built with a `Vec<Weighted<T>>`,
@@ -266,4 +482,3 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
## [0.10-pre] - 2014-03-02
### Added
- Seperate `rand` out of the standard library
-
diff --git a/rand/COPYRIGHT b/rand/COPYRIGHT
new file mode 100644
index 0000000..468d907
--- /dev/null
+++ b/rand/COPYRIGHT
@@ -0,0 +1,12 @@
+Copyrights in the Rand project are retained by their contributors. No
+copyright assignment is required to contribute to the Rand project.
+
+For full authorship information, see the version control history.
+
+Except as otherwise noted (below and/or in individual files), Rand is
+licensed under the Apache License, Version 2.0 <LICENSE-APACHE> or
+<http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+<LICENSE-MIT> or <http://opensource.org/licenses/MIT>, at your option.
+
+The Rand project includes code from the Rust project
+published under these same licenses.
diff --git a/rand/Cargo.toml b/rand/Cargo.toml
index c21f53e..5f95c37 100644
--- a/rand/Cargo.toml
+++ b/rand/Cargo.toml
@@ -1,35 +1,76 @@
[package]
name = "rand"
-version = "0.4.3"
-authors = ["The Rust Project Developers"]
+version = "0.6.1"
+authors = ["The Rand Project Developers", "The Rust Project Developers"]
license = "MIT/Apache-2.0"
readme = "README.md"
-repository = "https://github.com/rust-lang-nursery/rand"
-documentation = "https://docs.rs/rand"
-homepage = "https://github.com/rust-lang-nursery/rand"
+repository = "https://github.com/rust-random/rand"
+documentation = "https://rust-random.github.io/rand"
+homepage = "https://crates.io/crates/rand"
description = """
Random number generators and other randomness functionality.
"""
keywords = ["random", "rng"]
-categories = ["algorithms"]
+categories = ["algorithms", "no-std"]
+build = "build.rs"
+exclude = ["/utils/*", "/.travis.yml", "/appveyor.yml", ".gitignore"]
+
+[badges]
+travis-ci = { repository = "rust-random/rand" }
+appveyor = { repository = "rust-random/rand" }
[features]
-default = ["std"]
-nightly = ["i128_support"] # enables all features requiring nightly rust
+default = ["std" ] # without "std" rand uses libcore
+nightly = ["simd_support"] # enables all features requiring nightly rust
+std = ["rand_core/std", "alloc", "libc", "winapi", "cloudabi", "fuchsia-zircon"]
+alloc = ["rand_core/alloc"] # enables Vec and Box support (without std)
+i128_support = [] # enables i128 and u128 support
+simd_support = ["packed_simd"] # enables SIMD support
+serde1 = ["rand_core/serde1", "rand_isaac/serde1", "rand_xorshift/serde1"] # enables serialization for PRNGs
-std = ["libc"] # default feature; without this rand uses libcore
-alloc = [] # enables Vec and Box support without std
+[workspace]
+members = ["rand_core", "rand_isaac", "rand_chacha", "rand_hc", "rand_pcg", "rand_xorshift"]
-i128_support = [] # enables i128 and u128 support
+[dependencies]
+rand_core = { path = "rand_core", version = "0.3", default-features = false }
+rand_pcg = { path = "rand_pcg", version = "0.1" }
+# only for deprecations and benches:
+rand_isaac = { path = "rand_isaac", version = "0.1" }
+rand_chacha = { path = "rand_chacha", version = "0.1" }
+rand_hc = { path = "rand_hc", version = "0.1" }
+rand_xorshift = { path = "rand_xorshift", version = "0.1" }
+log = { version = "0.4", optional = true }
+
+[dependencies.packed_simd]
+# NOTE: so far no version works reliably due to dependence on unstable features
+version = "0.3"
+# git = "https://github.com/rust-lang-nursery/packed_simd"
+optional = true
+features = ["into_bits"]
[target.'cfg(unix)'.dependencies]
-libc = { version = "0.2", optional = true }
+libc = { version = "0.2", optional = true, default-features = false }
[target.'cfg(windows)'.dependencies]
-winapi = { version = "0.3", features = ["minwindef", "ntsecapi", "profileapi", "winnt"] }
+winapi = { version = "0.3", features = ["minwindef", "ntsecapi", "profileapi", "winnt"], optional = true }
-[workspace]
-members = ["rand-derive"]
+[target.'cfg(target_os = "cloudabi")'.dependencies]
+cloudabi = { version = "0.0.3", optional = true }
[target.'cfg(target_os = "fuchsia")'.dependencies]
-fuchsia-zircon = "0.3.2"
+fuchsia-zircon = { version = "0.3.2", optional = true }
+
+[target.wasm32-unknown-unknown.dependencies]
+# use with `--target wasm32-unknown-unknown --features=stdweb`
+stdweb = { version = "0.4", optional = true }
+wasm-bindgen = { version = "0.2.12", optional = true }
+
+[dev-dependencies]
+# This has a histogram implementation used for testing uniformity.
+average = "0.9.2"
+
+[build-dependencies]
+rustc_version = "0.2"
+
+[package.metadata.docs.rs]
+all-features = true
diff --git a/rand/LICENSE-APACHE b/rand/LICENSE-APACHE
index 16fe87b..17d7468 100644
--- a/rand/LICENSE-APACHE
+++ b/rand/LICENSE-APACHE
@@ -1,6 +1,6 @@
Apache License
Version 2.0, January 2004
- http://www.apache.org/licenses/
+ https://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
@@ -192,7 +192,7 @@ Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
+ https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/rand/LICENSE-MIT b/rand/LICENSE-MIT
index 39d4bdb..d93b5ba 100644
--- a/rand/LICENSE-MIT
+++ b/rand/LICENSE-MIT
@@ -1,3 +1,4 @@
+Copyright 2018 Developers of the Rand project
Copyright (c) 2014 The Rust Project Developers
Permission is hereby granted, free of charge, to any
diff --git a/rand/README.md b/rand/README.md
index f72bd51..95970af 100644
--- a/rand/README.md
+++ b/rand/README.md
@@ -1,12 +1,28 @@
-rand
-====
+# Rand
-A Rust library for random number generators and other randomness functionality.
+[![Build Status](https://travis-ci.org/rust-random/rand.svg?branch=master)](https://travis-ci.org/rust-random/rand)
+[![Build Status](https://ci.appveyor.com/api/projects/status/github/rust-random/rand?svg=true)](https://ci.appveyor.com/project/rust-random/rand)
+[![Crate](https://img.shields.io/crates/v/rand.svg)](https://crates.io/crates/rand)
+[![Book](https://img.shields.io/badge/book-master-yellow.svg)](https://rust-random.github.io/book/)
+[![API](https://img.shields.io/badge/api-master-yellow.svg)](https://rust-random.github.io/rand)
+[![API](https://docs.rs/rand/badge.svg)](https://docs.rs/rand)
+[![Minimum rustc version](https://img.shields.io/badge/rustc-1.22+-lightgray.svg)](https://github.com/rust-random/rand#rust-version-requirements)
-[![Build Status](https://travis-ci.org/rust-lang-nursery/rand.svg?branch=master)](https://travis-ci.org/rust-lang-nursery/rand)
-[![Build status](https://ci.appveyor.com/api/projects/status/rm5c9o33k3jhchbw?svg=true)](https://ci.appveyor.com/project/alexcrichton/rand)
+A Rust library for random number generation.
+
+Rand provides utilities to generate random numbers, to convert them to useful
+types and distributions, and some randomness-related algorithms.
+
+The core random number generation traits of Rand live in the [rand_core](
+https://crates.io/crates/rand_core) crate but are also exposed here; RNG
+implementations should prefer to use `rand_core` while most other users should
+depend on `rand`.
+
+Documentation:
+- [The Rust Rand Book](https://rust-random.github.io/book)
+- [API reference (master)](https://rust-random.github.io/rand)
+- [API reference (docs.rs)](https://docs.rs/rand)
-[Documentation](https://docs.rs/rand)
## Usage
@@ -14,126 +30,86 @@ Add this to your `Cargo.toml`:
```toml
[dependencies]
-rand = "0.4"
+rand = "0.6"
```
-and this to your crate root:
+To get started using Rand, see [The Book](https://rust-random.github.io/book).
-```rust
-extern crate rand;
-```
-### Versions
+## Versions
-Version `0.4`was released in December 2017. It contains almost no breaking
-changes since the `0.3` series, but nevertheless contains some significant
-new code, including a new "external" entropy source (`JitterRng`) and `no_std`
-support.
+The Rand lib is not yet stable, however we are careful to limit breaking changes
+and warn via deprecation wherever possible. Patch versions never introduce
+breaking changes. The following minor versions are supported:
-Version `0.5` is in development and contains significant performance
-improvements for the ISAAC random number generators.
+- Version 0.6 was released in November 2018, redesigning the `seq` module,
+ moving most PRNGs to external crates, and many small changes.
+- Version 0.5 was released in May 2018, as a major reorganisation
+ (introducing `RngCore` and `rand_core`, and deprecating `Rand` and the
+ previous distribution traits).
+- Version 0.4 was released in December 2017, but contained almost no breaking
+ changes from the 0.3 series.
-## Examples
+A detailed [changelog](CHANGELOG.md) is available.
-There is built-in support for a random number generator (RNG) associated with each thread stored in thread-local storage. This RNG can be accessed via thread_rng, or used implicitly via random. This RNG is normally randomly seeded from an operating-system source of randomness, e.g. /dev/urandom on Unix systems, and will automatically reseed itself from this source after generating 32 KiB of random data.
+When upgrading to the next minor series (especially 0.4 → 0.5), we recommend
+reading the [Upgrade Guide](https://rust-random.github.io/book/update.html).
-```rust
-let tuple = rand::random::<(f64, char)>();
-println!("{:?}", tuple)
-```
+### Rust version requirements
-```rust
-use rand::Rng;
+Since version 0.5, Rand requires **Rustc version 1.22 or greater**.
+Rand 0.4 and 0.3 (since approx. June 2017) require Rustc version 1.15 or
+greater. Subsets of the Rand code may work with older Rust versions, but this
+is not supported.
-let mut rng = rand::thread_rng();
-if rng.gen() { // random bool
- println!("i32: {}, u32: {}", rng.gen::<i32>(), rng.gen::<u32>())
-}
-```
+Travis CI always has a build with a pinned version of Rustc matching the oldest
+supported Rust release. The current policy is that this can be updated in any
+Rand release if required, but the change must be noted in the changelog.
-It is also possible to use other RNG types, which have a similar interface. The following uses the "ChaCha" algorithm instead of the default.
+To avoid bumping the required version unnecessarily, we use a `build.rs` script
+to auto-detect the compiler version and enable certain features or change code
+paths automatically. Since this makes it easy to unintentionally make use of
+features requiring a more recent Rust version, we recommend testing with a
+pinned version of Rustc if you require compatibility with a specific version.
-```rust
-use rand::{Rng, ChaChaRng};
+## Crate Features
-let mut rng = rand::ChaChaRng::new_unseeded();
-println!("i32: {}, u32: {}", rng.gen::<i32>(), rng.gen::<u32>())
-```
-
-## Features
-
-By default, `rand` is built with all stable features available. The following
+Rand is built with only the `std` feature enabled by default. The following
optional features are available:
-- `i128_support` enables support for generating `u128` and `i128` values
-- `nightly` enables all unstable features (`i128_support`)
-- `std` enabled by default; by setting "default-features = false" `no_std`
- mode is activated; this removes features depending on `std` functionality:
-
- - `OsRng` is entirely unavailable
- - `JitterRng` code is still present, but a nanosecond timer must be
- provided via `JitterRng::new_with_timer`
- - Since no external entropy is available, it is not possible to create
- generators with fresh seeds (user must provide entropy)
- - `thread_rng`, `weak_rng` and `random` are all disabled
- - exponential, normal and gamma type distributions are unavailable
- since `exp` and `log` functions are not provided in `core`
- - any code requiring `Vec` or `Box`
-- `alloc` can be used instead of `std` to provide `Vec` and `Box`
-
-## Testing
-
-Unfortunately, `cargo test` does not test everything. The following tests are
-recommended:
-
-```
-# Basic tests for rand and sub-crates
-cargo test --all
-
-# Test no_std support (build only since nearly all tests require std)
-cargo build --all --no-default-features
-
-# Test 128-bit support (requires nightly)
-cargo test --all --features nightly
-
-# Benchmarks (requires nightly)
-cargo bench
-# or just to test the benchmark code:
-cargo test --benches
-```
-
-# `derive(Rand)`
-
-You can derive the `Rand` trait for your custom type via the `#[derive(Rand)]`
-directive. To use this first add this to your Cargo.toml:
-
-```toml
-rand = "0.4"
-rand_derive = "0.3"
-```
-
-Next in your crate:
-
-```rust
-extern crate rand;
-#[macro_use]
-extern crate rand_derive;
-
-#[derive(Rand, Debug)]
-struct MyStruct {
- a: i32,
- b: u32,
-}
-
-fn main() {
- println!("{:?}", rand::random::<MyStruct>());
-}
-```
+- `alloc` can be used instead of `std` to provide `Vec` and `Box`.
+- `log` enables some logging via the `log` crate.
+- `nightly` enables all unstable features (`simd_support`).
+- `serde1` enables serialization for some types, via Serde version 1.
+- `simd_support` enables uniform sampling of SIMD types (integers and floats).
+- `stdweb` enables support for `OsRng` on `wasm32-unknown-unknown` via `stdweb`
+ combined with `cargo-web`.
+- `wasm-bindgen` enables support for `OsRng` on `wasm32-unknown-unknown` via
+ [`wasm-bindgen`]
+
+[`wasm-bindgen`]: https://github.com/rustwasm/wasm-bindgen
+
+`no_std` mode is activated by setting `default-features = false`; this removes
+functionality depending on `std`:
+
+- `thread_rng()`, and `random()` are not available, as they require thread-local
+ storage and an entropy source.
+- `OsRng` and `EntropyRng` are unavailable.
+- `JitterRng` code is still present, but a nanosecond timer must be provided via
+ `JitterRng::new_with_timer`
+- Since no external entropy is available, it is not possible to create
+ generators with fresh seeds using the `FromEntropy` trait (user must provide
+ a seed).
+- Several non-linear distributions distributions are unavailable since `exp`
+ and `log` functions are not provided in `core`.
+- Large parts of the `seq`-uence module are unavailable, unless the `alloc`
+ feature is used (several APIs and many implementations require `Vec`).
# License
-`rand` is primarily distributed under the terms of both the MIT
-license and the Apache License (Version 2.0).
+Rand is distributed under the terms of both the MIT license and the
+Apache License (Version 2.0).
-See LICENSE-APACHE, and LICENSE-MIT for details.
+See [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT), and
+[COPYRIGHT](COPYRIGHT) for details.
diff --git a/rand/appveyor.yml b/rand/appveyor.yml
index 02e217f..a0e518e 100644
--- a/rand/appveyor.yml
+++ b/rand/appveyor.yml
@@ -32,7 +32,21 @@ install:
build: false
test_script:
- - cargo test --benches
- - cargo test
- - cargo test --features nightly
- - cargo test --manifest-path rand-derive/Cargo.toml
+ - cargo test --lib --no-default-features --features alloc
+ # TODO: use --all-features once simd_support is sufficiently stable:
+ - cargo test --features=serde1,log
+ - cargo test --benches --features=nightly
+ - cargo test --examples
+ - cargo test --package rand_core
+ - cargo test --package rand_core --no-default-features --features=alloc
+ - cargo test --package rand_isaac --features=serde1
+ - cargo test --package rand_xorshift --features=serde1
+ - cargo test --package rand_chacha
+ - cargo test --package rand_hc
+ - cargo test --manifest-path rand_core/Cargo.toml
+ - cargo test --manifest-path rand_core/Cargo.toml --no-default-features --features=alloc
+ - cargo test --manifest-path rand_isaac/Cargo.toml --features=serde1
+ - cargo test --manifest-path rand_pcg/Cargo.toml --features=serde1
+ - cargo test --manifest-path rand_xorshift/Cargo.toml --features=serde1
+ - cargo test --manifest-path rand_chacha/Cargo.toml
+ - cargo test --manifest-path rand_hc/Cargo.toml
diff --git a/rand/benches/bench.rs b/rand/benches/bench.rs
deleted file mode 100644
index d396f25..0000000
--- a/rand/benches/bench.rs
+++ /dev/null
@@ -1,34 +0,0 @@
-#![feature(test)]
-
-extern crate test;
-extern crate rand;
-
-const RAND_BENCH_N: u64 = 1000;
-
-mod distributions;
-
-use std::mem::size_of;
-use test::{black_box, Bencher};
-use rand::{StdRng, Rng};
-
-#[bench]
-fn rand_f32(b: &mut Bencher) {
- let mut rng = StdRng::new().unwrap();
- b.iter(|| {
- for _ in 0..RAND_BENCH_N {
- black_box(rng.next_f32());
- }
- });
- b.bytes = size_of::<f32>() as u64 * RAND_BENCH_N;
-}
-
-#[bench]
-fn rand_f64(b: &mut Bencher) {
- let mut rng = StdRng::new().unwrap();
- b.iter(|| {
- for _ in 0..RAND_BENCH_N {
- black_box(rng.next_f64());
- }
- });
- b.bytes = size_of::<f64>() as u64 * RAND_BENCH_N;
-}
diff --git a/rand/benches/distributions.rs b/rand/benches/distributions.rs
new file mode 100644
index 0000000..7ac1a6a
--- /dev/null
+++ b/rand/benches/distributions.rs
@@ -0,0 +1,237 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(test)]
+
+extern crate test;
+extern crate rand;
+
+const RAND_BENCH_N: u64 = 1000;
+
+use std::mem::size_of;
+use test::Bencher;
+use std::time::Duration;
+
+use rand::{Rng, FromEntropy};
+use rand::rngs::SmallRng;
+use rand::distributions::*;
+
+macro_rules! distr_int {
+ ($fnn:ident, $ty:ty, $distr:expr) => {
+ #[bench]
+ fn $fnn(b: &mut Bencher) {
+ let mut rng = SmallRng::from_entropy();
+ let distr = $distr;
+
+ b.iter(|| {
+ let mut accum = 0 as $ty;
+ for _ in 0..::RAND_BENCH_N {
+ let x: $ty = distr.sample(&mut rng);
+ accum = accum.wrapping_add(x);
+ }
+ accum
+ });
+ b.bytes = size_of::<$ty>() as u64 * ::RAND_BENCH_N;
+ }
+ }
+}
+
+macro_rules! distr_float {
+ ($fnn:ident, $ty:ty, $distr:expr) => {
+ #[bench]
+ fn $fnn(b: &mut Bencher) {
+ let mut rng = SmallRng::from_entropy();
+ let distr = $distr;
+
+ b.iter(|| {
+ let mut accum = 0.0;
+ for _ in 0..::RAND_BENCH_N {
+ let x: $ty = distr.sample(&mut rng);
+ accum += x;
+ }
+ accum
+ });
+ b.bytes = size_of::<$ty>() as u64 * ::RAND_BENCH_N;
+ }
+ }
+}
+
+macro_rules! distr_duration {
+ ($fnn:ident, $distr:expr) => {
+ #[bench]
+ fn $fnn(b: &mut Bencher) {
+ let mut rng = SmallRng::from_entropy();
+ let distr = $distr;
+
+ b.iter(|| {
+ let mut accum = Duration::new(0, 0);
+ for _ in 0..::RAND_BENCH_N {
+ let x: Duration = distr.sample(&mut rng);
+ accum = accum.checked_add(x).unwrap_or(Duration::new(u64::max_value(), 999_999_999));
+ }
+ accum
+ });
+ b.bytes = size_of::<Duration>() as u64 * ::RAND_BENCH_N;
+ }
+ }
+}
+
+macro_rules! distr {
+ ($fnn:ident, $ty:ty, $distr:expr) => {
+ #[bench]
+ fn $fnn(b: &mut Bencher) {
+ let mut rng = SmallRng::from_entropy();
+ let distr = $distr;
+
+ b.iter(|| {
+ let mut accum = 0u32;
+ for _ in 0..::RAND_BENCH_N {
+ let x: $ty = distr.sample(&mut rng);
+ accum = accum.wrapping_add(x as u32);
+ }
+ accum
+ });
+ b.bytes = size_of::<$ty>() as u64 * ::RAND_BENCH_N;
+ }
+ }
+}
+
+// uniform
+distr_int!(distr_uniform_i8, i8, Uniform::new(20i8, 100));
+distr_int!(distr_uniform_i16, i16, Uniform::new(-500i16, 2000));
+distr_int!(distr_uniform_i32, i32, Uniform::new(-200_000_000i32, 800_000_000));
+distr_int!(distr_uniform_i64, i64, Uniform::new(3i64, 123_456_789_123));
+distr_int!(distr_uniform_i128, i128, Uniform::new(-123_456_789_123i128, 123_456_789_123_456_789));
+
+distr_float!(distr_uniform_f32, f32, Uniform::new(2.26f32, 2.319));
+distr_float!(distr_uniform_f64, f64, Uniform::new(2.26f64, 2.319));
+
+const LARGE_SEC: u64 = u64::max_value() / 1000;
+
+distr_duration!(distr_uniform_duration_largest,
+ Uniform::new_inclusive(Duration::new(0, 0), Duration::new(u64::max_value(), 999_999_999))
+);
+distr_duration!(distr_uniform_duration_large,
+ Uniform::new(Duration::new(0, 0), Duration::new(LARGE_SEC, 1_000_000_000 / 2))
+);
+distr_duration!(distr_uniform_duration_one,
+ Uniform::new(Duration::new(0, 0), Duration::new(1, 0))
+);
+distr_duration!(distr_uniform_duration_variety,
+ Uniform::new(Duration::new(10000, 423423), Duration::new(200000, 6969954))
+);
+distr_duration!(distr_uniform_duration_edge,
+ Uniform::new_inclusive(Duration::new(LARGE_SEC, 999_999_999), Duration::new(LARGE_SEC + 1, 1))
+);
+
+
+// standard
+distr_int!(distr_standard_i8, i8, Standard);
+distr_int!(distr_standard_i16, i16, Standard);
+distr_int!(distr_standard_i32, i32, Standard);
+distr_int!(distr_standard_i64, i64, Standard);
+distr_int!(distr_standard_i128, i128, Standard);
+
+distr!(distr_standard_bool, bool, Standard);
+distr!(distr_standard_alphanumeric, char, Alphanumeric);
+distr!(distr_standard_codepoint, char, Standard);
+
+distr_float!(distr_standard_f32, f32, Standard);
+distr_float!(distr_standard_f64, f64, Standard);
+distr_float!(distr_open01_f32, f32, Open01);
+distr_float!(distr_open01_f64, f64, Open01);
+distr_float!(distr_openclosed01_f32, f32, OpenClosed01);
+distr_float!(distr_openclosed01_f64, f64, OpenClosed01);
+
+// distributions
+distr_float!(distr_exp, f64, Exp::new(1.23 * 4.56));
+distr_float!(distr_normal, f64, Normal::new(-1.23, 4.56));
+distr_float!(distr_log_normal, f64, LogNormal::new(-1.23, 4.56));
+distr_float!(distr_gamma_large_shape, f64, Gamma::new(10., 1.0));
+distr_float!(distr_gamma_small_shape, f64, Gamma::new(0.1, 1.0));
+distr_float!(distr_cauchy, f64, Cauchy::new(4.2, 6.9));
+distr_int!(distr_binomial, u64, Binomial::new(20, 0.7));
+distr_int!(distr_poisson, u64, Poisson::new(4.0));
+distr!(distr_bernoulli, bool, Bernoulli::new(0.18));
+
+// Weighted
+distr_int!(distr_weighted_i8, usize, WeightedIndex::new(&[1i8, 2, 3, 4, 12, 0, 2, 1]).unwrap());
+distr_int!(distr_weighted_u32, usize, WeightedIndex::new(&[1u32, 2, 3, 4, 12, 0, 2, 1]).unwrap());
+distr_int!(distr_weighted_f64, usize, WeightedIndex::new(&[1.0f64, 0.001, 1.0/3.0, 4.01, 0.0, 3.3, 22.0, 0.001]).unwrap());
+distr_int!(distr_weighted_large_set, usize, WeightedIndex::new((0..10000).rev().chain(1..10001)).unwrap());
+
+// construct and sample from a range
+macro_rules! gen_range_int {
+ ($fnn:ident, $ty:ident, $low:expr, $high:expr) => {
+ #[bench]
+ fn $fnn(b: &mut Bencher) {
+ let mut rng = SmallRng::from_entropy();
+
+ b.iter(|| {
+ let mut high = $high;
+ let mut accum: $ty = 0;
+ for _ in 0..::RAND_BENCH_N {
+ accum = accum.wrapping_add(rng.gen_range($low, high));
+ // force recalculation of range each time
+ high = high.wrapping_add(1) & std::$ty::MAX;
+ }
+ accum
+ });
+ b.bytes = size_of::<$ty>() as u64 * ::RAND_BENCH_N;
+ }
+ }
+}
+
+gen_range_int!(gen_range_i8, i8, -20i8, 100);
+gen_range_int!(gen_range_i16, i16, -500i16, 2000);
+gen_range_int!(gen_range_i32, i32, -200_000_000i32, 800_000_000);
+gen_range_int!(gen_range_i64, i64, 3i64, 123_456_789_123);
+gen_range_int!(gen_range_i128, i128, -12345678901234i128, 123_456_789_123_456_789);
+
+// construct and sample from a floating-point range
+macro_rules! gen_range_float {
+ ($fnn:ident, $ty:ident, $low:expr, $high:expr) => {
+ #[bench]
+ fn $fnn(b: &mut Bencher) {
+ let mut rng = SmallRng::from_entropy();
+
+ b.iter(|| {
+ let mut high = $high;
+ let mut low = $low;
+ let mut accum: $ty = 0.0;
+ for _ in 0..::RAND_BENCH_N {
+ accum += rng.gen_range(low, high);
+ // force recalculation of range each time
+ low += 0.9;
+ high += 1.1;
+ }
+ accum
+ });
+ b.bytes = size_of::<$ty>() as u64 * ::RAND_BENCH_N;
+ }
+ }
+}
+
+gen_range_float!(gen_range_f32, f32, -20000.0f32, 100000.0);
+gen_range_float!(gen_range_f64, f64, 123.456f64, 7890.12);
+
+#[bench]
+fn dist_iter(b: &mut Bencher) {
+ let mut rng = SmallRng::from_entropy();
+ let distr = Normal::new(-2.71828, 3.14159);
+ let mut iter = distr.sample_iter(&mut rng);
+
+ b.iter(|| {
+ let mut accum = 0.0;
+ for _ in 0..::RAND_BENCH_N {
+ accum += iter.next().unwrap();
+ }
+ accum
+ });
+ b.bytes = size_of::<f64>() as u64 * ::RAND_BENCH_N;
+}
diff --git a/rand/benches/distributions/exponential.rs b/rand/benches/distributions/exponential.rs
deleted file mode 100644
index 152615d..0000000
--- a/rand/benches/distributions/exponential.rs
+++ /dev/null
@@ -1,18 +0,0 @@
-use std::mem::size_of;
-use test::Bencher;
-use rand;
-use rand::distributions::exponential::Exp;
-use rand::distributions::Sample;
-
-#[bench]
-fn rand_exp(b: &mut Bencher) {
- let mut rng = rand::weak_rng();
- let mut exp = Exp::new(2.71828 * 3.14159);
-
- b.iter(|| {
- for _ in 0..::RAND_BENCH_N {
- exp.sample(&mut rng);
- }
- });
- b.bytes = size_of::<f64>() as u64 * ::RAND_BENCH_N;
-}
diff --git a/rand/benches/distributions/gamma.rs b/rand/benches/distributions/gamma.rs
deleted file mode 100644
index bf3fd36..0000000
--- a/rand/benches/distributions/gamma.rs
+++ /dev/null
@@ -1,31 +0,0 @@
-use std::mem::size_of;
-use test::Bencher;
-use rand;
-use rand::distributions::IndependentSample;
-use rand::distributions::gamma::Gamma;
-
-#[bench]
-fn bench_gamma_large_shape(b: &mut Bencher) {
- let gamma = Gamma::new(10., 1.0);
- let mut rng = rand::weak_rng();
-
- b.iter(|| {
- for _ in 0..::RAND_BENCH_N {
- gamma.ind_sample(&mut rng);
- }
- });
- b.bytes = size_of::<f64>() as u64 * ::RAND_BENCH_N;
-}
-
-#[bench]
-fn bench_gamma_small_shape(b: &mut Bencher) {
- let gamma = Gamma::new(0.1, 1.0);
- let mut rng = rand::weak_rng();
-
- b.iter(|| {
- for _ in 0..::RAND_BENCH_N {
- gamma.ind_sample(&mut rng);
- }
- });
- b.bytes = size_of::<f64>() as u64 * ::RAND_BENCH_N;
-}
diff --git a/rand/benches/distributions/mod.rs b/rand/benches/distributions/mod.rs
deleted file mode 100644
index 49f6bd9..0000000
--- a/rand/benches/distributions/mod.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-mod exponential;
-mod normal;
-mod gamma;
diff --git a/rand/benches/distributions/normal.rs b/rand/benches/distributions/normal.rs
deleted file mode 100644
index 1c858b1..0000000
--- a/rand/benches/distributions/normal.rs
+++ /dev/null
@@ -1,18 +0,0 @@
-use std::mem::size_of;
-use test::Bencher;
-use rand;
-use rand::distributions::Sample;
-use rand::distributions::normal::Normal;
-
-#[bench]
-fn rand_normal(b: &mut Bencher) {
- let mut rng = rand::weak_rng();
- let mut normal = Normal::new(-2.71828, 3.14159);
-
- b.iter(|| {
- for _ in 0..::RAND_BENCH_N {
- normal.sample(&mut rng);
- }
- });
- b.bytes = size_of::<f64>() as u64 * ::RAND_BENCH_N;
-}
diff --git a/rand/benches/generators.rs b/rand/benches/generators.rs
index daee7c5..a12b5a6 100644
--- a/rand/benches/generators.rs
+++ b/rand/benches/generators.rs
@@ -1,7 +1,20 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
#![feature(test)]
extern crate test;
extern crate rand;
+extern crate rand_isaac;
+extern crate rand_chacha;
+extern crate rand_hc;
+extern crate rand_pcg;
+extern crate rand_xorshift;
const RAND_BENCH_N: u64 = 1000;
const BYTES_LEN: usize = 1024;
@@ -9,31 +22,20 @@ const BYTES_LEN: usize = 1024;
use std::mem::size_of;
use test::{black_box, Bencher};
-use rand::{Rng, StdRng, OsRng, JitterRng};
-use rand::{XorShiftRng, IsaacRng, Isaac64Rng, ChaChaRng};
+use rand::prelude::*;
+use rand::rngs::adapter::ReseedingRng;
+use rand::rngs::{OsRng, JitterRng, EntropyRng};
+use rand_isaac::{IsaacRng, Isaac64Rng};
+use rand_chacha::ChaChaRng;
+use rand_hc::{Hc128Rng, Hc128Core};
+use rand_pcg::{Lcg64Xsh32, Mcg128Xsl64};
+use rand_xorshift::XorShiftRng;
macro_rules! gen_bytes {
- ($fnn:ident, $gen:ident) => {
- #[bench]
- fn $fnn(b: &mut Bencher) {
- let mut rng: $gen = OsRng::new().unwrap().gen();
- let mut buf = [0u8; BYTES_LEN];
- b.iter(|| {
- for _ in 0..RAND_BENCH_N {
- rng.fill_bytes(&mut buf);
- black_box(buf);
- }
- });
- b.bytes = BYTES_LEN as u64 * RAND_BENCH_N;
- }
- }
-}
-
-macro_rules! gen_bytes_new {
- ($fnn:ident, $gen:ident) => {
+ ($fnn:ident, $gen:expr) => {
#[bench]
fn $fnn(b: &mut Bencher) {
- let mut rng = $gen::new().unwrap();
+ let mut rng = $gen;
let mut buf = [0u8; BYTES_LEN];
b.iter(|| {
for _ in 0..RAND_BENCH_N {
@@ -46,63 +48,63 @@ macro_rules! gen_bytes_new {
}
}
-gen_bytes!(gen_bytes_xorshift, XorShiftRng);
-gen_bytes!(gen_bytes_isaac, IsaacRng);
-gen_bytes!(gen_bytes_isaac64, Isaac64Rng);
-gen_bytes!(gen_bytes_chacha, ChaChaRng);
-gen_bytes_new!(gen_bytes_std, StdRng);
-gen_bytes_new!(gen_bytes_os, OsRng);
-
+gen_bytes!(gen_bytes_xorshift, XorShiftRng::from_entropy());
+gen_bytes!(gen_bytes_lcg64_xsh32, Lcg64Xsh32::from_entropy());
+gen_bytes!(gen_bytes_mcg128_xsh64, Mcg128Xsl64::from_entropy());
+gen_bytes!(gen_bytes_chacha20, ChaChaRng::from_entropy());
+gen_bytes!(gen_bytes_hc128, Hc128Rng::from_entropy());
+gen_bytes!(gen_bytes_isaac, IsaacRng::from_entropy());
+gen_bytes!(gen_bytes_isaac64, Isaac64Rng::from_entropy());
+gen_bytes!(gen_bytes_std, StdRng::from_entropy());
+gen_bytes!(gen_bytes_small, SmallRng::from_entropy());
+gen_bytes!(gen_bytes_os, OsRng::new().unwrap());
macro_rules! gen_uint {
- ($fnn:ident, $ty:ty, $gen:ident) => {
- #[bench]
- fn $fnn(b: &mut Bencher) {
- let mut rng: $gen = OsRng::new().unwrap().gen();
- b.iter(|| {
- for _ in 0..RAND_BENCH_N {
- black_box(rng.gen::<$ty>());
- }
- });
- b.bytes = size_of::<$ty>() as u64 * RAND_BENCH_N;
- }
- }
-}
-
-macro_rules! gen_uint_new {
- ($fnn:ident, $ty:ty, $gen:ident) => {
+ ($fnn:ident, $ty:ty, $gen:expr) => {
#[bench]
fn $fnn(b: &mut Bencher) {
- let mut rng = $gen::new().unwrap();
+ let mut rng = $gen;
b.iter(|| {
+ let mut accum: $ty = 0;
for _ in 0..RAND_BENCH_N {
- black_box(rng.gen::<$ty>());
+ accum = accum.wrapping_add(rng.gen::<$ty>());
}
+ accum
});
b.bytes = size_of::<$ty>() as u64 * RAND_BENCH_N;
}
}
}
-gen_uint!(gen_u32_xorshift, u32, XorShiftRng);
-gen_uint!(gen_u32_isaac, u32, IsaacRng);
-gen_uint!(gen_u32_isaac64, u32, Isaac64Rng);
-gen_uint!(gen_u32_chacha, u32, ChaChaRng);
-gen_uint_new!(gen_u32_std, u32, StdRng);
-gen_uint_new!(gen_u32_os, u32, OsRng);
-
-gen_uint!(gen_u64_xorshift, u64, XorShiftRng);
-gen_uint!(gen_u64_isaac, u64, IsaacRng);
-gen_uint!(gen_u64_isaac64, u64, Isaac64Rng);
-gen_uint!(gen_u64_chacha, u64, ChaChaRng);
-gen_uint_new!(gen_u64_std, u64, StdRng);
-gen_uint_new!(gen_u64_os, u64, OsRng);
-
+gen_uint!(gen_u32_xorshift, u32, XorShiftRng::from_entropy());
+gen_uint!(gen_u32_lcg64_xsh32, u32, Lcg64Xsh32::from_entropy());
+gen_uint!(gen_u32_mcg128_xsh64, u32, Mcg128Xsl64::from_entropy());
+gen_uint!(gen_u32_chacha20, u32, ChaChaRng::from_entropy());
+gen_uint!(gen_u32_hc128, u32, Hc128Rng::from_entropy());
+gen_uint!(gen_u32_isaac, u32, IsaacRng::from_entropy());
+gen_uint!(gen_u32_isaac64, u32, Isaac64Rng::from_entropy());
+gen_uint!(gen_u32_std, u32, StdRng::from_entropy());
+gen_uint!(gen_u32_small, u32, SmallRng::from_entropy());
+gen_uint!(gen_u32_os, u32, OsRng::new().unwrap());
+
+gen_uint!(gen_u64_xorshift, u64, XorShiftRng::from_entropy());
+gen_uint!(gen_u64_lcg64_xsh32, u64, Lcg64Xsh32::from_entropy());
+gen_uint!(gen_u64_mcg128_xsh64, u64, Mcg128Xsl64::from_entropy());
+gen_uint!(gen_u64_chacha20, u64, ChaChaRng::from_entropy());
+gen_uint!(gen_u64_hc128, u64, Hc128Rng::from_entropy());
+gen_uint!(gen_u64_isaac, u64, IsaacRng::from_entropy());
+gen_uint!(gen_u64_isaac64, u64, Isaac64Rng::from_entropy());
+gen_uint!(gen_u64_std, u64, StdRng::from_entropy());
+gen_uint!(gen_u64_small, u64, SmallRng::from_entropy());
+gen_uint!(gen_u64_os, u64, OsRng::new().unwrap());
+
+// Do not test JitterRng like the others by running it RAND_BENCH_N times per,
+// measurement, because it is way too slow. Only run it once.
#[bench]
fn gen_u64_jitter(b: &mut Bencher) {
let mut rng = JitterRng::new().unwrap();
b.iter(|| {
- black_box(rng.gen::<u64>());
+ rng.gen::<u64>()
});
b.bytes = size_of::<u64>() as u64;
}
@@ -111,16 +113,19 @@ macro_rules! init_gen {
($fnn:ident, $gen:ident) => {
#[bench]
fn $fnn(b: &mut Bencher) {
- let mut rng: XorShiftRng = OsRng::new().unwrap().gen();
+ let mut rng = XorShiftRng::from_entropy();
b.iter(|| {
- let r2: $gen = rng.gen();
- black_box(r2);
+ let r2 = $gen::from_rng(&mut rng).unwrap();
+ r2
});
}
}
}
init_gen!(init_xorshift, XorShiftRng);
+init_gen!(init_lcg64_xsh32, Lcg64Xsh32);
+init_gen!(init_mcg128_xsh64, Mcg128Xsl64);
+init_gen!(init_hc128, Hc128Rng);
init_gen!(init_isaac, IsaacRng);
init_gen!(init_isaac64, Isaac64Rng);
init_gen!(init_chacha, ChaChaRng);
@@ -128,6 +133,68 @@ init_gen!(init_chacha, ChaChaRng);
#[bench]
fn init_jitter(b: &mut Bencher) {
b.iter(|| {
- black_box(JitterRng::new().unwrap());
+ JitterRng::new().unwrap()
+ });
+}
+
+
+const RESEEDING_THRESHOLD: u64 = 1024*1024*1024; // something high enough to get
+ // deterministic measurements
+
+#[bench]
+fn reseeding_hc128_bytes(b: &mut Bencher) {
+ let mut rng = ReseedingRng::new(Hc128Core::from_entropy(),
+ RESEEDING_THRESHOLD,
+ EntropyRng::new());
+ let mut buf = [0u8; BYTES_LEN];
+ b.iter(|| {
+ for _ in 0..RAND_BENCH_N {
+ rng.fill_bytes(&mut buf);
+ black_box(buf);
+ }
});
+ b.bytes = BYTES_LEN as u64 * RAND_BENCH_N;
+}
+
+macro_rules! reseeding_uint {
+ ($fnn:ident, $ty:ty) => {
+ #[bench]
+ fn $fnn(b: &mut Bencher) {
+ let mut rng = ReseedingRng::new(Hc128Core::from_entropy(),
+ RESEEDING_THRESHOLD,
+ EntropyRng::new());
+ b.iter(|| {
+ let mut accum: $ty = 0;
+ for _ in 0..RAND_BENCH_N {
+ accum = accum.wrapping_add(rng.gen::<$ty>());
+ }
+ accum
+ });
+ b.bytes = size_of::<$ty>() as u64 * RAND_BENCH_N;
+ }
+ }
+}
+
+reseeding_uint!(reseeding_hc128_u32, u32);
+reseeding_uint!(reseeding_hc128_u64, u64);
+
+
+macro_rules! threadrng_uint {
+ ($fnn:ident, $ty:ty) => {
+ #[bench]
+ fn $fnn(b: &mut Bencher) {
+ let mut rng = thread_rng();
+ b.iter(|| {
+ let mut accum: $ty = 0;
+ for _ in 0..RAND_BENCH_N {
+ accum = accum.wrapping_add(rng.gen::<$ty>());
+ }
+ accum
+ });
+ b.bytes = size_of::<$ty>() as u64 * RAND_BENCH_N;
+ }
+ }
}
+
+threadrng_uint!(thread_rng_u32, u32);
+threadrng_uint!(thread_rng_u64, u64);
diff --git a/rand/benches/misc.rs b/rand/benches/misc.rs
index 4251761..8fb3a83 100644
--- a/rand/benches/misc.rs
+++ b/rand/benches/misc.rs
@@ -1,62 +1,160 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
#![feature(test)]
extern crate test;
extern crate rand;
-use test::{black_box, Bencher};
+const RAND_BENCH_N: u64 = 1000;
+
+use test::Bencher;
-use rand::{Rng, weak_rng};
-use rand::seq::*;
+use rand::prelude::*;
#[bench]
-fn misc_shuffle_100(b: &mut Bencher) {
- let mut rng = weak_rng();
- let x : &mut [usize] = &mut [1; 100];
+fn misc_gen_bool_const(b: &mut Bencher) {
+ let mut rng = StdRng::from_rng(&mut thread_rng()).unwrap();
b.iter(|| {
- rng.shuffle(x);
- black_box(&x);
+ let mut accum = true;
+ for _ in 0..::RAND_BENCH_N {
+ accum ^= rng.gen_bool(0.18);
+ }
+ accum
})
}
#[bench]
-fn misc_sample_iter_10_of_100(b: &mut Bencher) {
- let mut rng = weak_rng();
- let x : &[usize] = &[1; 100];
+fn misc_gen_bool_var(b: &mut Bencher) {
+ let mut rng = StdRng::from_rng(&mut thread_rng()).unwrap();
b.iter(|| {
- black_box(sample_iter(&mut rng, x, 10).unwrap_or_else(|e| e));
+ let mut accum = true;
+ let mut p = 0.18;
+ for _ in 0..::RAND_BENCH_N {
+ accum ^= rng.gen_bool(p);
+ p += 0.0001;
+ }
+ accum
})
}
#[bench]
-fn misc_sample_slice_10_of_100(b: &mut Bencher) {
- let mut rng = weak_rng();
- let x : &[usize] = &[1; 100];
+fn misc_gen_ratio_const(b: &mut Bencher) {
+ let mut rng = StdRng::from_rng(&mut thread_rng()).unwrap();
b.iter(|| {
- black_box(sample_slice(&mut rng, x, 10));
+ let mut accum = true;
+ for _ in 0..::RAND_BENCH_N {
+ accum ^= rng.gen_ratio(2, 3);
+ }
+ accum
+ })
+}
+
+#[bench]
+fn misc_gen_ratio_var(b: &mut Bencher) {
+ let mut rng = StdRng::from_rng(&mut thread_rng()).unwrap();
+ b.iter(|| {
+ let mut accum = true;
+ for i in 2..(::RAND_BENCH_N as u32 + 2) {
+ accum ^= rng.gen_ratio(i, i + 1);
+ }
+ accum
+ })
+}
+
+#[bench]
+fn misc_bernoulli_const(b: &mut Bencher) {
+ let mut rng = StdRng::from_rng(&mut thread_rng()).unwrap();
+ b.iter(|| {
+ let d = rand::distributions::Bernoulli::new(0.18);
+ let mut accum = true;
+ for _ in 0..::RAND_BENCH_N {
+ accum ^= rng.sample(d);
+ }
+ accum
})
}
#[bench]
-fn misc_sample_slice_ref_10_of_100(b: &mut Bencher) {
- let mut rng = weak_rng();
- let x : &[usize] = &[1; 100];
+fn misc_bernoulli_var(b: &mut Bencher) {
+ let mut rng = StdRng::from_rng(&mut thread_rng()).unwrap();
b.iter(|| {
- black_box(sample_slice_ref(&mut rng, x, 10));
+ let mut accum = true;
+ let mut p = 0.18;
+ for _ in 0..::RAND_BENCH_N {
+ let d = rand::distributions::Bernoulli::new(p);
+ accum ^= rng.sample(d);
+ p += 0.0001;
+ }
+ accum
})
}
-macro_rules! sample_indices {
- ($name:ident, $amount:expr, $length:expr) => {
+macro_rules! sample_binomial {
+ ($name:ident, $n:expr, $p:expr) => {
#[bench]
fn $name(b: &mut Bencher) {
- let mut rng = weak_rng();
+ let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap();
+ let (n, p) = ($n, $p);
b.iter(|| {
- black_box(sample_indices(&mut rng, $length, $amount));
+ let d = rand::distributions::Binomial::new(n, p);
+ rng.sample(d)
})
}
}
}
-sample_indices!(misc_sample_indices_10_of_1k, 10, 1000);
-sample_indices!(misc_sample_indices_50_of_1k, 50, 1000);
-sample_indices!(misc_sample_indices_100_of_1k, 100, 1000);
+sample_binomial!(misc_binomial_1, 1, 0.9);
+sample_binomial!(misc_binomial_10, 10, 0.9);
+sample_binomial!(misc_binomial_100, 100, 0.99);
+sample_binomial!(misc_binomial_1000, 1000, 0.01);
+sample_binomial!(misc_binomial_1e12, 1000_000_000_000, 0.2);
+
+#[bench]
+fn gen_1k_iter_repeat(b: &mut Bencher) {
+ use std::iter;
+ let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap();
+ b.iter(|| {
+ let v: Vec<u64> = iter::repeat(()).map(|()| rng.gen()).take(128).collect();
+ v
+ });
+ b.bytes = 1024;
+}
+
+#[bench]
+fn gen_1k_sample_iter(b: &mut Bencher) {
+ use rand::distributions::{Distribution, Standard};
+ let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap();
+ b.iter(|| {
+ let v: Vec<u64> = Standard.sample_iter(&mut rng).take(128).collect();
+ v
+ });
+ b.bytes = 1024;
+}
+
+#[bench]
+fn gen_1k_gen_array(b: &mut Bencher) {
+ let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap();
+ b.iter(|| {
+ // max supported array length is 32!
+ let v: [[u64; 32]; 4] = rng.gen();
+ v
+ });
+ b.bytes = 1024;
+}
+
+#[bench]
+fn gen_1k_fill(b: &mut Bencher) {
+ let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap();
+ let mut buf = [0u64; 128];
+ b.iter(|| {
+ rng.fill(&mut buf[..]);
+ buf
+ });
+ b.bytes = 1024;
+}
diff --git a/rand/benches/seq.rs b/rand/benches/seq.rs
new file mode 100644
index 0000000..0ca3398
--- /dev/null
+++ b/rand/benches/seq.rs
@@ -0,0 +1,174 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(test)]
+#![allow(non_snake_case)]
+
+extern crate test;
+extern crate rand;
+
+use test::Bencher;
+
+use rand::prelude::*;
+use rand::seq::*;
+use std::mem::size_of;
+
+const RAND_BENCH_N: u64 = 1000;
+
+#[bench]
+fn seq_shuffle_100(b: &mut Bencher) {
+ let mut rng = SmallRng::from_rng(thread_rng()).unwrap();
+ let x : &mut [usize] = &mut [1; 100];
+ b.iter(|| {
+ x.shuffle(&mut rng);
+ x[0]
+ })
+}
+
+#[bench]
+fn seq_slice_choose_1_of_1000(b: &mut Bencher) {
+ let mut rng = SmallRng::from_rng(thread_rng()).unwrap();
+ let x : &mut [usize] = &mut [1; 1000];
+ for i in 0..1000 {
+ x[i] = i;
+ }
+ b.iter(|| {
+ let mut s = 0;
+ for _ in 0..RAND_BENCH_N {
+ s += x.choose(&mut rng).unwrap();
+ }
+ s
+ });
+ b.bytes = size_of::<usize>() as u64 * ::RAND_BENCH_N;
+}
+
+macro_rules! seq_slice_choose_multiple {
+ ($name:ident, $amount:expr, $length:expr) => {
+ #[bench]
+ fn $name(b: &mut Bencher) {
+ let mut rng = SmallRng::from_rng(thread_rng()).unwrap();
+ let x : &[i32] = &[$amount; $length];
+ let mut result = [0i32; $amount];
+ b.iter(|| {
+ // Collect full result to prevent unwanted shortcuts getting
+ // first element (in case sample_indices returns an iterator).
+ for (slot, sample) in result.iter_mut().zip(
+ x.choose_multiple(&mut rng, $amount)) {
+ *slot = *sample;
+ }
+ result[$amount-1]
+ })
+ }
+ }
+}
+
+seq_slice_choose_multiple!(seq_slice_choose_multiple_1_of_1000, 1, 1000);
+seq_slice_choose_multiple!(seq_slice_choose_multiple_950_of_1000, 950, 1000);
+seq_slice_choose_multiple!(seq_slice_choose_multiple_10_of_100, 10, 100);
+seq_slice_choose_multiple!(seq_slice_choose_multiple_90_of_100, 90, 100);
+
+#[bench]
+fn seq_iter_choose_from_1000(b: &mut Bencher) {
+ let mut rng = SmallRng::from_rng(thread_rng()).unwrap();
+ let x : &mut [usize] = &mut [1; 1000];
+ for i in 0..1000 {
+ x[i] = i;
+ }
+ b.iter(|| {
+ let mut s = 0;
+ for _ in 0..RAND_BENCH_N {
+ s += x.iter().choose(&mut rng).unwrap();
+ }
+ s
+ });
+ b.bytes = size_of::<usize>() as u64 * ::RAND_BENCH_N;
+}
+
+#[derive(Clone)]
+struct UnhintedIterator<I: Iterator + Clone> {
+ iter: I,
+}
+impl<I: Iterator + Clone> Iterator for UnhintedIterator<I> {
+ type Item = I::Item;
+ fn next(&mut self) -> Option<Self::Item> {
+ self.iter.next()
+ }
+}
+
+#[derive(Clone)]
+struct WindowHintedIterator<I: ExactSizeIterator + Iterator + Clone> {
+ iter: I,
+ window_size: usize,
+}
+impl<I: ExactSizeIterator + Iterator + Clone> Iterator for WindowHintedIterator<I> {
+ type Item = I::Item;
+ fn next(&mut self) -> Option<Self::Item> {
+ self.iter.next()
+ }
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (std::cmp::min(self.iter.len(), self.window_size), None)
+ }
+}
+
+#[bench]
+fn seq_iter_unhinted_choose_from_1000(b: &mut Bencher) {
+ let mut rng = SmallRng::from_rng(thread_rng()).unwrap();
+ let x : &[usize] = &[1; 1000];
+ b.iter(|| {
+ UnhintedIterator { iter: x.iter() }.choose(&mut rng).unwrap()
+ })
+}
+
+#[bench]
+fn seq_iter_window_hinted_choose_from_1000(b: &mut Bencher) {
+ let mut rng = SmallRng::from_rng(thread_rng()).unwrap();
+ let x : &[usize] = &[1; 1000];
+ b.iter(|| {
+ WindowHintedIterator { iter: x.iter(), window_size: 7 }.choose(&mut rng)
+ })
+}
+
+#[bench]
+fn seq_iter_choose_multiple_10_of_100(b: &mut Bencher) {
+ let mut rng = SmallRng::from_rng(thread_rng()).unwrap();
+ let x : &[usize] = &[1; 100];
+ b.iter(|| {
+ x.iter().cloned().choose_multiple(&mut rng, 10)
+ })
+}
+
+#[bench]
+fn seq_iter_choose_multiple_fill_10_of_100(b: &mut Bencher) {
+ let mut rng = SmallRng::from_rng(thread_rng()).unwrap();
+ let x : &[usize] = &[1; 100];
+ let mut buf = [0; 10];
+ b.iter(|| {
+ x.iter().cloned().choose_multiple_fill(&mut rng, &mut buf)
+ })
+}
+
+macro_rules! sample_indices {
+ ($name:ident, $fn:ident, $amount:expr, $length:expr) => {
+ #[bench]
+ fn $name(b: &mut Bencher) {
+ let mut rng = SmallRng::from_rng(thread_rng()).unwrap();
+ b.iter(|| {
+ index::$fn(&mut rng, $length, $amount)
+ })
+ }
+ }
+}
+
+sample_indices!(misc_sample_indices_1_of_1k, sample, 1, 1000);
+sample_indices!(misc_sample_indices_10_of_1k, sample, 10, 1000);
+sample_indices!(misc_sample_indices_100_of_1k, sample, 100, 1000);
+sample_indices!(misc_sample_indices_100_of_1M, sample, 100, 1000_000);
+sample_indices!(misc_sample_indices_100_of_1G, sample, 100, 1000_000_000);
+sample_indices!(misc_sample_indices_200_of_1G, sample, 200, 1000_000_000);
+sample_indices!(misc_sample_indices_400_of_1G, sample, 400, 1000_000_000);
+sample_indices!(misc_sample_indices_600_of_1G, sample, 600, 1000_000_000);
diff --git a/rand/build.rs b/rand/build.rs
new file mode 100644
index 0000000..e44b643
--- /dev/null
+++ b/rand/build.rs
@@ -0,0 +1,14 @@
+extern crate rustc_version;
+use rustc_version::{version, Version};
+
+fn main() {
+ if version().unwrap() >= Version::parse("1.25.0").unwrap() {
+ println!("cargo:rustc-cfg=rust_1_25");
+ }
+ if version().unwrap() >= Version::parse("1.26.0").unwrap() {
+ println!("cargo:rustc-cfg=rust_1_26");
+ }
+ if version().unwrap() >= Version::parse("1.27.0").unwrap() {
+ println!("cargo:rustc-cfg=rust_1_27");
+ }
+}
diff --git a/rand/examples/monte-carlo.rs b/rand/examples/monte-carlo.rs
new file mode 100644
index 0000000..9162996
--- /dev/null
+++ b/rand/examples/monte-carlo.rs
@@ -0,0 +1,51 @@
+// Copyright 2018 Developers of the Rand project.
+// Copyright 2013-2018 The Rust Project Developers.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! # Monte Carlo estimation of π
+//!
+//! Imagine that we have a square with sides of length 2 and a unit circle
+//! (radius = 1), both centered at the origin. The areas are:
+//!
+//! ```text
+//! area of circle = πr² = π * r * r = π
+//! area of square = 2² = 4
+//! ```
+//!
+//! The circle is entirely within the square, so if we sample many points
+//! randomly from the square, roughly π / 4 of them should be inside the circle.
+//!
+//! We can use the above fact to estimate the value of π: pick many points in
+//! the square at random, calculate the fraction that fall within the circle,
+//! and multiply this fraction by 4.
+
+#![cfg(feature="std")]
+
+
+extern crate rand;
+
+use rand::distributions::{Distribution, Uniform};
+
+fn main() {
+ let range = Uniform::new(-1.0f64, 1.0);
+ let mut rng = rand::thread_rng();
+
+ let total = 1_000_000;
+ let mut in_circle = 0;
+
+ for _ in 0..total {
+ let a = range.sample(&mut rng);
+ let b = range.sample(&mut rng);
+ if a*a + b*b <= 1.0 {
+ in_circle += 1;
+ }
+ }
+
+ // prints something close to 3.14159...
+ println!("Ï€ is approximately {}", 4. * (in_circle as f64) / (total as f64));
+}
diff --git a/rand/examples/monty-hall.rs b/rand/examples/monty-hall.rs
new file mode 100644
index 0000000..0932c5e
--- /dev/null
+++ b/rand/examples/monty-hall.rs
@@ -0,0 +1,116 @@
+// Copyright 2018 Developers of the Rand project.
+// Copyright 2013-2018 The Rust Project Developers.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! ## Monty Hall Problem
+//!
+//! This is a simulation of the [Monty Hall Problem][]:
+//!
+//! > Suppose you're on a game show, and you're given the choice of three doors:
+//! > Behind one door is a car; behind the others, goats. You pick a door, say
+//! > No. 1, and the host, who knows what's behind the doors, opens another
+//! > door, say No. 3, which has a goat. He then says to you, "Do you want to
+//! > pick door No. 2?" Is it to your advantage to switch your choice?
+//!
+//! The rather unintuitive answer is that you will have a 2/3 chance of winning
+//! if you switch and a 1/3 chance of winning if you don't, so it's better to
+//! switch.
+//!
+//! This program will simulate the game show and with large enough simulation
+//! steps it will indeed confirm that it is better to switch.
+//!
+//! [Monty Hall Problem]: https://en.wikipedia.org/wiki/Monty_Hall_problem
+
+#![cfg(feature="std")]
+
+
+extern crate rand;
+
+use rand::Rng;
+use rand::distributions::{Distribution, Uniform};
+
+struct SimulationResult {
+ win: bool,
+ switch: bool,
+}
+
+// Run a single simulation of the Monty Hall problem.
+fn simulate<R: Rng>(random_door: &Uniform<u32>, rng: &mut R)
+ -> SimulationResult {
+ let car = random_door.sample(rng);
+
+ // This is our initial choice
+ let mut choice = random_door.sample(rng);
+
+ // The game host opens a door
+ let open = game_host_open(car, choice, rng);
+
+ // Shall we switch?
+ let switch = rng.gen();
+ if switch {
+ choice = switch_door(choice, open);
+ }
+
+ SimulationResult { win: choice == car, switch }
+}
+
+// Returns the door the game host opens given our choice and knowledge of
+// where the car is. The game host will never open the door with the car.
+fn game_host_open<R: Rng>(car: u32, choice: u32, rng: &mut R) -> u32 {
+ use rand::seq::SliceRandom;
+ *free_doors(&[car, choice]).choose(rng).unwrap()
+}
+
+// Returns the door we switch to, given our current choice and
+// the open door. There will only be one valid door.
+fn switch_door(choice: u32, open: u32) -> u32 {
+ free_doors(&[choice, open])[0]
+}
+
+fn free_doors(blocked: &[u32]) -> Vec<u32> {
+ (0..3).filter(|x| !blocked.contains(x)).collect()
+}
+
+fn main() {
+ // The estimation will be more accurate with more simulations
+ let num_simulations = 10000;
+
+ let mut rng = rand::thread_rng();
+ let random_door = Uniform::new(0u32, 3);
+
+ let (mut switch_wins, mut switch_losses) = (0, 0);
+ let (mut keep_wins, mut keep_losses) = (0, 0);
+
+ println!("Running {} simulations...", num_simulations);
+ for _ in 0..num_simulations {
+ let result = simulate(&random_door, &mut rng);
+
+ match (result.win, result.switch) {
+ (true, true) => switch_wins += 1,
+ (true, false) => keep_wins += 1,
+ (false, true) => switch_losses += 1,
+ (false, false) => keep_losses += 1,
+ }
+ }
+
+ let total_switches = switch_wins + switch_losses;
+ let total_keeps = keep_wins + keep_losses;
+
+ println!("Switched door {} times with {} wins and {} losses",
+ total_switches, switch_wins, switch_losses);
+
+ println!("Kept our choice {} times with {} wins and {} losses",
+ total_keeps, keep_wins, keep_losses);
+
+ // With a large number of simulations, the values should converge to
+ // 0.667 and 0.333 respectively.
+ println!("Estimated chance to win if we switch: {}",
+ switch_wins as f32 / total_switches as f32);
+ println!("Estimated chance to win if we don't: {}",
+ keep_wins as f32 / total_keeps as f32);
+}
diff --git a/rand/rand-derive/Cargo.toml b/rand/rand-derive/Cargo.toml
deleted file mode 100644
index 1a2dbe1..0000000
--- a/rand/rand-derive/Cargo.toml
+++ /dev/null
@@ -1,23 +0,0 @@
-[package]
-
-name = "rand_derive"
-version = "0.3.1"
-authors = ["The Rust Project Developers"]
-license = "MIT/Apache-2.0"
-readme = "README.md"
-repository = "https://github.com/rust-lang-nursery/rand"
-documentation = "https://docs.rs/rand_derive"
-homepage = "https://github.com/rust-lang-nursery/rand"
-description = """
-`#[derive(Rand)]` functionality for the `rand::Rand` trait.
-"""
-
-[lib]
-proc-macro = true
-
-[dependencies]
-quote = "0.3"
-syn = "0.11"
-
-[dev-dependencies]
-rand = { path = "..", version = "0.4" }
diff --git a/rand/rand-derive/README.md b/rand/rand-derive/README.md
deleted file mode 100644
index 3d1fedb..0000000
--- a/rand/rand-derive/README.md
+++ /dev/null
@@ -1,51 +0,0 @@
-
-rand_macros
-====
-
-`#[derive(Rand)]` functionality for the `rand::Rand` trait.
-
-## Usage
-Add this to your `Cargo.toml`:
-
-```toml
-[dependencies]
-rand = "0.4"
-rand_macros = "0.2"
-```
-
-and this to your crate root:
-
-```rust
-extern crate rand;
-#[macro_use]
-extern crate rand_macros;
-```
-
-## Examples
-
-`#[derive(Rand)]` can be used on any `struct` or `enum` where all fields/variants implement `rand::Rand`.
-
-```rust
-#[derive(Debug, Rand)]
-struct Foo {
- x: u16,
- y: Option<f64>,
-}
-
-#[derive(Debug, Rand)]
-enum Bar {
- X{x: u8, y: isize},
- Y([bool; 4]),
- Z,
-}
-```
-Now you can call the `Rng::gen()` function on your custom types.
-
-```rust
-use rand::Rng;
-
-let mut rng = rand::thread_rng();
-
-println!("{:?}", rng.gen::<Foo>());
-println!("{:?}", rng.gen::<Bar>());
-```
diff --git a/rand/rand-derive/src/lib.rs b/rand/rand-derive/src/lib.rs
deleted file mode 100644
index 80c803a..0000000
--- a/rand/rand-derive/src/lib.rs
+++ /dev/null
@@ -1,116 +0,0 @@
-//! Support for `#[derive(Rand)]`
-//!
-//! # Examples
-//!
-//! ```
-//! extern crate rand;
-//! #[macro_use]
-//! extern crate rand_derive;
-//!
-//! #[derive(Rand, Debug)]
-//! struct MyStruct {
-//! a: i32,
-//! b: u32,
-//! }
-//!
-//! fn main() {
-//! println!("{:?}", rand::random::<MyStruct>());
-//! }
-//! ```
-
-extern crate proc_macro;
-#[macro_use]
-extern crate quote;
-extern crate syn;
-
-use proc_macro::TokenStream;
-
-#[proc_macro_derive(Rand)]
-pub fn rand_derive(input: TokenStream) -> TokenStream {
- let s = input.to_string();
- let ast = syn::parse_derive_input(&s).unwrap();
- let gen = impl_rand_derive(&ast);
- gen.parse().unwrap()
-}
-
-fn impl_rand_derive(ast: &syn::MacroInput) -> quote::Tokens {
- let name = &ast.ident;
- let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
-
- let rand = match ast.body {
- syn::Body::Struct(syn::VariantData::Struct(ref body)) => {
- let fields = body
- .iter()
- .filter_map(|field| field.ident.as_ref())
- .map(|ident| quote! { #ident: __rng.gen() })
- .collect::<Vec<_>>();
-
- quote! { #name { #(#fields,)* } }
- },
- syn::Body::Struct(syn::VariantData::Tuple(ref body)) => {
- let fields = (0..body.len())
- .map(|_| quote! { __rng.gen() })
- .collect::<Vec<_>>();
-
- quote! { #name (#(#fields),*) }
- },
- syn::Body::Struct(syn::VariantData::Unit) => {
- quote! { #name }
- },
- syn::Body::Enum(ref body) => {
- if body.is_empty() {
- panic!("`Rand` cannot be derived for enums with no variants");
- }
-
- let len = body.len();
- let mut arms = body
- .iter()
- .map(|variant| {
- let ident = &variant.ident;
- match variant.data {
- syn::VariantData::Struct(ref body) => {
- let fields = body
- .iter()
- .filter_map(|field| field.ident.as_ref())
- .map(|ident| quote! { #ident: __rng.gen() })
- .collect::<Vec<_>>();
- quote! { #name::#ident { #(#fields,)* } }
- },
- syn::VariantData::Tuple(ref body) => {
- let fields = (0..body.len())
- .map(|_| quote! { __rng.gen() })
- .collect::<Vec<_>>();
-
- quote! { #name::#ident (#(#fields),*) }
- },
- syn::VariantData::Unit => quote! { #name::#ident }
- }
- });
-
- match len {
- 1 => quote! { #(#arms)* },
- 2 => {
- let (a, b) = (arms.next(), arms.next());
- quote! { if __rng.gen() { #a } else { #b } }
- },
- _ => {
- let mut variants = arms
- .enumerate()
- .map(|(index, arm)| quote! { #index => #arm })
- .collect::<Vec<_>>();
- variants.push(quote! { _ => unreachable!() });
- quote! { match __rng.gen_range(0, #len) { #(#variants,)* } }
- },
- }
- }
- };
-
- quote! {
- impl #impl_generics ::rand::Rand for #name #ty_generics #where_clause {
- #[inline]
- fn rand<__R: ::rand::Rng>(__rng: &mut __R) -> Self {
- #rand
- }
- }
- }
-}
diff --git a/rand/rand-derive/tests/rand_macros.rs b/rand/rand-derive/tests/rand_macros.rs
deleted file mode 100644
index 938f2b0..0000000
--- a/rand/rand-derive/tests/rand_macros.rs
+++ /dev/null
@@ -1,58 +0,0 @@
-#![allow(dead_code)]
-
-extern crate rand;
-#[macro_use]
-extern crate rand_derive;
-
-use rand::Rng;
-
-#[derive(Rand)]
-struct Struct {
- x: u16,
- y: Option<f64>,
-}
-
-#[derive(Rand)]
-struct Tuple(i16, Option<f64>);
-
-#[derive(Rand)]
-struct Unit;
-
-#[derive(Rand)]
-enum EnumUnit {
- X,
-}
-
-#[derive(Rand)]
-enum Enum1 {
- X(u8, f32),
-}
-
-#[derive(Rand)]
-enum Enum2 {
- X(bool),
- Y,
-}
-
-#[derive(Rand)]
-enum Enum3 {
- X { x: u8, y: isize },
- Y([bool; 4]),
- Z,
-}
-
-#[test]
-fn smoke() {
- let mut rng = rand::XorShiftRng::new_unseeded();
-
- // check nothing horrible happens internally:
- for _ in 0..100 {
- let _ = rng.gen::<Struct>();
- let _ = rng.gen::<Tuple>();
- let _ = rng.gen::<Unit>();
- let _ = rng.gen::<EnumUnit>();
- let _ = rng.gen::<Enum1>();
- let _ = rng.gen::<Enum2>();
- let _ = rng.gen::<Enum3>();
- }
-}
diff --git a/rand/rand_chacha/CHANGELOG.md b/rand/rand_chacha/CHANGELOG.md
new file mode 100644
index 0000000..d0c4a2f
--- /dev/null
+++ b/rand/rand_chacha/CHANGELOG.md
@@ -0,0 +1,8 @@
+# Changelog
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+## [0.1.0] - 2018-10-17
+- Pulled out of the Rand crate
diff --git a/rand/rand_chacha/COPYRIGHT b/rand/rand_chacha/COPYRIGHT
new file mode 100644
index 0000000..468d907
--- /dev/null
+++ b/rand/rand_chacha/COPYRIGHT
@@ -0,0 +1,12 @@
+Copyrights in the Rand project are retained by their contributors. No
+copyright assignment is required to contribute to the Rand project.
+
+For full authorship information, see the version control history.
+
+Except as otherwise noted (below and/or in individual files), Rand is
+licensed under the Apache License, Version 2.0 <LICENSE-APACHE> or
+<http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+<LICENSE-MIT> or <http://opensource.org/licenses/MIT>, at your option.
+
+The Rand project includes code from the Rust project
+published under these same licenses.
diff --git a/rand/rand_chacha/Cargo.toml b/rand/rand_chacha/Cargo.toml
new file mode 100644
index 0000000..af70969
--- /dev/null
+++ b/rand/rand_chacha/Cargo.toml
@@ -0,0 +1,25 @@
+[package]
+name = "rand_chacha"
+version = "0.1.0"
+authors = ["The Rand Project Developers", "The Rust Project Developers"]
+license = "MIT/Apache-2.0"
+readme = "README.md"
+repository = "https://github.com/rust-random/rand"
+documentation = "https://rust-random.github.io/rand/rand_chacha"
+homepage = "https://crates.io/crates/rand_chacha"
+description = """
+ChaCha random number generator
+"""
+keywords = ["random", "rng", "chacha"]
+categories = ["algorithms", "no-std"]
+build = "build.rs"
+
+[badges]
+travis-ci = { repository = "rust-random/rand" }
+appveyor = { repository = "rust-random/rand" }
+
+[dependencies]
+rand_core = { path = "../rand_core", version = ">=0.2, <0.4", default-features=false }
+
+[build-dependencies]
+rustc_version = "0.2"
diff --git a/rand/rand_chacha/LICENSE-APACHE b/rand/rand_chacha/LICENSE-APACHE
new file mode 100644
index 0000000..17d7468
--- /dev/null
+++ b/rand/rand_chacha/LICENSE-APACHE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ https://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/rand/rand_chacha/LICENSE-MIT b/rand/rand_chacha/LICENSE-MIT
new file mode 100644
index 0000000..d93b5ba
--- /dev/null
+++ b/rand/rand_chacha/LICENSE-MIT
@@ -0,0 +1,26 @@
+Copyright 2018 Developers of the Rand project
+Copyright (c) 2014 The Rust Project Developers
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/rand/rand_chacha/README.md b/rand/rand_chacha/README.md
new file mode 100644
index 0000000..5a1dbac
--- /dev/null
+++ b/rand/rand_chacha/README.md
@@ -0,0 +1,45 @@
+# rand_chacha
+
+[![Build Status](https://travis-ci.org/rust-random/rand.svg)](https://travis-ci.org/rust-random/rand)
+[![Build Status](https://ci.appveyor.com/api/projects/status/github/rust-random/rand?svg=true)](https://ci.appveyor.com/project/rust-random/rand)
+[![Latest version](https://img.shields.io/crates/v/rand_chacha.svg)](https://crates.io/crates/rand_chacha)
+[![Book](https://img.shields.io/badge/book-master-yellow.svg)](https://rust-random.github.io/book/)
+[![API](https://img.shields.io/badge/api-master-yellow.svg)](https://rust-random.github.io/rand/rand_chacha)
+[![API](https://docs.rs/rand_chacha/badge.svg)](https://docs.rs/rand_chacha)
+[![Minimum rustc version](https://img.shields.io/badge/rustc-1.22+-lightgray.svg)](https://github.com/rust-random/rand#rust-version-requirements)
+
+A cryptographically secure random number generator that uses the ChaCha
+algorithm.
+
+ChaCha is a stream cipher designed by Daniel J. Bernstein[^1], that we use
+as an RNG. It is an improved variant of the Salsa20 cipher family, which was
+selected as one of the "stream ciphers suitable for widespread adoption" by
+eSTREAM[^2].
+
+Links:
+
+- [API documentation (master)](https://rust-random.github.io/rand/rand_chacha)
+- [API documentation (docs.rs)](https://docs.rs/rand_chacha)
+- [Changelog](CHANGELOG.md)
+
+[rand]: https://crates.io/crates/rand
+[^1]: D. J. Bernstein, [*ChaCha, a variant of Salsa20*](
+ https://cr.yp.to/chacha.html)
+
+[^2]: [eSTREAM: the ECRYPT Stream Cipher Project](
+ http://www.ecrypt.eu.org/stream/)
+
+
+## Crate Features
+
+`rand_chacha` is `no_std` compatible. It does not require any functionality
+outside of the `core` lib, thus there are no features to configure.
+
+
+# License
+
+`rand_chacha` is distributed under the terms of both the MIT license and the
+Apache License (Version 2.0).
+
+See [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT), and
+[COPYRIGHT](COPYRIGHT) for details.
diff --git a/rand/rand_chacha/build.rs b/rand/rand_chacha/build.rs
new file mode 100644
index 0000000..cb3ae20
--- /dev/null
+++ b/rand/rand_chacha/build.rs
@@ -0,0 +1,8 @@
+extern crate rustc_version;
+use rustc_version::{version, Version};
+
+fn main() {
+ if version().unwrap() >= Version::parse("1.26.0").unwrap() {
+ println!("cargo:rustc-cfg=rust_1_26");
+ }
+}
diff --git a/rand/rand_chacha/src/chacha.rs b/rand/rand_chacha/src/chacha.rs
new file mode 100644
index 0000000..3e90409
--- /dev/null
+++ b/rand/rand_chacha/src/chacha.rs
@@ -0,0 +1,449 @@
+// Copyright 2018 Developers of the Rand project.
+// Copyright 2014 The Rust Project Developers.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! The ChaCha random number generator.
+
+use core::fmt;
+use rand_core::{CryptoRng, RngCore, SeedableRng, Error, le};
+use rand_core::block::{BlockRngCore, BlockRng};
+
+const SEED_WORDS: usize = 8; // 8 words for the 256-bit key
+const STATE_WORDS: usize = 16;
+
+/// A cryptographically secure random number generator that uses the ChaCha
+/// algorithm.
+///
+/// ChaCha is a stream cipher designed by Daniel J. Bernstein[^1], that we use
+/// as an RNG. It is an improved variant of the Salsa20 cipher family, which was
+/// selected as one of the "stream ciphers suitable for widespread adoption" by
+/// eSTREAM[^2].
+///
+/// ChaCha uses add-rotate-xor (ARX) operations as its basis. These are safe
+/// against timing attacks, although that is mostly a concern for ciphers and
+/// not for RNGs. Also it is very suitable for SIMD implementation.
+/// Here we do not provide a SIMD implementation yet, except for what is
+/// provided by auto-vectorisation.
+///
+/// With the ChaCha algorithm it is possible to choose the number of rounds the
+/// core algorithm should run. The number of rounds is a tradeoff between
+/// performance and security, where 8 rounds is the minimum potentially
+/// secure configuration, and 20 rounds is widely used as a conservative choice.
+/// We use 20 rounds in this implementation, but hope to allow type-level
+/// configuration in the future.
+///
+/// We use a 64-bit counter and 64-bit stream identifier as in Bernstein's
+/// implementation[^1] except that we use a stream identifier in place of a
+/// nonce. A 64-bit counter over 64-byte (16 word) blocks allows 1 ZiB of output
+/// before cycling, and the stream identifier allows 2<sup>64</sup> unique
+/// streams of output per seed. Both counter and stream are initialized to zero
+/// but may be set via [`set_word_pos`] and [`set_stream`].
+///
+/// The word layout is:
+///
+/// ```text
+/// constant constant constant constant
+/// seed seed seed seed
+/// seed seed seed seed
+/// counter counter stream_id stream_id
+/// ```
+///
+/// This implementation uses an output buffer of sixteen `u32` words, and uses
+/// [`BlockRng`] to implement the [`RngCore`] methods.
+///
+/// [^1]: D. J. Bernstein, [*ChaCha, a variant of Salsa20*](
+/// https://cr.yp.to/chacha.html)
+///
+/// [^2]: [eSTREAM: the ECRYPT Stream Cipher Project](
+/// http://www.ecrypt.eu.org/stream/)
+///
+/// [`set_word_pos`]: #method.set_word_pos
+/// [`set_stream`]: #method.set_stream
+/// [`BlockRng`]: ../rand_core/block/struct.BlockRng.html
+/// [`RngCore`]: ../rand_core/trait.RngCore.html
+#[derive(Clone, Debug)]
+pub struct ChaChaRng(BlockRng<ChaChaCore>);
+
+impl RngCore for ChaChaRng {
+ #[inline]
+ fn next_u32(&mut self) -> u32 {
+ self.0.next_u32()
+ }
+
+ #[inline]
+ fn next_u64(&mut self) -> u64 {
+ self.0.next_u64()
+ }
+
+ #[inline]
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
+ self.0.fill_bytes(dest)
+ }
+
+ #[inline]
+ fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ self.0.try_fill_bytes(dest)
+ }
+}
+
+impl SeedableRng for ChaChaRng {
+ type Seed = <ChaChaCore as SeedableRng>::Seed;
+
+ fn from_seed(seed: Self::Seed) -> Self {
+ ChaChaRng(BlockRng::<ChaChaCore>::from_seed(seed))
+ }
+
+ fn from_rng<R: RngCore>(rng: R) -> Result<Self, Error> {
+ BlockRng::<ChaChaCore>::from_rng(rng).map(ChaChaRng)
+ }
+}
+
+impl CryptoRng for ChaChaRng {}
+
+impl ChaChaRng {
+ /// Get the offset from the start of the stream, in 32-bit words.
+ ///
+ /// Since the generated blocks are 16 words (2<sup>4</sup>) long and the
+ /// counter is 64-bits, the offset is a 68-bit number. Sub-word offsets are
+ /// not supported, hence the result can simply be multiplied by 4 to get a
+ /// byte-offset.
+ ///
+ /// Note: this function is currently only available with Rust 1.26 or later.
+ #[cfg(rust_1_26)]
+ pub fn get_word_pos(&self) -> u128 {
+ let mut c = (self.0.core.state[13] as u64) << 32
+ | (self.0.core.state[12] as u64);
+ let mut index = self.0.index();
+ // c is the end of the last block generated, unless index is at end
+ if index >= STATE_WORDS {
+ index = 0;
+ } else {
+ c = c.wrapping_sub(1);
+ }
+ ((c as u128) << 4) | (index as u128)
+ }
+
+ /// Set the offset from the start of the stream, in 32-bit words.
+ ///
+ /// As with `get_word_pos`, we use a 68-bit number. Since the generator
+ /// simply cycles at the end of its period (1 ZiB), we ignore the upper
+ /// 60 bits.
+ ///
+ /// Note: this function is currently only available with Rust 1.26 or later.
+ #[cfg(rust_1_26)]
+ pub fn set_word_pos(&mut self, word_offset: u128) {
+ let index = (word_offset as usize) & 0xF;
+ let counter = (word_offset >> 4) as u64;
+ self.0.core.state[12] = counter as u32;
+ self.0.core.state[13] = (counter >> 32) as u32;
+ if index != 0 {
+ self.0.generate_and_set(index); // also increments counter
+ } else {
+ self.0.reset();
+ }
+ }
+
+ /// Set the stream number.
+ ///
+ /// This is initialized to zero; 2<sup>64</sup> unique streams of output
+ /// are available per seed/key.
+ ///
+ /// Note that in order to reproduce ChaCha output with a specific 64-bit
+ /// nonce, one can convert that nonce to a `u64` in little-endian fashion
+ /// and pass to this function. In theory a 96-bit nonce can be used by
+ /// passing the last 64-bits to this function and using the first 32-bits as
+ /// the most significant half of the 64-bit counter (which may be set
+ /// indirectly via `set_word_pos`), but this is not directly supported.
+ pub fn set_stream(&mut self, stream: u64) {
+ let index = self.0.index();
+ self.0.core.state[14] = stream as u32;
+ self.0.core.state[15] = (stream >> 32) as u32;
+ if index < STATE_WORDS {
+ // we need to regenerate a partial result buffer
+ {
+ // reverse of counter adjustment in generate()
+ if self.0.core.state[12] == 0 {
+ self.0.core.state[13] = self.0.core.state[13].wrapping_sub(1);
+ }
+ self.0.core.state[12] = self.0.core.state[12].wrapping_sub(1);
+ }
+ self.0.generate_and_set(index);
+ }
+ }
+}
+
+/// The core of `ChaChaRng`, used with `BlockRng`.
+#[derive(Clone)]
+pub struct ChaChaCore {
+ state: [u32; STATE_WORDS],
+}
+
+// Custom Debug implementation that does not expose the internal state
+impl fmt::Debug for ChaChaCore {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "ChaChaCore {{}}")
+ }
+}
+
+macro_rules! quarter_round{
+ ($a: expr, $b: expr, $c: expr, $d: expr) => {{
+ $a = $a.wrapping_add($b); $d ^= $a; $d = $d.rotate_left(16);
+ $c = $c.wrapping_add($d); $b ^= $c; $b = $b.rotate_left(12);
+ $a = $a.wrapping_add($b); $d ^= $a; $d = $d.rotate_left( 8);
+ $c = $c.wrapping_add($d); $b ^= $c; $b = $b.rotate_left( 7);
+ }}
+}
+
+macro_rules! double_round{
+ ($x: expr) => {{
+ // Column round
+ quarter_round!($x[ 0], $x[ 4], $x[ 8], $x[12]);
+ quarter_round!($x[ 1], $x[ 5], $x[ 9], $x[13]);
+ quarter_round!($x[ 2], $x[ 6], $x[10], $x[14]);
+ quarter_round!($x[ 3], $x[ 7], $x[11], $x[15]);
+ // Diagonal round
+ quarter_round!($x[ 0], $x[ 5], $x[10], $x[15]);
+ quarter_round!($x[ 1], $x[ 6], $x[11], $x[12]);
+ quarter_round!($x[ 2], $x[ 7], $x[ 8], $x[13]);
+ quarter_round!($x[ 3], $x[ 4], $x[ 9], $x[14]);
+ }}
+}
+
+impl BlockRngCore for ChaChaCore {
+ type Item = u32;
+ type Results = [u32; STATE_WORDS];
+
+ fn generate(&mut self, results: &mut Self::Results) {
+ // For some reason extracting this part into a separate function
+ // improves performance by 50%.
+ fn core(results: &mut [u32; STATE_WORDS],
+ state: &[u32; STATE_WORDS])
+ {
+ let mut tmp = *state;
+ let rounds = 20;
+ for _ in 0..rounds / 2 {
+ double_round!(tmp);
+ }
+ for i in 0..STATE_WORDS {
+ results[i] = tmp[i].wrapping_add(state[i]);
+ }
+ }
+
+ core(results, &self.state);
+
+ // update 64-bit counter
+ self.state[12] = self.state[12].wrapping_add(1);
+ if self.state[12] != 0 { return; };
+ self.state[13] = self.state[13].wrapping_add(1);
+ }
+}
+
+impl SeedableRng for ChaChaCore {
+ type Seed = [u8; SEED_WORDS*4];
+
+ fn from_seed(seed: Self::Seed) -> Self {
+ let mut seed_le = [0u32; SEED_WORDS];
+ le::read_u32_into(&seed, &mut seed_le);
+ Self {
+ state: [0x61707865, 0x3320646E, 0x79622D32, 0x6B206574, // constants
+ seed_le[0], seed_le[1], seed_le[2], seed_le[3], // seed
+ seed_le[4], seed_le[5], seed_le[6], seed_le[7], // seed
+ 0, 0, 0, 0], // counter
+ }
+ }
+}
+
+impl CryptoRng for ChaChaCore {}
+
+impl From<ChaChaCore> for ChaChaRng {
+ fn from(core: ChaChaCore) -> Self {
+ ChaChaRng(BlockRng::new(core))
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use ::rand_core::{RngCore, SeedableRng};
+ use super::ChaChaRng;
+
+ #[test]
+ fn test_chacha_construction() {
+ let seed = [0,0,0,0,0,0,0,0,
+ 1,0,0,0,0,0,0,0,
+ 2,0,0,0,0,0,0,0,
+ 3,0,0,0,0,0,0,0];
+ let mut rng1 = ChaChaRng::from_seed(seed);
+ assert_eq!(rng1.next_u32(), 137206642);
+
+ let mut rng2 = ChaChaRng::from_rng(rng1).unwrap();
+ assert_eq!(rng2.next_u32(), 1325750369);
+ }
+
+ #[test]
+ fn test_chacha_true_values_a() {
+ // Test vectors 1 and 2 from
+ // https://tools.ietf.org/html/draft-nir-cfrg-chacha20-poly1305-04
+ let seed = [0u8; 32];
+ let mut rng = ChaChaRng::from_seed(seed);
+
+ let mut results = [0u32; 16];
+ for i in results.iter_mut() { *i = rng.next_u32(); }
+ let expected = [0xade0b876, 0x903df1a0, 0xe56a5d40, 0x28bd8653,
+ 0xb819d2bd, 0x1aed8da0, 0xccef36a8, 0xc70d778b,
+ 0x7c5941da, 0x8d485751, 0x3fe02477, 0x374ad8b8,
+ 0xf4b8436a, 0x1ca11815, 0x69b687c3, 0x8665eeb2];
+ assert_eq!(results, expected);
+
+ for i in results.iter_mut() { *i = rng.next_u32(); }
+ let expected = [0xbee7079f, 0x7a385155, 0x7c97ba98, 0x0d082d73,
+ 0xa0290fcb, 0x6965e348, 0x3e53c612, 0xed7aee32,
+ 0x7621b729, 0x434ee69c, 0xb03371d5, 0xd539d874,
+ 0x281fed31, 0x45fb0a51, 0x1f0ae1ac, 0x6f4d794b];
+ assert_eq!(results, expected);
+ }
+
+ #[test]
+ fn test_chacha_true_values_b() {
+ // Test vector 3 from
+ // https://tools.ietf.org/html/draft-nir-cfrg-chacha20-poly1305-04
+ let seed = [0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1];
+ let mut rng = ChaChaRng::from_seed(seed);
+
+ // Skip block 0
+ for _ in 0..16 { rng.next_u32(); }
+
+ let mut results = [0u32; 16];
+ for i in results.iter_mut() { *i = rng.next_u32(); }
+ let expected = [0x2452eb3a, 0x9249f8ec, 0x8d829d9b, 0xddd4ceb1,
+ 0xe8252083, 0x60818b01, 0xf38422b8, 0x5aaa49c9,
+ 0xbb00ca8e, 0xda3ba7b4, 0xc4b592d1, 0xfdf2732f,
+ 0x4436274e, 0x2561b3c8, 0xebdd4aa6, 0xa0136c00];
+ assert_eq!(results, expected);
+ }
+
+ #[test]
+ #[cfg(rust_1_26)]
+ fn test_chacha_true_values_c() {
+ // Test vector 4 from
+ // https://tools.ietf.org/html/draft-nir-cfrg-chacha20-poly1305-04
+ let seed = [0, 0xff, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0];
+ let expected = [0xfb4dd572, 0x4bc42ef1, 0xdf922636, 0x327f1394,
+ 0xa78dea8f, 0x5e269039, 0xa1bebbc1, 0xcaf09aae,
+ 0xa25ab213, 0x48a6b46c, 0x1b9d9bcb, 0x092c5be6,
+ 0x546ca624, 0x1bec45d5, 0x87f47473, 0x96f0992e];
+ let expected_end = 3 * 16;
+ let mut results = [0u32; 16];
+
+ // Test block 2 by skipping block 0 and 1
+ let mut rng1 = ChaChaRng::from_seed(seed);
+ for _ in 0..32 { rng1.next_u32(); }
+ for i in results.iter_mut() { *i = rng1.next_u32(); }
+ assert_eq!(results, expected);
+ assert_eq!(rng1.get_word_pos(), expected_end);
+
+ // Test block 2 by using `set_word_pos`
+ let mut rng2 = ChaChaRng::from_seed(seed);
+ rng2.set_word_pos(2 * 16);
+ for i in results.iter_mut() { *i = rng2.next_u32(); }
+ assert_eq!(results, expected);
+ assert_eq!(rng2.get_word_pos(), expected_end);
+
+ // Test skipping behaviour with other types
+ let mut buf = [0u8; 32];
+ rng2.fill_bytes(&mut buf[..]);
+ assert_eq!(rng2.get_word_pos(), expected_end + 8);
+ rng2.fill_bytes(&mut buf[0..25]);
+ assert_eq!(rng2.get_word_pos(), expected_end + 15);
+ rng2.next_u64();
+ assert_eq!(rng2.get_word_pos(), expected_end + 17);
+ rng2.next_u32();
+ rng2.next_u64();
+ assert_eq!(rng2.get_word_pos(), expected_end + 20);
+ rng2.fill_bytes(&mut buf[0..1]);
+ assert_eq!(rng2.get_word_pos(), expected_end + 21);
+ }
+
+ #[test]
+ fn test_chacha_multiple_blocks() {
+ let seed = [0,0,0,0, 1,0,0,0, 2,0,0,0, 3,0,0,0, 4,0,0,0, 5,0,0,0, 6,0,0,0, 7,0,0,0];
+ let mut rng = ChaChaRng::from_seed(seed);
+
+ // Store the 17*i-th 32-bit word,
+ // i.e., the i-th word of the i-th 16-word block
+ let mut results = [0u32; 16];
+ for i in results.iter_mut() {
+ *i = rng.next_u32();
+ for _ in 0..16 {
+ rng.next_u32();
+ }
+ }
+ let expected = [0xf225c81a, 0x6ab1be57, 0x04d42951, 0x70858036,
+ 0x49884684, 0x64efec72, 0x4be2d186, 0x3615b384,
+ 0x11cfa18e, 0xd3c50049, 0x75c775f6, 0x434c6530,
+ 0x2c5bad8f, 0x898881dc, 0x5f1c86d9, 0xc1f8e7f4];
+ assert_eq!(results, expected);
+ }
+
+ #[test]
+ fn test_chacha_true_bytes() {
+ let seed = [0u8; 32];
+ let mut rng = ChaChaRng::from_seed(seed);
+ let mut results = [0u8; 32];
+ rng.fill_bytes(&mut results);
+ let expected = [118, 184, 224, 173, 160, 241, 61, 144,
+ 64, 93, 106, 229, 83, 134, 189, 40,
+ 189, 210, 25, 184, 160, 141, 237, 26,
+ 168, 54, 239, 204, 139, 119, 13, 199];
+ assert_eq!(results, expected);
+ }
+
+ #[test]
+ fn test_chacha_nonce() {
+ // Test vector 5 from
+ // https://tools.ietf.org/html/draft-nir-cfrg-chacha20-poly1305-04
+ // Although we do not support setting a nonce, we try it here anyway so
+ // we can use this test vector.
+ let seed = [0u8; 32];
+ let mut rng = ChaChaRng::from_seed(seed);
+ // 96-bit nonce in LE order is: 0,0,0,0, 0,0,0,0, 0,0,0,2
+ rng.set_stream(2u64 << (24 + 32));
+
+ let mut results = [0u32; 16];
+ for i in results.iter_mut() { *i = rng.next_u32(); }
+ let expected = [0x374dc6c2, 0x3736d58c, 0xb904e24a, 0xcd3f93ef,
+ 0x88228b1a, 0x96a4dfb3, 0x5b76ab72, 0xc727ee54,
+ 0x0e0e978a, 0xf3145c95, 0x1b748ea8, 0xf786c297,
+ 0x99c28f5f, 0x628314e8, 0x398a19fa, 0x6ded1b53];
+ assert_eq!(results, expected);
+ }
+
+ #[test]
+ fn test_chacha_clone_streams() {
+ let seed = [0,0,0,0, 1,0,0,0, 2,0,0,0, 3,0,0,0, 4,0,0,0, 5,0,0,0, 6,0,0,0, 7,0,0,0];
+ let mut rng = ChaChaRng::from_seed(seed);
+ let mut clone = rng.clone();
+ for _ in 0..16 {
+ assert_eq!(rng.next_u64(), clone.next_u64());
+ }
+
+ rng.set_stream(51);
+ for _ in 0..7 {
+ assert!(rng.next_u32() != clone.next_u32());
+ }
+ clone.set_stream(51); // switch part way through block
+ for _ in 7..16 {
+ assert_eq!(rng.next_u32(), clone.next_u32());
+ }
+ }
+}
diff --git a/rand/rand_chacha/src/lib.rs b/rand/rand_chacha/src/lib.rs
new file mode 100644
index 0000000..8cff03a
--- /dev/null
+++ b/rand/rand_chacha/src/lib.rs
@@ -0,0 +1,25 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! The ChaCha random number generator.
+
+#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png",
+ html_favicon_url = "https://www.rust-lang.org/favicon.ico",
+ html_root_url = "https://rust-random.github.io/rand/")]
+
+#![deny(missing_docs)]
+#![deny(missing_debug_implementations)]
+#![doc(test(attr(allow(unused_variables), deny(warnings))))]
+
+#![no_std]
+
+extern crate rand_core;
+
+mod chacha;
+
+pub use chacha::{ChaChaRng, ChaChaCore};
diff --git a/rand/rand_core/CHANGELOG.md b/rand/rand_core/CHANGELOG.md
new file mode 100644
index 0000000..2cbb259
--- /dev/null
+++ b/rand/rand_core/CHANGELOG.md
@@ -0,0 +1,33 @@
+# Changelog
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+## [0.3.0] - 2018-09-24
+- Add `SeedableRng::seed_from_u64` for convenient seeding. (#537)
+
+## [0.2.1] - 2018-06-08
+- References to a `CryptoRng` now also implement `CryptoRng`. (#470)
+
+## [0.2.0] - 2018-05-21
+- Enable the `std` feature by default. (#409)
+- Remove `BlockRng{64}::inner` and `BlockRng::inner_mut`; instead making `core` public
+- Add `BlockRng{64}::index` and `BlockRng{64}::generate_and_set`. (#374, #419)
+- Change `BlockRngCore::Results` bound to also require `AsMut<[Self::Item]>`. (#419)
+- Implement `std::io::Read` for RngCore. (#434)
+
+## [0.1.0] - 2018-04-17
+(Split out of the Rand crate, changes here are relative to rand 0.4.2)
+- `RngCore` and `SeedableRng` are now part of `rand_core`. (#288)
+- Add modules to help implementing RNGs `impl` and `le`. (#209, #228)
+- Add `Error` and `ErrorKind`. (#225)
+- Add `CryptoRng` marker trait. (#273)
+- Add `BlockRngCore` trait. (#281)
+- Add `BlockRng` and `BlockRng64` wrappers to help implementations. (#281, #325)
+- Revise the `SeedableRng` trait. (#233)
+- Remove default implementations for `RngCore::next_u64` and `RngCore::fill_bytes`. (#288)
+- Add `RngCore::try_fill_bytes`. (#225)
+
+## [0.0.1] - 2017-09-14 (yanked)
+Experimental version as part of the rand crate refactor.
diff --git a/rand/rand_core/COPYRIGHT b/rand/rand_core/COPYRIGHT
new file mode 100644
index 0000000..468d907
--- /dev/null
+++ b/rand/rand_core/COPYRIGHT
@@ -0,0 +1,12 @@
+Copyrights in the Rand project are retained by their contributors. No
+copyright assignment is required to contribute to the Rand project.
+
+For full authorship information, see the version control history.
+
+Except as otherwise noted (below and/or in individual files), Rand is
+licensed under the Apache License, Version 2.0 <LICENSE-APACHE> or
+<http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+<LICENSE-MIT> or <http://opensource.org/licenses/MIT>, at your option.
+
+The Rand project includes code from the Rust project
+published under these same licenses.
diff --git a/rand/rand_core/Cargo.toml b/rand/rand_core/Cargo.toml
new file mode 100644
index 0000000..1678773
--- /dev/null
+++ b/rand/rand_core/Cargo.toml
@@ -0,0 +1,28 @@
+[package]
+name = "rand_core"
+version = "0.3.0"
+authors = ["The Rand Project Developers", "The Rust Project Developers"]
+license = "MIT/Apache-2.0"
+readme = "README.md"
+repository = "https://github.com/rust-random/rand"
+documentation = "https://rust-random.github.io/rand/rand_core"
+homepage = "https://crates.io/crates/rand_core"
+description = """
+Core random number generator traits and tools for implementation.
+"""
+keywords = ["random", "rng"]
+categories = ["algorithms", "no-std"]
+
+[badges]
+travis-ci = { repository = "rust-random/rand" }
+appveyor = { repository = "rust-random/rand" }
+
+[features]
+default = ["std"]
+std = ["alloc"] # use std library; should be default but for above bug
+alloc = [] # enables Vec and Box support without std
+serde1 = ["serde", "serde_derive"] # enables serde for BlockRng wrapper
+
+[dependencies]
+serde = { version = "1", optional = true }
+serde_derive = { version = "^1.0.38", optional = true }
diff --git a/rand/rand_core/LICENSE-APACHE b/rand/rand_core/LICENSE-APACHE
new file mode 100644
index 0000000..17d7468
--- /dev/null
+++ b/rand/rand_core/LICENSE-APACHE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ https://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/rand/rand_core/LICENSE-MIT b/rand/rand_core/LICENSE-MIT
new file mode 100644
index 0000000..d93b5ba
--- /dev/null
+++ b/rand/rand_core/LICENSE-MIT
@@ -0,0 +1,26 @@
+Copyright 2018 Developers of the Rand project
+Copyright (c) 2014 The Rust Project Developers
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/rand/rand_core/README.md b/rand/rand_core/README.md
new file mode 100644
index 0000000..dee6504
--- /dev/null
+++ b/rand/rand_core/README.md
@@ -0,0 +1,65 @@
+# rand_core
+
+[![Build Status](https://travis-ci.org/rust-random/rand.svg)](https://travis-ci.org/rust-random/rand)
+[![Build Status](https://ci.appveyor.com/api/projects/status/github/rust-random/rand?svg=true)](https://ci.appveyor.com/project/rust-random/rand)
+[![Latest version](https://img.shields.io/crates/v/rand_core.svg)](https://crates.io/crates/rand_core)
+[![Book](https://img.shields.io/badge/book-master-yellow.svg)](https://rust-random.github.io/book/)
+[![API](https://img.shields.io/badge/api-master-yellow.svg)](https://rust-random.github.io/rand/rand_core)
+[![API](https://docs.rs/rand_core/badge.svg)](https://docs.rs/rand_core)
+[![Minimum rustc version](https://img.shields.io/badge/rustc-1.22+-lightgray.svg)](https://github.com/rust-random/rand#rust-version-requirements)
+
+Core traits and error types of the [rand] library, plus tools for implementing
+RNGs.
+
+This crate is intended for use when implementing the core trait, `RngCore`; it
+defines the core traits to be implemented as well as several small functions to
+aid in their implementation and types required for error handling.
+
+The main [rand] crate re-exports most items defined in this crate, along with
+tools to convert the integer samples generated by `RngCore` to many different
+applications (including sampling from restricted ranges, conversion to floating
+point, list permutations and secure initialisation of RNGs). Most users should
+prefer to use the main [rand] crate.
+
+Links:
+
+- [API documentation (master)](https://rust-random.github.io/rand/rand_core)
+- [API documentation (docs.rs)](https://docs.rs/rand_core)
+- [Changelog](CHANGELOG.md)
+
+[rand]: https://crates.io/crates/rand
+
+
+## Functionality
+
+The `rand_core` crate provides:
+
+- base random number generator traits
+- error-reporting types
+- functionality to aid implementation of RNGs
+
+The traits and error types are also available via `rand`.
+
+## Crate Features
+
+`rand_core` supports `no_std` and `alloc`-only configurations, as well as full
+`std` functionality. The differences between `no_std` and full `std` are small,
+comprising `RngCore` support for `Box<R>` types where `R: RngCore`, as well as
+extensions to the `Error` type's functionality.
+
+Due to [rust-lang/cargo#1596](https://github.com/rust-lang/cargo/issues/1596),
+`rand_core` is built without `std` support by default. Since features are
+unioned across the whole dependency tree, any crate using `rand` with its
+default features will also enable `std` support in `rand_core`.
+
+The `serde1` feature can be used to derive `Serialize` and `Deserialize` for RNG
+implementations that use the `BlockRng` or `BlockRng64` wrappers.
+
+
+# License
+
+`rand_core` is distributed under the terms of both the MIT license and the
+Apache License (Version 2.0).
+
+See [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT), and
+[COPYRIGHT](COPYRIGHT) for details.
diff --git a/rand/rand_core/src/block.rs b/rand/rand_core/src/block.rs
new file mode 100644
index 0000000..de480e4
--- /dev/null
+++ b/rand/rand_core/src/block.rs
@@ -0,0 +1,508 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! The `BlockRngCore` trait and implementation helpers
+//!
+//! The [`BlockRngCore`] trait exists to assist in the implementation of RNGs
+//! which generate a block of data in a cache instead of returning generated
+//! values directly.
+//!
+//! Usage of this trait is optional, but provides two advantages:
+//! implementations only need to concern themselves with generation of the
+//! block, not the various [`RngCore`] methods (especially [`fill_bytes`], where
+//! the optimal implementations are not trivial), and this allows
+//! [`ReseedingRng`] perform periodic reseeding with very low overhead.
+//!
+//! # Example
+//!
+//! ```norun
+//! use rand_core::block::{BlockRngCore, BlockRng};
+//!
+//! struct MyRngCore;
+//!
+//! impl BlockRngCore for MyRngCore {
+//! type Results = [u32; 16];
+//!
+//! fn generate(&mut self, results: &mut Self::Results) {
+//! unimplemented!()
+//! }
+//! }
+//!
+//! impl SeedableRng for MyRngCore {
+//! type Seed = unimplemented!();
+//! fn from_seed(seed: Self::Seed) -> Self {
+//! unimplemented!()
+//! }
+//! }
+//!
+//! // optionally, also implement CryptoRng for MyRngCore
+//!
+//! // Final RNG.
+//! type MyRng = BlockRng<u32, MyRngCore>;
+//! ```
+//!
+//! [`BlockRngCore`]: trait.BlockRngCore.html
+//! [`RngCore`]: ../trait.RngCore.html
+//! [`fill_bytes`]: ../trait.RngCore.html#tymethod.fill_bytes
+//! [`ReseedingRng`]: ../../rand/rngs/adapter/struct.ReseedingRng.html
+
+use core::convert::AsRef;
+use core::fmt;
+use {RngCore, CryptoRng, SeedableRng, Error};
+use impls::{fill_via_u32_chunks, fill_via_u64_chunks};
+
+/// A trait for RNGs which do not generate random numbers individually, but in
+/// blocks (typically `[u32; N]`). This technique is commonly used by
+/// cryptographic RNGs to improve performance.
+///
+/// See the [module documentation](index.html) for details.
+pub trait BlockRngCore {
+ /// Results element type, e.g. `u32`.
+ type Item;
+
+ /// Results type. This is the 'block' an RNG implementing `BlockRngCore`
+ /// generates, which will usually be an array like `[u32; 16]`.
+ type Results: AsRef<[Self::Item]> + AsMut<[Self::Item]> + Default;
+
+ /// Generate a new block of results.
+ fn generate(&mut self, results: &mut Self::Results);
+}
+
+
+/// A wrapper type implementing [`RngCore`] for some type implementing
+/// [`BlockRngCore`] with `u32` array buffer; i.e. this can be used to implement
+/// a full RNG from just a `generate` function.
+///
+/// The `core` field may be accessed directly but the results buffer may not.
+/// PRNG implementations can simply use a type alias
+/// (`pub type MyRng = BlockRng<MyRngCore>;`) but might prefer to use a
+/// wrapper type (`pub struct MyRng(BlockRng<MyRngCore>);`); the latter must
+/// re-implement `RngCore` but hides the implementation details and allows
+/// extra functionality to be defined on the RNG
+/// (e.g. `impl MyRng { fn set_stream(...){...} }`).
+///
+/// `BlockRng` has heavily optimized implementations of the [`RngCore`] methods
+/// reading values from the results buffer, as well as
+/// calling [`BlockRngCore::generate`] directly on the output array when
+/// [`fill_bytes`] / [`try_fill_bytes`] is called on a large array. These methods
+/// also handle the bookkeeping of when to generate a new batch of values.
+///
+/// No whole generated `u32` values are thown away and all values are consumed
+/// in-order. [`next_u32`] simply takes the next available `u32` value.
+/// [`next_u64`] is implemented by combining two `u32` values, least
+/// significant first. [`fill_bytes`] and [`try_fill_bytes`] consume a whole
+/// number of `u32` values, converting each `u32` to a byte slice in
+/// little-endian order. If the requested byte length is not a multiple of 4,
+/// some bytes will be discarded.
+///
+/// See also [`BlockRng64`] which uses `u64` array buffers. Currently there is
+/// no direct support for other buffer types.
+///
+/// For easy initialization `BlockRng` also implements [`SeedableRng`].
+///
+/// [`BlockRngCore`]: BlockRngCore.t.html
+/// [`BlockRngCore::generate`]: trait.BlockRngCore.html#tymethod.generate
+/// [`BlockRng64`]: struct.BlockRng64.html
+/// [`RngCore`]: ../RngCore.t.html
+/// [`next_u32`]: ../trait.RngCore.html#tymethod.next_u32
+/// [`next_u64`]: ../trait.RngCore.html#tymethod.next_u64
+/// [`fill_bytes`]: ../trait.RngCore.html#tymethod.fill_bytes
+/// [`try_fill_bytes`]: ../trait.RngCore.html#tymethod.try_fill_bytes
+/// [`SeedableRng`]: ../SeedableRng.t.html
+#[derive(Clone)]
+#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))]
+pub struct BlockRng<R: BlockRngCore + ?Sized> {
+ results: R::Results,
+ index: usize,
+ /// The *core* part of the RNG, implementing the `generate` function.
+ pub core: R,
+}
+
+// Custom Debug implementation that does not expose the contents of `results`.
+impl<R: BlockRngCore + fmt::Debug> fmt::Debug for BlockRng<R> {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ fmt.debug_struct("BlockRng")
+ .field("core", &self.core)
+ .field("result_len", &self.results.as_ref().len())
+ .field("index", &self.index)
+ .finish()
+ }
+}
+
+impl<R: BlockRngCore> BlockRng<R> {
+ /// Create a new `BlockRng` from an existing RNG implementing
+ /// `BlockRngCore`. Results will be generated on first use.
+ pub fn new(core: R) -> BlockRng<R>{
+ let results_empty = R::Results::default();
+ BlockRng {
+ core,
+ index: results_empty.as_ref().len(),
+ results: results_empty,
+ }
+ }
+
+ /// Get the index into the result buffer.
+ ///
+ /// If this is equal to or larger than the size of the result buffer then
+ /// the buffer is "empty" and `generate()` must be called to produce new
+ /// results.
+ pub fn index(&self) -> usize {
+ self.index
+ }
+
+ /// Reset the number of available results.
+ /// This will force a new set of results to be generated on next use.
+ pub fn reset(&mut self) {
+ self.index = self.results.as_ref().len();
+ }
+
+ /// Generate a new set of results immediately, setting the index to the
+ /// given value.
+ pub fn generate_and_set(&mut self, index: usize) {
+ assert!(index < self.results.as_ref().len());
+ self.core.generate(&mut self.results);
+ self.index = index;
+ }
+}
+
+impl<R: BlockRngCore<Item=u32>> RngCore for BlockRng<R>
+where <R as BlockRngCore>::Results: AsRef<[u32]> + AsMut<[u32]>
+{
+ #[inline(always)]
+ fn next_u32(&mut self) -> u32 {
+ if self.index >= self.results.as_ref().len() {
+ self.generate_and_set(0);
+ }
+
+ let value = self.results.as_ref()[self.index];
+ self.index += 1;
+ value
+ }
+
+ #[inline(always)]
+ fn next_u64(&mut self) -> u64 {
+ let read_u64 = |results: &[u32], index| {
+ if cfg!(any(target_arch = "x86", target_arch = "x86_64")) {
+ // requires little-endian CPU supporting unaligned reads:
+ unsafe { *(&results[index] as *const u32 as *const u64) }
+ } else {
+ let x = u64::from(results[index]);
+ let y = u64::from(results[index + 1]);
+ (y << 32) | x
+ }
+ };
+
+ let len = self.results.as_ref().len();
+
+ let index = self.index;
+ if index < len-1 {
+ self.index += 2;
+ // Read an u64 from the current index
+ read_u64(self.results.as_ref(), index)
+ } else if index >= len {
+ self.generate_and_set(2);
+ read_u64(self.results.as_ref(), 0)
+ } else {
+ let x = u64::from(self.results.as_ref()[len-1]);
+ self.generate_and_set(1);
+ let y = u64::from(self.results.as_ref()[0]);
+ (y << 32) | x
+ }
+ }
+
+ // As an optimization we try to write directly into the output buffer.
+ // This is only enabled for little-endian platforms where unaligned writes
+ // are known to be safe and fast.
+ #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
+ let mut filled = 0;
+
+ // Continue filling from the current set of results
+ if self.index < self.results.as_ref().len() {
+ let (consumed_u32, filled_u8) =
+ fill_via_u32_chunks(&self.results.as_ref()[self.index..],
+ dest);
+
+ self.index += consumed_u32;
+ filled += filled_u8;
+ }
+
+ let len_remainder =
+ (dest.len() - filled) % (self.results.as_ref().len() * 4);
+ let end_direct = dest.len() - len_remainder;
+
+ while filled < end_direct {
+ let dest_u32: &mut R::Results = unsafe {
+ &mut *(dest[filled..].as_mut_ptr() as
+ *mut <R as BlockRngCore>::Results)
+ };
+ self.core.generate(dest_u32);
+ filled += self.results.as_ref().len() * 4;
+ self.index = self.results.as_ref().len();
+ }
+
+ if len_remainder > 0 {
+ self.core.generate(&mut self.results);
+ let (consumed_u32, _) =
+ fill_via_u32_chunks(self.results.as_ref(),
+ &mut dest[filled..]);
+
+ self.index = consumed_u32;
+ }
+ }
+
+ #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
+ let mut read_len = 0;
+ while read_len < dest.len() {
+ if self.index >= self.results.as_ref().len() {
+ self.generate_and_set(0);
+ }
+ let (consumed_u32, filled_u8) =
+ fill_via_u32_chunks(&self.results.as_ref()[self.index..],
+ &mut dest[read_len..]);
+
+ self.index += consumed_u32;
+ read_len += filled_u8;
+ }
+ }
+
+ fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ self.fill_bytes(dest);
+ Ok(())
+ }
+}
+
+impl<R: BlockRngCore + SeedableRng> SeedableRng for BlockRng<R> {
+ type Seed = R::Seed;
+
+ fn from_seed(seed: Self::Seed) -> Self {
+ Self::new(R::from_seed(seed))
+ }
+
+ fn seed_from_u64(seed: u64) -> Self {
+ Self::new(R::seed_from_u64(seed))
+ }
+
+ fn from_rng<S: RngCore>(rng: S) -> Result<Self, Error> {
+ Ok(Self::new(R::from_rng(rng)?))
+ }
+}
+
+
+
+/// A wrapper type implementing [`RngCore`] for some type implementing
+/// [`BlockRngCore`] with `u64` array buffer; i.e. this can be used to implement
+/// a full RNG from just a `generate` function.
+///
+/// This is similar to [`BlockRng`], but specialized for algorithms that operate
+/// on `u64` values.
+///
+/// No whole generated `u64` values are thrown away and all values are consumed
+/// in-order. [`next_u64`] simply takes the next available `u64` value.
+/// [`next_u32`] is however a bit special: half of a `u64` is consumed, leaving
+/// the other half in the buffer. If the next function called is [`next_u32`]
+/// then the other half is then consumed, however both [`next_u64`] and
+/// [`fill_bytes`] discard the rest of any half-consumed `u64`s when called.
+///
+/// [`fill_bytes`] and [`try_fill_bytes`] consume a whole number of `u64`
+/// values. If the requested length is not a multiple of 8, some bytes will be
+/// discarded.
+///
+/// [`BlockRngCore`]: BlockRngCore.t.html
+/// [`RngCore`]: ../RngCore.t.html
+/// [`next_u32`]: ../trait.RngCore.html#tymethod.next_u32
+/// [`next_u64`]: ../trait.RngCore.html#tymethod.next_u64
+/// [`fill_bytes`]: ../trait.RngCore.html#tymethod.fill_bytes
+/// [`try_fill_bytes`]: ../trait.RngCore.html#tymethod.try_fill_bytes
+/// [`BlockRng`]: struct.BlockRng.html
+#[derive(Clone)]
+#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))]
+pub struct BlockRng64<R: BlockRngCore + ?Sized> {
+ results: R::Results,
+ index: usize,
+ half_used: bool, // true if only half of the previous result is used
+ /// The *core* part of the RNG, implementing the `generate` function.
+ pub core: R,
+}
+
+// Custom Debug implementation that does not expose the contents of `results`.
+impl<R: BlockRngCore + fmt::Debug> fmt::Debug for BlockRng64<R> {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ fmt.debug_struct("BlockRng64")
+ .field("core", &self.core)
+ .field("result_len", &self.results.as_ref().len())
+ .field("index", &self.index)
+ .field("half_used", &self.half_used)
+ .finish()
+ }
+}
+
+impl<R: BlockRngCore> BlockRng64<R> {
+ /// Create a new `BlockRng` from an existing RNG implementing
+ /// `BlockRngCore`. Results will be generated on first use.
+ pub fn new(core: R) -> BlockRng64<R>{
+ let results_empty = R::Results::default();
+ BlockRng64 {
+ core,
+ index: results_empty.as_ref().len(),
+ half_used: false,
+ results: results_empty,
+ }
+ }
+
+ /// Get the index into the result buffer.
+ ///
+ /// If this is equal to or larger than the size of the result buffer then
+ /// the buffer is "empty" and `generate()` must be called to produce new
+ /// results.
+ pub fn index(&self) -> usize {
+ self.index
+ }
+
+ /// Reset the number of available results.
+ /// This will force a new set of results to be generated on next use.
+ pub fn reset(&mut self) {
+ self.index = self.results.as_ref().len();
+ self.half_used = false;
+ }
+
+ /// Generate a new set of results immediately, setting the index to the
+ /// given value.
+ pub fn generate_and_set(&mut self, index: usize) {
+ assert!(index < self.results.as_ref().len());
+ self.core.generate(&mut self.results);
+ self.index = index;
+ self.half_used = false;
+ }
+}
+
+impl<R: BlockRngCore<Item=u64>> RngCore for BlockRng64<R>
+where <R as BlockRngCore>::Results: AsRef<[u64]> + AsMut<[u64]>
+{
+ #[inline(always)]
+ fn next_u32(&mut self) -> u32 {
+ let mut index = self.index * 2 - self.half_used as usize;
+ if index >= self.results.as_ref().len() * 2 {
+ self.core.generate(&mut self.results);
+ self.index = 0;
+ // `self.half_used` is by definition `false`
+ self.half_used = false;
+ index = 0;
+ }
+
+ self.half_used = !self.half_used;
+ self.index += self.half_used as usize;
+
+ // Index as if this is a u32 slice.
+ unsafe {
+ let results =
+ &*(self.results.as_ref() as *const [u64] as *const [u32]);
+ if cfg!(target_endian = "little") {
+ *results.get_unchecked(index)
+ } else {
+ *results.get_unchecked(index ^ 1)
+ }
+ }
+ }
+
+ #[inline(always)]
+ fn next_u64(&mut self) -> u64 {
+ if self.index >= self.results.as_ref().len() {
+ self.core.generate(&mut self.results);
+ self.index = 0;
+ }
+
+ let value = self.results.as_ref()[self.index];
+ self.index += 1;
+ self.half_used = false;
+ value
+ }
+
+ // As an optimization we try to write directly into the output buffer.
+ // This is only enabled for little-endian platforms where unaligned writes
+ // are known to be safe and fast.
+ #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
+ let mut filled = 0;
+ self.half_used = false;
+
+ // Continue filling from the current set of results
+ if self.index < self.results.as_ref().len() {
+ let (consumed_u64, filled_u8) =
+ fill_via_u64_chunks(&self.results.as_ref()[self.index..],
+ dest);
+
+ self.index += consumed_u64;
+ filled += filled_u8;
+ }
+
+ let len_remainder =
+ (dest.len() - filled) % (self.results.as_ref().len() * 8);
+ let end_direct = dest.len() - len_remainder;
+
+ while filled < end_direct {
+ let dest_u64: &mut R::Results = unsafe {
+ ::core::mem::transmute(dest[filled..].as_mut_ptr())
+ };
+ self.core.generate(dest_u64);
+ filled += self.results.as_ref().len() * 8;
+ self.index = self.results.as_ref().len();
+ }
+
+ if len_remainder > 0 {
+ self.core.generate(&mut self.results);
+ let (consumed_u64, _) =
+ fill_via_u64_chunks(&mut self.results.as_ref(),
+ &mut dest[filled..]);
+
+ self.index = consumed_u64;
+ }
+ }
+
+ #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
+ let mut read_len = 0;
+ self.half_used = false;
+ while read_len < dest.len() {
+ if self.index as usize >= self.results.as_ref().len() {
+ self.core.generate(&mut self.results);
+ self.index = 0;
+ }
+
+ let (consumed_u64, filled_u8) =
+ fill_via_u64_chunks(&self.results.as_ref()[self.index as usize..],
+ &mut dest[read_len..]);
+
+ self.index += consumed_u64;
+ read_len += filled_u8;
+ }
+ }
+
+ fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ Ok(self.fill_bytes(dest))
+ }
+}
+
+impl<R: BlockRngCore + SeedableRng> SeedableRng for BlockRng64<R> {
+ type Seed = R::Seed;
+
+ fn from_seed(seed: Self::Seed) -> Self {
+ Self::new(R::from_seed(seed))
+ }
+
+ fn seed_from_u64(seed: u64) -> Self {
+ Self::new(R::seed_from_u64(seed))
+ }
+
+ fn from_rng<S: RngCore>(rng: S) -> Result<Self, Error> {
+ Ok(Self::new(R::from_rng(rng)?))
+ }
+}
+
+impl<R: BlockRngCore + CryptoRng> CryptoRng for BlockRng<R> {}
diff --git a/rand/rand_core/src/error.rs b/rand/rand_core/src/error.rs
new file mode 100644
index 0000000..5a8459e
--- /dev/null
+++ b/rand/rand_core/src/error.rs
@@ -0,0 +1,177 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Error types
+
+use core::fmt;
+
+#[cfg(feature="std")]
+use std::error::Error as stdError;
+#[cfg(feature="std")]
+use std::io;
+
+/// Error kind which can be matched over.
+#[derive(PartialEq, Eq, Debug, Copy, Clone)]
+pub enum ErrorKind {
+ /// Feature is not available; not recoverable.
+ ///
+ /// This is the most permanent failure type and implies the error cannot be
+ /// resolved simply by retrying (e.g. the feature may not exist in this
+ /// build of the application or on the current platform).
+ Unavailable,
+ /// General failure; there may be a chance of recovery on retry.
+ ///
+ /// This is the catch-all kind for errors from known and unknown sources
+ /// which do not have a more specific kind / handling method.
+ ///
+ /// It is suggested to retry a couple of times or retry later when
+ /// handling; some error sources may be able to resolve themselves,
+ /// although this is not likely.
+ Unexpected,
+ /// A transient failure which likely can be resolved or worked around.
+ ///
+ /// This error kind exists for a few specific cases where it is known that
+ /// the error likely can be resolved internally, but is reported anyway.
+ Transient,
+ /// Not ready yet: recommended to try again a little later.
+ ///
+ /// This error kind implies the generator needs more time or needs some
+ /// other part of the application to do something else first before it is
+ /// ready for use; for example this may be used by external generators
+ /// which require time for initialization.
+ NotReady,
+ #[doc(hidden)]
+ __Nonexhaustive,
+}
+
+impl ErrorKind {
+ /// True if this kind of error may resolve itself on retry.
+ ///
+ /// See also `should_wait()`.
+ pub fn should_retry(self) -> bool {
+ self != ErrorKind::Unavailable
+ }
+
+ /// True if we should retry but wait before retrying
+ ///
+ /// This implies `should_retry()` is true.
+ pub fn should_wait(self) -> bool {
+ self == ErrorKind::NotReady
+ }
+
+ /// A description of this error kind
+ pub fn description(self) -> &'static str {
+ match self {
+ ErrorKind::Unavailable => "permanently unavailable",
+ ErrorKind::Unexpected => "unexpected failure",
+ ErrorKind::Transient => "transient failure",
+ ErrorKind::NotReady => "not ready yet",
+ ErrorKind::__Nonexhaustive => unreachable!(),
+ }
+ }
+}
+
+
+/// Error type of random number generators
+///
+/// This is a relatively simple error type, designed for compatibility with and
+/// without the Rust `std` library. It embeds a "kind" code, a message (static
+/// string only), and an optional chained cause (`std` only). The `kind` and
+/// `msg` fields can be accessed directly; cause can be accessed via
+/// `std::error::Error::cause` or `Error::take_cause`. Construction can only be
+/// done via `Error::new` or `Error::with_cause`.
+#[derive(Debug)]
+pub struct Error {
+ /// The error kind
+ pub kind: ErrorKind,
+ /// The error message
+ pub msg: &'static str,
+ #[cfg(feature="std")]
+ cause: Option<Box<stdError + Send + Sync>>,
+}
+
+impl Error {
+ /// Create a new instance, with specified kind and a message.
+ pub fn new(kind: ErrorKind, msg: &'static str) -> Self {
+ #[cfg(feature="std")] {
+ Error { kind, msg, cause: None }
+ }
+ #[cfg(not(feature="std"))] {
+ Error { kind, msg }
+ }
+ }
+
+ /// Create a new instance, with specified kind, message, and a
+ /// chained cause.
+ ///
+ /// Note: `stdError` is an alias for `std::error::Error`.
+ ///
+ /// If not targetting `std` (i.e. `no_std`), this function is replaced by
+ /// another with the same prototype, except that there are no bounds on the
+ /// type `E` (because both `Box` and `stdError` are unavailable), and the
+ /// `cause` is ignored.
+ #[cfg(feature="std")]
+ pub fn with_cause<E>(kind: ErrorKind, msg: &'static str, cause: E) -> Self
+ where E: Into<Box<stdError + Send + Sync>>
+ {
+ Error { kind, msg, cause: Some(cause.into()) }
+ }
+
+ /// Create a new instance, with specified kind, message, and a
+ /// chained cause.
+ ///
+ /// In `no_std` mode the *cause* is ignored.
+ #[cfg(not(feature="std"))]
+ pub fn with_cause<E>(kind: ErrorKind, msg: &'static str, _cause: E) -> Self {
+ Error { kind, msg }
+ }
+
+ /// Take the cause, if any. This allows the embedded cause to be extracted.
+ /// This uses `Option::take`, leaving `self` with no cause.
+ #[cfg(feature="std")]
+ pub fn take_cause(&mut self) -> Option<Box<stdError + Send + Sync>> {
+ self.cause.take()
+ }
+}
+
+impl fmt::Display for Error {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ #[cfg(feature="std")] {
+ if let Some(ref cause) = self.cause {
+ return write!(f, "{} ({}); cause: {}",
+ self.msg, self.kind.description(), cause);
+ }
+ }
+ write!(f, "{} ({})", self.msg, self.kind.description())
+ }
+}
+
+#[cfg(feature="std")]
+impl stdError for Error {
+ fn description(&self) -> &str {
+ self.msg
+ }
+
+ fn cause(&self) -> Option<&stdError> {
+ self.cause.as_ref().map(|e| e.as_ref() as &stdError)
+ }
+}
+
+#[cfg(feature="std")]
+impl From<Error> for io::Error {
+ fn from(error: Error) -> Self {
+ use std::io::ErrorKind::*;
+ match error.kind {
+ ErrorKind::Unavailable => io::Error::new(NotFound, error),
+ ErrorKind::Unexpected |
+ ErrorKind::Transient => io::Error::new(Other, error),
+ ErrorKind::NotReady => io::Error::new(WouldBlock, error),
+ ErrorKind::__Nonexhaustive => unreachable!(),
+ }
+ }
+}
diff --git a/rand/rand_core/src/impls.rs b/rand/rand_core/src/impls.rs
new file mode 100644
index 0000000..57bdd07
--- /dev/null
+++ b/rand/rand_core/src/impls.rs
@@ -0,0 +1,165 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Helper functions for implementing `RngCore` functions.
+//!
+//! For cross-platform reproducibility, these functions all use Little Endian:
+//! least-significant part first. For example, `next_u64_via_u32` takes `u32`
+//! values `x, y`, then outputs `(y << 32) | x`. To implement `next_u32`
+//! from `next_u64` in little-endian order, one should use `next_u64() as u32`.
+//!
+//! Byte-swapping (like the std `to_le` functions) is only needed to convert
+//! to/from byte sequences, and since its purpose is reproducibility,
+//! non-reproducible sources (e.g. `OsRng`) need not bother with it.
+
+use core::intrinsics::transmute;
+use core::ptr::copy_nonoverlapping;
+use core::slice;
+use core::cmp::min;
+use core::mem::size_of;
+use RngCore;
+
+
+/// Implement `next_u64` via `next_u32`, little-endian order.
+pub fn next_u64_via_u32<R: RngCore + ?Sized>(rng: &mut R) -> u64 {
+ // Use LE; we explicitly generate one value before the next.
+ let x = u64::from(rng.next_u32());
+ let y = u64::from(rng.next_u32());
+ (y << 32) | x
+}
+
+/// Implement `fill_bytes` via `next_u64` and `next_u32`, little-endian order.
+///
+/// The fastest way to fill a slice is usually to work as long as possible with
+/// integers. That is why this method mostly uses `next_u64`, and only when
+/// there are 4 or less bytes remaining at the end of the slice it uses
+/// `next_u32` once.
+pub fn fill_bytes_via_next<R: RngCore + ?Sized>(rng: &mut R, dest: &mut [u8]) {
+ let mut left = dest;
+ while left.len() >= 8 {
+ let (l, r) = {left}.split_at_mut(8);
+ left = r;
+ let chunk: [u8; 8] = unsafe {
+ transmute(rng.next_u64().to_le())
+ };
+ l.copy_from_slice(&chunk);
+ }
+ let n = left.len();
+ if n > 4 {
+ let chunk: [u8; 8] = unsafe {
+ transmute(rng.next_u64().to_le())
+ };
+ left.copy_from_slice(&chunk[..n]);
+ } else if n > 0 {
+ let chunk: [u8; 4] = unsafe {
+ transmute(rng.next_u32().to_le())
+ };
+ left.copy_from_slice(&chunk[..n]);
+ }
+}
+
+macro_rules! impl_uint_from_fill {
+ ($rng:expr, $ty:ty, $N:expr) => ({
+ debug_assert!($N == size_of::<$ty>());
+
+ let mut int: $ty = 0;
+ unsafe {
+ let ptr = &mut int as *mut $ty as *mut u8;
+ let slice = slice::from_raw_parts_mut(ptr, $N);
+ $rng.fill_bytes(slice);
+ }
+ int
+ });
+}
+
+macro_rules! fill_via_chunks {
+ ($src:expr, $dst:expr, $ty:ty, $size:expr) => ({
+ let chunk_size_u8 = min($src.len() * $size, $dst.len());
+ let chunk_size = (chunk_size_u8 + $size - 1) / $size;
+ if cfg!(target_endian="little") {
+ unsafe {
+ copy_nonoverlapping(
+ $src.as_ptr() as *const u8,
+ $dst.as_mut_ptr(),
+ chunk_size_u8);
+ }
+ } else {
+ for (&n, chunk) in $src.iter().zip($dst.chunks_mut($size)) {
+ let tmp = n.to_le();
+ let src_ptr = &tmp as *const $ty as *const u8;
+ unsafe {
+ copy_nonoverlapping(src_ptr,
+ chunk.as_mut_ptr(),
+ chunk.len());
+ }
+ }
+ }
+
+ (chunk_size, chunk_size_u8)
+ });
+}
+
+/// Implement `fill_bytes` by reading chunks from the output buffer of a block
+/// based RNG.
+///
+/// The return values are `(consumed_u32, filled_u8)`.
+///
+/// `filled_u8` is the number of filled bytes in `dest`, which may be less than
+/// the length of `dest`.
+/// `consumed_u32` is the number of words consumed from `src`, which is the same
+/// as `filled_u8 / 4` rounded up.
+///
+/// # Example
+/// (from `IsaacRng`)
+///
+/// ```ignore
+/// fn fill_bytes(&mut self, dest: &mut [u8]) {
+/// let mut read_len = 0;
+/// while read_len < dest.len() {
+/// if self.index >= self.rsl.len() {
+/// self.isaac();
+/// }
+///
+/// let (consumed_u32, filled_u8) =
+/// impls::fill_via_u32_chunks(&mut self.rsl[self.index..],
+/// &mut dest[read_len..]);
+///
+/// self.index += consumed_u32;
+/// read_len += filled_u8;
+/// }
+/// }
+/// ```
+pub fn fill_via_u32_chunks(src: &[u32], dest: &mut [u8]) -> (usize, usize) {
+ fill_via_chunks!(src, dest, u32, 4)
+}
+
+/// Implement `fill_bytes` by reading chunks from the output buffer of a block
+/// based RNG.
+///
+/// The return values are `(consumed_u64, filled_u8)`.
+/// `filled_u8` is the number of filled bytes in `dest`, which may be less than
+/// the length of `dest`.
+/// `consumed_u64` is the number of words consumed from `src`, which is the same
+/// as `filled_u8 / 8` rounded up.
+///
+/// See `fill_via_u32_chunks` for an example.
+pub fn fill_via_u64_chunks(src: &[u64], dest: &mut [u8]) -> (usize, usize) {
+ fill_via_chunks!(src, dest, u64, 8)
+}
+
+/// Implement `next_u32` via `fill_bytes`, little-endian order.
+pub fn next_u32_via_fill<R: RngCore + ?Sized>(rng: &mut R) -> u32 {
+ impl_uint_from_fill!(rng, u32, 4)
+}
+
+/// Implement `next_u64` via `fill_bytes`, little-endian order.
+pub fn next_u64_via_fill<R: RngCore + ?Sized>(rng: &mut R) -> u64 {
+ impl_uint_from_fill!(rng, u64, 8)
+}
+
+// TODO: implement tests for the above
diff --git a/rand/rand_core/src/le.rs b/rand/rand_core/src/le.rs
new file mode 100644
index 0000000..266651f
--- /dev/null
+++ b/rand/rand_core/src/le.rs
@@ -0,0 +1,68 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Little-Endian utilities
+//!
+//! Little-Endian order has been chosen for internal usage; this makes some
+//! useful functions available.
+
+use core::ptr;
+
+macro_rules! read_slice {
+ ($src:expr, $dst:expr, $size:expr, $which:ident) => {{
+ assert_eq!($src.len(), $size * $dst.len());
+
+ unsafe {
+ ptr::copy_nonoverlapping(
+ $src.as_ptr(),
+ $dst.as_mut_ptr() as *mut u8,
+ $src.len());
+ }
+ for v in $dst.iter_mut() {
+ *v = v.$which();
+ }
+ }};
+}
+
+/// Reads unsigned 32 bit integers from `src` into `dst`.
+/// Borrowed from the `byteorder` crate.
+#[inline]
+pub fn read_u32_into(src: &[u8], dst: &mut [u32]) {
+ read_slice!(src, dst, 4, to_le);
+}
+
+/// Reads unsigned 64 bit integers from `src` into `dst`.
+/// Borrowed from the `byteorder` crate.
+#[inline]
+pub fn read_u64_into(src: &[u8], dst: &mut [u64]) {
+ read_slice!(src, dst, 8, to_le);
+}
+
+#[test]
+fn test_read() {
+ let bytes = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
+
+ let mut buf = [0u32; 4];
+ read_u32_into(&bytes, &mut buf);
+ assert_eq!(buf[0], 0x04030201);
+ assert_eq!(buf[3], 0x100F0E0D);
+
+ let mut buf = [0u32; 3];
+ read_u32_into(&bytes[1..13], &mut buf); // unaligned
+ assert_eq!(buf[0], 0x05040302);
+ assert_eq!(buf[2], 0x0D0C0B0A);
+
+ let mut buf = [0u64; 2];
+ read_u64_into(&bytes, &mut buf);
+ assert_eq!(buf[0], 0x0807060504030201);
+ assert_eq!(buf[1], 0x100F0E0D0C0B0A09);
+
+ let mut buf = [0u64; 1];
+ read_u64_into(&bytes[7..15], &mut buf); // unaligned
+ assert_eq!(buf[0], 0x0F0E0D0C0B0A0908);
+}
diff --git a/rand/rand_core/src/lib.rs b/rand/rand_core/src/lib.rs
new file mode 100644
index 0000000..a65db93
--- /dev/null
+++ b/rand/rand_core/src/lib.rs
@@ -0,0 +1,486 @@
+// Copyright 2018 Developers of the Rand project.
+// Copyright 2017-2018 The Rust Project Developers.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Random number generation traits
+//!
+//! This crate is mainly of interest to crates publishing implementations of
+//! [`RngCore`]. Other users are encouraged to use the [rand] crate instead
+//! which re-exports the main traits and error types.
+//!
+//! [`RngCore`] is the core trait implemented by algorithmic pseudo-random number
+//! generators and external random-number sources.
+//!
+//! [`SeedableRng`] is an extension trait for construction from fixed seeds and
+//! other random number generators.
+//!
+//! [`Error`] is provided for error-handling. It is safe to use in `no_std`
+//! environments.
+//!
+//! The [`impls`] and [`le`] sub-modules include a few small functions to assist
+//! implementation of [`RngCore`].
+//!
+//! [rand]: https://crates.io/crates/rand
+//! [`RngCore`]: trait.RngCore.html
+//! [`SeedableRng`]: trait.SeedableRng.html
+//! [`Error`]: struct.Error.html
+//! [`impls`]: impls/index.html
+//! [`le`]: le/index.html
+
+#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png",
+ html_favicon_url = "https://www.rust-lang.org/favicon.ico",
+ html_root_url = "https://rust-random.github.io/rand/")]
+
+#![deny(missing_docs)]
+#![deny(missing_debug_implementations)]
+#![doc(test(attr(allow(unused_variables), deny(warnings))))]
+
+#![cfg_attr(not(feature="std"), no_std)]
+#![cfg_attr(all(feature="alloc", not(feature="std")), feature(alloc))]
+
+#[cfg(feature="std")] extern crate core;
+#[cfg(all(feature = "alloc", not(feature="std")))] extern crate alloc;
+#[cfg(feature="serde1")] extern crate serde;
+#[cfg(feature="serde1")] #[macro_use] extern crate serde_derive;
+
+
+use core::default::Default;
+use core::convert::AsMut;
+use core::ptr::copy_nonoverlapping;
+
+#[cfg(all(feature="alloc", not(feature="std")))] use alloc::boxed::Box;
+
+pub use error::{ErrorKind, Error};
+
+
+mod error;
+pub mod block;
+pub mod impls;
+pub mod le;
+
+
+/// The core of a random number generator.
+///
+/// This trait encapsulates the low-level functionality common to all
+/// generators, and is the "back end", to be implemented by generators.
+/// End users should normally use [`Rng`] from the [rand] crate, which is
+/// automatically implemented for every type implementing `RngCore`.
+///
+/// Three different methods for generating random data are provided since the
+/// optimal implementation of each is dependent on the type of generator. There
+/// is no required relationship between the output of each; e.g. many
+/// implementations of [`fill_bytes`] consume a whole number of `u32` or `u64`
+/// values and drop any remaining unused bytes.
+///
+/// The [`try_fill_bytes`] method is a variant of [`fill_bytes`] allowing error
+/// handling; it is not deemed sufficiently useful to add equivalents for
+/// [`next_u32`] or [`next_u64`] since the latter methods are almost always used
+/// with algorithmic generators (PRNGs), which are normally infallible.
+///
+/// Algorithmic generators implementing [`SeedableRng`] should normally have
+/// *portable, reproducible* output, i.e. fix Endianness when converting values
+/// to avoid platform differences, and avoid making any changes which affect
+/// output (except by communicating that the release has breaking changes).
+///
+/// Typically implementators will implement only one of the methods available
+/// in this trait directly, then use the helper functions from the
+/// [`rand_core::impls`] module to implement the other methods.
+///
+/// It is recommended that implementations also implement:
+///
+/// - `Debug` with a custom implementation which *does not* print any internal
+/// state (at least, [`CryptoRng`]s should not risk leaking state through
+/// `Debug`).
+/// - `Serialize` and `Deserialize` (from Serde), preferably making Serde
+/// support optional at the crate level in PRNG libs.
+/// - `Clone`, if possible.
+/// - *never* implement `Copy` (accidental copies may cause repeated values).
+/// - *do not* implement `Default` for pseudorandom generators, but instead
+/// implement [`SeedableRng`], to guide users towards proper seeding.
+/// External / hardware RNGs can choose to implement `Default`.
+/// - `Eq` and `PartialEq` could be implemented, but are probably not useful.
+///
+/// # Example
+///
+/// A simple example, obviously not generating very *random* output:
+///
+/// ```
+/// #![allow(dead_code)]
+/// use rand_core::{RngCore, Error, impls};
+///
+/// struct CountingRng(u64);
+///
+/// impl RngCore for CountingRng {
+/// fn next_u32(&mut self) -> u32 {
+/// self.next_u64() as u32
+/// }
+///
+/// fn next_u64(&mut self) -> u64 {
+/// self.0 += 1;
+/// self.0
+/// }
+///
+/// fn fill_bytes(&mut self, dest: &mut [u8]) {
+/// impls::fill_bytes_via_next(self, dest)
+/// }
+///
+/// fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+/// Ok(self.fill_bytes(dest))
+/// }
+/// }
+/// ```
+///
+/// [rand]: https://crates.io/crates/rand
+/// [`Rng`]: ../rand/trait.Rng.html
+/// [`SeedableRng`]: trait.SeedableRng.html
+/// [`rand_core::impls`]: ../rand_core/impls/index.html
+/// [`try_fill_bytes`]: trait.RngCore.html#tymethod.try_fill_bytes
+/// [`fill_bytes`]: trait.RngCore.html#tymethod.fill_bytes
+/// [`next_u32`]: trait.RngCore.html#tymethod.next_u32
+/// [`next_u64`]: trait.RngCore.html#tymethod.next_u64
+/// [`CryptoRng`]: trait.CryptoRng.html
+pub trait RngCore {
+ /// Return the next random `u32`.
+ ///
+ /// RNGs must implement at least one method from this trait directly. In
+ /// the case this method is not implemented directly, it can be implemented
+ /// using `self.next_u64() as u32` or
+ /// [via `fill_bytes`](../rand_core/impls/fn.next_u32_via_fill.html).
+ fn next_u32(&mut self) -> u32;
+
+ /// Return the next random `u64`.
+ ///
+ /// RNGs must implement at least one method from this trait directly. In
+ /// the case this method is not implemented directly, it can be implemented
+ /// [via `next_u32`](../rand_core/impls/fn.next_u64_via_u32.html) or
+ /// [via `fill_bytes`](../rand_core/impls/fn.next_u64_via_fill.html).
+ fn next_u64(&mut self) -> u64;
+
+ /// Fill `dest` with random data.
+ ///
+ /// RNGs must implement at least one method from this trait directly. In
+ /// the case this method is not implemented directly, it can be implemented
+ /// [via `next_u*`](../rand_core/impls/fn.fill_bytes_via_next.html) or
+ /// via `try_fill_bytes`; if this generator can fail the implementation
+ /// must choose how best to handle errors here (e.g. panic with a
+ /// descriptive message or log a warning and retry a few times).
+ ///
+ /// This method should guarantee that `dest` is entirely filled
+ /// with new data, and may panic if this is impossible
+ /// (e.g. reading past the end of a file that is being used as the
+ /// source of randomness).
+ fn fill_bytes(&mut self, dest: &mut [u8]);
+
+ /// Fill `dest` entirely with random data.
+ ///
+ /// This is the only method which allows an RNG to report errors while
+ /// generating random data thus making this the primary method implemented
+ /// by external (true) RNGs (e.g. `OsRng`) which can fail. It may be used
+ /// directly to generate keys and to seed (infallible) PRNGs.
+ ///
+ /// Other than error handling, this method is identical to [`fill_bytes`];
+ /// thus this may be implemented using `Ok(self.fill_bytes(dest))` or
+ /// `fill_bytes` may be implemented with
+ /// `self.try_fill_bytes(dest).unwrap()` or more specific error handling.
+ ///
+ /// [`fill_bytes`]: trait.RngCore.html#method.fill_bytes
+ fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error>;
+}
+
+/// A marker trait used to indicate that an [`RngCore`] or [`BlockRngCore`]
+/// implementation is supposed to be cryptographically secure.
+///
+/// *Cryptographically secure generators*, also known as *CSPRNGs*, should
+/// satisfy an additional properties over other generators: given the first
+/// *k* bits of an algorithm's output
+/// sequence, it should not be possible using polynomial-time algorithms to
+/// predict the next bit with probability significantly greater than 50%.
+///
+/// Some generators may satisfy an additional property, however this is not
+/// required by this trait: if the CSPRNG's state is revealed, it should not be
+/// computationally-feasible to reconstruct output prior to this. Some other
+/// generators allow backwards-computation and are consided *reversible*.
+///
+/// Note that this trait is provided for guidance only and cannot guarantee
+/// suitability for cryptographic applications. In general it should only be
+/// implemented for well-reviewed code implementing well-regarded algorithms.
+///
+/// Note also that use of a `CryptoRng` does not protect against other
+/// weaknesses such as seeding from a weak entropy source or leaking state.
+///
+/// [`RngCore`]: trait.RngCore.html
+/// [`BlockRngCore`]: ../rand_core/block/trait.BlockRngCore.html
+pub trait CryptoRng {}
+
+/// A random number generator that can be explicitly seeded.
+///
+/// This trait encapsulates the low-level functionality common to all
+/// pseudo-random number generators (PRNGs, or algorithmic generators).
+///
+/// The [`rand::FromEntropy`] trait is automatically implemented for every type
+/// implementing `SeedableRng`, providing a convenient `from_entropy()`
+/// constructor.
+///
+/// [`rand::FromEntropy`]: ../rand/trait.FromEntropy.html
+pub trait SeedableRng: Sized {
+ /// Seed type, which is restricted to types mutably-dereferencable as `u8`
+ /// arrays (we recommend `[u8; N]` for some `N`).
+ ///
+ /// It is recommended to seed PRNGs with a seed of at least circa 100 bits,
+ /// which means an array of `[u8; 12]` or greater to avoid picking RNGs with
+ /// partially overlapping periods.
+ ///
+ /// For cryptographic RNG's a seed of 256 bits is recommended, `[u8; 32]`.
+ ///
+ ///
+ /// # Implementing `SeedableRng` for RNGs with large seeds
+ ///
+ /// Note that the required traits `core::default::Default` and
+ /// `core::convert::AsMut<u8>` are not implemented for large arrays
+ /// `[u8; N]` with `N` > 32. To be able to implement the traits required by
+ /// `SeedableRng` for RNGs with such large seeds, the newtype pattern can be
+ /// used:
+ ///
+ /// ```
+ /// use rand_core::SeedableRng;
+ ///
+ /// const N: usize = 64;
+ /// pub struct MyRngSeed(pub [u8; N]);
+ /// pub struct MyRng(MyRngSeed);
+ ///
+ /// impl Default for MyRngSeed {
+ /// fn default() -> MyRngSeed {
+ /// MyRngSeed([0; N])
+ /// }
+ /// }
+ ///
+ /// impl AsMut<[u8]> for MyRngSeed {
+ /// fn as_mut(&mut self) -> &mut [u8] {
+ /// &mut self.0
+ /// }
+ /// }
+ ///
+ /// impl SeedableRng for MyRng {
+ /// type Seed = MyRngSeed;
+ ///
+ /// fn from_seed(seed: MyRngSeed) -> MyRng {
+ /// MyRng(seed)
+ /// }
+ /// }
+ /// ```
+ type Seed: Sized + Default + AsMut<[u8]>;
+
+ /// Create a new PRNG using the given seed.
+ ///
+ /// PRNG implementations are allowed to assume that bits in the seed are
+ /// well distributed. That means usually that the number of one and zero
+ /// bits are about equal, and values like 0, 1 and (size - 1) are unlikely.
+ ///
+ /// PRNG implementations are recommended to be reproducible. A PRNG seeded
+ /// using this function with a fixed seed should produce the same sequence
+ /// of output in the future and on different architectures (with for example
+ /// different endianness).
+ ///
+ /// It is however not required that this function yield the same state as a
+ /// reference implementation of the PRNG given equivalent seed; if necessary
+ /// another constructor replicating behaviour from a reference
+ /// implementation can be added.
+ ///
+ /// PRNG implementations should make sure `from_seed` never panics. In the
+ /// case that some special values (like an all zero seed) are not viable
+ /// seeds it is preferable to map these to alternative constant value(s),
+ /// for example `0xBAD5EEDu32` or `0x0DDB1A5E5BAD5EEDu64` ("odd biases? bad
+ /// seed"). This is assuming only a small number of values must be rejected.
+ fn from_seed(seed: Self::Seed) -> Self;
+
+ /// Create a new PRNG using a `u64` seed.
+ ///
+ /// This is a convenience-wrapper around `from_seed` to allow construction
+ /// of any `SeedableRng` from a simple `u64` value. It is designed such that
+ /// low Hamming Weight numbers like 0 and 1 can be used and should still
+ /// result in good, independent seeds to the PRNG which is returned.
+ ///
+ /// This **is not suitable for cryptography**, as should be clear given that
+ /// the input size is only 64 bits.
+ ///
+ /// Implementations for PRNGs *may* provide their own implementations of
+ /// this function, but the default implementation should be good enough for
+ /// all purposes. *Changing* the implementation of this function should be
+ /// considered a value-breaking change.
+ fn seed_from_u64(mut state: u64) -> Self {
+ // We use PCG32 to generate a u32 sequence, and copy to the seed
+ const MUL: u64 = 6364136223846793005;
+ const INC: u64 = 11634580027462260723;
+
+ let mut seed = Self::Seed::default();
+ for chunk in seed.as_mut().chunks_mut(4) {
+ // We advance the state first (to get away from the input value,
+ // in case it has low Hamming Weight).
+ state = state.wrapping_mul(MUL).wrapping_add(INC);
+
+ // Use PCG output function with to_le to generate x:
+ let xorshifted = (((state >> 18) ^ state) >> 27) as u32;
+ let rot = (state >> 59) as u32;
+ let x = xorshifted.rotate_right(rot).to_le();
+
+ unsafe {
+ let p = &x as *const u32 as *const u8;
+ copy_nonoverlapping(p, chunk.as_mut_ptr(), chunk.len());
+ }
+ }
+
+ Self::from_seed(seed)
+ }
+
+ /// Create a new PRNG seeded from another `Rng`.
+ ///
+ /// This is the recommended way to initialize PRNGs with fresh entropy. The
+ /// [`FromEntropy`] trait provides a convenient `from_entropy` method
+ /// based on `from_rng`.
+ ///
+ /// Usage of this method is not recommended when reproducibility is required
+ /// since implementing PRNGs are not required to fix Endianness and are
+ /// allowed to modify implementations in new releases.
+ ///
+ /// It is important to use a good source of randomness to initialize the
+ /// PRNG. Cryptographic PRNG may be rendered insecure when seeded from a
+ /// non-cryptographic PRNG or with insufficient entropy.
+ /// Many non-cryptographic PRNGs will show statistical bias in their first
+ /// results if their seed numbers are small or if there is a simple pattern
+ /// between them.
+ ///
+ /// Prefer to seed from a strong external entropy source like [`OsRng`] or
+ /// from a cryptographic PRNG; if creating a new generator for cryptographic
+ /// uses you *must* seed from a strong source.
+ ///
+ /// Seeding a small PRNG from another small PRNG is possible, but
+ /// something to be careful with. An extreme example of how this can go
+ /// wrong is seeding an Xorshift RNG from another Xorshift RNG, which
+ /// will effectively clone the generator. In general seeding from a
+ /// generator which is hard to predict is probably okay.
+ ///
+ /// PRNG implementations are allowed to assume that a good RNG is provided
+ /// for seeding, and that it is cryptographically secure when appropriate.
+ ///
+ /// [`FromEntropy`]: ../rand/trait.FromEntropy.html
+ /// [`OsRng`]: ../rand/rngs/struct.OsRng.html
+ fn from_rng<R: RngCore>(mut rng: R) -> Result<Self, Error> {
+ let mut seed = Self::Seed::default();
+ rng.try_fill_bytes(seed.as_mut())?;
+ Ok(Self::from_seed(seed))
+ }
+}
+
+// Implement `RngCore` for references to an `RngCore`.
+// Force inlining all functions, so that it is up to the `RngCore`
+// implementation and the optimizer to decide on inlining.
+impl<'a, R: RngCore + ?Sized> RngCore for &'a mut R {
+ #[inline(always)]
+ fn next_u32(&mut self) -> u32 {
+ (**self).next_u32()
+ }
+
+ #[inline(always)]
+ fn next_u64(&mut self) -> u64 {
+ (**self).next_u64()
+ }
+
+ #[inline(always)]
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
+ (**self).fill_bytes(dest)
+ }
+
+ #[inline(always)]
+ fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ (**self).try_fill_bytes(dest)
+ }
+}
+
+// Implement `RngCore` for boxed references to an `RngCore`.
+// Force inlining all functions, so that it is up to the `RngCore`
+// implementation and the optimizer to decide on inlining.
+#[cfg(feature="alloc")]
+impl<R: RngCore + ?Sized> RngCore for Box<R> {
+ #[inline(always)]
+ fn next_u32(&mut self) -> u32 {
+ (**self).next_u32()
+ }
+
+ #[inline(always)]
+ fn next_u64(&mut self) -> u64 {
+ (**self).next_u64()
+ }
+
+ #[inline(always)]
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
+ (**self).fill_bytes(dest)
+ }
+
+ #[inline(always)]
+ fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ (**self).try_fill_bytes(dest)
+ }
+}
+
+#[cfg(feature="std")]
+impl std::io::Read for RngCore {
+ fn read(&mut self, buf: &mut [u8]) -> Result<usize, std::io::Error> {
+ self.try_fill_bytes(buf)?;
+ Ok(buf.len())
+ }
+}
+
+// Implement `CryptoRng` for references to an `CryptoRng`.
+impl<'a, R: CryptoRng + ?Sized> CryptoRng for &'a mut R {}
+
+// Implement `CryptoRng` for boxed references to an `CryptoRng`.
+#[cfg(feature="alloc")]
+impl<R: CryptoRng + ?Sized> CryptoRng for Box<R> {}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+
+ #[test]
+ fn test_seed_from_u64() {
+ struct SeedableNum(u64);
+ impl SeedableRng for SeedableNum {
+ type Seed = [u8; 8];
+ fn from_seed(seed: Self::Seed) -> Self {
+ let mut x = [0u64; 1];
+ le::read_u64_into(&seed, &mut x);
+ SeedableNum(x[0])
+ }
+ }
+
+ const N: usize = 8;
+ const SEEDS: [u64; N] = [0u64, 1, 2, 3, 4, 8, 16, -1i64 as u64];
+ let mut results = [0u64; N];
+ for (i, seed) in SEEDS.iter().enumerate() {
+ let SeedableNum(x) = SeedableNum::seed_from_u64(*seed);
+ results[i] = x;
+ }
+
+ for (i1, r1) in results.iter().enumerate() {
+ let weight = r1.count_ones();
+ // This is the binomial distribution B(64, 0.5), so chance of
+ // weight < 20 is binocdf(19, 64, 0.5) = 7.8e-4, and same for
+ // weight > 44.
+ assert!(weight >= 20 && weight <= 44);
+
+ for (i2, r2) in results.iter().enumerate() {
+ if i1 == i2 { continue; }
+ let diff_weight = (r1 ^ r2).count_ones();
+ assert!(diff_weight >= 20);
+ }
+ }
+
+ // value-breakage test:
+ assert_eq!(results[0], 5029875928683246316);
+ }
+}
diff --git a/rand/rand_hc/CHANGELOG.md b/rand/rand_hc/CHANGELOG.md
new file mode 100644
index 0000000..d0c4a2f
--- /dev/null
+++ b/rand/rand_hc/CHANGELOG.md
@@ -0,0 +1,8 @@
+# Changelog
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+## [0.1.0] - 2018-10-17
+- Pulled out of the Rand crate
diff --git a/rand/rand_hc/COPYRIGHT b/rand/rand_hc/COPYRIGHT
new file mode 100644
index 0000000..468d907
--- /dev/null
+++ b/rand/rand_hc/COPYRIGHT
@@ -0,0 +1,12 @@
+Copyrights in the Rand project are retained by their contributors. No
+copyright assignment is required to contribute to the Rand project.
+
+For full authorship information, see the version control history.
+
+Except as otherwise noted (below and/or in individual files), Rand is
+licensed under the Apache License, Version 2.0 <LICENSE-APACHE> or
+<http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+<LICENSE-MIT> or <http://opensource.org/licenses/MIT>, at your option.
+
+The Rand project includes code from the Rust project
+published under these same licenses.
diff --git a/rand/rand_hc/Cargo.toml b/rand/rand_hc/Cargo.toml
new file mode 100644
index 0000000..ed5dd5b
--- /dev/null
+++ b/rand/rand_hc/Cargo.toml
@@ -0,0 +1,21 @@
+[package]
+name = "rand_hc"
+version = "0.1.0"
+authors = ["The Rand Project Developers"]
+license = "MIT/Apache-2.0"
+readme = "README.md"
+repository = "https://github.com/rust-random/rand"
+documentation = "https://rust-random.github.io/rand/rand_hc"
+homepage = "https://crates.io/crates/rand_hc"
+description = """
+HC128 random number generator
+"""
+keywords = ["random", "rng", "hc128"]
+categories = ["algorithms", "no-std"]
+
+[badges]
+travis-ci = { repository = "rust-random/rand" }
+appveyor = { repository = "rust-random/rand" }
+
+[dependencies]
+rand_core = { path = "../rand_core", version = ">=0.2, <0.4", default-features=false }
diff --git a/rand/rand_hc/LICENSE-APACHE b/rand/rand_hc/LICENSE-APACHE
new file mode 100644
index 0000000..17d7468
--- /dev/null
+++ b/rand/rand_hc/LICENSE-APACHE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ https://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/rand/rand_hc/LICENSE-MIT b/rand/rand_hc/LICENSE-MIT
new file mode 100644
index 0000000..cf65607
--- /dev/null
+++ b/rand/rand_hc/LICENSE-MIT
@@ -0,0 +1,25 @@
+Copyright 2018 Developers of the Rand project
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/rand/rand_hc/README.md b/rand/rand_hc/README.md
new file mode 100644
index 0000000..178548a
--- /dev/null
+++ b/rand/rand_hc/README.md
@@ -0,0 +1,45 @@
+# rand_hc
+
+[![Build Status](https://travis-ci.org/rust-random/rand.svg)](https://travis-ci.org/rust-random/rand)
+[![Build Status](https://ci.appveyor.com/api/projects/status/github/rust-random/rand?svg=true)](https://ci.appveyor.com/project/rust-random/rand)
+[![Latest version](https://img.shields.io/crates/v/rand_hc.svg)](https://crates.io/crates/rand_hc)
+[[![Book](https://img.shields.io/badge/book-master-yellow.svg)](https://rust-random.github.io/book/)
+[![API](https://img.shields.io/badge/api-master-yellow.svg)](https://rust-random.github.io/rand/rand_hc)
+[![API](https://docs.rs/rand_hc/badge.svg)](https://docs.rs/rand_hc)
+[![Minimum rustc version](https://img.shields.io/badge/rustc-1.22+-lightgray.svg)](https://github.com/rust-random/rand#rust-version-requirements)
+
+A cryptographically secure random number generator that uses the HC-128
+algorithm.
+
+HC-128 is a stream cipher designed by Hongjun Wu[^1], that we use as an
+RNG. It is selected as one of the "stream ciphers suitable for widespread
+adoption" by eSTREAM[^2].
+
+Links:
+
+- [API documentation (master)](https://rust-random.github.io/rand/rand_hc)
+- [API documentation (docs.rs)](https://docs.rs/rand_hc)
+- [Changelog](CHANGELOG.md)
+
+[rand]: https://crates.io/crates/rand
+[^1]: Hongjun Wu (2008). ["The Stream Cipher HC-128"](
+ http://www.ecrypt.eu.org/stream/p3ciphers/hc/hc128_p3.pdf).
+ *The eSTREAM Finalists*, LNCS 4986, pp. 39–47, Springer-Verlag.
+
+[^2]: [eSTREAM: the ECRYPT Stream Cipher Project](
+ http://www.ecrypt.eu.org/stream/)
+
+
+## Crate Features
+
+`rand_hc` is `no_std` compatible. It does not require any functionality
+outside of the `core` lib, thus there are no features to configure.
+
+
+# License
+
+`rand_hc` is distributed under the terms of both the MIT license and the
+Apache License (Version 2.0).
+
+See [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT), and
+[COPYRIGHT](COPYRIGHT) for details.
diff --git a/rand/rand_hc/src/hc128.rs b/rand/rand_hc/src/hc128.rs
new file mode 100644
index 0000000..d1dadcc
--- /dev/null
+++ b/rand/rand_hc/src/hc128.rs
@@ -0,0 +1,462 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! The HC-128 random number generator.
+
+use core::fmt;
+use rand_core::{CryptoRng, RngCore, SeedableRng, Error, le};
+use rand_core::block::{BlockRngCore, BlockRng};
+
+const SEED_WORDS: usize = 8; // 128 bit key followed by 128 bit iv
+
+/// A cryptographically secure random number generator that uses the HC-128
+/// algorithm.
+///
+/// HC-128 is a stream cipher designed by Hongjun Wu[^1], that we use as an
+/// RNG. It is selected as one of the "stream ciphers suitable for widespread
+/// adoption" by eSTREAM[^2].
+///
+/// HC-128 is an array based RNG. In this it is similar to RC-4 and ISAAC before
+/// it, but those have never been proven cryptographically secure (or have even
+/// been significantly compromised, as in the case of RC-4[^5]).
+///
+/// Because HC-128 works with simple indexing into a large array and with a few
+/// operations that parallelize well, it has very good performance. The size of
+/// the array it needs, 4kb, can however be a disadvantage.
+///
+/// This implementation is not based on the version of HC-128 submitted to the
+/// eSTREAM contest, but on a later version by the author with a few small
+/// improvements from December 15, 2009[^3].
+///
+/// HC-128 has no known weaknesses that are easier to exploit than doing a
+/// brute-force search of 2<sup>128</sup>. A very comprehensive analysis of the
+/// current state of known attacks / weaknesses of HC-128 is given in *Some
+/// Results On Analysis And Implementation Of HC-128 Stream Cipher*[^4].
+///
+/// The average cycle length is expected to be
+/// 2<sup>1024*32+10-1</sup> = 2<sup>32777</sup>.
+/// We support seeding with a 256-bit array, which matches the 128-bit key
+/// concatenated with a 128-bit IV from the stream cipher.
+///
+/// This implementation uses an output buffer of sixteen `u32` words, and uses
+/// [`BlockRng`] to implement the [`RngCore`] methods.
+///
+/// ## References
+/// [^1]: Hongjun Wu (2008). ["The Stream Cipher HC-128"](
+/// http://www.ecrypt.eu.org/stream/p3ciphers/hc/hc128_p3.pdf).
+/// *The eSTREAM Finalists*, LNCS 4986, pp. 39–47, Springer-Verlag.
+///
+/// [^2]: [eSTREAM: the ECRYPT Stream Cipher Project](
+/// http://www.ecrypt.eu.org/stream/)
+///
+/// [^3]: Hongjun Wu, [Stream Ciphers HC-128 and HC-256](
+/// https://www.ntu.edu.sg/home/wuhj/research/hc/index.html)
+///
+/// [^4]: Shashwat Raizada (January 2015),["Some Results On Analysis And
+/// Implementation Of HC-128 Stream Cipher"](
+/// http://library.isical.ac.in:8080/jspui/bitstream/123456789/6636/1/TH431.pdf).
+///
+/// [^5]: Internet Engineering Task Force (February 2015),
+/// ["Prohibiting RC4 Cipher Suites"](https://tools.ietf.org/html/rfc7465).
+///
+/// [`BlockRng`]: ../rand_core/block/struct.BlockRng.html
+/// [`RngCore`]: ../rand_core/trait.RngCore.html
+#[derive(Clone, Debug)]
+pub struct Hc128Rng(BlockRng<Hc128Core>);
+
+impl RngCore for Hc128Rng {
+ #[inline(always)]
+ fn next_u32(&mut self) -> u32 {
+ self.0.next_u32()
+ }
+
+ #[inline(always)]
+ fn next_u64(&mut self) -> u64 {
+ self.0.next_u64()
+ }
+
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
+ self.0.fill_bytes(dest)
+ }
+
+ fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ self.0.try_fill_bytes(dest)
+ }
+}
+
+impl SeedableRng for Hc128Rng {
+ type Seed = <Hc128Core as SeedableRng>::Seed;
+
+ fn from_seed(seed: Self::Seed) -> Self {
+ Hc128Rng(BlockRng::<Hc128Core>::from_seed(seed))
+ }
+
+ fn from_rng<R: RngCore>(rng: R) -> Result<Self, Error> {
+ BlockRng::<Hc128Core>::from_rng(rng).map(Hc128Rng)
+ }
+}
+
+impl CryptoRng for Hc128Rng {}
+
+/// The core of `Hc128Rng`, used with `BlockRng`.
+#[derive(Clone)]
+pub struct Hc128Core {
+ t: [u32; 1024],
+ counter1024: usize,
+}
+
+// Custom Debug implementation that does not expose the internal state
+impl fmt::Debug for Hc128Core {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "Hc128Core {{}}")
+ }
+}
+
+impl BlockRngCore for Hc128Core {
+ type Item = u32;
+ type Results = [u32; 16];
+
+ fn generate(&mut self, results: &mut Self::Results) {
+ assert!(self.counter1024 % 16 == 0);
+
+ let cc = self.counter1024 % 512;
+ let dd = (cc + 16) % 512;
+ let ee = cc.wrapping_sub(16) % 512;
+
+ if self.counter1024 & 512 == 0 {
+ // P block
+ results[0] = self.step_p(cc+0, cc+1, ee+13, ee+6, ee+4);
+ results[1] = self.step_p(cc+1, cc+2, ee+14, ee+7, ee+5);
+ results[2] = self.step_p(cc+2, cc+3, ee+15, ee+8, ee+6);
+ results[3] = self.step_p(cc+3, cc+4, cc+0, ee+9, ee+7);
+ results[4] = self.step_p(cc+4, cc+5, cc+1, ee+10, ee+8);
+ results[5] = self.step_p(cc+5, cc+6, cc+2, ee+11, ee+9);
+ results[6] = self.step_p(cc+6, cc+7, cc+3, ee+12, ee+10);
+ results[7] = self.step_p(cc+7, cc+8, cc+4, ee+13, ee+11);
+ results[8] = self.step_p(cc+8, cc+9, cc+5, ee+14, ee+12);
+ results[9] = self.step_p(cc+9, cc+10, cc+6, ee+15, ee+13);
+ results[10] = self.step_p(cc+10, cc+11, cc+7, cc+0, ee+14);
+ results[11] = self.step_p(cc+11, cc+12, cc+8, cc+1, ee+15);
+ results[12] = self.step_p(cc+12, cc+13, cc+9, cc+2, cc+0);
+ results[13] = self.step_p(cc+13, cc+14, cc+10, cc+3, cc+1);
+ results[14] = self.step_p(cc+14, cc+15, cc+11, cc+4, cc+2);
+ results[15] = self.step_p(cc+15, dd+0, cc+12, cc+5, cc+3);
+ } else {
+ // Q block
+ results[0] = self.step_q(cc+0, cc+1, ee+13, ee+6, ee+4);
+ results[1] = self.step_q(cc+1, cc+2, ee+14, ee+7, ee+5);
+ results[2] = self.step_q(cc+2, cc+3, ee+15, ee+8, ee+6);
+ results[3] = self.step_q(cc+3, cc+4, cc+0, ee+9, ee+7);
+ results[4] = self.step_q(cc+4, cc+5, cc+1, ee+10, ee+8);
+ results[5] = self.step_q(cc+5, cc+6, cc+2, ee+11, ee+9);
+ results[6] = self.step_q(cc+6, cc+7, cc+3, ee+12, ee+10);
+ results[7] = self.step_q(cc+7, cc+8, cc+4, ee+13, ee+11);
+ results[8] = self.step_q(cc+8, cc+9, cc+5, ee+14, ee+12);
+ results[9] = self.step_q(cc+9, cc+10, cc+6, ee+15, ee+13);
+ results[10] = self.step_q(cc+10, cc+11, cc+7, cc+0, ee+14);
+ results[11] = self.step_q(cc+11, cc+12, cc+8, cc+1, ee+15);
+ results[12] = self.step_q(cc+12, cc+13, cc+9, cc+2, cc+0);
+ results[13] = self.step_q(cc+13, cc+14, cc+10, cc+3, cc+1);
+ results[14] = self.step_q(cc+14, cc+15, cc+11, cc+4, cc+2);
+ results[15] = self.step_q(cc+15, dd+0, cc+12, cc+5, cc+3);
+ }
+ self.counter1024 = self.counter1024.wrapping_add(16);
+ }
+}
+
+impl Hc128Core {
+ // One step of HC-128, update P and generate 32 bits keystream
+ #[inline(always)]
+ fn step_p(&mut self, i: usize, i511: usize, i3: usize, i10: usize, i12: usize)
+ -> u32
+ {
+ let (p, q) = self.t.split_at_mut(512);
+ // FIXME: it would be great if we the bounds checks here could be
+ // optimized out, and we would not need unsafe.
+ // This improves performance by about 7%.
+ unsafe {
+ let temp0 = p.get_unchecked(i511).rotate_right(23);
+ let temp1 = p.get_unchecked(i3).rotate_right(10);
+ let temp2 = p.get_unchecked(i10).rotate_right(8);
+ *p.get_unchecked_mut(i) = p.get_unchecked(i)
+ .wrapping_add(temp2)
+ .wrapping_add(temp0 ^ temp1);
+ let temp3 = {
+ // The h1 function in HC-128
+ let a = *p.get_unchecked(i12) as u8;
+ let c = (p.get_unchecked(i12) >> 16) as u8;
+ q[a as usize].wrapping_add(q[256 + c as usize])
+ };
+ temp3 ^ p.get_unchecked(i)
+ }
+ }
+
+ // One step of HC-128, update Q and generate 32 bits keystream
+ // Similar to `step_p`, but `p` and `q` are swapped, and the rotates are to
+ // the left instead of to the right.
+ #[inline(always)]
+ fn step_q(&mut self, i: usize, i511: usize, i3: usize, i10: usize, i12: usize)
+ -> u32
+ {
+ let (p, q) = self.t.split_at_mut(512);
+ unsafe {
+ let temp0 = q.get_unchecked(i511).rotate_left(23);
+ let temp1 = q.get_unchecked(i3).rotate_left(10);
+ let temp2 = q.get_unchecked(i10).rotate_left(8);
+ *q.get_unchecked_mut(i) = q.get_unchecked(i)
+ .wrapping_add(temp2)
+ .wrapping_add(temp0 ^ temp1);
+ let temp3 = {
+ // The h2 function in HC-128
+ let a = *q.get_unchecked(i12) as u8;
+ let c = (q.get_unchecked(i12) >> 16) as u8;
+ p[a as usize].wrapping_add(p[256 + c as usize])
+ };
+ temp3 ^ q.get_unchecked(i)
+ }
+ }
+
+ fn sixteen_steps(&mut self) {
+ assert!(self.counter1024 % 16 == 0);
+
+ let cc = self.counter1024 % 512;
+ let dd = (cc + 16) % 512;
+ let ee = cc.wrapping_sub(16) % 512;
+
+ if self.counter1024 < 512 {
+ // P block
+ self.t[cc+0] = self.step_p(cc+0, cc+1, ee+13, ee+6, ee+4);
+ self.t[cc+1] = self.step_p(cc+1, cc+2, ee+14, ee+7, ee+5);
+ self.t[cc+2] = self.step_p(cc+2, cc+3, ee+15, ee+8, ee+6);
+ self.t[cc+3] = self.step_p(cc+3, cc+4, cc+0, ee+9, ee+7);
+ self.t[cc+4] = self.step_p(cc+4, cc+5, cc+1, ee+10, ee+8);
+ self.t[cc+5] = self.step_p(cc+5, cc+6, cc+2, ee+11, ee+9);
+ self.t[cc+6] = self.step_p(cc+6, cc+7, cc+3, ee+12, ee+10);
+ self.t[cc+7] = self.step_p(cc+7, cc+8, cc+4, ee+13, ee+11);
+ self.t[cc+8] = self.step_p(cc+8, cc+9, cc+5, ee+14, ee+12);
+ self.t[cc+9] = self.step_p(cc+9, cc+10, cc+6, ee+15, ee+13);
+ self.t[cc+10] = self.step_p(cc+10, cc+11, cc+7, cc+0, ee+14);
+ self.t[cc+11] = self.step_p(cc+11, cc+12, cc+8, cc+1, ee+15);
+ self.t[cc+12] = self.step_p(cc+12, cc+13, cc+9, cc+2, cc+0);
+ self.t[cc+13] = self.step_p(cc+13, cc+14, cc+10, cc+3, cc+1);
+ self.t[cc+14] = self.step_p(cc+14, cc+15, cc+11, cc+4, cc+2);
+ self.t[cc+15] = self.step_p(cc+15, dd+0, cc+12, cc+5, cc+3);
+ } else {
+ // Q block
+ self.t[cc+512+0] = self.step_q(cc+0, cc+1, ee+13, ee+6, ee+4);
+ self.t[cc+512+1] = self.step_q(cc+1, cc+2, ee+14, ee+7, ee+5);
+ self.t[cc+512+2] = self.step_q(cc+2, cc+3, ee+15, ee+8, ee+6);
+ self.t[cc+512+3] = self.step_q(cc+3, cc+4, cc+0, ee+9, ee+7);
+ self.t[cc+512+4] = self.step_q(cc+4, cc+5, cc+1, ee+10, ee+8);
+ self.t[cc+512+5] = self.step_q(cc+5, cc+6, cc+2, ee+11, ee+9);
+ self.t[cc+512+6] = self.step_q(cc+6, cc+7, cc+3, ee+12, ee+10);
+ self.t[cc+512+7] = self.step_q(cc+7, cc+8, cc+4, ee+13, ee+11);
+ self.t[cc+512+8] = self.step_q(cc+8, cc+9, cc+5, ee+14, ee+12);
+ self.t[cc+512+9] = self.step_q(cc+9, cc+10, cc+6, ee+15, ee+13);
+ self.t[cc+512+10] = self.step_q(cc+10, cc+11, cc+7, cc+0, ee+14);
+ self.t[cc+512+11] = self.step_q(cc+11, cc+12, cc+8, cc+1, ee+15);
+ self.t[cc+512+12] = self.step_q(cc+12, cc+13, cc+9, cc+2, cc+0);
+ self.t[cc+512+13] = self.step_q(cc+13, cc+14, cc+10, cc+3, cc+1);
+ self.t[cc+512+14] = self.step_q(cc+14, cc+15, cc+11, cc+4, cc+2);
+ self.t[cc+512+15] = self.step_q(cc+15, dd+0, cc+12, cc+5, cc+3);
+ }
+ self.counter1024 += 16;
+ }
+
+ // Initialize an HC-128 random number generator. The seed has to be
+ // 256 bits in length (`[u32; 8]`), matching the 128 bit `key` followed by
+ // 128 bit `iv` when HC-128 where to be used as a stream cipher.
+ fn init(seed: [u32; SEED_WORDS]) -> Self {
+ #[inline]
+ fn f1(x: u32) -> u32 {
+ x.rotate_right(7) ^ x.rotate_right(18) ^ (x >> 3)
+ }
+
+ #[inline]
+ fn f2(x: u32) -> u32 {
+ x.rotate_right(17) ^ x.rotate_right(19) ^ (x >> 10)
+ }
+
+ let mut t = [0u32; 1024];
+
+ // Expand the key and iv into P and Q
+ let (key, iv) = seed.split_at(4);
+ t[..4].copy_from_slice(key);
+ t[4..8].copy_from_slice(key);
+ t[8..12].copy_from_slice(iv);
+ t[12..16].copy_from_slice(iv);
+
+ // Generate the 256 intermediate values W[16] ... W[256+16-1], and
+ // copy the last 16 generated values to the start op P.
+ for i in 16..256+16 {
+ t[i] = f2(t[i-2]).wrapping_add(t[i-7]).wrapping_add(f1(t[i-15]))
+ .wrapping_add(t[i-16]).wrapping_add(i as u32);
+ }
+ {
+ let (p1, p2) = t.split_at_mut(256);
+ p1[0..16].copy_from_slice(&p2[0..16]);
+ }
+
+ // Generate both the P and Q tables
+ for i in 16..1024 {
+ t[i] = f2(t[i-2]).wrapping_add(t[i-7]).wrapping_add(f1(t[i-15]))
+ .wrapping_add(t[i-16]).wrapping_add(256 + i as u32);
+ }
+
+ let mut core = Self { t, counter1024: 0 };
+
+ // run the cipher 1024 steps
+ for _ in 0..64 { core.sixteen_steps() };
+ core.counter1024 = 0;
+ core
+ }
+}
+
+impl SeedableRng for Hc128Core {
+ type Seed = [u8; SEED_WORDS*4];
+
+ /// Create an HC-128 random number generator with a seed. The seed has to be
+ /// 256 bits in length, matching the 128 bit `key` followed by 128 bit `iv`
+ /// when HC-128 where to be used as a stream cipher.
+ fn from_seed(seed: Self::Seed) -> Self {
+ let mut seed_u32 = [0u32; SEED_WORDS];
+ le::read_u32_into(&seed, &mut seed_u32);
+ Self::init(seed_u32)
+ }
+}
+
+impl CryptoRng for Hc128Core {}
+
+#[cfg(test)]
+mod test {
+ use ::rand_core::{RngCore, SeedableRng};
+ use super::Hc128Rng;
+
+ #[test]
+ // Test vector 1 from the paper "The Stream Cipher HC-128"
+ fn test_hc128_true_values_a() {
+ let seed = [0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // key
+ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; // iv
+ let mut rng = Hc128Rng::from_seed(seed);
+
+ let mut results = [0u32; 16];
+ for i in results.iter_mut() { *i = rng.next_u32(); }
+ let expected = [0x73150082, 0x3bfd03a0, 0xfb2fd77f, 0xaa63af0e,
+ 0xde122fc6, 0xa7dc29b6, 0x62a68527, 0x8b75ec68,
+ 0x9036db1e, 0x81896005, 0x00ade078, 0x491fbf9a,
+ 0x1cdc3013, 0x6c3d6e24, 0x90f664b2, 0x9cd57102];
+ assert_eq!(results, expected);
+ }
+
+ #[test]
+ // Test vector 2 from the paper "The Stream Cipher HC-128"
+ fn test_hc128_true_values_b() {
+ let seed = [0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // key
+ 1,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; // iv
+ let mut rng = Hc128Rng::from_seed(seed);
+
+ let mut results = [0u32; 16];
+ for i in results.iter_mut() { *i = rng.next_u32(); }
+ let expected = [0xc01893d5, 0xb7dbe958, 0x8f65ec98, 0x64176604,
+ 0x36fc6724, 0xc82c6eec, 0x1b1c38a7, 0xc9b42a95,
+ 0x323ef123, 0x0a6a908b, 0xce757b68, 0x9f14f7bb,
+ 0xe4cde011, 0xaeb5173f, 0x89608c94, 0xb5cf46ca];
+ assert_eq!(results, expected);
+ }
+
+ #[test]
+ // Test vector 3 from the paper "The Stream Cipher HC-128"
+ fn test_hc128_true_values_c() {
+ let seed = [0x55,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // key
+ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; // iv
+ let mut rng = Hc128Rng::from_seed(seed);
+
+ let mut results = [0u32; 16];
+ for i in results.iter_mut() { *i = rng.next_u32(); }
+ let expected = [0x518251a4, 0x04b4930a, 0xb02af931, 0x0639f032,
+ 0xbcb4a47a, 0x5722480b, 0x2bf99f72, 0xcdc0e566,
+ 0x310f0c56, 0xd3cc83e8, 0x663db8ef, 0x62dfe07f,
+ 0x593e1790, 0xc5ceaa9c, 0xab03806f, 0xc9a6e5a0];
+ assert_eq!(results, expected);
+ }
+
+ #[test]
+ fn test_hc128_true_values_u64() {
+ let seed = [0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // key
+ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; // iv
+ let mut rng = Hc128Rng::from_seed(seed);
+
+ let mut results = [0u64; 8];
+ for i in results.iter_mut() { *i = rng.next_u64(); }
+ let expected = [0x3bfd03a073150082, 0xaa63af0efb2fd77f,
+ 0xa7dc29b6de122fc6, 0x8b75ec6862a68527,
+ 0x818960059036db1e, 0x491fbf9a00ade078,
+ 0x6c3d6e241cdc3013, 0x9cd5710290f664b2];
+ assert_eq!(results, expected);
+
+ // The RNG operates in a P block of 512 results and next a Q block.
+ // After skipping 2*800 u32 results we end up somewhere in the Q block
+ // of the second round
+ for _ in 0..800 { rng.next_u64(); }
+
+ for i in results.iter_mut() { *i = rng.next_u64(); }
+ let expected = [0xd8c4d6ca84d0fc10, 0xf16a5d91dc66e8e7,
+ 0xd800de5bc37a8653, 0x7bae1f88c0dfbb4c,
+ 0x3bfe1f374e6d4d14, 0x424b55676be3fa06,
+ 0xe3a1e8758cbff579, 0x417f7198c5652bcd];
+ assert_eq!(results, expected);
+ }
+
+ #[test]
+ fn test_hc128_true_values_bytes() {
+ let seed = [0x55,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // key
+ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; // iv
+ let mut rng = Hc128Rng::from_seed(seed);
+ let expected = [0x31, 0xf9, 0x2a, 0xb0, 0x32, 0xf0, 0x39, 0x06,
+ 0x7a, 0xa4, 0xb4, 0xbc, 0x0b, 0x48, 0x22, 0x57,
+ 0x72, 0x9f, 0xf9, 0x2b, 0x66, 0xe5, 0xc0, 0xcd,
+ 0x56, 0x0c, 0x0f, 0x31, 0xe8, 0x83, 0xcc, 0xd3,
+ 0xef, 0xb8, 0x3d, 0x66, 0x7f, 0xe0, 0xdf, 0x62,
+ 0x90, 0x17, 0x3e, 0x59, 0x9c, 0xaa, 0xce, 0xc5,
+ 0x6f, 0x80, 0x03, 0xab, 0xa0, 0xe5, 0xa6, 0xc9,
+ 0x60, 0x95, 0x84, 0x7a, 0xa5, 0x68, 0x5a, 0x84,
+ 0xea, 0xd5, 0xf3, 0xea, 0x73, 0xa9, 0xad, 0x01,
+ 0x79, 0x7d, 0xbe, 0x9f, 0xea, 0xe3, 0xf9, 0x74,
+ 0x0e, 0xda, 0x2f, 0xa0, 0xe4, 0x7b, 0x4b, 0x1b,
+ 0xdd, 0x17, 0x69, 0x4a, 0xfe, 0x9f, 0x56, 0x95,
+ 0xad, 0x83, 0x6b, 0x9d, 0x60, 0xa1, 0x99, 0x96,
+ 0x90, 0x00, 0x66, 0x7f, 0xfa, 0x7e, 0x65, 0xe9,
+ 0xac, 0x8b, 0x92, 0x34, 0x77, 0xb4, 0x23, 0xd0,
+ 0xb9, 0xab, 0xb1, 0x47, 0x7d, 0x4a, 0x13, 0x0a];
+
+ // Pick a somewhat large buffer so we can test filling with the
+ // remainder from `state.results`, directly filling the buffer, and
+ // filling the remainder of the buffer.
+ let mut buffer = [0u8; 16*4*2];
+ // Consume a value so that we have a remainder.
+ assert!(rng.next_u64() == 0x04b4930a518251a4);
+ rng.fill_bytes(&mut buffer);
+
+ // [u8; 128] doesn't implement PartialEq
+ assert_eq!(buffer.len(), expected.len());
+ for (b, e) in buffer.iter().zip(expected.iter()) {
+ assert_eq!(b, e);
+ }
+ }
+
+ #[test]
+ fn test_hc128_clone() {
+ let seed = [0x55,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // key
+ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; // iv
+ let mut rng1 = Hc128Rng::from_seed(seed);
+ let mut rng2 = rng1.clone();
+ for _ in 0..16 {
+ assert_eq!(rng1.next_u32(), rng2.next_u32());
+ }
+ }
+}
diff --git a/rand/rand_hc/src/lib.rs b/rand/rand_hc/src/lib.rs
new file mode 100644
index 0000000..f1d772d
--- /dev/null
+++ b/rand/rand_hc/src/lib.rs
@@ -0,0 +1,25 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! The HC128 random number generator.
+
+#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png",
+ html_favicon_url = "https://www.rust-lang.org/favicon.ico",
+ html_root_url = "https://rust-random.github.io/rand/")]
+
+#![deny(missing_docs)]
+#![deny(missing_debug_implementations)]
+#![doc(test(attr(allow(unused_variables), deny(warnings))))]
+
+#![no_std]
+
+extern crate rand_core;
+
+mod hc128;
+
+pub use hc128::{Hc128Rng, Hc128Core};
diff --git a/rand/rand_isaac/CHANGELOG.md b/rand/rand_isaac/CHANGELOG.md
new file mode 100644
index 0000000..d0c4a2f
--- /dev/null
+++ b/rand/rand_isaac/CHANGELOG.md
@@ -0,0 +1,8 @@
+# Changelog
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+## [0.1.0] - 2018-10-17
+- Pulled out of the Rand crate
diff --git a/rand/rand_isaac/COPYRIGHT b/rand/rand_isaac/COPYRIGHT
new file mode 100644
index 0000000..468d907
--- /dev/null
+++ b/rand/rand_isaac/COPYRIGHT
@@ -0,0 +1,12 @@
+Copyrights in the Rand project are retained by their contributors. No
+copyright assignment is required to contribute to the Rand project.
+
+For full authorship information, see the version control history.
+
+Except as otherwise noted (below and/or in individual files), Rand is
+licensed under the Apache License, Version 2.0 <LICENSE-APACHE> or
+<http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+<LICENSE-MIT> or <http://opensource.org/licenses/MIT>, at your option.
+
+The Rand project includes code from the Rust project
+published under these same licenses.
diff --git a/rand/rand_isaac/Cargo.toml b/rand/rand_isaac/Cargo.toml
new file mode 100644
index 0000000..07c4a36
--- /dev/null
+++ b/rand/rand_isaac/Cargo.toml
@@ -0,0 +1,31 @@
+[package]
+name = "rand_isaac"
+version = "0.1.0"
+authors = ["The Rand Project Developers", "The Rust Project Developers"]
+license = "MIT/Apache-2.0"
+readme = "README.md"
+repository = "https://github.com/rust-random/rand"
+documentation = "https://rust-random.github.io/rand/rand_isaac"
+homepage = "https://crates.io/crates/rand_isaac"
+description = """
+ISAAC random number generator
+"""
+keywords = ["random", "rng", "isaac"]
+categories = ["algorithms", "no-std"]
+
+[badges]
+travis-ci = { repository = "rust-random/rand" }
+appveyor = { repository = "rust-random/rand" }
+
+[features]
+serde1 = ["serde", "serde_derive", "rand_core/serde1"]
+
+[dependencies]
+rand_core = { path = "../rand_core", version = ">=0.2, <0.4", default-features=false }
+serde = { version = "1", optional = true }
+serde_derive = { version = "^1.0.38", optional = true }
+
+[dev-dependencies]
+# This is for testing serde, unfortunately we can't specify feature-gated dev
+# deps yet, see: https://github.com/rust-lang/cargo/issues/1596
+bincode = "1"
diff --git a/rand/rand_isaac/LICENSE-APACHE b/rand/rand_isaac/LICENSE-APACHE
new file mode 100644
index 0000000..17d7468
--- /dev/null
+++ b/rand/rand_isaac/LICENSE-APACHE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ https://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/rand/rand_isaac/LICENSE-MIT b/rand/rand_isaac/LICENSE-MIT
new file mode 100644
index 0000000..d93b5ba
--- /dev/null
+++ b/rand/rand_isaac/LICENSE-MIT
@@ -0,0 +1,26 @@
+Copyright 2018 Developers of the Rand project
+Copyright (c) 2014 The Rust Project Developers
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/rand/rand_isaac/README.md b/rand/rand_isaac/README.md
new file mode 100644
index 0000000..02d1230
--- /dev/null
+++ b/rand/rand_isaac/README.md
@@ -0,0 +1,47 @@
+# rand_isaac
+
+[![Build Status](https://travis-ci.org/rust-random/rand.svg)](https://travis-ci.org/rust-random/rand)
+[![Build Status](https://ci.appveyor.com/api/projects/status/github/rust-random/rand?svg=true)](https://ci.appveyor.com/project/rust-random/rand)
+[![Latest version](https://img.shields.io/crates/v/rand_isaac.svg)](https://crates.io/crates/rand_isaac)
+[![Book](https://img.shields.io/badge/book-master-yellow.svg)](https://rust-random.github.io/book/)
+[![API](https://img.shields.io/badge/api-master-yellow.svg)](https://rust-random.github.io/rand/rand_isaac)
+[![API](https://docs.rs/rand_isaac/badge.svg)](https://docs.rs/rand_isaac)
+[![Minimum rustc version](https://img.shields.io/badge/rustc-1.22+-lightgray.svg)](https://github.com/rust-random/rand#rust-version-requirements)
+
+Implements the ISAAC and ISAAC-64 random number generators.
+
+ISAAC stands for "Indirection, Shift, Accumulate, Add, and Count" which are
+the principal bitwise operations employed. It is the most advanced of a
+series of array based random number generator designed by Robert Jenkins
+in 1996[^1][^2].
+
+ISAAC is notably fast and produces excellent quality random numbers for
+non-cryptographic applications.
+
+Links:
+
+- [API documentation (master)](https://rust-random.github.io/rand/rand_isaac)
+- [API documentation (docs.rs)](https://docs.rs/rand_isaac)
+- [Changelog](CHANGELOG.md)
+
+[rand]: https://crates.io/crates/rand
+[^1]: Bob Jenkins, [*ISAAC: A fast cryptographic random number generator*](http://burtleburtle.net/bob/rand/isaacafa.html)
+[^2]: Bob Jenkins, [*ISAAC and RC4*](http://burtleburtle.net/bob/rand/isaac.html)
+
+
+## Crate Features
+
+`rand_isaac` is `no_std` compatible. It does not require any functionality
+outside of the `core` lib, thus there are no features to configure.
+
+The `serde1` feature includes implementations of `Serialize` and `Deserialize`
+for the included RNGs.
+
+
+# License
+
+`rand_isaac` is distributed under the terms of both the MIT license and the
+Apache License (Version 2.0).
+
+See [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT), and
+[COPYRIGHT](COPYRIGHT) for details.
diff --git a/rand/rand_isaac/src/isaac.rs b/rand/rand_isaac/src/isaac.rs
new file mode 100644
index 0000000..2bfdd94
--- /dev/null
+++ b/rand/rand_isaac/src/isaac.rs
@@ -0,0 +1,484 @@
+// Copyright 2018 Developers of the Rand project.
+// Copyright 2013-2018 The Rust Project Developers.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! The ISAAC random number generator.
+
+use core::{fmt, slice};
+use core::num::Wrapping as w;
+use rand_core::{RngCore, SeedableRng, Error, le};
+use rand_core::block::{BlockRngCore, BlockRng};
+use isaac_array::IsaacArray;
+
+#[allow(non_camel_case_types)]
+type w32 = w<u32>;
+
+const RAND_SIZE_LEN: usize = 8;
+const RAND_SIZE: usize = 1 << RAND_SIZE_LEN;
+
+/// A random number generator that uses the ISAAC algorithm.
+///
+/// ISAAC stands for "Indirection, Shift, Accumulate, Add, and Count" which are
+/// the principal bitwise operations employed. It is the most advanced of a
+/// series of array based random number generator designed by Robert Jenkins
+/// in 1996[^1][^2].
+///
+/// ISAAC is notably fast and produces excellent quality random numbers for
+/// non-cryptographic applications.
+///
+/// In spite of being designed with cryptographic security in mind, ISAAC hasn't
+/// been stringently cryptanalyzed and thus cryptographers do not not
+/// consensually trust it to be secure. When looking for a secure RNG, prefer
+/// [`Hc128Rng`] instead, which, like ISAAC, is an array-based RNG and one of
+/// the stream-ciphers selected the by eSTREAM contest.
+///
+/// In 2006 an improvement to ISAAC was suggested by Jean-Philippe Aumasson,
+/// named ISAAC+[^3]. But because the specification is not complete, because
+/// there is no good implementation, and because the suggested bias may not
+/// exist, it is not implemented here.
+///
+/// ## Overview of the ISAAC algorithm:
+/// (in pseudo-code)
+///
+/// ```text
+/// Input: a, b, c, s[256] // state
+/// Output: r[256] // results
+///
+/// mix(a,i) = a ^ a << 13 if i = 0 mod 4
+/// a ^ a >> 6 if i = 1 mod 4
+/// a ^ a << 2 if i = 2 mod 4
+/// a ^ a >> 16 if i = 3 mod 4
+///
+/// c = c + 1
+/// b = b + c
+///
+/// for i in 0..256 {
+/// x = s_[i]
+/// a = f(a,i) + s[i+128 mod 256]
+/// y = a + b + s[x>>2 mod 256]
+/// s[i] = y
+/// b = x + s[y>>10 mod 256]
+/// r[i] = b
+/// }
+/// ```
+///
+/// Numbers are generated in blocks of 256. This means the function above only
+/// runs once every 256 times you ask for a next random number. In all other
+/// circumstances the last element of the results array is returned.
+///
+/// ISAAC therefore needs a lot of memory, relative to other non-crypto RNGs.
+/// 2 * 256 * 4 = 2 kb to hold the state and results.
+///
+/// This implementation uses [`BlockRng`] to implement the [`RngCore`] methods.
+///
+/// ## References
+/// [^1]: Bob Jenkins, [*ISAAC: A fast cryptographic random number generator*](
+/// http://burtleburtle.net/bob/rand/isaacafa.html)
+///
+/// [^2]: Bob Jenkins, [*ISAAC and RC4*](
+/// http://burtleburtle.net/bob/rand/isaac.html)
+///
+/// [^3]: Jean-Philippe Aumasson, [*On the pseudo-random generator ISAAC*](
+/// https://eprint.iacr.org/2006/438)
+///
+/// [`Hc128Rng`]: ../../rand_hc/struct.Hc128Rng.html
+/// [`BlockRng`]: ../../rand_core/block/struct.BlockRng.html
+/// [`RngCore`]: ../../rand_core/trait.RngCore.html
+#[derive(Clone, Debug)]
+#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))]
+pub struct IsaacRng(BlockRng<IsaacCore>);
+
+impl RngCore for IsaacRng {
+ #[inline(always)]
+ fn next_u32(&mut self) -> u32 {
+ self.0.next_u32()
+ }
+
+ #[inline(always)]
+ fn next_u64(&mut self) -> u64 {
+ self.0.next_u64()
+ }
+
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
+ self.0.fill_bytes(dest)
+ }
+
+ fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ self.0.try_fill_bytes(dest)
+ }
+}
+
+impl SeedableRng for IsaacRng {
+ type Seed = <IsaacCore as SeedableRng>::Seed;
+
+ fn from_seed(seed: Self::Seed) -> Self {
+ IsaacRng(BlockRng::<IsaacCore>::from_seed(seed))
+ }
+
+ /// Create an ISAAC random number generator using an `u64` as seed.
+ /// If `seed == 0` this will produce the same stream of random numbers as
+ /// the reference implementation when used unseeded.
+ fn seed_from_u64(seed: u64) -> Self {
+ IsaacRng(BlockRng::<IsaacCore>::seed_from_u64(seed))
+ }
+
+ fn from_rng<S: RngCore>(rng: S) -> Result<Self, Error> {
+ BlockRng::<IsaacCore>::from_rng(rng).map(|rng| IsaacRng(rng))
+ }
+}
+
+impl IsaacRng {
+ /// Create an ISAAC random number generator using an `u64` as seed.
+ /// If `seed == 0` this will produce the same stream of random numbers as
+ /// the reference implementation when used unseeded.
+ #[deprecated(since="0.6.0", note="use SeedableRng::seed_from_u64 instead")]
+ pub fn new_from_u64(seed: u64) -> Self {
+ Self::seed_from_u64(seed)
+ }
+}
+
+/// The core of `IsaacRng`, used with `BlockRng`.
+#[derive(Clone)]
+#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))]
+pub struct IsaacCore {
+ #[cfg_attr(feature="serde1",serde(with="super::isaac_array::isaac_array_serde"))]
+ mem: [w32; RAND_SIZE],
+ a: w32,
+ b: w32,
+ c: w32,
+}
+
+// Custom Debug implementation that does not expose the internal state
+impl fmt::Debug for IsaacCore {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "IsaacCore {{}}")
+ }
+}
+
+impl BlockRngCore for IsaacCore {
+ type Item = u32;
+ type Results = IsaacArray<Self::Item>;
+
+ /// Refills the output buffer, `results`. See also the pseudocode desciption
+ /// of the algorithm in the [`IsaacRng`] documentation.
+ ///
+ /// Optimisations used (similar to the reference implementation):
+ ///
+ /// - The loop is unrolled 4 times, once for every constant of mix().
+ /// - The contents of the main loop are moved to a function `rngstep`, to
+ /// reduce code duplication.
+ /// - We use local variables for a and b, which helps with optimisations.
+ /// - We split the main loop in two, one that operates over 0..128 and one
+ /// over 128..256. This way we can optimise out the addition and modulus
+ /// from `s[i+128 mod 256]`.
+ /// - We maintain one index `i` and add `m` or `m2` as base (m2 for the
+ /// `s[i+128 mod 256]`), relying on the optimizer to turn it into pointer
+ /// arithmetic.
+ /// - We fill `results` backwards. The reference implementation reads values
+ /// from `results` in reverse. We read them in the normal direction, to
+ /// make `fill_bytes` a memcopy. To maintain compatibility we fill in
+ /// reverse.
+ ///
+ /// [`IsaacRng`]: struct.IsaacRng.html
+ fn generate(&mut self, results: &mut IsaacArray<Self::Item>) {
+ self.c += w(1);
+ // abbreviations
+ let mut a = self.a;
+ let mut b = self.b + self.c;
+ const MIDPOINT: usize = RAND_SIZE / 2;
+
+ #[inline]
+ fn ind(mem:&[w32; RAND_SIZE], v: w32, amount: usize) -> w32 {
+ let index = (v >> amount).0 as usize % RAND_SIZE;
+ mem[index]
+ }
+
+ #[inline]
+ fn rngstep(mem: &mut [w32; RAND_SIZE],
+ results: &mut [u32; RAND_SIZE],
+ mix: w32,
+ a: &mut w32,
+ b: &mut w32,
+ base: usize,
+ m: usize,
+ m2: usize) {
+ let x = mem[base + m];
+ *a = mix + mem[base + m2];
+ let y = *a + *b + ind(&mem, x, 2);
+ mem[base + m] = y;
+ *b = x + ind(&mem, y, 2 + RAND_SIZE_LEN);
+ results[RAND_SIZE - 1 - base - m] = (*b).0;
+ }
+
+ let mut m = 0;
+ let mut m2 = MIDPOINT;
+ for i in (0..MIDPOINT/4).map(|i| i * 4) {
+ rngstep(&mut self.mem, results, a ^ (a << 13), &mut a, &mut b, i + 0, m, m2);
+ rngstep(&mut self.mem, results, a ^ (a >> 6 ), &mut a, &mut b, i + 1, m, m2);
+ rngstep(&mut self.mem, results, a ^ (a << 2 ), &mut a, &mut b, i + 2, m, m2);
+ rngstep(&mut self.mem, results, a ^ (a >> 16), &mut a, &mut b, i + 3, m, m2);
+ }
+
+ m = MIDPOINT;
+ m2 = 0;
+ for i in (0..MIDPOINT/4).map(|i| i * 4) {
+ rngstep(&mut self.mem, results, a ^ (a << 13), &mut a, &mut b, i + 0, m, m2);
+ rngstep(&mut self.mem, results, a ^ (a >> 6 ), &mut a, &mut b, i + 1, m, m2);
+ rngstep(&mut self.mem, results, a ^ (a << 2 ), &mut a, &mut b, i + 2, m, m2);
+ rngstep(&mut self.mem, results, a ^ (a >> 16), &mut a, &mut b, i + 3, m, m2);
+ }
+
+ self.a = a;
+ self.b = b;
+ }
+}
+
+impl IsaacCore {
+ /// Create a new ISAAC random number generator.
+ ///
+ /// The author Bob Jenkins describes how to best initialize ISAAC here:
+ /// <https://rt.cpan.org/Public/Bug/Display.html?id=64324>
+ /// The answer is included here just in case:
+ ///
+ /// "No, you don't need a full 8192 bits of seed data. Normal key sizes will
+ /// do fine, and they should have their expected strength (eg a 40-bit key
+ /// will take as much time to brute force as 40-bit keys usually will). You
+ /// could fill the remainder with 0, but set the last array element to the
+ /// length of the key provided (to distinguish keys that differ only by
+ /// different amounts of 0 padding). You do still need to call `randinit()`
+ /// to make sure the initial state isn't uniform-looking."
+ /// "After publishing ISAAC, I wanted to limit the key to half the size of
+ /// `r[]`, and repeat it twice. That would have made it hard to provide a
+ /// key that sets the whole internal state to anything convenient. But I'd
+ /// already published it."
+ ///
+ /// And his answer to the question "For my code, would repeating the key
+ /// over and over to fill 256 integers be a better solution than
+ /// zero-filling, or would they essentially be the same?":
+ /// "If the seed is under 32 bytes, they're essentially the same, otherwise
+ /// repeating the seed would be stronger. randinit() takes a chunk of 32
+ /// bytes, mixes it, and combines that with the next 32 bytes, et cetera.
+ /// Then loops over all the elements the same way a second time."
+ #[inline]
+ fn init(mut mem: [w32; RAND_SIZE], rounds: u32) -> Self {
+ fn mix(a: &mut w32, b: &mut w32, c: &mut w32, d: &mut w32,
+ e: &mut w32, f: &mut w32, g: &mut w32, h: &mut w32) {
+ *a ^= *b << 11; *d += *a; *b += *c;
+ *b ^= *c >> 2; *e += *b; *c += *d;
+ *c ^= *d << 8; *f += *c; *d += *e;
+ *d ^= *e >> 16; *g += *d; *e += *f;
+ *e ^= *f << 10; *h += *e; *f += *g;
+ *f ^= *g >> 4; *a += *f; *g += *h;
+ *g ^= *h << 8; *b += *g; *h += *a;
+ *h ^= *a >> 9; *c += *h; *a += *b;
+ }
+
+ // These numbers are the result of initializing a...h with the
+ // fractional part of the golden ratio in binary (0x9e3779b9)
+ // and applying mix() 4 times.
+ let mut a = w(0x1367df5a);
+ let mut b = w(0x95d90059);
+ let mut c = w(0xc3163e4b);
+ let mut d = w(0x0f421ad8);
+ let mut e = w(0xd92a4a78);
+ let mut f = w(0xa51a3c49);
+ let mut g = w(0xc4efea1b);
+ let mut h = w(0x30609119);
+
+ // Normally this should do two passes, to make all of the seed effect
+ // all of `mem`
+ for _ in 0..rounds {
+ for i in (0..RAND_SIZE/8).map(|i| i * 8) {
+ a += mem[i ]; b += mem[i+1];
+ c += mem[i+2]; d += mem[i+3];
+ e += mem[i+4]; f += mem[i+5];
+ g += mem[i+6]; h += mem[i+7];
+ mix(&mut a, &mut b, &mut c, &mut d,
+ &mut e, &mut f, &mut g, &mut h);
+ mem[i ] = a; mem[i+1] = b;
+ mem[i+2] = c; mem[i+3] = d;
+ mem[i+4] = e; mem[i+5] = f;
+ mem[i+6] = g; mem[i+7] = h;
+ }
+ }
+
+ Self { mem, a: w(0), b: w(0), c: w(0) }
+ }
+}
+
+impl SeedableRng for IsaacCore {
+ type Seed = [u8; 32];
+
+ fn from_seed(seed: Self::Seed) -> Self {
+ let mut seed_u32 = [0u32; 8];
+ le::read_u32_into(&seed, &mut seed_u32);
+ // Convert the seed to `Wrapping<u32>` and zero-extend to `RAND_SIZE`.
+ let mut seed_extended = [w(0); RAND_SIZE];
+ for (x, y) in seed_extended.iter_mut().zip(seed_u32.iter()) {
+ *x = w(*y);
+ }
+ Self::init(seed_extended, 2)
+ }
+
+ /// Create an ISAAC random number generator using an `u64` as seed.
+ /// If `seed == 0` this will produce the same stream of random numbers as
+ /// the reference implementation when used unseeded.
+ fn seed_from_u64(seed: u64) -> Self {
+ let mut key = [w(0); RAND_SIZE];
+ key[0] = w(seed as u32);
+ key[1] = w((seed >> 32) as u32);
+ // Initialize with only one pass.
+ // A second pass does not improve the quality here, because all of the
+ // seed was already available in the first round.
+ // Not doing the second pass has the small advantage that if
+ // `seed == 0` this method produces exactly the same state as the
+ // reference implementation when used unseeded.
+ Self::init(key, 1)
+ }
+
+ fn from_rng<R: RngCore>(mut rng: R) -> Result<Self, Error> {
+ // Custom `from_rng` implementation that fills a seed with the same size
+ // as the entire state.
+ let mut seed = [w(0u32); RAND_SIZE];
+ unsafe {
+ let ptr = seed.as_mut_ptr() as *mut u8;
+
+ let slice = slice::from_raw_parts_mut(ptr, RAND_SIZE * 4);
+ rng.try_fill_bytes(slice)?;
+ }
+ for i in seed.iter_mut() {
+ *i = w(i.0.to_le());
+ }
+
+ Ok(Self::init(seed, 2))
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use rand_core::{RngCore, SeedableRng};
+ use super::IsaacRng;
+
+ #[test]
+ fn test_isaac_construction() {
+ // Test that various construction techniques produce a working RNG.
+ let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0,
+ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0];
+ let mut rng1 = IsaacRng::from_seed(seed);
+ assert_eq!(rng1.next_u32(), 2869442790);
+
+ let mut rng2 = IsaacRng::from_rng(rng1).unwrap();
+ assert_eq!(rng2.next_u32(), 3094074039);
+ }
+
+ #[test]
+ fn test_isaac_true_values_32() {
+ let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0,
+ 57,48,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0];
+ let mut rng1 = IsaacRng::from_seed(seed);
+ let mut results = [0u32; 10];
+ for i in results.iter_mut() { *i = rng1.next_u32(); }
+ let expected = [
+ 2558573138, 873787463, 263499565, 2103644246, 3595684709,
+ 4203127393, 264982119, 2765226902, 2737944514, 3900253796];
+ assert_eq!(results, expected);
+
+ let seed = [57,48,0,0, 50,9,1,0, 49,212,0,0, 148,38,0,0,
+ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0];
+ let mut rng2 = IsaacRng::from_seed(seed);
+ // skip forward to the 10000th number
+ for _ in 0..10000 { rng2.next_u32(); }
+
+ for i in results.iter_mut() { *i = rng2.next_u32(); }
+ let expected = [
+ 3676831399, 3183332890, 2834741178, 3854698763, 2717568474,
+ 1576568959, 3507990155, 179069555, 141456972, 2478885421];
+ assert_eq!(results, expected);
+ }
+
+ #[test]
+ fn test_isaac_true_values_64() {
+ // As above, using little-endian versions of above values
+ let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0,
+ 57,48,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0];
+ let mut rng = IsaacRng::from_seed(seed);
+ let mut results = [0u64; 5];
+ for i in results.iter_mut() { *i = rng.next_u64(); }
+ let expected = [
+ 3752888579798383186, 9035083239252078381,18052294697452424037,
+ 11876559110374379111, 16751462502657800130];
+ assert_eq!(results, expected);
+ }
+
+ #[test]
+ fn test_isaac_true_bytes() {
+ let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0,
+ 57,48,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0];
+ let mut rng = IsaacRng::from_seed(seed);
+ let mut results = [0u8; 32];
+ rng.fill_bytes(&mut results);
+ // Same as first values in test_isaac_true_values as bytes in LE order
+ let expected = [82, 186, 128, 152, 71, 240, 20, 52,
+ 45, 175, 180, 15, 86, 16, 99, 125,
+ 101, 203, 81, 214, 97, 162, 134, 250,
+ 103, 78, 203, 15, 150, 3, 210, 164];
+ assert_eq!(results, expected);
+ }
+
+ #[test]
+ fn test_isaac_new_uninitialized() {
+ // Compare the results from initializing `IsaacRng` with
+ // `seed_from_u64(0)`, to make sure it is the same as the reference
+ // implementation when used uninitialized.
+ // Note: We only test the first 16 integers, not the full 256 of the
+ // first block.
+ let mut rng = IsaacRng::seed_from_u64(0);
+ let mut results = [0u32; 16];
+ for i in results.iter_mut() { *i = rng.next_u32(); }
+ let expected: [u32; 16] = [
+ 0x71D71FD2, 0xB54ADAE7, 0xD4788559, 0xC36129FA,
+ 0x21DC1EA9, 0x3CB879CA, 0xD83B237F, 0xFA3CE5BD,
+ 0x8D048509, 0xD82E9489, 0xDB452848, 0xCA20E846,
+ 0x500F972E, 0x0EEFF940, 0x00D6B993, 0xBC12C17F];
+ assert_eq!(results, expected);
+ }
+
+ #[test]
+ fn test_isaac_clone() {
+ let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0,
+ 57,48,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0];
+ let mut rng1 = IsaacRng::from_seed(seed);
+ let mut rng2 = rng1.clone();
+ for _ in 0..16 {
+ assert_eq!(rng1.next_u32(), rng2.next_u32());
+ }
+ }
+
+ #[test]
+ #[cfg(feature="serde1")]
+ fn test_isaac_serde() {
+ use bincode;
+ use std::io::{BufWriter, BufReader};
+
+ let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0,
+ 57,48,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0];
+ let mut rng = IsaacRng::from_seed(seed);
+
+ let buf: Vec<u8> = Vec::new();
+ let mut buf = BufWriter::new(buf);
+ bincode::serialize_into(&mut buf, &rng).expect("Could not serialize");
+
+ let buf = buf.into_inner().unwrap();
+ let mut read = BufReader::new(&buf[..]);
+ let mut deserialized: IsaacRng = bincode::deserialize_from(&mut read).expect("Could not deserialize");
+
+ for _ in 0..300 { // more than the 256 buffered results
+ assert_eq!(rng.next_u32(), deserialized.next_u32());
+ }
+ }
+}
diff --git a/rand/rand_isaac/src/isaac64.rs b/rand/rand_isaac/src/isaac64.rs
new file mode 100644
index 0000000..2712762
--- /dev/null
+++ b/rand/rand_isaac/src/isaac64.rs
@@ -0,0 +1,481 @@
+// Copyright 2018 Developers of the Rand project.
+// Copyright 2013-2018 The Rust Project Developers.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! The ISAAC-64 random number generator.
+
+use core::{fmt, slice};
+use core::num::Wrapping as w;
+use rand_core::{RngCore, SeedableRng, Error, le};
+use rand_core::block::{BlockRngCore, BlockRng64};
+use isaac_array::IsaacArray;
+
+#[allow(non_camel_case_types)]
+type w64 = w<u64>;
+
+const RAND_SIZE_LEN: usize = 8;
+const RAND_SIZE: usize = 1 << RAND_SIZE_LEN;
+
+/// A random number generator that uses ISAAC-64, the 64-bit variant of the
+/// ISAAC algorithm.
+///
+/// ISAAC stands for "Indirection, Shift, Accumulate, Add, and Count" which are
+/// the principal bitwise operations employed. It is the most advanced of a
+/// series of array based random number generator designed by Robert Jenkins
+/// in 1996[^1].
+///
+/// ISAAC-64 is mostly similar to ISAAC. Because it operates on 64-bit integers
+/// instead of 32-bit, it uses twice as much memory to hold its state and
+/// results. Also it uses different constants for shifts and indirect indexing,
+/// optimized to give good results for 64bit arithmetic.
+///
+/// ISAAC-64 is notably fast and produces excellent quality random numbers for
+/// non-cryptographic applications.
+///
+/// In spite of being designed with cryptographic security in mind, ISAAC hasn't
+/// been stringently cryptanalyzed and thus cryptographers do not not
+/// consensually trust it to be secure. When looking for a secure RNG, prefer
+/// [`Hc128Rng`] instead, which, like ISAAC, is an array-based RNG and one of
+/// the stream-ciphers selected the by eSTREAM contest.
+///
+/// ## Overview of the ISAAC-64 algorithm:
+/// (in pseudo-code)
+///
+/// ```text
+/// Input: a, b, c, s[256] // state
+/// Output: r[256] // results
+///
+/// mix(a,i) = !(a ^ a << 21) if i = 0 mod 4
+/// a ^ a >> 5 if i = 1 mod 4
+/// a ^ a << 12 if i = 2 mod 4
+/// a ^ a >> 33 if i = 3 mod 4
+///
+/// c = c + 1
+/// b = b + c
+///
+/// for i in 0..256 {
+/// x = s_[i]
+/// a = mix(a,i) + s[i+128 mod 256]
+/// y = a + b + s[x>>3 mod 256]
+/// s[i] = y
+/// b = x + s[y>>11 mod 256]
+/// r[i] = b
+/// }
+/// ```
+///
+/// This implementation uses [`BlockRng64`] to implement the [`RngCore`] methods.
+///
+/// See for more information the documentation of [`IsaacRng`].
+///
+/// [^1]: Bob Jenkins, [*ISAAC and RC4*](
+/// http://burtleburtle.net/bob/rand/isaac.html)
+///
+/// [`IsaacRng`]: ../isaac/struct.IsaacRng.html
+/// [`Hc128Rng`]: ../../rand_hc/struct.Hc128Rng.html
+/// [`BlockRng64`]: ../../rand_core/block/struct.BlockRng64.html
+/// [`RngCore`]: ../../rand_core/trait.RngCore.html
+#[derive(Clone, Debug)]
+#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))]
+pub struct Isaac64Rng(BlockRng64<Isaac64Core>);
+
+impl RngCore for Isaac64Rng {
+ #[inline(always)]
+ fn next_u32(&mut self) -> u32 {
+ self.0.next_u32()
+ }
+
+ #[inline(always)]
+ fn next_u64(&mut self) -> u64 {
+ self.0.next_u64()
+ }
+
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
+ self.0.fill_bytes(dest)
+ }
+
+ fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ self.0.try_fill_bytes(dest)
+ }
+}
+
+impl SeedableRng for Isaac64Rng {
+ type Seed = <Isaac64Core as SeedableRng>::Seed;
+
+ fn from_seed(seed: Self::Seed) -> Self {
+ Isaac64Rng(BlockRng64::<Isaac64Core>::from_seed(seed))
+ }
+
+ /// Create an ISAAC random number generator using an `u64` as seed.
+ /// If `seed == 0` this will produce the same stream of random numbers as
+ /// the reference implementation when used unseeded.
+ fn seed_from_u64(seed: u64) -> Self {
+ Isaac64Rng(BlockRng64::<Isaac64Core>::seed_from_u64(seed))
+ }
+
+ fn from_rng<S: RngCore>(rng: S) -> Result<Self, Error> {
+ BlockRng64::<Isaac64Core>::from_rng(rng).map(|rng| Isaac64Rng(rng))
+ }
+}
+
+impl Isaac64Rng {
+ /// Create an ISAAC-64 random number generator using an `u64` as seed.
+ /// If `seed == 0` this will produce the same stream of random numbers as
+ /// the reference implementation when used unseeded.
+ #[deprecated(since="0.6.0", note="use SeedableRng::seed_from_u64 instead")]
+ pub fn new_from_u64(seed: u64) -> Self {
+ Self::seed_from_u64(seed)
+ }
+}
+
+/// The core of `Isaac64Rng`, used with `BlockRng`.
+#[derive(Clone)]
+#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))]
+pub struct Isaac64Core {
+ #[cfg_attr(feature="serde1",serde(with="super::isaac_array::isaac_array_serde"))]
+ mem: [w64; RAND_SIZE],
+ a: w64,
+ b: w64,
+ c: w64,
+}
+
+// Custom Debug implementation that does not expose the internal state
+impl fmt::Debug for Isaac64Core {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "Isaac64Core {{}}")
+ }
+}
+
+impl BlockRngCore for Isaac64Core {
+ type Item = u64;
+ type Results = IsaacArray<Self::Item>;
+
+ /// Refills the output buffer, `results`. See also the pseudocode desciption
+ /// of the algorithm in the [`Isaac64Rng`] documentation.
+ ///
+ /// Optimisations used (similar to the reference implementation):
+ ///
+ /// - The loop is unrolled 4 times, once for every constant of mix().
+ /// - The contents of the main loop are moved to a function `rngstep`, to
+ /// reduce code duplication.
+ /// - We use local variables for a and b, which helps with optimisations.
+ /// - We split the main loop in two, one that operates over 0..128 and one
+ /// over 128..256. This way we can optimise out the addition and modulus
+ /// from `s[i+128 mod 256]`.
+ /// - We maintain one index `i` and add `m` or `m2` as base (m2 for the
+ /// `s[i+128 mod 256]`), relying on the optimizer to turn it into pointer
+ /// arithmetic.
+ /// - We fill `results` backwards. The reference implementation reads values
+ /// from `results` in reverse. We read them in the normal direction, to
+ /// make `fill_bytes` a memcopy. To maintain compatibility we fill in
+ /// reverse.
+ ///
+ /// [`Isaac64Rng`]: struct.Isaac64Rng.html
+ fn generate(&mut self, results: &mut IsaacArray<Self::Item>) {
+ self.c += w(1);
+ // abbreviations
+ let mut a = self.a;
+ let mut b = self.b + self.c;
+ const MIDPOINT: usize = RAND_SIZE / 2;
+
+ #[inline]
+ fn ind(mem:&[w64; RAND_SIZE], v: w64, amount: usize) -> w64 {
+ let index = (v >> amount).0 as usize % RAND_SIZE;
+ mem[index]
+ }
+
+ #[inline]
+ fn rngstep(mem: &mut [w64; RAND_SIZE],
+ results: &mut [u64; RAND_SIZE],
+ mix: w64,
+ a: &mut w64,
+ b: &mut w64,
+ base: usize,
+ m: usize,
+ m2: usize) {
+ let x = mem[base + m];
+ *a = mix + mem[base + m2];
+ let y = *a + *b + ind(&mem, x, 3);
+ mem[base + m] = y;
+ *b = x + ind(&mem, y, 3 + RAND_SIZE_LEN);
+ results[RAND_SIZE - 1 - base - m] = (*b).0;
+ }
+
+ let mut m = 0;
+ let mut m2 = MIDPOINT;
+ for i in (0..MIDPOINT/4).map(|i| i * 4) {
+ rngstep(&mut self.mem, results, !(a ^ (a << 21)), &mut a, &mut b, i + 0, m, m2);
+ rngstep(&mut self.mem, results, a ^ (a >> 5 ), &mut a, &mut b, i + 1, m, m2);
+ rngstep(&mut self.mem, results, a ^ (a << 12), &mut a, &mut b, i + 2, m, m2);
+ rngstep(&mut self.mem, results, a ^ (a >> 33), &mut a, &mut b, i + 3, m, m2);
+ }
+
+ m = MIDPOINT;
+ m2 = 0;
+ for i in (0..MIDPOINT/4).map(|i| i * 4) {
+ rngstep(&mut self.mem, results, !(a ^ (a << 21)), &mut a, &mut b, i + 0, m, m2);
+ rngstep(&mut self.mem, results, a ^ (a >> 5 ), &mut a, &mut b, i + 1, m, m2);
+ rngstep(&mut self.mem, results, a ^ (a << 12), &mut a, &mut b, i + 2, m, m2);
+ rngstep(&mut self.mem, results, a ^ (a >> 33), &mut a, &mut b, i + 3, m, m2);
+ }
+
+ self.a = a;
+ self.b = b;
+ }
+}
+
+impl Isaac64Core {
+ /// Create a new ISAAC-64 random number generator.
+ fn init(mut mem: [w64; RAND_SIZE], rounds: u32) -> Self {
+ fn mix(a: &mut w64, b: &mut w64, c: &mut w64, d: &mut w64,
+ e: &mut w64, f: &mut w64, g: &mut w64, h: &mut w64) {
+ *a -= *e; *f ^= *h >> 9; *h += *a;
+ *b -= *f; *g ^= *a << 9; *a += *b;
+ *c -= *g; *h ^= *b >> 23; *b += *c;
+ *d -= *h; *a ^= *c << 15; *c += *d;
+ *e -= *a; *b ^= *d >> 14; *d += *e;
+ *f -= *b; *c ^= *e << 20; *e += *f;
+ *g -= *c; *d ^= *f >> 17; *f += *g;
+ *h -= *d; *e ^= *g << 14; *g += *h;
+ }
+
+ // These numbers are the result of initializing a...h with the
+ // fractional part of the golden ratio in binary (0x9e3779b97f4a7c13)
+ // and applying mix() 4 times.
+ let mut a = w(0x647c4677a2884b7c);
+ let mut b = w(0xb9f8b322c73ac862);
+ let mut c = w(0x8c0ea5053d4712a0);
+ let mut d = w(0xb29b2e824a595524);
+ let mut e = w(0x82f053db8355e0ce);
+ let mut f = w(0x48fe4a0fa5a09315);
+ let mut g = w(0xae985bf2cbfc89ed);
+ let mut h = w(0x98f5704f6c44c0ab);
+
+ // Normally this should do two passes, to make all of the seed effect
+ // all of `mem`
+ for _ in 0..rounds {
+ for i in (0..RAND_SIZE/8).map(|i| i * 8) {
+ a += mem[i ]; b += mem[i+1];
+ c += mem[i+2]; d += mem[i+3];
+ e += mem[i+4]; f += mem[i+5];
+ g += mem[i+6]; h += mem[i+7];
+ mix(&mut a, &mut b, &mut c, &mut d,
+ &mut e, &mut f, &mut g, &mut h);
+ mem[i ] = a; mem[i+1] = b;
+ mem[i+2] = c; mem[i+3] = d;
+ mem[i+4] = e; mem[i+5] = f;
+ mem[i+6] = g; mem[i+7] = h;
+ }
+ }
+
+ Self { mem, a: w(0), b: w(0), c: w(0) }
+ }
+
+ /// Create an ISAAC-64 random number generator using an `u64` as seed.
+ /// If `seed == 0` this will produce the same stream of random numbers as
+ /// the reference implementation when used unseeded.
+ #[deprecated(since="0.6.0", note="use SeedableRng::seed_from_u64 instead")]
+ pub fn new_from_u64(seed: u64) -> Self {
+ Self::seed_from_u64(seed)
+ }
+}
+
+impl SeedableRng for Isaac64Core {
+ type Seed = [u8; 32];
+
+ fn from_seed(seed: Self::Seed) -> Self {
+ let mut seed_u64 = [0u64; 4];
+ le::read_u64_into(&seed, &mut seed_u64);
+ // Convert the seed to `Wrapping<u64>` and zero-extend to `RAND_SIZE`.
+ let mut seed_extended = [w(0); RAND_SIZE];
+ for (x, y) in seed_extended.iter_mut().zip(seed_u64.iter()) {
+ *x = w(*y);
+ }
+ Self::init(seed_extended, 2)
+ }
+
+ fn seed_from_u64(seed: u64) -> Self {
+ let mut key = [w(0); RAND_SIZE];
+ key[0] = w(seed);
+ // Initialize with only one pass.
+ // A second pass does not improve the quality here, because all of the
+ // seed was already available in the first round.
+ // Not doing the second pass has the small advantage that if
+ // `seed == 0` this method produces exactly the same state as the
+ // reference implementation when used unseeded.
+ Self::init(key, 1)
+ }
+
+ fn from_rng<R: RngCore>(mut rng: R) -> Result<Self, Error> {
+ // Custom `from_rng` implementation that fills a seed with the same size
+ // as the entire state.
+ let mut seed = [w(0u64); RAND_SIZE];
+ unsafe {
+ let ptr = seed.as_mut_ptr() as *mut u8;
+ let slice = slice::from_raw_parts_mut(ptr, RAND_SIZE * 8);
+ rng.try_fill_bytes(slice)?;
+ }
+ for i in seed.iter_mut() {
+ *i = w(i.0.to_le());
+ }
+
+ Ok(Self::init(seed, 2))
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use rand_core::{RngCore, SeedableRng};
+ use super::Isaac64Rng;
+
+ #[test]
+ fn test_isaac64_construction() {
+ // Test that various construction techniques produce a working RNG.
+ let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0,
+ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0];
+ let mut rng1 = Isaac64Rng::from_seed(seed);
+ assert_eq!(rng1.next_u64(), 14964555543728284049);
+
+ let mut rng2 = Isaac64Rng::from_rng(rng1).unwrap();
+ assert_eq!(rng2.next_u64(), 919595328260451758);
+ }
+
+ #[test]
+ fn test_isaac64_true_values_64() {
+ let seed = [1,0,0,0, 0,0,0,0, 23,0,0,0, 0,0,0,0,
+ 200,1,0,0, 0,0,0,0, 210,30,0,0, 0,0,0,0];
+ let mut rng1 = Isaac64Rng::from_seed(seed);
+ let mut results = [0u64; 10];
+ for i in results.iter_mut() { *i = rng1.next_u64(); }
+ let expected = [
+ 15071495833797886820, 7720185633435529318,
+ 10836773366498097981, 5414053799617603544,
+ 12890513357046278984, 17001051845652595546,
+ 9240803642279356310, 12558996012687158051,
+ 14673053937227185542, 1677046725350116783];
+ assert_eq!(results, expected);
+
+ let seed = [57,48,0,0, 0,0,0,0, 50,9,1,0, 0,0,0,0,
+ 49,212,0,0, 0,0,0,0, 148,38,0,0, 0,0,0,0];
+ let mut rng2 = Isaac64Rng::from_seed(seed);
+ // skip forward to the 10000th number
+ for _ in 0..10000 { rng2.next_u64(); }
+
+ for i in results.iter_mut() { *i = rng2.next_u64(); }
+ let expected = [
+ 18143823860592706164, 8491801882678285927, 2699425367717515619,
+ 17196852593171130876, 2606123525235546165, 15790932315217671084,
+ 596345674630742204, 9947027391921273664, 11788097613744130851,
+ 10391409374914919106];
+ assert_eq!(results, expected);
+ }
+
+ #[test]
+ fn test_isaac64_true_values_32() {
+ let seed = [1,0,0,0, 0,0,0,0, 23,0,0,0, 0,0,0,0,
+ 200,1,0,0, 0,0,0,0, 210,30,0,0, 0,0,0,0];
+ let mut rng = Isaac64Rng::from_seed(seed);
+ let mut results = [0u32; 12];
+ for i in results.iter_mut() { *i = rng.next_u32(); }
+ // Subset of above values, as an LE u32 sequence
+ let expected = [
+ 3477963620, 3509106075,
+ 687845478, 1797495790,
+ 227048253, 2523132918,
+ 4044335064, 1260557630,
+ 4079741768, 3001306521,
+ 69157722, 3958365844];
+ assert_eq!(results, expected);
+ }
+
+ #[test]
+ fn test_isaac64_true_values_mixed() {
+ let seed = [1,0,0,0, 0,0,0,0, 23,0,0,0, 0,0,0,0,
+ 200,1,0,0, 0,0,0,0, 210,30,0,0, 0,0,0,0];
+ let mut rng = Isaac64Rng::from_seed(seed);
+ // Test alternating between `next_u64` and `next_u32` works as expected.
+ // Values are the same as `test_isaac64_true_values` and
+ // `test_isaac64_true_values_32`.
+ assert_eq!(rng.next_u64(), 15071495833797886820);
+ assert_eq!(rng.next_u32(), 687845478);
+ assert_eq!(rng.next_u32(), 1797495790);
+ assert_eq!(rng.next_u64(), 10836773366498097981);
+ assert_eq!(rng.next_u32(), 4044335064);
+ // Skip one u32
+ assert_eq!(rng.next_u64(), 12890513357046278984);
+ assert_eq!(rng.next_u32(), 69157722);
+ }
+
+ #[test]
+ fn test_isaac64_true_bytes() {
+ let seed = [1,0,0,0, 0,0,0,0, 23,0,0,0, 0,0,0,0,
+ 200,1,0,0, 0,0,0,0, 210,30,0,0, 0,0,0,0];
+ let mut rng = Isaac64Rng::from_seed(seed);
+ let mut results = [0u8; 32];
+ rng.fill_bytes(&mut results);
+ // Same as first values in test_isaac64_true_values as bytes in LE order
+ let expected = [100, 131, 77, 207, 155, 181, 40, 209,
+ 102, 176, 255, 40, 238, 155, 35, 107,
+ 61, 123, 136, 13, 246, 243, 99, 150,
+ 216, 167, 15, 241, 62, 149, 34, 75];
+ assert_eq!(results, expected);
+ }
+
+ #[test]
+ fn test_isaac64_new_uninitialized() {
+ // Compare the results from initializing `IsaacRng` with
+ // `seed_from_u64(0)`, to make sure it is the same as the reference
+ // implementation when used uninitialized.
+ // Note: We only test the first 16 integers, not the full 256 of the
+ // first block.
+ let mut rng = Isaac64Rng::seed_from_u64(0);
+ let mut results = [0u64; 16];
+ for i in results.iter_mut() { *i = rng.next_u64(); }
+ let expected: [u64; 16] = [
+ 0xF67DFBA498E4937C, 0x84A5066A9204F380, 0xFEE34BD5F5514DBB,
+ 0x4D1664739B8F80D6, 0x8607459AB52A14AA, 0x0E78BC5A98529E49,
+ 0xFE5332822AD13777, 0x556C27525E33D01A, 0x08643CA615F3149F,
+ 0xD0771FAF3CB04714, 0x30E86F68A37B008D, 0x3074EBC0488A3ADF,
+ 0x270645EA7A2790BC, 0x5601A0A8D3763C6A, 0x2F83071F53F325DD,
+ 0xB9090F3D42D2D2EA];
+ assert_eq!(results, expected);
+ }
+
+ #[test]
+ fn test_isaac64_clone() {
+ let seed = [1,0,0,0, 0,0,0,0, 23,0,0,0, 0,0,0,0,
+ 200,1,0,0, 0,0,0,0, 210,30,0,0, 0,0,0,0];
+ let mut rng1 = Isaac64Rng::from_seed(seed);
+ let mut rng2 = rng1.clone();
+ for _ in 0..16 {
+ assert_eq!(rng1.next_u64(), rng2.next_u64());
+ }
+ }
+
+ #[test]
+ #[cfg(feature="serde1")]
+ fn test_isaac64_serde() {
+ use bincode;
+ use std::io::{BufWriter, BufReader};
+
+ let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0,
+ 57,48,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0];
+ let mut rng = Isaac64Rng::from_seed(seed);
+
+ let buf: Vec<u8> = Vec::new();
+ let mut buf = BufWriter::new(buf);
+ bincode::serialize_into(&mut buf, &rng).expect("Could not serialize");
+
+ let buf = buf.into_inner().unwrap();
+ let mut read = BufReader::new(&buf[..]);
+ let mut deserialized: Isaac64Rng = bincode::deserialize_from(&mut read).expect("Could not deserialize");
+
+ for _ in 0..300 { // more than the 256 buffered results
+ assert_eq!(rng.next_u64(), deserialized.next_u64());
+ }
+ }
+}
diff --git a/rand/rand_isaac/src/isaac_array.rs b/rand/rand_isaac/src/isaac_array.rs
new file mode 100644
index 0000000..0fa6147
--- /dev/null
+++ b/rand/rand_isaac/src/isaac_array.rs
@@ -0,0 +1,136 @@
+// Copyright 2018 Developers of the Rand project.
+// Copyright 2017-2018 The Rust Project Developers.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! ISAAC helper functions for 256-element arrays.
+
+// Terrible workaround because arrays with more than 32 elements do not
+// implement `AsRef`, `Default`, `Serialize`, `Deserialize`, or any other
+// traits for that matter.
+
+#[cfg(feature="serde1")] use serde::{Serialize, Deserialize};
+
+const RAND_SIZE_LEN: usize = 8;
+const RAND_SIZE: usize = 1 << RAND_SIZE_LEN;
+
+
+#[derive(Copy, Clone)]
+#[allow(missing_debug_implementations)]
+#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))]
+pub struct IsaacArray<T> {
+ #[cfg_attr(feature="serde1",serde(with="isaac_array_serde"))]
+ #[cfg_attr(feature="serde1", serde(bound(
+ serialize = "T: Serialize",
+ deserialize = "T: Deserialize<'de> + Copy + Default")))]
+ inner: [T; RAND_SIZE]
+}
+
+impl<T> ::core::convert::AsRef<[T]> for IsaacArray<T> {
+ #[inline(always)]
+ fn as_ref(&self) -> &[T] {
+ &self.inner[..]
+ }
+}
+
+impl<T> ::core::convert::AsMut<[T]> for IsaacArray<T> {
+ #[inline(always)]
+ fn as_mut(&mut self) -> &mut [T] {
+ &mut self.inner[..]
+ }
+}
+
+impl<T> ::core::ops::Deref for IsaacArray<T> {
+ type Target = [T; RAND_SIZE];
+ #[inline(always)]
+ fn deref(&self) -> &Self::Target {
+ &self.inner
+ }
+}
+
+impl<T> ::core::ops::DerefMut for IsaacArray<T> {
+ #[inline(always)]
+ fn deref_mut(&mut self) -> &mut [T; RAND_SIZE] {
+ &mut self.inner
+ }
+}
+
+impl<T> ::core::default::Default for IsaacArray<T> where T: Copy + Default {
+ fn default() -> IsaacArray<T> {
+ IsaacArray { inner: [T::default(); RAND_SIZE] }
+ }
+}
+
+
+#[cfg(feature="serde1")]
+pub(super) mod isaac_array_serde {
+ const RAND_SIZE_LEN: usize = 8;
+ const RAND_SIZE: usize = 1 << RAND_SIZE_LEN;
+
+ use serde::{Deserialize, Deserializer, Serialize, Serializer};
+ use serde::de::{Visitor,SeqAccess};
+ use serde::de;
+
+ use core::fmt;
+
+ pub fn serialize<T, S>(arr: &[T;RAND_SIZE], ser: S) -> Result<S::Ok, S::Error>
+ where
+ T: Serialize,
+ S: Serializer
+ {
+ use serde::ser::SerializeTuple;
+
+ let mut seq = ser.serialize_tuple(RAND_SIZE)?;
+
+ for e in arr.iter() {
+ seq.serialize_element(&e)?;
+ }
+
+ seq.end()
+ }
+
+ #[inline]
+ pub fn deserialize<'de, T, D>(de: D) -> Result<[T;RAND_SIZE], D::Error>
+ where
+ T: Deserialize<'de>+Default+Copy,
+ D: Deserializer<'de>,
+ {
+ use core::marker::PhantomData;
+ struct ArrayVisitor<T> {
+ _pd: PhantomData<T>,
+ };
+ impl<'de,T> Visitor<'de> for ArrayVisitor<T>
+ where
+ T: Deserialize<'de>+Default+Copy
+ {
+ type Value = [T; RAND_SIZE];
+
+ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Isaac state array")
+ }
+
+ #[inline]
+ fn visit_seq<A>(self, mut seq: A) -> Result<[T; RAND_SIZE], A::Error>
+ where
+ A: SeqAccess<'de>,
+ {
+ let mut out = [Default::default();RAND_SIZE];
+
+ for i in 0..RAND_SIZE {
+ match seq.next_element()? {
+ Some(val) => out[i] = val,
+ None => return Err(de::Error::invalid_length(i, &self)),
+ };
+ }
+
+ Ok(out)
+ }
+ }
+
+ de.deserialize_tuple(RAND_SIZE, ArrayVisitor{_pd: PhantomData})
+ }
+}
diff --git a/rand/rand_isaac/src/lib.rs b/rand/rand_isaac/src/lib.rs
new file mode 100644
index 0000000..ec82d8e
--- /dev/null
+++ b/rand/rand_isaac/src/lib.rs
@@ -0,0 +1,36 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! The ISAAC and ISAAC-64 random number generators.
+
+#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png",
+ html_favicon_url = "https://www.rust-lang.org/favicon.ico",
+ html_root_url = "https://rust-random.github.io/rand/")]
+
+#![deny(missing_docs)]
+#![deny(missing_debug_implementations)]
+#![doc(test(attr(allow(unused_variables), deny(warnings))))]
+
+#![cfg_attr(not(all(feature="serde1", test)), no_std)]
+
+extern crate rand_core;
+
+#[cfg(feature="serde1")] extern crate serde;
+#[cfg(feature="serde1")] #[macro_use] extern crate serde_derive;
+
+// To test serialization we need bincode and the standard library
+#[cfg(all(feature="serde1", test))] extern crate bincode;
+#[cfg(all(feature="serde1", test))] extern crate std as core;
+
+pub mod isaac;
+pub mod isaac64;
+
+mod isaac_array;
+
+pub use self::isaac::IsaacRng;
+pub use self::isaac64::Isaac64Rng;
diff --git a/rand/rand_pcg/CHANGELOG.md b/rand/rand_pcg/CHANGELOG.md
new file mode 100644
index 0000000..d37408d
--- /dev/null
+++ b/rand/rand_pcg/CHANGELOG.md
@@ -0,0 +1,14 @@
+# Changelog
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+## [0.1.1] - 2018-10-04
+- make `bincode` an explicit dependency when using Serde
+
+## [0.1.0] - 2018-10-04
+Initial release, including:
+
+- `Lcg64Xsh32` aka `Pcg32`
+- `Mcg128Xsl64` aka `Pcg64Mcg`
diff --git a/rand/rand_pcg/COPYRIGHT b/rand/rand_pcg/COPYRIGHT
new file mode 100644
index 0000000..468d907
--- /dev/null
+++ b/rand/rand_pcg/COPYRIGHT
@@ -0,0 +1,12 @@
+Copyrights in the Rand project are retained by their contributors. No
+copyright assignment is required to contribute to the Rand project.
+
+For full authorship information, see the version control history.
+
+Except as otherwise noted (below and/or in individual files), Rand is
+licensed under the Apache License, Version 2.0 <LICENSE-APACHE> or
+<http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+<LICENSE-MIT> or <http://opensource.org/licenses/MIT>, at your option.
+
+The Rand project includes code from the Rust project
+published under these same licenses.
diff --git a/rand/rand_pcg/Cargo.toml b/rand/rand_pcg/Cargo.toml
new file mode 100644
index 0000000..c8a29fc
--- /dev/null
+++ b/rand/rand_pcg/Cargo.toml
@@ -0,0 +1,37 @@
+[package]
+name = "rand_pcg"
+version = "0.1.1"
+authors = ["The Rand Project Developers"]
+license = "MIT/Apache-2.0"
+readme = "README.md"
+repository = "https://github.com/rust-random/rand"
+documentation = "https://rust-random.github.io/rand/rand_pcg"
+homepage = "https://crates.io/crates/rand_pcg"
+description = """
+Selected PCG random number generators
+"""
+keywords = ["random", "rng", "pcg"]
+categories = ["algorithms", "no-std"]
+build = "build.rs"
+
+[badges]
+travis-ci = { repository = "rust-random/rand" }
+appveyor = { repository = "rust-random/rand" }
+
+[features]
+serde1 = ["serde", "serde_derive"]
+
+[dependencies]
+rand_core = { path = "../rand_core", version = "0.3", default-features=false }
+serde = { version = "1", optional = true }
+serde_derive = { version = "^1.0.38", optional = true }
+
+[dev-dependencies]
+# This is for testing serde, unfortunately we can't specify feature-gated dev
+# deps yet, see: https://github.com/rust-lang/cargo/issues/1596
+# TODO: we shouldn't have to depend on i128 directly; it breaks tests on old
+# compilers. `bincode` should automatically support this.
+bincode = { version = "1", features = ["i128"] }
+
+[build-dependencies]
+rustc_version = "0.2"
diff --git a/rand/rand_pcg/LICENSE-APACHE b/rand/rand_pcg/LICENSE-APACHE
new file mode 100644
index 0000000..17d7468
--- /dev/null
+++ b/rand/rand_pcg/LICENSE-APACHE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ https://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/rand/rand_pcg/LICENSE-MIT b/rand/rand_pcg/LICENSE-MIT
new file mode 100644
index 0000000..d46f058
--- /dev/null
+++ b/rand/rand_pcg/LICENSE-MIT
@@ -0,0 +1,26 @@
+Copyright (c) 2014-2017 Melissa O'Neill and PCG Project contributors
+Copyright 2018 Developers of the Rand project
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/rand/rand_pcg/README.md b/rand/rand_pcg/README.md
new file mode 100644
index 0000000..4599813
--- /dev/null
+++ b/rand/rand_pcg/README.md
@@ -0,0 +1,51 @@
+# rand_pcg
+
+[![Build Status](https://travis-ci.org/rust-random/rand.svg?branch=master)](https://travis-ci.org/rust-random/rand)
+[![Build Status](https://ci.appveyor.com/api/projects/status/github/rust-random/rand?svg=true)](https://ci.appveyor.com/project/rust-random/rand)
+[![Latest version](https://img.shields.io/crates/v/rand_pcg.svg)](https://crates.io/crates/rand_pcg)
+[[![Book](https://img.shields.io/badge/book-master-yellow.svg)](https://rust-random.github.io/book/)
+[![API](https://img.shields.io/badge/api-master-yellow.svg)](https://rust-random.github.io/rand/rand_pcg)
+[![API](https://docs.rs/rand_pcg/badge.svg)](https://docs.rs/rand_pcg)
+[![Minimum rustc version](https://img.shields.io/badge/rustc-1.22+-lightgray.svg)](https://github.com/rust-random/rand#rust-version-requirements)
+
+Implements a selection of PCG random number generators.
+
+> PCG is a family of simple fast space-efficient statistically good algorithms
+> for random number generation. [Melissa O'Neill, Harvey Mudd College, 2014].
+
+The PCG algorithms are not suitable for cryptographic uses, but perform well
+in statistical tests, use little memory and are fairly fast.
+See the [pcg-random website](http://www.pcg-random.org/).
+
+This crate depends on [rand_core](https://crates.io/crates/rand_core) and is
+part of the [Rand project](https://github.com/rust-random/rand).
+
+Links:
+
+- [API documentation (master)](https://rust-random.github.io/rand/rand_pcg)
+- [API documentation (docs.rs)](https://docs.rs/rand_pcg)
+- [Changelog](CHANGELOG.md)
+
+
+## Crate Features
+
+`rand_pcg` is `no_std` compatible. It does not require any functionality
+outside of the `core` lib, thus there are no features to configure.
+
+The `serde1` feature includes implementations of `Serialize` and `Deserialize`
+for the included RNGs. NOTE: to use binary serialisation with any of the 64-bit
+output (128-bit internal) RNGs, you must add the following dependency, since the
+`i128` feature is not current enabled by default (this should be fixed soon):
+
+```
+bincode = { version = "1", features = ["i128"] }
+```
+
+
+## License
+
+`rand_pcg` is distributed under the terms of both the MIT license and the
+Apache License (Version 2.0).
+
+See [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT), and
+[COPYRIGHT](COPYRIGHT) for details.
diff --git a/rand/rand_pcg/build.rs b/rand/rand_pcg/build.rs
new file mode 100644
index 0000000..cb3ae20
--- /dev/null
+++ b/rand/rand_pcg/build.rs
@@ -0,0 +1,8 @@
+extern crate rustc_version;
+use rustc_version::{version, Version};
+
+fn main() {
+ if version().unwrap() >= Version::parse("1.26.0").unwrap() {
+ println!("cargo:rustc-cfg=rust_1_26");
+ }
+}
diff --git a/rand/rand_pcg/src/lib.rs b/rand/rand_pcg/src/lib.rs
new file mode 100644
index 0000000..5160e87
--- /dev/null
+++ b/rand/rand_pcg/src/lib.rs
@@ -0,0 +1,48 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! The PCG random number generators.
+//!
+//! This is a native Rust implementation of a small selection of PCG generators.
+//! The primary goal of this crate is simple, minimal, well-tested code; in
+//! other words it is explicitly not a goal to re-implement all of PCG.
+//!
+//! This crate provides:
+//!
+//! - `Pcg32` aka `Lcg64Xsh32`, officially known as `pcg32`, a general
+//! purpose RNG. This is a good choice on both 32-bit and 64-bit CPUs
+//! (for 32-bit output).
+//! - `Pcg64Mcg` aka `Mcg128Xsl64`, officially known as `mcg_xsl_rr_128_64`,
+//! a general purpose RNG using 128-bit multiplications. This has poor
+//! performance on 32-bit CPUs but is a good choice on 64-bit CPUs for
+//! both 32-bit and 64-bit output. (Note: this RNG is only available using
+//! Rust 1.26 or later.)
+//!
+//! Both of these use 16 bytes of state and 128-bit seeds, and are considered
+//! value-stable (i.e. any change affecting the output given a fixed seed would
+//! be considered a breaking change to the crate).
+
+#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png",
+ html_favicon_url = "https://www.rust-lang.org/favicon.ico",
+ html_root_url = "https://rust-random.github.io/rand/")]
+
+#![deny(missing_docs)]
+#![deny(missing_debug_implementations)]
+
+#![no_std]
+
+extern crate rand_core;
+
+#[cfg(feature="serde1")] extern crate serde;
+#[cfg(feature="serde1")] #[macro_use] extern crate serde_derive;
+
+mod pcg64;
+#[cfg(rust_1_26)] mod pcg128;
+
+pub use self::pcg64::{Pcg32, Lcg64Xsh32};
+#[cfg(rust_1_26)] pub use self::pcg128::{Pcg64Mcg, Mcg128Xsl64};
diff --git a/rand/rand_pcg/src/pcg128.rs b/rand/rand_pcg/src/pcg128.rs
new file mode 100644
index 0000000..9aff506
--- /dev/null
+++ b/rand/rand_pcg/src/pcg128.rs
@@ -0,0 +1,122 @@
+// Copyright 2018 Developers of the Rand project.
+// Copyright 2017 Paul Dicker.
+// Copyright 2014-2017 Melissa O'Neill and PCG Project contributors
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! PCG random number generators
+
+// This is the default multiplier used by PCG for 64-bit state.
+const MULTIPLIER: u128 = 0x2360_ED05_1FC6_5DA4_4385_DF64_9FCC_F645;
+
+use core::fmt;
+use core::mem::transmute;
+use rand_core::{RngCore, SeedableRng, Error, le};
+
+/// A PCG random number generator (XSL 128/64 (MCG) variant).
+///
+/// Permuted Congruential Generator with 128-bit state, internal Multiplicative
+/// Congruential Generator, and 64-bit output via "xorshift low (bits),
+/// random rotation" output function.
+///
+/// This is a 128-bit MCG with the PCG-XSL-RR output function.
+/// Note that compared to the standard `pcg64` (128-bit LCG with PCG-XSL-RR
+/// output function), this RNG is faster, also has a long cycle, and still has
+/// good performance on statistical tests.
+///
+/// Note: this RNG is only available using Rust 1.26 or later.
+#[derive(Clone)]
+#[cfg_attr(feature="serde1", derive(Serialize,Deserialize))]
+pub struct Mcg128Xsl64 {
+ state: u128,
+}
+
+/// A friendly name for `Mcg128Xsl64`.
+pub type Pcg64Mcg = Mcg128Xsl64;
+
+impl Mcg128Xsl64 {
+ /// Construct an instance compatible with PCG seed.
+ ///
+ /// Note that PCG specifies a default value for the parameter:
+ ///
+ /// - `state = 0xcafef00dd15ea5e5`
+ pub fn new(state: u128) -> Self {
+ // Force low bit to 1, as in C version (C++ uses `state | 3` instead).
+ Mcg128Xsl64 { state: state | 1 }
+ }
+}
+
+// Custom Debug implementation that does not expose the internal state
+impl fmt::Debug for Mcg128Xsl64 {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "Mcg128Xsl64 {{}}")
+ }
+}
+
+/// We use a single 126-bit seed to initialise the state and select a stream.
+/// Two `seed` bits (lowest order of last byte) are ignored.
+impl SeedableRng for Mcg128Xsl64 {
+ type Seed = [u8; 16];
+
+ fn from_seed(seed: Self::Seed) -> Self {
+ // Read as if a little-endian u128 value:
+ let mut seed_u64 = [0u64; 2];
+ le::read_u64_into(&seed, &mut seed_u64);
+ let state = (seed_u64[0] as u128) |
+ (seed_u64[1] as u128) << 64;
+ Mcg128Xsl64::new(state)
+ }
+}
+
+impl RngCore for Mcg128Xsl64 {
+ #[inline]
+ fn next_u32(&mut self) -> u32 {
+ self.next_u64() as u32
+ }
+
+ #[inline]
+ fn next_u64(&mut self) -> u64 {
+ // prepare the LCG for the next round
+ let state = self.state.wrapping_mul(MULTIPLIER);
+ self.state = state;
+
+ // Output function XSL RR ("xorshift low (bits), random rotation")
+ // Constants are for 128-bit state, 64-bit output
+ const XSHIFT: u32 = 64; // (128 - 64 + 64) / 2
+ const ROTATE: u32 = 122; // 128 - 6
+
+ let rot = (state >> ROTATE) as u32;
+ let xsl = ((state >> XSHIFT) as u64) ^ (state as u64);
+ xsl.rotate_right(rot)
+ }
+
+ #[inline]
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
+ // specialisation of impls::fill_bytes_via_next; approx 3x faster
+ let mut left = dest;
+ while left.len() >= 8 {
+ let (l, r) = {left}.split_at_mut(8);
+ left = r;
+ let chunk: [u8; 8] = unsafe {
+ transmute(self.next_u64().to_le())
+ };
+ l.copy_from_slice(&chunk);
+ }
+ let n = left.len();
+ if n > 0 {
+ let chunk: [u8; 8] = unsafe {
+ transmute(self.next_u64().to_le())
+ };
+ left.copy_from_slice(&chunk[..n]);
+ }
+ }
+
+ #[inline]
+ fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ Ok(self.fill_bytes(dest))
+ }
+}
diff --git a/rand/rand_pcg/src/pcg64.rs b/rand/rand_pcg/src/pcg64.rs
new file mode 100644
index 0000000..9177ec2
--- /dev/null
+++ b/rand/rand_pcg/src/pcg64.rs
@@ -0,0 +1,141 @@
+// Copyright 2018 Developers of the Rand project.
+// Copyright 2017 Paul Dicker.
+// Copyright 2014-2017 Melissa O'Neill and PCG Project contributors
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! PCG random number generators
+
+use core::fmt;
+use core::mem::transmute;
+use rand_core::{RngCore, SeedableRng, Error, le, impls};
+
+// This is the default multiplier used by PCG for 64-bit state.
+const MULTIPLIER: u64 = 6364136223846793005;
+
+/// A PCG random number generator (XSH RR 64/32 (LCG) variant).
+///
+/// Permuted Congruential Generator with 64-bit state, internal Linear
+/// Congruential Generator, and 32-bit output via "xorshift high (bits),
+/// random rotation" output function.
+///
+/// This is a 64-bit LCG with explicitly chosen stream with the PCG-XSH-RR
+/// output function. This combination is the standard `pcg32`.
+///
+/// Despite the name, this implementation uses 16 bytes (128 bit) space
+/// comprising 64 bits of state and 64 bits stream selector. These are both set
+/// by `SeedableRng`, using a 128-bit seed.
+#[derive(Clone)]
+#[cfg_attr(feature="serde1", derive(Serialize,Deserialize))]
+pub struct Lcg64Xsh32 {
+ state: u64,
+ increment: u64,
+}
+
+/// `Lcg64Xsh32` is also officially known as `pcg32`.
+pub type Pcg32 = Lcg64Xsh32;
+
+impl Lcg64Xsh32 {
+ /// Construct an instance compatible with PCG seed and stream.
+ ///
+ /// Note that PCG specifies default values for both parameters:
+ ///
+ /// - `state = 0xcafef00dd15ea5e5`
+ /// - `stream = 721347520444481703`
+ pub fn new(state: u64, stream: u64) -> Self {
+ // The increment must be odd, hence we discard one bit:
+ let increment = (stream << 1) | 1;
+ Lcg64Xsh32::from_state_incr(state, increment)
+ }
+
+ #[inline]
+ fn from_state_incr(state: u64, increment: u64) -> Self {
+ let mut pcg = Lcg64Xsh32 { state, increment };
+ // Move away from inital value:
+ pcg.state = pcg.state.wrapping_add(pcg.increment);
+ pcg.step();
+ pcg
+ }
+
+ #[inline]
+ fn step(&mut self) {
+ // prepare the LCG for the next round
+ self.state = self.state
+ .wrapping_mul(MULTIPLIER)
+ .wrapping_add(self.increment);
+ }
+}
+
+// Custom Debug implementation that does not expose the internal state
+impl fmt::Debug for Lcg64Xsh32 {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "Lcg64Xsh32 {{}}")
+ }
+}
+
+/// We use a single 127-bit seed to initialise the state and select a stream.
+/// One `seed` bit (lowest bit of `seed[8]`) is ignored.
+impl SeedableRng for Lcg64Xsh32 {
+ type Seed = [u8; 16];
+
+ fn from_seed(seed: Self::Seed) -> Self {
+ let mut seed_u64 = [0u64; 2];
+ le::read_u64_into(&seed, &mut seed_u64);
+
+ // The increment must be odd, hence we discard one bit:
+ Lcg64Xsh32::from_state_incr(seed_u64[0], seed_u64[1] | 1)
+ }
+}
+
+impl RngCore for Lcg64Xsh32 {
+ #[inline]
+ fn next_u32(&mut self) -> u32 {
+ let state = self.state;
+ self.step();
+
+ // Output function XSH RR: xorshift high (bits), followed by a random rotate
+ // Constants are for 64-bit state, 32-bit output
+ const ROTATE: u32 = 59; // 64 - 5
+ const XSHIFT: u32 = 18; // (5 + 32) / 2
+ const SPARE: u32 = 27; // 64 - 32 - 5
+
+ let rot = (state >> ROTATE) as u32;
+ let xsh = (((state >> XSHIFT) ^ state) >> SPARE) as u32;
+ xsh.rotate_right(rot)
+ }
+
+ #[inline]
+ fn next_u64(&mut self) -> u64 {
+ impls::next_u64_via_u32(self)
+ }
+
+ #[inline]
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
+ // specialisation of impls::fill_bytes_via_next; approx 40% faster
+ let mut left = dest;
+ while left.len() >= 4 {
+ let (l, r) = {left}.split_at_mut(4);
+ left = r;
+ let chunk: [u8; 4] = unsafe {
+ transmute(self.next_u32().to_le())
+ };
+ l.copy_from_slice(&chunk);
+ }
+ let n = left.len();
+ if n > 0 {
+ let chunk: [u8; 4] = unsafe {
+ transmute(self.next_u32().to_le())
+ };
+ left.copy_from_slice(&chunk[..n]);
+ }
+ }
+
+ #[inline]
+ fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ Ok(self.fill_bytes(dest))
+ }
+}
diff --git a/rand/rand_pcg/tests/lcg64xsh32.rs b/rand/rand_pcg/tests/lcg64xsh32.rs
new file mode 100644
index 0000000..775b12c
--- /dev/null
+++ b/rand/rand_pcg/tests/lcg64xsh32.rs
@@ -0,0 +1,58 @@
+extern crate rand_pcg;
+extern crate rand_core;
+#[cfg(all(feature="serde1", test))] extern crate bincode;
+
+use rand_core::{RngCore, SeedableRng};
+use rand_pcg::{Lcg64Xsh32, Pcg32};
+
+#[test]
+fn test_lcg64xsh32_construction() {
+ // Test that various construction techniques produce a working RNG.
+ let seed = [1,2,3,4, 5,6,7,8, 9,10,11,12, 13,14,15,16];
+ let mut rng1 = Lcg64Xsh32::from_seed(seed);
+ assert_eq!(rng1.next_u64(), 1204678643940597513);
+
+ let mut rng2 = Lcg64Xsh32::from_rng(&mut rng1).unwrap();
+ assert_eq!(rng2.next_u64(), 12384929573776311845);
+
+ let mut rng3 = Lcg64Xsh32::seed_from_u64(0);
+ assert_eq!(rng3.next_u64(), 18195738587432868099);
+
+ // This is the same as Lcg64Xsh32, so we only have a single test:
+ let mut rng4 = Pcg32::seed_from_u64(0);
+ assert_eq!(rng4.next_u64(), 18195738587432868099);
+}
+
+#[test]
+fn test_lcg64xsh32_true_values() {
+ // Numbers copied from official test suite.
+ let mut rng = Lcg64Xsh32::new(42, 54);
+
+ let mut results = [0u32; 6];
+ for i in results.iter_mut() { *i = rng.next_u32(); }
+ let expected: [u32; 6] = [0xa15c02b7, 0x7b47f409, 0xba1d3330,
+ 0x83d2f293, 0xbfa4784b, 0xcbed606e];
+ assert_eq!(results, expected);
+}
+
+#[cfg(feature="serde1")]
+#[test]
+fn test_lcg64xsh32_serde() {
+ use bincode;
+ use std::io::{BufWriter, BufReader};
+
+ let mut rng = Lcg64Xsh32::seed_from_u64(0);
+
+ let buf: Vec<u8> = Vec::new();
+ let mut buf = BufWriter::new(buf);
+ bincode::serialize_into(&mut buf, &rng).expect("Could not serialize");
+
+ let buf = buf.into_inner().unwrap();
+ let mut read = BufReader::new(&buf[..]);
+ let mut deserialized: Lcg64Xsh32 = bincode::deserialize_from(&mut read)
+ .expect("Could not deserialize");
+
+ for _ in 0..16 {
+ assert_eq!(rng.next_u64(), deserialized.next_u64());
+ }
+}
diff --git a/rand/rand_pcg/tests/mcg128xsl64.rs b/rand/rand_pcg/tests/mcg128xsl64.rs
new file mode 100644
index 0000000..2508917
--- /dev/null
+++ b/rand/rand_pcg/tests/mcg128xsl64.rs
@@ -0,0 +1,59 @@
+#![cfg(rust_1_26)]
+extern crate rand_pcg;
+extern crate rand_core;
+#[cfg(all(feature="serde1", test))] extern crate bincode;
+
+use rand_core::{RngCore, SeedableRng};
+use rand_pcg::{Mcg128Xsl64, Pcg64Mcg};
+
+#[test]
+fn test_mcg128xsl64_construction() {
+ // Test that various construction techniques produce a working RNG.
+ let seed = [1,2,3,4, 5,6,7,8, 9,10,11,12, 13,14,15,16];
+ let mut rng1 = Mcg128Xsl64::from_seed(seed);
+ assert_eq!(rng1.next_u64(), 7071994460355047496);
+
+ let mut rng2 = Mcg128Xsl64::from_rng(&mut rng1).unwrap();
+ assert_eq!(rng2.next_u64(), 12300796107712034932);
+
+ let mut rng3 = Mcg128Xsl64::seed_from_u64(0);
+ assert_eq!(rng3.next_u64(), 6198063878555692194);
+
+ // This is the same as Mcg128Xsl64, so we only have a single test:
+ let mut rng4 = Pcg64Mcg::seed_from_u64(0);
+ assert_eq!(rng4.next_u64(), 6198063878555692194);
+}
+
+#[test]
+fn test_mcg128xsl64_true_values() {
+ // Numbers copied from official test suite (C version).
+ let mut rng = Mcg128Xsl64::new(42);
+
+ let mut results = [0u64; 6];
+ for i in results.iter_mut() { *i = rng.next_u64(); }
+ let expected: [u64; 6] = [0x63b4a3a813ce700a, 0x382954200617ab24,
+ 0xa7fd85ae3fe950ce, 0xd715286aa2887737, 0x60c92fee2e59f32c, 0x84c4e96beff30017];
+ assert_eq!(results, expected);
+}
+
+#[cfg(feature="serde1")]
+#[test]
+fn test_mcg128xsl64_serde() {
+ use bincode;
+ use std::io::{BufWriter, BufReader};
+
+ let mut rng = Mcg128Xsl64::seed_from_u64(0);
+
+ let buf: Vec<u8> = Vec::new();
+ let mut buf = BufWriter::new(buf);
+ bincode::serialize_into(&mut buf, &rng).expect("Could not serialize");
+
+ let buf = buf.into_inner().unwrap();
+ let mut read = BufReader::new(&buf[..]);
+ let mut deserialized: Mcg128Xsl64 = bincode::deserialize_from(&mut read)
+ .expect("Could not deserialize");
+
+ for _ in 0..16 {
+ assert_eq!(rng.next_u64(), deserialized.next_u64());
+ }
+}
diff --git a/rand/rand_xorshift/CHANGELOG.md b/rand/rand_xorshift/CHANGELOG.md
new file mode 100644
index 0000000..9a896a5
--- /dev/null
+++ b/rand/rand_xorshift/CHANGELOG.md
@@ -0,0 +1,8 @@
+# Changelog
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+## [0.1.0] - 2018-07-16
+- Pulled out of the Rand crate
diff --git a/rand/rand_xorshift/COPYRIGHT b/rand/rand_xorshift/COPYRIGHT
new file mode 100644
index 0000000..468d907
--- /dev/null
+++ b/rand/rand_xorshift/COPYRIGHT
@@ -0,0 +1,12 @@
+Copyrights in the Rand project are retained by their contributors. No
+copyright assignment is required to contribute to the Rand project.
+
+For full authorship information, see the version control history.
+
+Except as otherwise noted (below and/or in individual files), Rand is
+licensed under the Apache License, Version 2.0 <LICENSE-APACHE> or
+<http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+<LICENSE-MIT> or <http://opensource.org/licenses/MIT>, at your option.
+
+The Rand project includes code from the Rust project
+published under these same licenses.
diff --git a/rand/rand_xorshift/Cargo.toml b/rand/rand_xorshift/Cargo.toml
new file mode 100644
index 0000000..b763bfc
--- /dev/null
+++ b/rand/rand_xorshift/Cargo.toml
@@ -0,0 +1,31 @@
+[package]
+name = "rand_xorshift"
+version = "0.1.0"
+authors = ["The Rand Project Developers", "The Rust Project Developers"]
+license = "MIT/Apache-2.0"
+readme = "README.md"
+repository = "https://github.com/rust-random/rand"
+documentation = "https://rust-random.github.io/rand/rand_xorshift"
+homepage = "https://crates.io/crates/rand_xorshift"
+description = """
+Xorshift random number generator
+"""
+keywords = ["random", "rng", "xorshift"]
+categories = ["algorithms", "no-std"]
+
+[badges]
+travis-ci = { repository = "rust-random/rand" }
+appveyor = { repository = "rust-random/rand" }
+
+[features]
+serde1 = ["serde", "serde_derive"]
+
+[dependencies]
+rand_core = { path = "../rand_core", version = ">=0.2, <0.4", default-features=false }
+serde = { version = "1", optional = true }
+serde_derive = { version = "^1.0.38", optional = true }
+
+[dev-dependencies]
+# This is for testing serde, unfortunately we can't specify feature-gated dev
+# deps yet, see: https://github.com/rust-lang/cargo/issues/1596
+bincode = "1"
diff --git a/rand/rand_xorshift/LICENSE-APACHE b/rand/rand_xorshift/LICENSE-APACHE
new file mode 100644
index 0000000..17d7468
--- /dev/null
+++ b/rand/rand_xorshift/LICENSE-APACHE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ https://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/rand/rand_xorshift/LICENSE-MIT b/rand/rand_xorshift/LICENSE-MIT
new file mode 100644
index 0000000..d93b5ba
--- /dev/null
+++ b/rand/rand_xorshift/LICENSE-MIT
@@ -0,0 +1,26 @@
+Copyright 2018 Developers of the Rand project
+Copyright (c) 2014 The Rust Project Developers
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/rand/rand_xorshift/README.md b/rand/rand_xorshift/README.md
new file mode 100644
index 0000000..573ee12
--- /dev/null
+++ b/rand/rand_xorshift/README.md
@@ -0,0 +1,45 @@
+# rand_xorshift
+
+[![Build Status](https://travis-ci.org/rust-random/rand.svg)](https://travis-ci.org/rust-random/rand)
+[![Build Status](https://ci.appveyor.com/api/projects/status/github/rust-random/rand?svg=true)](https://ci.appveyor.com/project/rust-random/rand)
+[![Latest version](https://img.shields.io/crates/v/rand_xorshift.svg)](https://crates.io/crates/rand_xorshift)
+[![Book](https://img.shields.io/badge/book-master-yellow.svg)](https://rust-random.github.io/book/)
+[![API](https://img.shields.io/badge/api-master-yellow.svg)](https://rust-random.github.io/rand/rand_xorshift)
+[![API](https://docs.rs/rand_xorshift/badge.svg)](https://docs.rs/rand_xorshift)
+[![Minimum rustc version](https://img.shields.io/badge/rustc-1.22+-lightgray.svg)](https://github.com/rust-random/rand#rust-version-requirements)
+
+Implements the Xorshift random number generator.
+
+The Xorshift[^1] algorithm is not suitable for cryptographic purposes
+but is very fast. If you do not know for sure that it fits your
+requirements, use a more secure one such as `StdRng` or `OsRng`.
+
+[^1]: Marsaglia, George (July 2003).
+ ["Xorshift RNGs"](https://www.jstatsoft.org/v08/i14/paper).
+ *Journal of Statistical Software*. Vol. 8 (Issue 14).
+
+Links:
+
+- [API documentation (master)](https://rust-random.github.io/rand/rand_xorshift)
+- [API documentation (docs.rs)](https://docs.rs/rand_xorshift)
+- [Changelog](CHANGELOG.md)
+
+[rand]: https://crates.io/crates/rand
+
+
+## Crate Features
+
+`rand_xorshift` is `no_std` compatible. It does not require any functionality
+outside of the `core` lib, thus there are no features to configure.
+
+The `serde1` feature includes implementations of `Serialize` and `Deserialize`
+for the included RNGs.
+
+
+## License
+
+`rand_xorshift` is distributed under the terms of both the MIT license and the
+Apache License (Version 2.0).
+
+See [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT), and
+[COPYRIGHT](COPYRIGHT) for details.
diff --git a/rand/rand_xorshift/src/lib.rs b/rand/rand_xorshift/src/lib.rs
new file mode 100644
index 0000000..aad74e4
--- /dev/null
+++ b/rand/rand_xorshift/src/lib.rs
@@ -0,0 +1,123 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! The xorshift random number generator.
+
+#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png",
+ html_favicon_url = "https://www.rust-lang.org/favicon.ico",
+ html_root_url = "https://rust-random.github.io/rand/")]
+
+#![deny(missing_docs)]
+#![deny(missing_debug_implementations)]
+
+#![no_std]
+
+extern crate rand_core;
+
+#[cfg(feature="serde1")] extern crate serde;
+#[cfg(feature="serde1")] #[macro_use] extern crate serde_derive;
+
+use core::num::Wrapping as w;
+use core::{fmt, slice};
+use rand_core::{RngCore, SeedableRng, Error, impls, le};
+
+/// An Xorshift random number generator.
+///
+/// The Xorshift[^1] algorithm is not suitable for cryptographic purposes
+/// but is very fast. If you do not know for sure that it fits your
+/// requirements, use a more secure one such as `StdRng` or `OsRng`.
+///
+/// [^1]: Marsaglia, George (July 2003).
+/// ["Xorshift RNGs"](https://www.jstatsoft.org/v08/i14/paper).
+/// *Journal of Statistical Software*. Vol. 8 (Issue 14).
+#[derive(Clone)]
+#[cfg_attr(feature="serde1", derive(Serialize,Deserialize))]
+pub struct XorShiftRng {
+ x: w<u32>,
+ y: w<u32>,
+ z: w<u32>,
+ w: w<u32>,
+}
+
+// Custom Debug implementation that does not expose the internal state
+impl fmt::Debug for XorShiftRng {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "XorShiftRng {{}}")
+ }
+}
+
+impl RngCore for XorShiftRng {
+ #[inline]
+ fn next_u32(&mut self) -> u32 {
+ let x = self.x;
+ let t = x ^ (x << 11);
+ self.x = self.y;
+ self.y = self.z;
+ self.z = self.w;
+ let w_ = self.w;
+ self.w = w_ ^ (w_ >> 19) ^ (t ^ (t >> 8));
+ self.w.0
+ }
+
+ #[inline]
+ fn next_u64(&mut self) -> u64 {
+ impls::next_u64_via_u32(self)
+ }
+
+ #[inline]
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
+ impls::fill_bytes_via_next(self, dest)
+ }
+
+ fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ Ok(self.fill_bytes(dest))
+ }
+}
+
+impl SeedableRng for XorShiftRng {
+ type Seed = [u8; 16];
+
+ fn from_seed(seed: Self::Seed) -> Self {
+ let mut seed_u32 = [0u32; 4];
+ le::read_u32_into(&seed, &mut seed_u32);
+
+ // Xorshift cannot be seeded with 0 and we cannot return an Error, but
+ // also do not wish to panic (because a random seed can legitimately be
+ // 0); our only option is therefore to use a preset value.
+ if seed_u32.iter().all(|&x| x == 0) {
+ seed_u32 = [0xBAD_5EED, 0xBAD_5EED, 0xBAD_5EED, 0xBAD_5EED];
+ }
+
+ XorShiftRng {
+ x: w(seed_u32[0]),
+ y: w(seed_u32[1]),
+ z: w(seed_u32[2]),
+ w: w(seed_u32[3]),
+ }
+ }
+
+ fn from_rng<R: RngCore>(mut rng: R) -> Result<Self, Error> {
+ let mut seed_u32 = [0u32; 4];
+ loop {
+ unsafe {
+ let ptr = seed_u32.as_mut_ptr() as *mut u8;
+
+ let slice = slice::from_raw_parts_mut(ptr, 4 * 4);
+ rng.try_fill_bytes(slice)?;
+ }
+ if !seed_u32.iter().all(|&x| x == 0) { break; }
+ }
+
+ Ok(XorShiftRng {
+ x: w(seed_u32[0]),
+ y: w(seed_u32[1]),
+ z: w(seed_u32[2]),
+ w: w(seed_u32[3]),
+ })
+ }
+}
diff --git a/rand/rand_xorshift/tests/mod.rs b/rand/rand_xorshift/tests/mod.rs
new file mode 100644
index 0000000..8374b64
--- /dev/null
+++ b/rand/rand_xorshift/tests/mod.rs
@@ -0,0 +1,92 @@
+extern crate rand_core;
+extern crate rand_xorshift;
+#[cfg(all(feature="serde1", test))] extern crate bincode;
+
+use rand_core::{RngCore, SeedableRng};
+use rand_xorshift::XorShiftRng;
+
+#[test]
+fn test_xorshift_construction() {
+ // Test that various construction techniques produce a working RNG.
+ let seed = [1,2,3,4, 5,6,7,8, 9,10,11,12, 13,14,15,16];
+ let mut rng1 = XorShiftRng::from_seed(seed);
+ assert_eq!(rng1.next_u64(), 4325440999699518727);
+
+ let _rng2 = XorShiftRng::from_rng(rng1).unwrap();
+ // Note: we cannot test the state of _rng2 because from_rng does not
+ // fix Endianness. This is allowed in the trait specification.
+}
+
+#[test]
+fn test_xorshift_true_values() {
+ let seed = [16,15,14,13, 12,11,10,9, 8,7,6,5, 4,3,2,1];
+ let mut rng = XorShiftRng::from_seed(seed);
+
+ let mut results = [0u32; 9];
+ for i in results.iter_mut() { *i = rng.next_u32(); }
+ let expected: [u32; 9] = [
+ 2081028795, 620940381, 269070770, 16943764, 854422573, 29242889,
+ 1550291885, 1227154591, 271695242];
+ assert_eq!(results, expected);
+
+ let mut results = [0u64; 9];
+ for i in results.iter_mut() { *i = rng.next_u64(); }
+ let expected: [u64; 9] = [
+ 9247529084182843387, 8321512596129439293, 14104136531997710878,
+ 6848554330849612046, 343577296533772213, 17828467390962600268,
+ 9847333257685787782, 7717352744383350108, 1133407547287910111];
+ assert_eq!(results, expected);
+
+ let mut results = [0u8; 32];
+ rng.fill_bytes(&mut results);
+ let expected = [102, 57, 212, 16, 233, 130, 49, 183,
+ 158, 187, 44, 203, 63, 149, 45, 17,
+ 117, 129, 131, 160, 70, 121, 158, 155,
+ 224, 209, 192, 53, 10, 62, 57, 72];
+ assert_eq!(results, expected);
+}
+
+#[test]
+fn test_xorshift_zero_seed() {
+ // Xorshift does not work with an all zero seed.
+ // Assert it does not panic.
+ let seed = [0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0];
+ let mut rng = XorShiftRng::from_seed(seed);
+ let a = rng.next_u64();
+ let b = rng.next_u64();
+ assert!(a != 0);
+ assert!(b != a);
+}
+
+#[test]
+fn test_xorshift_clone() {
+ let seed = [1,2,3,4, 5,5,7,8, 8,7,6,5, 4,3,2,1];
+ let mut rng1 = XorShiftRng::from_seed(seed);
+ let mut rng2 = rng1.clone();
+ for _ in 0..16 {
+ assert_eq!(rng1.next_u64(), rng2.next_u64());
+ }
+}
+
+#[cfg(feature="serde1")]
+#[test]
+fn test_xorshift_serde() {
+ use bincode;
+ use std::io::{BufWriter, BufReader};
+
+ let seed = [1,2,3,4, 5,6,7,8, 9,10,11,12, 13,14,15,16];
+ let mut rng = XorShiftRng::from_seed(seed);
+
+ let buf: Vec<u8> = Vec::new();
+ let mut buf = BufWriter::new(buf);
+ bincode::serialize_into(&mut buf, &rng).expect("Could not serialize");
+
+ let buf = buf.into_inner().unwrap();
+ let mut read = BufReader::new(&buf[..]);
+ let mut deserialized: XorShiftRng = bincode::deserialize_from(&mut read)
+ .expect("Could not deserialize");
+
+ for _ in 0..16 {
+ assert_eq!(rng.next_u64(), deserialized.next_u64());
+ }
+}
diff --git a/rand/src/deprecated.rs b/rand/src/deprecated.rs
new file mode 100644
index 0000000..985ae61
--- /dev/null
+++ b/rand/src/deprecated.rs
@@ -0,0 +1,611 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Deprecated re-exports (we can't add deprecation warnings otherwise)
+
+#![allow(deprecated)]
+
+use rngs;
+use {RngCore, CryptoRng, SeedableRng, Error};
+use rand_core::block::BlockRngCore;
+use rand_isaac;
+use rand_chacha;
+use rand_hc;
+
+#[cfg(feature="std")]
+use std::io::Read;
+
+#[derive(Clone, Debug)]
+#[deprecated(since="0.6.0",
+ note="import from rand_isaac crate instead, or use the newer Hc128Rng")]
+pub struct IsaacRng(rand_isaac::IsaacRng);
+
+impl RngCore for IsaacRng {
+ #[inline(always)]
+ fn next_u32(&mut self) -> u32 {
+ self.0.next_u32()
+ }
+
+ #[inline(always)]
+ fn next_u64(&mut self) -> u64 {
+ self.0.next_u64()
+ }
+
+ #[inline(always)]
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
+ self.0.fill_bytes(dest);
+ }
+
+ #[inline(always)]
+ fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ self.0.try_fill_bytes(dest)
+ }
+}
+
+impl SeedableRng for IsaacRng {
+ type Seed = <rand_isaac::IsaacRng as SeedableRng>::Seed;
+
+ fn from_seed(seed: Self::Seed) -> Self {
+ IsaacRng(rand_isaac::IsaacRng::from_seed(seed))
+ }
+
+ fn from_rng<R: RngCore>(rng: R) -> Result<Self, Error> {
+ rand_isaac::IsaacRng::from_rng(rng).map(IsaacRng)
+ }
+}
+
+impl IsaacRng {
+ pub fn new_from_u64(seed: u64) -> Self {
+ IsaacRng(rand_isaac::IsaacRng::new_from_u64(seed))
+ }
+}
+
+
+#[derive(Clone, Debug)]
+#[deprecated(since="0.6.0",
+ note="import from rand_isaac crate instead, or use newer Hc128Rng")]
+pub struct Isaac64Rng(rand_isaac::Isaac64Rng);
+
+impl RngCore for Isaac64Rng {
+ #[inline(always)]
+ fn next_u32(&mut self) -> u32 {
+ self.0.next_u32()
+ }
+
+ #[inline(always)]
+ fn next_u64(&mut self) -> u64 {
+ self.0.next_u64()
+ }
+
+ #[inline(always)]
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
+ self.0.fill_bytes(dest);
+ }
+
+ #[inline(always)]
+ fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ self.0.try_fill_bytes(dest)
+ }
+}
+
+impl SeedableRng for Isaac64Rng {
+ type Seed = <rand_isaac::Isaac64Rng as SeedableRng>::Seed;
+
+ fn from_seed(seed: Self::Seed) -> Self {
+ Isaac64Rng(rand_isaac::Isaac64Rng::from_seed(seed))
+ }
+
+ fn from_rng<R: RngCore>(rng: R) -> Result<Self, Error> {
+ rand_isaac::Isaac64Rng::from_rng(rng).map(Isaac64Rng)
+ }
+}
+
+impl Isaac64Rng {
+ pub fn new_from_u64(seed: u64) -> Self {
+ Isaac64Rng(rand_isaac::Isaac64Rng::new_from_u64(seed))
+ }
+}
+
+
+#[derive(Clone, Debug)]
+#[deprecated(since="0.6.0", note="import from rand_chacha crate instead")]
+pub struct ChaChaRng(rand_chacha::ChaChaRng);
+
+impl RngCore for ChaChaRng {
+ #[inline(always)]
+ fn next_u32(&mut self) -> u32 {
+ self.0.next_u32()
+ }
+
+ #[inline(always)]
+ fn next_u64(&mut self) -> u64 {
+ self.0.next_u64()
+ }
+
+ #[inline(always)]
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
+ self.0.fill_bytes(dest);
+ }
+
+ #[inline(always)]
+ fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ self.0.try_fill_bytes(dest)
+ }
+}
+
+impl SeedableRng for ChaChaRng {
+ type Seed = <rand_chacha::ChaChaRng as SeedableRng>::Seed;
+
+ fn from_seed(seed: Self::Seed) -> Self {
+ ChaChaRng(rand_chacha::ChaChaRng::from_seed(seed))
+ }
+
+ fn from_rng<R: RngCore>(rng: R) -> Result<Self, Error> {
+ rand_chacha::ChaChaRng::from_rng(rng).map(ChaChaRng)
+ }
+}
+
+impl ChaChaRng {
+ #[cfg(rust_1_26)]
+ pub fn get_word_pos(&self) -> u128 {
+ self.0.get_word_pos()
+ }
+
+ #[cfg(rust_1_26)]
+ pub fn set_word_pos(&mut self, word_offset: u128) {
+ self.0.set_word_pos(word_offset)
+ }
+
+ pub fn set_stream(&mut self, stream: u64) {
+ self.0.set_stream(stream)
+ }
+}
+
+impl CryptoRng for ChaChaRng {}
+
+
+#[derive(Clone, Debug)]
+#[deprecated(since="0.6.0", note="import from rand_hc crate instead")]
+pub struct Hc128Rng(rand_hc::Hc128Rng);
+
+impl RngCore for Hc128Rng {
+ #[inline(always)]
+ fn next_u32(&mut self) -> u32 {
+ self.0.next_u32()
+ }
+
+ #[inline(always)]
+ fn next_u64(&mut self) -> u64 {
+ self.0.next_u64()
+ }
+
+ #[inline(always)]
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
+ self.0.fill_bytes(dest);
+ }
+
+ #[inline(always)]
+ fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ self.0.try_fill_bytes(dest)
+ }
+}
+
+impl SeedableRng for Hc128Rng {
+ type Seed = <rand_hc::Hc128Rng as SeedableRng>::Seed;
+
+ fn from_seed(seed: Self::Seed) -> Self {
+ Hc128Rng(rand_hc::Hc128Rng::from_seed(seed))
+ }
+
+ fn from_rng<R: RngCore>(rng: R) -> Result<Self, Error> {
+ rand_hc::Hc128Rng::from_rng(rng).map(Hc128Rng)
+ }
+}
+
+impl CryptoRng for Hc128Rng {}
+
+
+#[derive(Clone, Debug)]
+#[deprecated(since="0.6.0", note="import from rand_xorshift crate instead")]
+pub struct XorShiftRng(::rand_xorshift::XorShiftRng);
+
+impl RngCore for XorShiftRng {
+ #[inline(always)]
+ fn next_u32(&mut self) -> u32 {
+ self.0.next_u32()
+ }
+
+ #[inline(always)]
+ fn next_u64(&mut self) -> u64 {
+ self.0.next_u64()
+ }
+
+ #[inline(always)]
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
+ self.0.fill_bytes(dest);
+ }
+
+ #[inline(always)]
+ fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ self.0.try_fill_bytes(dest)
+ }
+}
+
+impl SeedableRng for XorShiftRng {
+ type Seed = <::rand_xorshift::XorShiftRng as SeedableRng>::Seed;
+
+ fn from_seed(seed: Self::Seed) -> Self {
+ XorShiftRng(::rand_xorshift::XorShiftRng::from_seed(seed))
+ }
+
+ fn from_rng<R: RngCore>(rng: R) -> Result<Self, Error> {
+ ::rand_xorshift::XorShiftRng::from_rng(rng).map(XorShiftRng)
+ }
+}
+
+
+#[derive(Clone, Debug)]
+#[deprecated(since="0.6.0",
+ note="import with rand::prelude::* or rand::rngs::StdRng instead")]
+pub struct StdRng(rngs::StdRng);
+
+impl RngCore for StdRng {
+ #[inline(always)]
+ fn next_u32(&mut self) -> u32 {
+ self.0.next_u32()
+ }
+
+ #[inline(always)]
+ fn next_u64(&mut self) -> u64 {
+ self.0.next_u64()
+ }
+
+ #[inline(always)]
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
+ self.0.fill_bytes(dest);
+ }
+
+ #[inline(always)]
+ fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ self.0.try_fill_bytes(dest)
+ }
+}
+
+impl SeedableRng for StdRng {
+ type Seed = <rngs::StdRng as SeedableRng>::Seed;
+
+ fn from_seed(seed: Self::Seed) -> Self {
+ StdRng(rngs::StdRng::from_seed(seed))
+ }
+
+ fn from_rng<R: RngCore>(rng: R) -> Result<Self, Error> {
+ rngs::StdRng::from_rng(rng).map(StdRng)
+ }
+}
+
+impl CryptoRng for StdRng {}
+
+
+#[cfg(all(feature="std",
+ any(target_os = "linux", target_os = "android",
+ target_os = "netbsd",
+ target_os = "dragonfly",
+ target_os = "haiku",
+ target_os = "emscripten",
+ target_os = "solaris",
+ target_os = "cloudabi",
+ target_os = "macos", target_os = "ios",
+ target_os = "freebsd",
+ target_os = "openbsd", target_os = "bitrig",
+ target_os = "redox",
+ target_os = "fuchsia",
+ windows,
+ all(target_arch = "wasm32", feature = "stdweb"),
+ all(target_arch = "wasm32", feature = "wasm-bindgen"),
+)))]
+#[derive(Clone, Debug)]
+#[deprecated(since="0.6.0", note="import with rand::rngs::OsRng instead")]
+pub struct OsRng(rngs::OsRng);
+
+#[cfg(all(feature="std",
+ any(target_os = "linux", target_os = "android",
+ target_os = "netbsd",
+ target_os = "dragonfly",
+ target_os = "haiku",
+ target_os = "emscripten",
+ target_os = "solaris",
+ target_os = "cloudabi",
+ target_os = "macos", target_os = "ios",
+ target_os = "freebsd",
+ target_os = "openbsd", target_os = "bitrig",
+ target_os = "redox",
+ target_os = "fuchsia",
+ windows,
+ all(target_arch = "wasm32", feature = "stdweb"),
+ all(target_arch = "wasm32", feature = "wasm-bindgen"),
+)))]
+#[cfg(feature="std")]
+impl RngCore for OsRng {
+ #[inline(always)]
+ fn next_u32(&mut self) -> u32 {
+ self.0.next_u32()
+ }
+
+ #[inline(always)]
+ fn next_u64(&mut self) -> u64 {
+ self.0.next_u64()
+ }
+
+ #[inline(always)]
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
+ self.0.fill_bytes(dest);
+ }
+
+ #[inline(always)]
+ fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ self.0.try_fill_bytes(dest)
+ }
+}
+
+#[cfg(all(feature="std",
+ any(target_os = "linux", target_os = "android",
+ target_os = "netbsd",
+ target_os = "dragonfly",
+ target_os = "haiku",
+ target_os = "emscripten",
+ target_os = "solaris",
+ target_os = "cloudabi",
+ target_os = "macos", target_os = "ios",
+ target_os = "freebsd",
+ target_os = "openbsd", target_os = "bitrig",
+ target_os = "redox",
+ target_os = "fuchsia",
+ windows,
+ all(target_arch = "wasm32", feature = "stdweb"),
+ all(target_arch = "wasm32", feature = "wasm-bindgen"),
+)))]
+#[cfg(feature="std")]
+impl OsRng {
+ pub fn new() -> Result<Self, Error> {
+ rngs::OsRng::new().map(OsRng)
+ }
+}
+
+#[cfg(all(feature="std",
+ any(target_os = "linux", target_os = "android",
+ target_os = "netbsd",
+ target_os = "dragonfly",
+ target_os = "haiku",
+ target_os = "emscripten",
+ target_os = "solaris",
+ target_os = "cloudabi",
+ target_os = "macos", target_os = "ios",
+ target_os = "freebsd",
+ target_os = "openbsd", target_os = "bitrig",
+ target_os = "redox",
+ target_os = "fuchsia",
+ windows,
+ all(target_arch = "wasm32", feature = "stdweb"),
+ all(target_arch = "wasm32", feature = "wasm-bindgen"),
+)))]
+#[cfg(feature="std")]
+impl CryptoRng for OsRng {}
+
+
+#[cfg(feature="std")]
+#[derive(Debug)]
+#[deprecated(since="0.6.0", note="import with rand::rngs::EntropyRng instead")]
+pub struct EntropyRng(rngs::EntropyRng);
+
+#[cfg(feature="std")]
+impl RngCore for EntropyRng {
+ #[inline(always)]
+ fn next_u32(&mut self) -> u32 {
+ self.0.next_u32()
+ }
+
+ #[inline(always)]
+ fn next_u64(&mut self) -> u64 {
+ self.0.next_u64()
+ }
+
+ #[inline(always)]
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
+ self.0.fill_bytes(dest);
+ }
+
+ #[inline(always)]
+ fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ self.0.try_fill_bytes(dest)
+ }
+}
+
+#[cfg(feature="std")]
+impl EntropyRng {
+ pub fn new() -> Self {
+ EntropyRng(rngs::EntropyRng::new())
+ }
+}
+
+#[cfg(feature="std")]
+impl Default for EntropyRng {
+ fn default() -> Self {
+ EntropyRng::new()
+ }
+}
+
+#[cfg(feature="std")]
+impl CryptoRng for EntropyRng {}
+
+
+#[derive(Clone, Debug)]
+#[deprecated(since="0.6.0", note="import with rand::rngs::JitterRng instead")]
+pub struct JitterRng(rngs::JitterRng);
+
+impl RngCore for JitterRng {
+ #[inline(always)]
+ fn next_u32(&mut self) -> u32 {
+ self.0.next_u32()
+ }
+
+ #[inline(always)]
+ fn next_u64(&mut self) -> u64 {
+ self.0.next_u64()
+ }
+
+ #[inline(always)]
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
+ self.0.fill_bytes(dest);
+ }
+
+ #[inline(always)]
+ fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ self.0.try_fill_bytes(dest)
+ }
+}
+
+impl JitterRng {
+ #[cfg(all(feature="std", not(target_arch = "wasm32")))]
+ pub fn new() -> Result<JitterRng, rngs::TimerError> {
+ rngs::JitterRng::new().map(JitterRng)
+ }
+
+ pub fn new_with_timer(timer: fn() -> u64) -> JitterRng {
+ JitterRng(rngs::JitterRng::new_with_timer(timer))
+ }
+
+ pub fn set_rounds(&mut self, rounds: u8) {
+ self.0.set_rounds(rounds)
+ }
+
+ pub fn test_timer(&mut self) -> Result<u8, rngs::TimerError> {
+ self.0.test_timer()
+ }
+
+ #[cfg(feature="std")]
+ pub fn timer_stats(&mut self, var_rounds: bool) -> i64 {
+ self.0.timer_stats(var_rounds)
+ }
+}
+
+impl CryptoRng for JitterRng {}
+
+
+#[cfg(feature="std")]
+#[derive(Clone, Debug)]
+#[deprecated(since="0.6.0",
+ note="import with rand::prelude::* or rand::rngs::ThreadRng instead")]
+pub struct ThreadRng(rngs::ThreadRng);
+
+#[cfg(feature="std")]
+impl RngCore for ThreadRng {
+ #[inline(always)]
+ fn next_u32(&mut self) -> u32 {
+ self.0.next_u32()
+ }
+
+ #[inline(always)]
+ fn next_u64(&mut self) -> u64 {
+ self.0.next_u64()
+ }
+
+ #[inline(always)]
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
+ self.0.fill_bytes(dest);
+ }
+
+ #[inline(always)]
+ fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ self.0.try_fill_bytes(dest)
+ }
+}
+
+#[cfg(feature="std")]
+impl CryptoRng for ThreadRng {}
+
+
+#[cfg(feature="std")]
+#[derive(Debug)]
+#[deprecated(since="0.6.0", note="import with rand::rngs::adapter::ReadRng instead")]
+pub struct ReadRng<R>(rngs::adapter::ReadRng<R>);
+
+#[cfg(feature="std")]
+impl<R: Read> RngCore for ReadRng<R> {
+ #[inline(always)]
+ fn next_u32(&mut self) -> u32 {
+ self.0.next_u32()
+ }
+
+ #[inline(always)]
+ fn next_u64(&mut self) -> u64 {
+ self.0.next_u64()
+ }
+
+ #[inline(always)]
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
+ self.0.fill_bytes(dest);
+ }
+
+ #[inline(always)]
+ fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ self.0.try_fill_bytes(dest)
+ }
+}
+
+#[cfg(feature="std")]
+impl<R: Read> ReadRng<R> {
+ pub fn new(r: R) -> ReadRng<R> {
+ ReadRng(rngs::adapter::ReadRng::new(r))
+ }
+}
+
+
+#[derive(Clone, Debug)]
+pub struct ReseedingRng<R, Rsdr>(rngs::adapter::ReseedingRng<R, Rsdr>)
+where R: BlockRngCore + SeedableRng,
+ Rsdr: RngCore;
+
+impl<R, Rsdr: RngCore> RngCore for ReseedingRng<R, Rsdr>
+where R: BlockRngCore<Item = u32> + SeedableRng,
+ <R as BlockRngCore>::Results: AsRef<[u32]> + AsMut<[u32]>
+{
+ #[inline(always)]
+ fn next_u32(&mut self) -> u32 {
+ self.0.next_u32()
+ }
+
+ #[inline(always)]
+ fn next_u64(&mut self) -> u64 {
+ self.0.next_u64()
+ }
+
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
+ self.0.fill_bytes(dest)
+ }
+
+ fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ self.0.try_fill_bytes(dest)
+ }
+}
+
+impl<R, Rsdr> ReseedingRng<R, Rsdr>
+where R: BlockRngCore + SeedableRng,
+ Rsdr: RngCore
+{
+ pub fn new(rng: R, threshold: u64, reseeder: Rsdr) -> Self {
+ ReseedingRng(rngs::adapter::ReseedingRng::new(rng, threshold, reseeder))
+ }
+
+ pub fn reseed(&mut self) -> Result<(), Error> {
+ self.0.reseed()
+ }
+}
+
+impl<R, Rsdr> CryptoRng for ReseedingRng<R, Rsdr>
+where R: BlockRngCore + SeedableRng + CryptoRng,
+ Rsdr: RngCore + CryptoRng {}
diff --git a/rand/src/distributions/bernoulli.rs b/rand/src/distributions/bernoulli.rs
new file mode 100644
index 0000000..f49618c
--- /dev/null
+++ b/rand/src/distributions/bernoulli.rs
@@ -0,0 +1,165 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! The Bernoulli distribution.
+
+use Rng;
+use distributions::Distribution;
+
+/// The Bernoulli distribution.
+///
+/// This is a special case of the Binomial distribution where `n = 1`.
+///
+/// # Example
+///
+/// ```rust
+/// use rand::distributions::{Bernoulli, Distribution};
+///
+/// let d = Bernoulli::new(0.3);
+/// let v = d.sample(&mut rand::thread_rng());
+/// println!("{} is from a Bernoulli distribution", v);
+/// ```
+///
+/// # Precision
+///
+/// This `Bernoulli` distribution uses 64 bits from the RNG (a `u64`),
+/// so only probabilities that are multiples of 2<sup>-64</sup> can be
+/// represented.
+#[derive(Clone, Copy, Debug)]
+pub struct Bernoulli {
+ /// Probability of success, relative to the maximal integer.
+ p_int: u64,
+}
+
+// To sample from the Bernoulli distribution we use a method that compares a
+// random `u64` value `v < (p * 2^64)`.
+//
+// If `p == 1.0`, the integer `v` to compare against can not represented as a
+// `u64`. We manually set it to `u64::MAX` instead (2^64 - 1 instead of 2^64).
+// Note that value of `p < 1.0` can never result in `u64::MAX`, because an
+// `f64` only has 53 bits of precision, and the next largest value of `p` will
+// result in `2^64 - 2048`.
+//
+// Also there is a 100% theoretical concern: if someone consistenly wants to
+// generate `true` using the Bernoulli distribution (i.e. by using a probability
+// of `1.0`), just using `u64::MAX` is not enough. On average it would return
+// false once every 2^64 iterations. Some people apparently care about this
+// case.
+//
+// That is why we special-case `u64::MAX` to always return `true`, without using
+// the RNG, and pay the performance price for all uses that *are* reasonable.
+// Luckily, if `new()` and `sample` are close, the compiler can optimize out the
+// extra check.
+const ALWAYS_TRUE: u64 = ::core::u64::MAX;
+
+// This is just `2.0.powi(64)`, but written this way because it is not available
+// in `no_std` mode.
+const SCALE: f64 = 2.0 * (1u64 << 63) as f64;
+
+impl Bernoulli {
+ /// Construct a new `Bernoulli` with the given probability of success `p`.
+ ///
+ /// # Panics
+ ///
+ /// If `p < 0` or `p > 1`.
+ ///
+ /// # Precision
+ ///
+ /// For `p = 1.0`, the resulting distribution will always generate true.
+ /// For `p = 0.0`, the resulting distribution will always generate false.
+ ///
+ /// This method is accurate for any input `p` in the range `[0, 1]` which is
+ /// a multiple of 2<sup>-64</sup>. (Note that not all multiples of
+ /// 2<sup>-64</sup> in `[0, 1]` can be represented as a `f64`.)
+ #[inline]
+ pub fn new(p: f64) -> Bernoulli {
+ if p < 0.0 || p >= 1.0 {
+ if p == 1.0 { return Bernoulli { p_int: ALWAYS_TRUE } }
+ panic!("Bernoulli::new not called with 0.0 <= p <= 1.0");
+ }
+ Bernoulli { p_int: (p * SCALE) as u64 }
+ }
+
+ /// Construct a new `Bernoulli` with the probability of success of
+ /// `numerator`-in-`denominator`. I.e. `new_ratio(2, 3)` will return
+ /// a `Bernoulli` with a 2-in-3 chance, or about 67%, of returning `true`.
+ ///
+ /// If `numerator == denominator` then the returned `Bernoulli` will always
+ /// return `true`. If `numerator == 0` it will always return `false`.
+ ///
+ /// # Panics
+ ///
+ /// If `denominator == 0` or `numerator > denominator`.
+ ///
+ #[inline]
+ pub fn from_ratio(numerator: u32, denominator: u32) -> Bernoulli {
+ assert!(numerator <= denominator);
+ if numerator == denominator {
+ return Bernoulli { p_int: ::core::u64::MAX }
+ }
+ let p_int = ((numerator as f64 / denominator as f64) * SCALE) as u64;
+ Bernoulli { p_int }
+ }
+}
+
+impl Distribution<bool> for Bernoulli {
+ #[inline]
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> bool {
+ // Make sure to always return true for p = 1.0.
+ if self.p_int == ALWAYS_TRUE { return true; }
+ let v: u64 = rng.gen();
+ v < self.p_int
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use Rng;
+ use distributions::Distribution;
+ use super::Bernoulli;
+
+ #[test]
+ fn test_trivial() {
+ let mut r = ::test::rng(1);
+ let always_false = Bernoulli::new(0.0);
+ let always_true = Bernoulli::new(1.0);
+ for _ in 0..5 {
+ assert_eq!(r.sample::<bool, _>(&always_false), false);
+ assert_eq!(r.sample::<bool, _>(&always_true), true);
+ assert_eq!(Distribution::<bool>::sample(&always_false, &mut r), false);
+ assert_eq!(Distribution::<bool>::sample(&always_true, &mut r), true);
+ }
+ }
+
+ #[test]
+ fn test_average() {
+ const P: f64 = 0.3;
+ const NUM: u32 = 3;
+ const DENOM: u32 = 10;
+ let d1 = Bernoulli::new(P);
+ let d2 = Bernoulli::from_ratio(NUM, DENOM);
+ const N: u32 = 100_000;
+
+ let mut sum1: u32 = 0;
+ let mut sum2: u32 = 0;
+ let mut rng = ::test::rng(2);
+ for _ in 0..N {
+ if d1.sample(&mut rng) {
+ sum1 += 1;
+ }
+ if d2.sample(&mut rng) {
+ sum2 += 1;
+ }
+ }
+ let avg1 = (sum1 as f64) / (N as f64);
+ assert!((avg1 - P).abs() < 5e-3);
+
+ let avg2 = (sum2 as f64) / (N as f64);
+ assert!((avg2 - (NUM as f64)/(DENOM as f64)).abs() < 5e-3);
+ }
+}
diff --git a/rand/src/distributions/binomial.rs b/rand/src/distributions/binomial.rs
new file mode 100644
index 0000000..2df393e
--- /dev/null
+++ b/rand/src/distributions/binomial.rs
@@ -0,0 +1,177 @@
+// Copyright 2018 Developers of the Rand project.
+// Copyright 2016-2017 The Rust Project Developers.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! The binomial distribution.
+
+use Rng;
+use distributions::{Distribution, Bernoulli, Cauchy};
+use distributions::utils::log_gamma;
+
+/// The binomial distribution `Binomial(n, p)`.
+///
+/// This distribution has density function:
+/// `f(k) = n!/(k! (n-k)!) p^k (1-p)^(n-k)` for `k >= 0`.
+///
+/// # Example
+///
+/// ```
+/// use rand::distributions::{Binomial, Distribution};
+///
+/// let bin = Binomial::new(20, 0.3);
+/// let v = bin.sample(&mut rand::thread_rng());
+/// println!("{} is from a binomial distribution", v);
+/// ```
+#[derive(Clone, Copy, Debug)]
+pub struct Binomial {
+ /// Number of trials.
+ n: u64,
+ /// Probability of success.
+ p: f64,
+}
+
+impl Binomial {
+ /// Construct a new `Binomial` with the given shape parameters `n` (number
+ /// of trials) and `p` (probability of success).
+ ///
+ /// Panics if `p < 0` or `p > 1`.
+ pub fn new(n: u64, p: f64) -> Binomial {
+ assert!(p >= 0.0, "Binomial::new called with p < 0");
+ assert!(p <= 1.0, "Binomial::new called with p > 1");
+ Binomial { n, p }
+ }
+}
+
+impl Distribution<u64> for Binomial {
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u64 {
+ // Handle these values directly.
+ if self.p == 0.0 {
+ return 0;
+ } else if self.p == 1.0 {
+ return self.n;
+ }
+
+ // For low n, it is faster to sample directly. For both methods,
+ // performance is independent of p. On Intel Haswell CPU this method
+ // appears to be faster for approx n < 300.
+ if self.n < 300 {
+ let mut result = 0;
+ let d = Bernoulli::new(self.p);
+ for _ in 0 .. self.n {
+ result += rng.sample(d) as u32;
+ }
+ return result as u64;
+ }
+
+ // binomial distribution is symmetrical with respect to p -> 1-p, k -> n-k
+ // switch p so that it is less than 0.5 - this allows for lower expected values
+ // we will just invert the result at the end
+ let p = if self.p <= 0.5 {
+ self.p
+ } else {
+ 1.0 - self.p
+ };
+
+ // prepare some cached values
+ let float_n = self.n as f64;
+ let ln_fact_n = log_gamma(float_n + 1.0);
+ let pc = 1.0 - p;
+ let log_p = p.ln();
+ let log_pc = pc.ln();
+ let expected = self.n as f64 * p;
+ let sq = (expected * (2.0 * pc)).sqrt();
+
+ let mut lresult;
+
+ // we use the Cauchy distribution as the comparison distribution
+ // f(x) ~ 1/(1+x^2)
+ let cauchy = Cauchy::new(0.0, 1.0);
+ loop {
+ let mut comp_dev: f64;
+ loop {
+ // draw from the Cauchy distribution
+ comp_dev = rng.sample(cauchy);
+ // shift the peak of the comparison ditribution
+ lresult = expected + sq * comp_dev;
+ // repeat the drawing until we are in the range of possible values
+ if lresult >= 0.0 && lresult < float_n + 1.0 {
+ break;
+ }
+ }
+
+ // the result should be discrete
+ lresult = lresult.floor();
+
+ let log_binomial_dist = ln_fact_n - log_gamma(lresult+1.0) -
+ log_gamma(float_n - lresult + 1.0) + lresult*log_p + (float_n - lresult)*log_pc;
+ // this is the binomial probability divided by the comparison probability
+ // we will generate a uniform random value and if it is larger than this,
+ // we interpret it as a value falling out of the distribution and repeat
+ let comparison_coeff = (log_binomial_dist.exp() * sq) * (1.2 * (1.0 + comp_dev*comp_dev));
+
+ if comparison_coeff >= rng.gen() {
+ break;
+ }
+ }
+
+ // invert the result for p < 0.5
+ if p != self.p {
+ self.n - lresult as u64
+ } else {
+ lresult as u64
+ }
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use Rng;
+ use distributions::Distribution;
+ use super::Binomial;
+
+ fn test_binomial_mean_and_variance<R: Rng>(n: u64, p: f64, rng: &mut R) {
+ let binomial = Binomial::new(n, p);
+
+ let expected_mean = n as f64 * p;
+ let expected_variance = n as f64 * p * (1.0 - p);
+
+ let mut results = [0.0; 1000];
+ for i in results.iter_mut() { *i = binomial.sample(rng) as f64; }
+
+ let mean = results.iter().sum::<f64>() / results.len() as f64;
+ assert!((mean as f64 - expected_mean).abs() < expected_mean / 50.0);
+
+ let variance =
+ results.iter().map(|x| (x - mean) * (x - mean)).sum::<f64>()
+ / results.len() as f64;
+ assert!((variance - expected_variance).abs() < expected_variance / 10.0);
+ }
+
+ #[test]
+ fn test_binomial() {
+ let mut rng = ::test::rng(351);
+ test_binomial_mean_and_variance(150, 0.1, &mut rng);
+ test_binomial_mean_and_variance(70, 0.6, &mut rng);
+ test_binomial_mean_and_variance(40, 0.5, &mut rng);
+ test_binomial_mean_and_variance(20, 0.7, &mut rng);
+ test_binomial_mean_and_variance(20, 0.5, &mut rng);
+ }
+
+ #[test]
+ fn test_binomial_end_points() {
+ let mut rng = ::test::rng(352);
+ assert_eq!(rng.sample(Binomial::new(20, 0.0)), 0);
+ assert_eq!(rng.sample(Binomial::new(20, 1.0)), 20);
+ }
+
+ #[test]
+ #[should_panic]
+ fn test_binomial_invalid_lambda_neg() {
+ Binomial::new(20, -10.0);
+ }
+}
diff --git a/rand/src/distributions/cauchy.rs b/rand/src/distributions/cauchy.rs
new file mode 100644
index 0000000..feef015
--- /dev/null
+++ b/rand/src/distributions/cauchy.rs
@@ -0,0 +1,115 @@
+// Copyright 2018 Developers of the Rand project.
+// Copyright 2016-2017 The Rust Project Developers.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! The Cauchy distribution.
+
+use Rng;
+use distributions::Distribution;
+use std::f64::consts::PI;
+
+/// The Cauchy distribution `Cauchy(median, scale)`.
+///
+/// This distribution has a density function:
+/// `f(x) = 1 / (pi * scale * (1 + ((x - median) / scale)^2))`
+///
+/// # Example
+///
+/// ```
+/// use rand::distributions::{Cauchy, Distribution};
+///
+/// let cau = Cauchy::new(2.0, 5.0);
+/// let v = cau.sample(&mut rand::thread_rng());
+/// println!("{} is from a Cauchy(2, 5) distribution", v);
+/// ```
+#[derive(Clone, Copy, Debug)]
+pub struct Cauchy {
+ median: f64,
+ scale: f64
+}
+
+impl Cauchy {
+ /// Construct a new `Cauchy` with the given shape parameters
+ /// `median` the peak location and `scale` the scale factor.
+ /// Panics if `scale <= 0`.
+ pub fn new(median: f64, scale: f64) -> Cauchy {
+ assert!(scale > 0.0, "Cauchy::new called with scale factor <= 0");
+ Cauchy {
+ median,
+ scale
+ }
+ }
+}
+
+impl Distribution<f64> for Cauchy {
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
+ // sample from [0, 1)
+ let x = rng.gen::<f64>();
+ // get standard cauchy random number
+ // note that π/2 is not exactly representable, even if x=0.5 the result is finite
+ let comp_dev = (PI * x).tan();
+ // shift and scale according to parameters
+ let result = self.median + self.scale * comp_dev;
+ result
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use distributions::Distribution;
+ use super::Cauchy;
+
+ fn median(mut numbers: &mut [f64]) -> f64 {
+ sort(&mut numbers);
+ let mid = numbers.len() / 2;
+ numbers[mid]
+ }
+
+ fn sort(numbers: &mut [f64]) {
+ numbers.sort_by(|a, b| a.partial_cmp(b).unwrap());
+ }
+
+ #[test]
+ fn test_cauchy_median() {
+ let cauchy = Cauchy::new(10.0, 5.0);
+ let mut rng = ::test::rng(123);
+ let mut numbers: [f64; 1000] = [0.0; 1000];
+ for i in 0..1000 {
+ numbers[i] = cauchy.sample(&mut rng);
+ }
+ let median = median(&mut numbers);
+ println!("Cauchy median: {}", median);
+ assert!((median - 10.0).abs() < 0.5); // not 100% certain, but probable enough
+ }
+
+ #[test]
+ fn test_cauchy_mean() {
+ let cauchy = Cauchy::new(10.0, 5.0);
+ let mut rng = ::test::rng(123);
+ let mut sum = 0.0;
+ for _ in 0..1000 {
+ sum += cauchy.sample(&mut rng);
+ }
+ let mean = sum / 1000.0;
+ println!("Cauchy mean: {}", mean);
+ // for a Cauchy distribution the mean should not converge
+ assert!((mean - 10.0).abs() > 0.5); // not 100% certain, but probable enough
+ }
+
+ #[test]
+ #[should_panic]
+ fn test_cauchy_invalid_scale_zero() {
+ Cauchy::new(0.0, 0.0);
+ }
+
+ #[test]
+ #[should_panic]
+ fn test_cauchy_invalid_scale_neg() {
+ Cauchy::new(0.0, -10.0);
+ }
+}
diff --git a/rand/src/distributions/dirichlet.rs b/rand/src/distributions/dirichlet.rs
new file mode 100644
index 0000000..19384b8
--- /dev/null
+++ b/rand/src/distributions/dirichlet.rs
@@ -0,0 +1,137 @@
+// Copyright 2018 Developers of the Rand project.
+// Copyright 2013 The Rust Project Developers.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! The dirichlet distribution.
+
+use Rng;
+use distributions::Distribution;
+use distributions::gamma::Gamma;
+
+/// The dirichelet distribution `Dirichlet(alpha)`.
+///
+/// The Dirichlet distribution is a family of continuous multivariate
+/// probability distributions parameterized by a vector alpha of positive reals.
+/// It is a multivariate generalization of the beta distribution.
+///
+/// # Example
+///
+/// ```
+/// use rand::prelude::*;
+/// use rand::distributions::Dirichlet;
+///
+/// let dirichlet = Dirichlet::new(vec![1.0, 2.0, 3.0]);
+/// let samples = dirichlet.sample(&mut rand::thread_rng());
+/// println!("{:?} is from a Dirichlet([1.0, 2.0, 3.0]) distribution", samples);
+/// ```
+
+#[derive(Clone, Debug)]
+pub struct Dirichlet {
+ /// Concentration parameters (alpha)
+ alpha: Vec<f64>,
+}
+
+impl Dirichlet {
+ /// Construct a new `Dirichlet` with the given alpha parameter `alpha`.
+ ///
+ /// # Panics
+ /// - if `alpha.len() < 2`
+ ///
+ #[inline]
+ pub fn new<V: Into<Vec<f64>>>(alpha: V) -> Dirichlet {
+ let a = alpha.into();
+ assert!(a.len() > 1);
+ for i in 0..a.len() {
+ assert!(a[i] > 0.0);
+ }
+
+ Dirichlet { alpha: a }
+ }
+
+ /// Construct a new `Dirichlet` with the given shape parameter `alpha` and `size`.
+ ///
+ /// # Panics
+ /// - if `alpha <= 0.0`
+ /// - if `size < 2`
+ ///
+ #[inline]
+ pub fn new_with_param(alpha: f64, size: usize) -> Dirichlet {
+ assert!(alpha > 0.0);
+ assert!(size > 1);
+ Dirichlet {
+ alpha: vec![alpha; size],
+ }
+ }
+}
+
+impl Distribution<Vec<f64>> for Dirichlet {
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Vec<f64> {
+ let n = self.alpha.len();
+ let mut samples = vec![0.0f64; n];
+ let mut sum = 0.0f64;
+
+ for i in 0..n {
+ let g = Gamma::new(self.alpha[i], 1.0);
+ samples[i] = g.sample(rng);
+ sum += samples[i];
+ }
+ let invacc = 1.0 / sum;
+ for i in 0..n {
+ samples[i] *= invacc;
+ }
+ samples
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::Dirichlet;
+ use distributions::Distribution;
+
+ #[test]
+ fn test_dirichlet() {
+ let d = Dirichlet::new(vec![1.0, 2.0, 3.0]);
+ let mut rng = ::test::rng(221);
+ let samples = d.sample(&mut rng);
+ let _: Vec<f64> = samples
+ .into_iter()
+ .map(|x| {
+ assert!(x > 0.0);
+ x
+ })
+ .collect();
+ }
+
+ #[test]
+ fn test_dirichlet_with_param() {
+ let alpha = 0.5f64;
+ let size = 2;
+ let d = Dirichlet::new_with_param(alpha, size);
+ let mut rng = ::test::rng(221);
+ let samples = d.sample(&mut rng);
+ let _: Vec<f64> = samples
+ .into_iter()
+ .map(|x| {
+ assert!(x > 0.0);
+ x
+ })
+ .collect();
+ }
+
+ #[test]
+ #[should_panic]
+ fn test_dirichlet_invalid_length() {
+ Dirichlet::new_with_param(0.5f64, 1);
+ }
+
+ #[test]
+ #[should_panic]
+ fn test_dirichlet_invalid_alpha() {
+ Dirichlet::new_with_param(0.0f64, 2);
+ }
+}
diff --git a/rand/src/distributions/exponential.rs b/rand/src/distributions/exponential.rs
index c3c924c..a7d0500 100644
--- a/rand/src/distributions/exponential.rs
+++ b/rand/src/distributions/exponential.rs
@@ -1,74 +1,78 @@
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
+// Copyright 2018 Developers of the Rand project.
+// Copyright 2013 The Rust Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! The exponential distribution.
-use {Rng, Rand};
-use distributions::{ziggurat, ziggurat_tables, Sample, IndependentSample};
+use {Rng};
+use distributions::{ziggurat_tables, Distribution};
+use distributions::utils::ziggurat;
-/// A wrapper around an `f64` to generate Exp(1) random numbers.
+/// Samples floating-point numbers according to the exponential distribution,
+/// with rate parameter `λ = 1`. This is equivalent to `Exp::new(1.0)` or
+/// sampling with `-rng.gen::<f64>().ln()`, but faster.
///
/// See `Exp` for the general exponential distribution.
///
-/// Implemented via the ZIGNOR variant[1] of the Ziggurat method. The
-/// exact description in the paper was adjusted to use tables for the
-/// exponential distribution rather than normal.
+/// Implemented via the ZIGNOR variant[^1] of the Ziggurat method. The exact
+/// description in the paper was adjusted to use tables for the exponential
+/// distribution rather than normal.
///
-/// [1]: Jurgen A. Doornik (2005). [*An Improved Ziggurat Method to
-/// Generate Normal Random
-/// Samples*](http://www.doornik.com/research/ziggurat.pdf). Nuffield
-/// College, Oxford
+/// [^1]: Jurgen A. Doornik (2005). [*An Improved Ziggurat Method to
+/// Generate Normal Random Samples*](
+/// https://www.doornik.com/research/ziggurat.pdf).
+/// Nuffield College, Oxford
///
/// # Example
+/// ```
+/// use rand::prelude::*;
+/// use rand::distributions::Exp1;
///
-/// ```rust
-/// use rand::distributions::exponential::Exp1;
-///
-/// let Exp1(x) = rand::random();
-/// println!("{}", x);
+/// let val: f64 = SmallRng::from_entropy().sample(Exp1);
+/// println!("{}", val);
/// ```
#[derive(Clone, Copy, Debug)]
-pub struct Exp1(pub f64);
+pub struct Exp1;
// This could be done via `-rng.gen::<f64>().ln()` but that is slower.
-impl Rand for Exp1 {
+impl Distribution<f64> for Exp1 {
#[inline]
- fn rand<R:Rng>(rng: &mut R) -> Exp1 {
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
#[inline]
fn pdf(x: f64) -> f64 {
(-x).exp()
}
#[inline]
- fn zero_case<R:Rng>(rng: &mut R, _u: f64) -> f64 {
+ fn zero_case<R: Rng + ?Sized>(rng: &mut R, _u: f64) -> f64 {
ziggurat_tables::ZIG_EXP_R - rng.gen::<f64>().ln()
}
- Exp1(ziggurat(rng, false,
- &ziggurat_tables::ZIG_EXP_X,
- &ziggurat_tables::ZIG_EXP_F,
- pdf, zero_case))
+ ziggurat(rng, false,
+ &ziggurat_tables::ZIG_EXP_X,
+ &ziggurat_tables::ZIG_EXP_F,
+ pdf, zero_case)
}
}
/// The exponential distribution `Exp(lambda)`.
///
-/// This distribution has density function: `f(x) = lambda *
-/// exp(-lambda * x)` for `x > 0`.
+/// This distribution has density function: `f(x) = lambda * exp(-lambda * x)`
+/// for `x > 0`.
+///
+/// Note that [`Exp1`](struct.Exp1.html) is an optimised implementation for `lambda = 1`.
///
/// # Example
///
-/// ```rust
-/// use rand::distributions::{Exp, IndependentSample};
+/// ```
+/// use rand::distributions::{Exp, Distribution};
///
/// let exp = Exp::new(2.0);
-/// let v = exp.ind_sample(&mut rand::thread_rng());
+/// let v = exp.sample(&mut rand::thread_rng());
/// println!("{} is from a Exp(2) distribution", v);
/// ```
#[derive(Clone, Copy, Debug)]
@@ -87,28 +91,24 @@ impl Exp {
}
}
-impl Sample<f64> for Exp {
- fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
-}
-impl IndependentSample<f64> for Exp {
- fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
- let Exp1(n) = rng.gen::<Exp1>();
+impl Distribution<f64> for Exp {
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
+ let n: f64 = rng.sample(Exp1);
n * self.lambda_inverse
}
}
#[cfg(test)]
mod test {
- use distributions::{Sample, IndependentSample};
+ use distributions::Distribution;
use super::Exp;
#[test]
fn test_exp() {
- let mut exp = Exp::new(10.0);
- let mut rng = ::test::rng();
+ let exp = Exp::new(10.0);
+ let mut rng = ::test::rng(221);
for _ in 0..1000 {
assert!(exp.sample(&mut rng) >= 0.0);
- assert!(exp.ind_sample(&mut rng) >= 0.0);
}
}
#[test]
diff --git a/rand/src/distributions/float.rs b/rand/src/distributions/float.rs
new file mode 100644
index 0000000..ece12f5
--- /dev/null
+++ b/rand/src/distributions/float.rs
@@ -0,0 +1,259 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Basic floating-point number distributions
+
+use core::mem;
+use Rng;
+use distributions::{Distribution, Standard};
+use distributions::utils::FloatSIMDUtils;
+#[cfg(feature="simd_support")]
+use packed_simd::*;
+
+/// A distribution to sample floating point numbers uniformly in the half-open
+/// interval `(0, 1]`, i.e. including 1 but not 0.
+///
+/// All values that can be generated are of the form `n * ε/2`. For `f32`
+/// the 23 most significant random bits of a `u32` are used and for `f64` the
+/// 53 most significant bits of a `u64` are used. The conversion uses the
+/// multiplicative method.
+///
+/// See also: [`Standard`] which samples from `[0, 1)`, [`Open01`]
+/// which samples from `(0, 1)` and [`Uniform`] which samples from arbitrary
+/// ranges.
+///
+/// # Example
+/// ```
+/// use rand::{thread_rng, Rng};
+/// use rand::distributions::OpenClosed01;
+///
+/// let val: f32 = thread_rng().sample(OpenClosed01);
+/// println!("f32 from (0, 1): {}", val);
+/// ```
+///
+/// [`Standard`]: struct.Standard.html
+/// [`Open01`]: struct.Open01.html
+/// [`Uniform`]: uniform/struct.Uniform.html
+#[derive(Clone, Copy, Debug)]
+pub struct OpenClosed01;
+
+/// A distribution to sample floating point numbers uniformly in the open
+/// interval `(0, 1)`, i.e. not including either endpoint.
+///
+/// All values that can be generated are of the form `n * ε + ε/2`. For `f32`
+/// the 22 most significant random bits of an `u32` are used, for `f64` 52 from
+/// an `u64`. The conversion uses a transmute-based method.
+///
+/// See also: [`Standard`] which samples from `[0, 1)`, [`OpenClosed01`]
+/// which samples from `(0, 1]` and [`Uniform`] which samples from arbitrary
+/// ranges.
+///
+/// # Example
+/// ```
+/// use rand::{thread_rng, Rng};
+/// use rand::distributions::Open01;
+///
+/// let val: f32 = thread_rng().sample(Open01);
+/// println!("f32 from (0, 1): {}", val);
+/// ```
+///
+/// [`Standard`]: struct.Standard.html
+/// [`OpenClosed01`]: struct.OpenClosed01.html
+/// [`Uniform`]: uniform/struct.Uniform.html
+#[derive(Clone, Copy, Debug)]
+pub struct Open01;
+
+
+pub(crate) trait IntoFloat {
+ type F;
+
+ /// Helper method to combine the fraction and a contant exponent into a
+ /// float.
+ ///
+ /// Only the least significant bits of `self` may be set, 23 for `f32` and
+ /// 52 for `f64`.
+ /// The resulting value will fall in a range that depends on the exponent.
+ /// As an example the range with exponent 0 will be
+ /// [2<sup>0</sup>..2<sup>1</sup>), which is [1..2).
+ fn into_float_with_exponent(self, exponent: i32) -> Self::F;
+}
+
+macro_rules! float_impls {
+ ($ty:ident, $uty:ident, $f_scalar:ident, $u_scalar:ty,
+ $fraction_bits:expr, $exponent_bias:expr) => {
+ impl IntoFloat for $uty {
+ type F = $ty;
+ #[inline(always)]
+ fn into_float_with_exponent(self, exponent: i32) -> $ty {
+ // The exponent is encoded using an offset-binary representation
+ let exponent_bits: $u_scalar =
+ (($exponent_bias + exponent) as $u_scalar) << $fraction_bits;
+ // TODO: use from_bits when min compiler > 1.25 (see #545)
+ // $ty::from_bits(self | exponent_bits)
+ unsafe{ mem::transmute(self | exponent_bits) }
+ }
+ }
+
+ impl Distribution<$ty> for Standard {
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> $ty {
+ // Multiply-based method; 24/53 random bits; [0, 1) interval.
+ // We use the most significant bits because for simple RNGs
+ // those are usually more random.
+ let float_size = mem::size_of::<$f_scalar>() as u32 * 8;
+ let precision = $fraction_bits + 1;
+ let scale = 1.0 / ((1 as $u_scalar << precision) as $f_scalar);
+
+ let value: $uty = rng.gen();
+ let value = value >> (float_size - precision);
+ scale * $ty::cast_from_int(value)
+ }
+ }
+
+ impl Distribution<$ty> for OpenClosed01 {
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> $ty {
+ // Multiply-based method; 24/53 random bits; (0, 1] interval.
+ // We use the most significant bits because for simple RNGs
+ // those are usually more random.
+ let float_size = mem::size_of::<$f_scalar>() as u32 * 8;
+ let precision = $fraction_bits + 1;
+ let scale = 1.0 / ((1 as $u_scalar << precision) as $f_scalar);
+
+ let value: $uty = rng.gen();
+ let value = value >> (float_size - precision);
+ // Add 1 to shift up; will not overflow because of right-shift:
+ scale * $ty::cast_from_int(value + 1)
+ }
+ }
+
+ impl Distribution<$ty> for Open01 {
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> $ty {
+ // Transmute-based method; 23/52 random bits; (0, 1) interval.
+ // We use the most significant bits because for simple RNGs
+ // those are usually more random.
+ use core::$f_scalar::EPSILON;
+ let float_size = mem::size_of::<$f_scalar>() as u32 * 8;
+
+ let value: $uty = rng.gen();
+ let fraction = value >> (float_size - $fraction_bits);
+ fraction.into_float_with_exponent(0) - (1.0 - EPSILON / 2.0)
+ }
+ }
+ }
+}
+
+float_impls! { f32, u32, f32, u32, 23, 127 }
+float_impls! { f64, u64, f64, u64, 52, 1023 }
+
+#[cfg(feature="simd_support")]
+float_impls! { f32x2, u32x2, f32, u32, 23, 127 }
+#[cfg(feature="simd_support")]
+float_impls! { f32x4, u32x4, f32, u32, 23, 127 }
+#[cfg(feature="simd_support")]
+float_impls! { f32x8, u32x8, f32, u32, 23, 127 }
+#[cfg(feature="simd_support")]
+float_impls! { f32x16, u32x16, f32, u32, 23, 127 }
+
+#[cfg(feature="simd_support")]
+float_impls! { f64x2, u64x2, f64, u64, 52, 1023 }
+#[cfg(feature="simd_support")]
+float_impls! { f64x4, u64x4, f64, u64, 52, 1023 }
+#[cfg(feature="simd_support")]
+float_impls! { f64x8, u64x8, f64, u64, 52, 1023 }
+
+
+#[cfg(test)]
+mod tests {
+ use Rng;
+ use distributions::{Open01, OpenClosed01};
+ use rngs::mock::StepRng;
+ #[cfg(feature="simd_support")]
+ use packed_simd::*;
+
+ const EPSILON32: f32 = ::core::f32::EPSILON;
+ const EPSILON64: f64 = ::core::f64::EPSILON;
+
+ macro_rules! test_f32 {
+ ($fnn:ident, $ty:ident, $ZERO:expr, $EPSILON:expr) => {
+ #[test]
+ fn $fnn() {
+ // Standard
+ let mut zeros = StepRng::new(0, 0);
+ assert_eq!(zeros.gen::<$ty>(), $ZERO);
+ let mut one = StepRng::new(1 << 8 | 1 << (8 + 32), 0);
+ assert_eq!(one.gen::<$ty>(), $EPSILON / 2.0);
+ let mut max = StepRng::new(!0, 0);
+ assert_eq!(max.gen::<$ty>(), 1.0 - $EPSILON / 2.0);
+
+ // OpenClosed01
+ let mut zeros = StepRng::new(0, 0);
+ assert_eq!(zeros.sample::<$ty, _>(OpenClosed01),
+ 0.0 + $EPSILON / 2.0);
+ let mut one = StepRng::new(1 << 8 | 1 << (8 + 32), 0);
+ assert_eq!(one.sample::<$ty, _>(OpenClosed01), $EPSILON);
+ let mut max = StepRng::new(!0, 0);
+ assert_eq!(max.sample::<$ty, _>(OpenClosed01), $ZERO + 1.0);
+
+ // Open01
+ let mut zeros = StepRng::new(0, 0);
+ assert_eq!(zeros.sample::<$ty, _>(Open01), 0.0 + $EPSILON / 2.0);
+ let mut one = StepRng::new(1 << 9 | 1 << (9 + 32), 0);
+ assert_eq!(one.sample::<$ty, _>(Open01), $EPSILON / 2.0 * 3.0);
+ let mut max = StepRng::new(!0, 0);
+ assert_eq!(max.sample::<$ty, _>(Open01), 1.0 - $EPSILON / 2.0);
+ }
+ }
+ }
+ test_f32! { f32_edge_cases, f32, 0.0, EPSILON32 }
+ #[cfg(feature="simd_support")]
+ test_f32! { f32x2_edge_cases, f32x2, f32x2::splat(0.0), f32x2::splat(EPSILON32) }
+ #[cfg(feature="simd_support")]
+ test_f32! { f32x4_edge_cases, f32x4, f32x4::splat(0.0), f32x4::splat(EPSILON32) }
+ #[cfg(feature="simd_support")]
+ test_f32! { f32x8_edge_cases, f32x8, f32x8::splat(0.0), f32x8::splat(EPSILON32) }
+ #[cfg(feature="simd_support")]
+ test_f32! { f32x16_edge_cases, f32x16, f32x16::splat(0.0), f32x16::splat(EPSILON32) }
+
+ macro_rules! test_f64 {
+ ($fnn:ident, $ty:ident, $ZERO:expr, $EPSILON:expr) => {
+ #[test]
+ fn $fnn() {
+ // Standard
+ let mut zeros = StepRng::new(0, 0);
+ assert_eq!(zeros.gen::<$ty>(), $ZERO);
+ let mut one = StepRng::new(1 << 11, 0);
+ assert_eq!(one.gen::<$ty>(), $EPSILON / 2.0);
+ let mut max = StepRng::new(!0, 0);
+ assert_eq!(max.gen::<$ty>(), 1.0 - $EPSILON / 2.0);
+
+ // OpenClosed01
+ let mut zeros = StepRng::new(0, 0);
+ assert_eq!(zeros.sample::<$ty, _>(OpenClosed01),
+ 0.0 + $EPSILON / 2.0);
+ let mut one = StepRng::new(1 << 11, 0);
+ assert_eq!(one.sample::<$ty, _>(OpenClosed01), $EPSILON);
+ let mut max = StepRng::new(!0, 0);
+ assert_eq!(max.sample::<$ty, _>(OpenClosed01), $ZERO + 1.0);
+
+ // Open01
+ let mut zeros = StepRng::new(0, 0);
+ assert_eq!(zeros.sample::<$ty, _>(Open01), 0.0 + $EPSILON / 2.0);
+ let mut one = StepRng::new(1 << 12, 0);
+ assert_eq!(one.sample::<$ty, _>(Open01), $EPSILON / 2.0 * 3.0);
+ let mut max = StepRng::new(!0, 0);
+ assert_eq!(max.sample::<$ty, _>(Open01), 1.0 - $EPSILON / 2.0);
+ }
+ }
+ }
+ test_f64! { f64_edge_cases, f64, 0.0, EPSILON64 }
+ #[cfg(feature="simd_support")]
+ test_f64! { f64x2_edge_cases, f64x2, f64x2::splat(0.0), f64x2::splat(EPSILON64) }
+ #[cfg(feature="simd_support")]
+ test_f64! { f64x4_edge_cases, f64x4, f64x4::splat(0.0), f64x4::splat(EPSILON64) }
+ #[cfg(feature="simd_support")]
+ test_f64! { f64x8_edge_cases, f64x8, f64x8::splat(0.0), f64x8::splat(EPSILON64) }
+}
diff --git a/rand/src/distributions/gamma.rs b/rand/src/distributions/gamma.rs
index 2806495..43ac2bc 100644
--- a/rand/src/distributions/gamma.rs
+++ b/rand/src/distributions/gamma.rs
@@ -1,23 +1,20 @@
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
+// Copyright 2018 Developers of the Rand project.
+// Copyright 2013 The Rust Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-//
-// ignore-lexer-test FIXME #15679
//! The Gamma and derived distributions.
use self::GammaRepr::*;
use self::ChiSquaredRepr::*;
-use {Rng, Open01};
-use super::normal::StandardNormal;
-use super::{IndependentSample, Sample, Exp};
+use Rng;
+use distributions::normal::StandardNormal;
+use distributions::{Distribution, Exp, Open01};
/// The Gamma distribution `Gamma(shape, scale)` distribution.
///
@@ -30,25 +27,25 @@ use super::{IndependentSample, Sample, Exp};
/// where `Γ` is the Gamma function, `k` is the shape and `θ` is the
/// scale and both `k` and `θ` are strictly positive.
///
-/// The algorithm used is that described by Marsaglia & Tsang 2000[1],
+/// The algorithm used is that described by Marsaglia & Tsang 2000[^1],
/// falling back to directly sampling from an Exponential for `shape
-/// == 1`, and using the boosting technique described in [1] for
+/// == 1`, and using the boosting technique described in that paper for
/// `shape < 1`.
///
/// # Example
///
-/// ```rust
-/// use rand::distributions::{IndependentSample, Gamma};
+/// ```
+/// use rand::distributions::{Distribution, Gamma};
///
/// let gamma = Gamma::new(2.0, 5.0);
-/// let v = gamma.ind_sample(&mut rand::thread_rng());
+/// let v = gamma.sample(&mut rand::thread_rng());
/// println!("{} is from a Gamma(2, 5) distribution", v);
/// ```
///
-/// [1]: George Marsaglia and Wai Wan Tsang. 2000. "A Simple Method
-/// for Generating Gamma Variables" *ACM Trans. Math. Softw.* 26, 3
-/// (September 2000),
-/// 363-372. DOI:[10.1145/358407.358414](http://doi.acm.org/10.1145/358407.358414)
+/// [^1]: George Marsaglia and Wai Wan Tsang. 2000. "A Simple Method for
+/// Generating Gamma Variables" *ACM Trans. Math. Softw.* 26, 3
+/// (September 2000), 363-372.
+/// DOI:[10.1145/358407.358414](https://doi.acm.org/10.1145/358407.358414)
#[derive(Clone, Copy, Debug)]
pub struct Gamma {
repr: GammaRepr,
@@ -109,7 +106,7 @@ impl Gamma {
} else {
Large(GammaLargeShape::new_raw(shape, scale))
};
- Gamma { repr: repr }
+ Gamma { repr }
}
}
@@ -126,50 +123,40 @@ impl GammaLargeShape {
fn new_raw(shape: f64, scale: f64) -> GammaLargeShape {
let d = shape - 1. / 3.;
GammaLargeShape {
- scale: scale,
+ scale,
c: 1. / (9. * d).sqrt(),
- d: d
+ d
}
}
}
-impl Sample<f64> for Gamma {
- fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
-}
-impl Sample<f64> for GammaSmallShape {
- fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
-}
-impl Sample<f64> for GammaLargeShape {
- fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
-}
-
-impl IndependentSample<f64> for Gamma {
- fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
+impl Distribution<f64> for Gamma {
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
match self.repr {
- Small(ref g) => g.ind_sample(rng),
- One(ref g) => g.ind_sample(rng),
- Large(ref g) => g.ind_sample(rng),
+ Small(ref g) => g.sample(rng),
+ One(ref g) => g.sample(rng),
+ Large(ref g) => g.sample(rng),
}
}
}
-impl IndependentSample<f64> for GammaSmallShape {
- fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
- let Open01(u) = rng.gen::<Open01<f64>>();
+impl Distribution<f64> for GammaSmallShape {
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
+ let u: f64 = rng.sample(Open01);
- self.large_shape.ind_sample(rng) * u.powf(self.inv_shape)
+ self.large_shape.sample(rng) * u.powf(self.inv_shape)
}
}
-impl IndependentSample<f64> for GammaLargeShape {
- fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
+impl Distribution<f64> for GammaLargeShape {
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
loop {
- let StandardNormal(x) = rng.gen::<StandardNormal>();
+ let x = rng.sample(StandardNormal);
let v_cbrt = 1.0 + self.c * x;
if v_cbrt <= 0.0 { // a^3 <= 0 iff a <= 0
continue
}
let v = v_cbrt * v_cbrt * v_cbrt;
- let Open01(u) = rng.gen::<Open01<f64>>();
+ let u: f64 = rng.sample(Open01);
let x_sqr = x * x;
if u < 1.0 - 0.0331 * x_sqr * x_sqr ||
@@ -190,11 +177,11 @@ impl IndependentSample<f64> for GammaLargeShape {
///
/// # Example
///
-/// ```rust
-/// use rand::distributions::{ChiSquared, IndependentSample};
+/// ```
+/// use rand::distributions::{ChiSquared, Distribution};
///
/// let chi = ChiSquared::new(11.0);
-/// let v = chi.ind_sample(&mut rand::thread_rng());
+/// let v = chi.sample(&mut rand::thread_rng());
/// println!("{} is from a χ²(11) distribution", v)
/// ```
#[derive(Clone, Copy, Debug)]
@@ -221,21 +208,18 @@ impl ChiSquared {
assert!(k > 0.0, "ChiSquared::new called with `k` < 0");
DoFAnythingElse(Gamma::new(0.5 * k, 2.0))
};
- ChiSquared { repr: repr }
+ ChiSquared { repr }
}
}
-impl Sample<f64> for ChiSquared {
- fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
-}
-impl IndependentSample<f64> for ChiSquared {
- fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
+impl Distribution<f64> for ChiSquared {
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
match self.repr {
DoFExactlyOne => {
// k == 1 => N(0,1)^2
- let StandardNormal(norm) = rng.gen::<StandardNormal>();
+ let norm = rng.sample(StandardNormal);
norm * norm
}
- DoFAnythingElse(ref g) => g.ind_sample(rng)
+ DoFAnythingElse(ref g) => g.sample(rng)
}
}
}
@@ -248,11 +232,11 @@ impl IndependentSample<f64> for ChiSquared {
///
/// # Example
///
-/// ```rust
-/// use rand::distributions::{FisherF, IndependentSample};
+/// ```
+/// use rand::distributions::{FisherF, Distribution};
///
/// let f = FisherF::new(2.0, 32.0);
-/// let v = f.ind_sample(&mut rand::thread_rng());
+/// let v = f.sample(&mut rand::thread_rng());
/// println!("{} is from an F(2, 32) distribution", v)
/// ```
#[derive(Clone, Copy, Debug)]
@@ -278,12 +262,9 @@ impl FisherF {
}
}
}
-impl Sample<f64> for FisherF {
- fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
-}
-impl IndependentSample<f64> for FisherF {
- fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
- self.numer.ind_sample(rng) / self.denom.ind_sample(rng) * self.dof_ratio
+impl Distribution<f64> for FisherF {
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
+ self.numer.sample(rng) / self.denom.sample(rng) * self.dof_ratio
}
}
@@ -292,11 +273,11 @@ impl IndependentSample<f64> for FisherF {
///
/// # Example
///
-/// ```rust
-/// use rand::distributions::{StudentT, IndependentSample};
+/// ```
+/// use rand::distributions::{StudentT, Distribution};
///
/// let t = StudentT::new(11.0);
-/// let v = t.ind_sample(&mut rand::thread_rng());
+/// let v = t.sample(&mut rand::thread_rng());
/// println!("{} is from a t(11) distribution", v)
/// ```
#[derive(Clone, Copy, Debug)]
@@ -316,46 +297,79 @@ impl StudentT {
}
}
}
-impl Sample<f64> for StudentT {
- fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
+impl Distribution<f64> for StudentT {
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
+ let norm = rng.sample(StandardNormal);
+ norm * (self.dof / self.chi.sample(rng)).sqrt()
+ }
+}
+
+/// The Beta distribution with shape parameters `alpha` and `beta`.
+///
+/// # Example
+///
+/// ```
+/// use rand::distributions::{Distribution, Beta};
+///
+/// let beta = Beta::new(2.0, 5.0);
+/// let v = beta.sample(&mut rand::thread_rng());
+/// println!("{} is from a Beta(2, 5) distribution", v);
+/// ```
+#[derive(Clone, Copy, Debug)]
+pub struct Beta {
+ gamma_a: Gamma,
+ gamma_b: Gamma,
+}
+
+impl Beta {
+ /// Construct an object representing the `Beta(alpha, beta)`
+ /// distribution.
+ ///
+ /// Panics if `shape <= 0` or `scale <= 0`.
+ pub fn new(alpha: f64, beta: f64) -> Beta {
+ assert!((alpha > 0.) & (beta > 0.));
+ Beta {
+ gamma_a: Gamma::new(alpha, 1.),
+ gamma_b: Gamma::new(beta, 1.),
+ }
+ }
}
-impl IndependentSample<f64> for StudentT {
- fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
- let StandardNormal(norm) = rng.gen::<StandardNormal>();
- norm * (self.dof / self.chi.ind_sample(rng)).sqrt()
+
+impl Distribution<f64> for Beta {
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
+ let x = self.gamma_a.sample(rng);
+ let y = self.gamma_b.sample(rng);
+ x / (x + y)
}
}
#[cfg(test)]
mod test {
- use distributions::{Sample, IndependentSample};
- use super::{ChiSquared, StudentT, FisherF};
+ use distributions::Distribution;
+ use super::{Beta, ChiSquared, StudentT, FisherF};
#[test]
fn test_chi_squared_one() {
- let mut chi = ChiSquared::new(1.0);
- let mut rng = ::test::rng();
+ let chi = ChiSquared::new(1.0);
+ let mut rng = ::test::rng(201);
for _ in 0..1000 {
chi.sample(&mut rng);
- chi.ind_sample(&mut rng);
}
}
#[test]
fn test_chi_squared_small() {
- let mut chi = ChiSquared::new(0.5);
- let mut rng = ::test::rng();
+ let chi = ChiSquared::new(0.5);
+ let mut rng = ::test::rng(202);
for _ in 0..1000 {
chi.sample(&mut rng);
- chi.ind_sample(&mut rng);
}
}
#[test]
fn test_chi_squared_large() {
- let mut chi = ChiSquared::new(30.0);
- let mut rng = ::test::rng();
+ let chi = ChiSquared::new(30.0);
+ let mut rng = ::test::rng(203);
for _ in 0..1000 {
chi.sample(&mut rng);
- chi.ind_sample(&mut rng);
}
}
#[test]
@@ -366,21 +380,34 @@ mod test {
#[test]
fn test_f() {
- let mut f = FisherF::new(2.0, 32.0);
- let mut rng = ::test::rng();
+ let f = FisherF::new(2.0, 32.0);
+ let mut rng = ::test::rng(204);
for _ in 0..1000 {
f.sample(&mut rng);
- f.ind_sample(&mut rng);
}
}
#[test]
fn test_t() {
- let mut t = StudentT::new(11.0);
- let mut rng = ::test::rng();
+ let t = StudentT::new(11.0);
+ let mut rng = ::test::rng(205);
for _ in 0..1000 {
t.sample(&mut rng);
- t.ind_sample(&mut rng);
}
}
+
+ #[test]
+ fn test_beta() {
+ let beta = Beta::new(1.0, 2.0);
+ let mut rng = ::test::rng(201);
+ for _ in 0..1000 {
+ beta.sample(&mut rng);
+ }
+ }
+
+ #[test]
+ #[should_panic]
+ fn test_beta_invalid_dof() {
+ Beta::new(0., 0.);
+ }
}
diff --git a/rand/src/distributions/integer.rs b/rand/src/distributions/integer.rs
new file mode 100644
index 0000000..4e6604d
--- /dev/null
+++ b/rand/src/distributions/integer.rs
@@ -0,0 +1,161 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! The implementations of the `Standard` distribution for integer types.
+
+use {Rng};
+use distributions::{Distribution, Standard};
+#[cfg(feature="simd_support")]
+use packed_simd::*;
+#[cfg(all(target_arch = "x86", feature="nightly"))]
+use core::arch::x86::*;
+#[cfg(all(target_arch = "x86_64", feature="nightly"))]
+use core::arch::x86_64::*;
+
+impl Distribution<u8> for Standard {
+ #[inline]
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u8 {
+ rng.next_u32() as u8
+ }
+}
+
+impl Distribution<u16> for Standard {
+ #[inline]
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u16 {
+ rng.next_u32() as u16
+ }
+}
+
+impl Distribution<u32> for Standard {
+ #[inline]
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u32 {
+ rng.next_u32()
+ }
+}
+
+impl Distribution<u64> for Standard {
+ #[inline]
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u64 {
+ rng.next_u64()
+ }
+}
+
+#[cfg(rust_1_26)]
+impl Distribution<u128> for Standard {
+ #[inline]
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u128 {
+ // Use LE; we explicitly generate one value before the next.
+ let x = rng.next_u64() as u128;
+ let y = rng.next_u64() as u128;
+ (y << 64) | x
+ }
+}
+
+impl Distribution<usize> for Standard {
+ #[inline]
+ #[cfg(any(target_pointer_width = "32", target_pointer_width = "16"))]
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> usize {
+ rng.next_u32() as usize
+ }
+
+ #[inline]
+ #[cfg(target_pointer_width = "64")]
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> usize {
+ rng.next_u64() as usize
+ }
+}
+
+macro_rules! impl_int_from_uint {
+ ($ty:ty, $uty:ty) => {
+ impl Distribution<$ty> for Standard {
+ #[inline]
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> $ty {
+ rng.gen::<$uty>() as $ty
+ }
+ }
+ }
+}
+
+impl_int_from_uint! { i8, u8 }
+impl_int_from_uint! { i16, u16 }
+impl_int_from_uint! { i32, u32 }
+impl_int_from_uint! { i64, u64 }
+#[cfg(rust_1_26)] impl_int_from_uint! { i128, u128 }
+impl_int_from_uint! { isize, usize }
+
+#[cfg(feature="simd_support")]
+macro_rules! simd_impl {
+ ($(($intrinsic:ident, $vec:ty),)+) => {$(
+ impl Distribution<$intrinsic> for Standard {
+ #[inline]
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> $intrinsic {
+ $intrinsic::from_bits(rng.gen::<$vec>())
+ }
+ }
+ )+};
+
+ ($bits:expr,) => {};
+ ($bits:expr, $ty:ty, $($ty_more:ty,)*) => {
+ simd_impl!($bits, $($ty_more,)*);
+
+ impl Distribution<$ty> for Standard {
+ #[inline]
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> $ty {
+ let mut vec: $ty = Default::default();
+ unsafe {
+ let ptr = &mut vec;
+ let b_ptr = &mut *(ptr as *mut $ty as *mut [u8; $bits/8]);
+ rng.fill_bytes(b_ptr);
+ }
+ vec.to_le()
+ }
+ }
+ };
+}
+
+#[cfg(feature="simd_support")]
+simd_impl!(16, u8x2, i8x2,);
+#[cfg(feature="simd_support")]
+simd_impl!(32, u8x4, i8x4, u16x2, i16x2,);
+#[cfg(feature="simd_support")]
+simd_impl!(64, u8x8, i8x8, u16x4, i16x4, u32x2, i32x2,);
+#[cfg(feature="simd_support")]
+simd_impl!(128, u8x16, i8x16, u16x8, i16x8, u32x4, i32x4, u64x2, i64x2,);
+#[cfg(feature="simd_support")]
+simd_impl!(256, u8x32, i8x32, u16x16, i16x16, u32x8, i32x8, u64x4, i64x4,);
+#[cfg(feature="simd_support")]
+simd_impl!(512, u8x64, i8x64, u16x32, i16x32, u32x16, i32x16, u64x8, i64x8,);
+#[cfg(all(feature="simd_support", feature="nightly", any(target_arch="x86", target_arch="x86_64")))]
+simd_impl!((__m64, u8x8), (__m128i, u8x16), (__m256i, u8x32),);
+
+#[cfg(test)]
+mod tests {
+ use Rng;
+ use distributions::{Standard};
+
+ #[test]
+ fn test_integers() {
+ let mut rng = ::test::rng(806);
+
+ rng.sample::<isize, _>(Standard);
+ rng.sample::<i8, _>(Standard);
+ rng.sample::<i16, _>(Standard);
+ rng.sample::<i32, _>(Standard);
+ rng.sample::<i64, _>(Standard);
+ #[cfg(rust_1_26)]
+ rng.sample::<i128, _>(Standard);
+
+ rng.sample::<usize, _>(Standard);
+ rng.sample::<u8, _>(Standard);
+ rng.sample::<u16, _>(Standard);
+ rng.sample::<u32, _>(Standard);
+ rng.sample::<u64, _>(Standard);
+ #[cfg(rust_1_26)]
+ rng.sample::<u128, _>(Standard);
+ }
+}
diff --git a/rand/src/distributions/mod.rs b/rand/src/distributions/mod.rs
index 5de8efb..160cd31 100644
--- a/rand/src/distributions/mod.rs
+++ b/rand/src/distributions/mod.rs
@@ -1,94 +1,394 @@
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
+// Copyright 2018 Developers of the Rand project.
+// Copyright 2013-2017 The Rust Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-//! Sampling from random distributions.
+//! Generating random samples from probability distributions.
//!
-//! This is a generalization of `Rand` to allow parameters to control the
-//! exact properties of the generated values, e.g. the mean and standard
-//! deviation of a normal distribution. The `Sample` trait is the most
-//! general, and allows for generating values that change some state
-//! internally. The `IndependentSample` trait is for generating values
-//! that do not need to record state.
-
-use core::marker;
-
-use {Rng, Rand};
-
-pub use self::range::Range;
-#[cfg(feature="std")]
-pub use self::gamma::{Gamma, ChiSquared, FisherF, StudentT};
-#[cfg(feature="std")]
-pub use self::normal::{Normal, LogNormal};
-#[cfg(feature="std")]
-pub use self::exponential::Exp;
-
-pub mod range;
-#[cfg(feature="std")]
-pub mod gamma;
-#[cfg(feature="std")]
-pub mod normal;
-#[cfg(feature="std")]
-pub mod exponential;
-
-#[cfg(feature="std")]
-mod ziggurat_tables;
-
-/// Types that can be used to create a random instance of `Support`.
-pub trait Sample<Support> {
- /// Generate a random value of `Support`, using `rng` as the
- /// source of randomness.
- fn sample<R: Rng>(&mut self, rng: &mut R) -> Support;
-}
-
-/// `Sample`s that do not require keeping track of state.
+//! This module is the home of the [`Distribution`] trait and several of its
+//! implementations. It is the workhorse behind some of the convenient
+//! functionality of the [`Rng`] trait, including [`gen`], [`gen_range`] and
+//! of course [`sample`].
+//!
+//! Abstractly, a [probability distribution] describes the probability of
+//! occurance of each value in its sample space.
+//!
+//! More concretely, an implementation of `Distribution<T>` for type `X` is an
+//! algorithm for choosing values from the sample space (a subset of `T`)
+//! according to the distribution `X` represents, using an external source of
+//! randomness (an RNG supplied to the `sample` function).
+//!
+//! A type `X` may implement `Distribution<T>` for multiple types `T`.
+//! Any type implementing [`Distribution`] is stateless (i.e. immutable),
+//! but it may have internal parameters set at construction time (for example,
+//! [`Uniform`] allows specification of its sample space as a range within `T`).
+//!
+//!
+//! # The `Standard` distribution
+//!
+//! The [`Standard`] distribution is important to mention. This is the
+//! distribution used by [`Rng::gen()`] and represents the "default" way to
+//! produce a random value for many different types, including most primitive
+//! types, tuples, arrays, and a few derived types. See the documentation of
+//! [`Standard`] for more details.
+//!
+//! Implementing `Distribution<T>` for [`Standard`] for user types `T` makes it
+//! possible to generate type `T` with [`Rng::gen()`], and by extension also
+//! with the [`random()`] function.
+//!
+//!
+//! # Distribution to sample from a `Uniform` range
+//!
+//! The [`Uniform`] distribution is more flexible than [`Standard`], but also
+//! more specialised: it supports fewer target types, but allows the sample
+//! space to be specified as an arbitrary range within its target type `T`.
+//! Both [`Standard`] and [`Uniform`] are in some sense uniform distributions.
+//!
+//! Values may be sampled from this distribution using [`Rng::gen_range`] or
+//! by creating a distribution object with [`Uniform::new`],
+//! [`Uniform::new_inclusive`] or `From<Range>`. When the range limits are not
+//! known at compile time it is typically faster to reuse an existing
+//! distribution object than to call [`Rng::gen_range`].
+//!
+//! User types `T` may also implement `Distribution<T>` for [`Uniform`],
+//! although this is less straightforward than for [`Standard`] (see the
+//! documentation in the [`uniform` module]. Doing so enables generation of
+//! values of type `T` with [`Rng::gen_range`].
+//!
+//!
+//! # Other distributions
+//!
+//! There are surprisingly many ways to uniformly generate random floats. A
+//! range between 0 and 1 is standard, but the exact bounds (open vs closed)
+//! and accuracy differ. In addition to the [`Standard`] distribution Rand offers
+//! [`Open01`] and [`OpenClosed01`]. See [Floating point implementation] for
+//! more details.
+//!
+//! [`Alphanumeric`] is a simple distribution to sample random letters and
+//! numbers of the `char` type; in contrast [`Standard`] may sample any valid
+//! `char`.
+//!
+//! [`WeightedIndex`] can be used to do weighted sampling from a set of items,
+//! such as from an array.
+//!
+//! # Non-uniform probability distributions
+//!
+//! Rand currently provides the following probability distributions:
+//!
+//! - Related to real-valued quantities that grow linearly
+//! (e.g. errors, offsets):
+//! - [`Normal`] distribution, and [`StandardNormal`] as a primitive
+//! - [`Cauchy`] distribution
+//! - Related to Bernoulli trials (yes/no events, with a given probability):
+//! - [`Binomial`] distribution
+//! - [`Bernoulli`] distribution, similar to [`Rng::gen_bool`].
+//! - Related to positive real-valued quantities that grow exponentially
+//! (e.g. prices, incomes, populations):
+//! - [`LogNormal`] distribution
+//! - Related to the occurrence of independent events at a given rate:
+//! - [`Pareto`] distribution
+//! - [`Poisson`] distribution
+//! - [`Exp`]onential distribution, and [`Exp1`] as a primitive
+//! - [`Weibull`] distribution
+//! - Gamma and derived distributions:
+//! - [`Gamma`] distribution
+//! - [`ChiSquared`] distribution
+//! - [`StudentT`] distribution
+//! - [`FisherF`] distribution
+//! - Triangular distribution:
+//! - [`Beta`] distribution
+//! - [`Triangular`] distribution
+//! - Multivariate probability distributions
+//! - [`Dirichlet`] distribution
+//! - [`UnitSphereSurface`] distribution
+//! - [`UnitCircle`] distribution
+//!
+//! # Examples
+//!
+//! Sampling from a distribution:
+//!
+//! ```
+//! use rand::{thread_rng, Rng};
+//! use rand::distributions::Exp;
+//!
+//! let exp = Exp::new(2.0);
+//! let v = thread_rng().sample(exp);
+//! println!("{} is from an Exp(2) distribution", v);
+//! ```
+//!
+//! Implementing the [`Standard`] distribution for a user type:
+//!
+//! ```
+//! # #![allow(dead_code)]
+//! use rand::Rng;
+//! use rand::distributions::{Distribution, Standard};
+//!
+//! struct MyF32 {
+//! x: f32,
+//! }
+//!
+//! impl Distribution<MyF32> for Standard {
+//! fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> MyF32 {
+//! MyF32 { x: rng.gen() }
+//! }
+//! }
+//! ```
+//!
+//!
+//! [probability distribution]: https://en.wikipedia.org/wiki/Probability_distribution
+//! [`Distribution`]: trait.Distribution.html
+//! [`gen_range`]: ../trait.Rng.html#method.gen_range
+//! [`gen`]: ../trait.Rng.html#method.gen
+//! [`sample`]: ../trait.Rng.html#method.sample
+//! [`new_inclusive`]: struct.Uniform.html#method.new_inclusive
+//! [`random()`]: ../fn.random.html
+//! [`Rng::gen_bool`]: ../trait.Rng.html#method.gen_bool
+//! [`Rng::gen_range`]: ../trait.Rng.html#method.gen_range
+//! [`Rng::gen()`]: ../trait.Rng.html#method.gen
+//! [`Rng`]: ../trait.Rng.html
+//! [`uniform` module]: uniform/index.html
+//! [Floating point implementation]: struct.Standard.html#floating-point-implementation
+// distributions
+//! [`Alphanumeric`]: struct.Alphanumeric.html
+//! [`Bernoulli`]: struct.Bernoulli.html
+//! [`Beta`]: struct.Beta.html
+//! [`Binomial`]: struct.Binomial.html
+//! [`Cauchy`]: struct.Cauchy.html
+//! [`ChiSquared`]: struct.ChiSquared.html
+//! [`Dirichlet`]: struct.Dirichlet.html
+//! [`Exp`]: struct.Exp.html
+//! [`Exp1`]: struct.Exp1.html
+//! [`FisherF`]: struct.FisherF.html
+//! [`Gamma`]: struct.Gamma.html
+//! [`LogNormal`]: struct.LogNormal.html
+//! [`Normal`]: struct.Normal.html
+//! [`Open01`]: struct.Open01.html
+//! [`OpenClosed01`]: struct.OpenClosed01.html
+//! [`Pareto`]: struct.Pareto.html
+//! [`Poisson`]: struct.Poisson.html
+//! [`Standard`]: struct.Standard.html
+//! [`StandardNormal`]: struct.StandardNormal.html
+//! [`StudentT`]: struct.StudentT.html
+//! [`Triangular`]: struct.Triangular.html
+//! [`Uniform`]: struct.Uniform.html
+//! [`Uniform::new`]: struct.Uniform.html#method.new
+//! [`Uniform::new_inclusive`]: struct.Uniform.html#method.new_inclusive
+//! [`UnitSphereSurface`]: struct.UnitSphereSurface.html
+//! [`UnitCircle`]: struct.UnitCircle.html
+//! [`Weibull`]: struct.Weibull.html
+//! [`WeightedIndex`]: struct.WeightedIndex.html
+
+#[cfg(any(rust_1_26, features="nightly"))]
+use core::iter;
+use Rng;
+
+pub use self::other::Alphanumeric;
+#[doc(inline)] pub use self::uniform::Uniform;
+pub use self::float::{OpenClosed01, Open01};
+pub use self::bernoulli::Bernoulli;
+#[cfg(feature="alloc")] pub use self::weighted::{WeightedIndex, WeightedError};
+#[cfg(feature="std")] pub use self::unit_sphere::UnitSphereSurface;
+#[cfg(feature="std")] pub use self::unit_circle::UnitCircle;
+#[cfg(feature="std")] pub use self::gamma::{Gamma, ChiSquared, FisherF,
+ StudentT, Beta};
+#[cfg(feature="std")] pub use self::normal::{Normal, LogNormal, StandardNormal};
+#[cfg(feature="std")] pub use self::exponential::{Exp, Exp1};
+#[cfg(feature="std")] pub use self::pareto::Pareto;
+#[cfg(feature="std")] pub use self::poisson::Poisson;
+#[cfg(feature="std")] pub use self::binomial::Binomial;
+#[cfg(feature="std")] pub use self::cauchy::Cauchy;
+#[cfg(feature="std")] pub use self::dirichlet::Dirichlet;
+#[cfg(feature="std")] pub use self::triangular::Triangular;
+#[cfg(feature="std")] pub use self::weibull::Weibull;
+
+pub mod uniform;
+mod bernoulli;
+#[cfg(feature="alloc")] mod weighted;
+#[cfg(feature="std")] mod unit_sphere;
+#[cfg(feature="std")] mod unit_circle;
+#[cfg(feature="std")] mod gamma;
+#[cfg(feature="std")] mod normal;
+#[cfg(feature="std")] mod exponential;
+#[cfg(feature="std")] mod pareto;
+#[cfg(feature="std")] mod poisson;
+#[cfg(feature="std")] mod binomial;
+#[cfg(feature="std")] mod cauchy;
+#[cfg(feature="std")] mod dirichlet;
+#[cfg(feature="std")] mod triangular;
+#[cfg(feature="std")] mod weibull;
+
+mod float;
+mod integer;
+mod other;
+mod utils;
+#[cfg(feature="std")] mod ziggurat_tables;
+
+/// Types (distributions) that can be used to create a random instance of `T`.
+///
+/// It is possible to sample from a distribution through both the
+/// `Distribution` and [`Rng`] traits, via `distr.sample(&mut rng)` and
+/// `rng.sample(distr)`. They also both offer the [`sample_iter`] method, which
+/// produces an iterator that samples from the distribution.
+///
+/// All implementations are expected to be immutable; this has the significant
+/// advantage of not needing to consider thread safety, and for most
+/// distributions efficient state-less sampling algorithms are available.
///
-/// Since no state is recorded, each sample is (statistically)
-/// independent of all others, assuming the `Rng` used has this
-/// property.
-// FIXME maybe having this separate is overkill (the only reason is to
-// take &self rather than &mut self)? or maybe this should be the
-// trait called `Sample` and the other should be `DependentSample`.
-pub trait IndependentSample<Support>: Sample<Support> {
- /// Generate a random value.
- fn ind_sample<R: Rng>(&self, &mut R) -> Support;
+/// [`Rng`]: ../trait.Rng.html
+/// [`sample_iter`]: trait.Distribution.html#method.sample_iter
+pub trait Distribution<T> {
+ /// Generate a random value of `T`, using `rng` as the source of randomness.
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> T;
+
+ /// Create an iterator that generates random values of `T`, using `rng` as
+ /// the source of randomness.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use rand::thread_rng;
+ /// use rand::distributions::{Distribution, Alphanumeric, Uniform, Standard};
+ ///
+ /// let mut rng = thread_rng();
+ ///
+ /// // Vec of 16 x f32:
+ /// let v: Vec<f32> = Standard.sample_iter(&mut rng).take(16).collect();
+ ///
+ /// // String:
+ /// let s: String = Alphanumeric.sample_iter(&mut rng).take(7).collect();
+ ///
+ /// // Dice-rolling:
+ /// let die_range = Uniform::new_inclusive(1, 6);
+ /// let mut roll_die = die_range.sample_iter(&mut rng);
+ /// while roll_die.next().unwrap() != 6 {
+ /// println!("Not a 6; rolling again!");
+ /// }
+ /// ```
+ fn sample_iter<'a, R>(&'a self, rng: &'a mut R) -> DistIter<'a, Self, R, T>
+ where Self: Sized, R: Rng
+ {
+ DistIter {
+ distr: self,
+ rng: rng,
+ phantom: ::core::marker::PhantomData,
+ }
+ }
}
-/// A wrapper for generating types that implement `Rand` via the
-/// `Sample` & `IndependentSample` traits.
-#[derive(Debug)]
-pub struct RandSample<Sup> {
- _marker: marker::PhantomData<fn() -> Sup>,
+impl<'a, T, D: Distribution<T>> Distribution<T> for &'a D {
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> T {
+ (*self).sample(rng)
+ }
}
-impl<Sup> Copy for RandSample<Sup> {}
-impl<Sup> Clone for RandSample<Sup> {
- fn clone(&self) -> Self { *self }
-}
-impl<Sup: Rand> Sample<Sup> for RandSample<Sup> {
- fn sample<R: Rng>(&mut self, rng: &mut R) -> Sup { self.ind_sample(rng) }
+/// An iterator that generates random values of `T` with distribution `D`,
+/// using `R` as the source of randomness.
+///
+/// This `struct` is created by the [`sample_iter`] method on [`Distribution`].
+/// See its documentation for more.
+///
+/// [`Distribution`]: trait.Distribution.html
+/// [`sample_iter`]: trait.Distribution.html#method.sample_iter
+#[derive(Debug)]
+pub struct DistIter<'a, D: 'a, R: 'a, T> {
+ distr: &'a D,
+ rng: &'a mut R,
+ phantom: ::core::marker::PhantomData<T>,
}
-impl<Sup: Rand> IndependentSample<Sup> for RandSample<Sup> {
- fn ind_sample<R: Rng>(&self, rng: &mut R) -> Sup {
- rng.gen()
+impl<'a, D, R, T> Iterator for DistIter<'a, D, R, T>
+ where D: Distribution<T>, R: Rng + 'a
+{
+ type Item = T;
+
+ #[inline(always)]
+ fn next(&mut self) -> Option<T> {
+ Some(self.distr.sample(self.rng))
}
-}
-impl<Sup> RandSample<Sup> {
- pub fn new() -> RandSample<Sup> {
- RandSample { _marker: marker::PhantomData }
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (usize::max_value(), None)
}
}
+#[cfg(rust_1_26)]
+impl<'a, D, R, T> iter::FusedIterator for DistIter<'a, D, R, T>
+ where D: Distribution<T>, R: Rng + 'a {}
+
+#[cfg(features = "nightly")]
+impl<'a, D, R, T> iter::TrustedLen for DistIter<'a, D, R, T>
+ where D: Distribution<T>, R: Rng + 'a {}
+
+
+/// A generic random value distribution, implemented for many primitive types.
+/// Usually generates values with a numerically uniform distribution, and with a
+/// range appropriate to the type.
+///
+/// ## Built-in Implementations
+///
+/// Assuming the provided `Rng` is well-behaved, these implementations
+/// generate values with the following ranges and distributions:
+///
+/// * Integers (`i32`, `u32`, `isize`, `usize`, etc.): Uniformly distributed
+/// over all values of the type.
+/// * `char`: Uniformly distributed over all Unicode scalar values, i.e. all
+/// code points in the range `0...0x10_FFFF`, except for the range
+/// `0xD800...0xDFFF` (the surrogate code points). This includes
+/// unassigned/reserved code points.
+/// * `bool`: Generates `false` or `true`, each with probability 0.5.
+/// * Floating point types (`f32` and `f64`): Uniformly distributed in the
+/// half-open range `[0, 1)`. See notes below.
+/// * Wrapping integers (`Wrapping<T>`), besides the type identical to their
+/// normal integer variants.
+///
+/// The following aggregate types also implement the distribution `Standard` as
+/// long as their component types implement it:
+///
+/// * Tuples and arrays: Each element of the tuple or array is generated
+/// independently, using the `Standard` distribution recursively.
+/// * `Option<T>` where `Standard` is implemented for `T`: Returns `None` with
+/// probability 0.5; otherwise generates a random `x: T` and returns `Some(x)`.
+///
+/// # Example
+/// ```
+/// use rand::prelude::*;
+/// use rand::distributions::Standard;
+///
+/// let val: f32 = SmallRng::from_entropy().sample(Standard);
+/// println!("f32 from [0, 1): {}", val);
+/// ```
+///
+/// # Floating point implementation
+/// The floating point implementations for `Standard` generate a random value in
+/// the half-open interval `[0, 1)`, i.e. including 0 but not 1.
+///
+/// All values that can be generated are of the form `n * ε/2`. For `f32`
+/// the 23 most significant random bits of a `u32` are used and for `f64` the
+/// 53 most significant bits of a `u64` are used. The conversion uses the
+/// multiplicative method: `(rng.gen::<$uty>() >> N) as $ty * (ε/2)`.
+///
+/// See also: [`Open01`] which samples from `(0, 1)`, [`OpenClosed01`] which
+/// samples from `(0, 1]` and `Rng::gen_range(0, 1)` which also samples from
+/// `[0, 1)`. Note that `Open01` and `gen_range` (which uses [`Uniform`]) use
+/// transmute-based methods which yield 1 bit less precision but may perform
+/// faster on some architectures (on modern Intel CPUs all methods have
+/// approximately equal performance).
+///
+/// [`Open01`]: struct.Open01.html
+/// [`OpenClosed01`]: struct.OpenClosed01.html
+/// [`Uniform`]: uniform/struct.Uniform.html
+#[derive(Clone, Copy, Debug)]
+pub struct Standard;
+
+
/// A value with a particular weight for use with `WeightedChoice`.
+#[deprecated(since="0.6.0", note="use WeightedIndex instead")]
+#[allow(deprecated)]
#[derive(Copy, Clone, Debug)]
pub struct Weighted<T> {
/// The numerical weight of this item
@@ -99,35 +399,19 @@ pub struct Weighted<T> {
/// A distribution that selects from a finite collection of weighted items.
///
-/// Each item has an associated weight that influences how likely it
-/// is to be chosen: higher weight is more likely.
-///
-/// The `Clone` restriction is a limitation of the `Sample` and
-/// `IndependentSample` traits. Note that `&T` is (cheaply) `Clone` for
-/// all `T`, as is `u32`, so one can store references or indices into
-/// another vector.
-///
-/// # Example
-///
-/// ```rust
-/// use rand::distributions::{Weighted, WeightedChoice, IndependentSample};
+/// Deprecated: use [`WeightedIndex`] instead.
///
-/// let mut items = vec!(Weighted { weight: 2, item: 'a' },
-/// Weighted { weight: 4, item: 'b' },
-/// Weighted { weight: 1, item: 'c' });
-/// let wc = WeightedChoice::new(&mut items);
-/// let mut rng = rand::thread_rng();
-/// for _ in 0..16 {
-/// // on average prints 'a' 4 times, 'b' 8 and 'c' twice.
-/// println!("{}", wc.ind_sample(&mut rng));
-/// }
-/// ```
+/// [`WeightedIndex`]: struct.WeightedIndex.html
+#[deprecated(since="0.6.0", note="use WeightedIndex instead")]
+#[allow(deprecated)]
#[derive(Debug)]
pub struct WeightedChoice<'a, T:'a> {
items: &'a mut [Weighted<T>],
- weight_range: Range<u32>
+ weight_range: Uniform<u32>,
}
+#[deprecated(since="0.6.0", note="use WeightedIndex instead")]
+#[allow(deprecated)]
impl<'a, T: Clone> WeightedChoice<'a, T> {
/// Create a new `WeightedChoice`.
///
@@ -157,26 +441,24 @@ impl<'a, T: Clone> WeightedChoice<'a, T> {
assert!(running_total != 0, "WeightedChoice::new called with a total weight of 0");
WeightedChoice {
- items: items,
+ items,
// we're likely to be generating numbers in this range
// relatively often, so might as well cache it
- weight_range: Range::new(0, running_total)
+ weight_range: Uniform::new(0, running_total)
}
}
}
-impl<'a, T: Clone> Sample<T> for WeightedChoice<'a, T> {
- fn sample<R: Rng>(&mut self, rng: &mut R) -> T { self.ind_sample(rng) }
-}
-
-impl<'a, T: Clone> IndependentSample<T> for WeightedChoice<'a, T> {
- fn ind_sample<R: Rng>(&self, rng: &mut R) -> T {
+#[deprecated(since="0.6.0", note="use WeightedIndex instead")]
+#[allow(deprecated)]
+impl<'a, T: Clone> Distribution<T> for WeightedChoice<'a, T> {
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> T {
// we want to find the first element that has cumulative
// weight > sample_weight, which we do by binary since the
// cumulative weights of self.items are sorted.
// choose a weight in [0, total_weight)
- let sample_weight = self.weight_range.ind_sample(rng);
+ let sample_weight = self.weight_range.sample(rng);
// short circuit when it's the first item
if sample_weight < self.items[0].weight {
@@ -208,163 +490,78 @@ impl<'a, T: Clone> IndependentSample<T> for WeightedChoice<'a, T> {
}
modifier /= 2;
}
- return self.items[idx + 1].item.clone();
- }
-}
-
-/// Sample a random number using the Ziggurat method (specifically the
-/// ZIGNOR variant from Doornik 2005). Most of the arguments are
-/// directly from the paper:
-///
-/// * `rng`: source of randomness
-/// * `symmetric`: whether this is a symmetric distribution, or one-sided with P(x < 0) = 0.
-/// * `X`: the $x_i$ abscissae.
-/// * `F`: precomputed values of the PDF at the $x_i$, (i.e. $f(x_i)$)
-/// * `F_DIFF`: precomputed values of $f(x_i) - f(x_{i+1})$
-/// * `pdf`: the probability density function
-/// * `zero_case`: manual sampling from the tail when we chose the
-/// bottom box (i.e. i == 0)
-
-// the perf improvement (25-50%) is definitely worth the extra code
-// size from force-inlining.
-#[cfg(feature="std")]
-#[inline(always)]
-fn ziggurat<R: Rng, P, Z>(
- rng: &mut R,
- symmetric: bool,
- x_tab: ziggurat_tables::ZigTable,
- f_tab: ziggurat_tables::ZigTable,
- mut pdf: P,
- mut zero_case: Z)
- -> f64 where P: FnMut(f64) -> f64, Z: FnMut(&mut R, f64) -> f64 {
- const SCALE: f64 = (1u64 << 53) as f64;
- loop {
- // reimplement the f64 generation as an optimisation suggested
- // by the Doornik paper: we have a lot of precision-space
- // (i.e. there are 11 bits of the 64 of a u64 to use after
- // creating a f64), so we might as well reuse some to save
- // generating a whole extra random number. (Seems to be 15%
- // faster.)
- //
- // This unfortunately misses out on the benefits of direct
- // floating point generation if an RNG like dSMFT is
- // used. (That is, such RNGs create floats directly, highly
- // efficiently and overload next_f32/f64, so by not calling it
- // this may be slower than it would be otherwise.)
- // FIXME: investigate/optimise for the above.
- let bits: u64 = rng.gen();
- let i = (bits & 0xff) as usize;
- let f = (bits >> 11) as f64 / SCALE;
-
- // u is either U(-1, 1) or U(0, 1) depending on if this is a
- // symmetric distribution or not.
- let u = if symmetric {2.0 * f - 1.0} else {f};
- let x = u * x_tab[i];
-
- let test_x = if symmetric { x.abs() } else {x};
-
- // algebraically equivalent to |u| < x_tab[i+1]/x_tab[i] (or u < x_tab[i+1]/x_tab[i])
- if test_x < x_tab[i + 1] {
- return x;
- }
- if i == 0 {
- return zero_case(rng, u);
- }
- // algebraically equivalent to f1 + DRanU()*(f0 - f1) < 1
- if f_tab[i + 1] + (f_tab[i] - f_tab[i + 1]) * rng.gen::<f64>() < pdf(x) {
- return x;
- }
+ self.items[idx + 1].item.clone()
}
}
#[cfg(test)]
mod tests {
+ use rngs::mock::StepRng;
+ #[allow(deprecated)]
+ use super::{WeightedChoice, Weighted, Distribution};
- use {Rng, Rand};
- use super::{RandSample, WeightedChoice, Weighted, Sample, IndependentSample};
-
- #[derive(PartialEq, Debug)]
- struct ConstRand(usize);
- impl Rand for ConstRand {
- fn rand<R: Rng>(_: &mut R) -> ConstRand {
- ConstRand(0)
- }
- }
-
- // 0, 1, 2, 3, ...
- struct CountingRng { i: u32 }
- impl Rng for CountingRng {
- fn next_u32(&mut self) -> u32 {
- self.i += 1;
- self.i - 1
- }
- fn next_u64(&mut self) -> u64 {
- self.next_u32() as u64
- }
- }
-
- #[test]
- fn test_rand_sample() {
- let mut rand_sample = RandSample::<ConstRand>::new();
-
- assert_eq!(rand_sample.sample(&mut ::test::rng()), ConstRand(0));
- assert_eq!(rand_sample.ind_sample(&mut ::test::rng()), ConstRand(0));
- }
#[test]
+ #[allow(deprecated)]
fn test_weighted_choice() {
// this makes assumptions about the internal implementation of
- // WeightedChoice, specifically: it doesn't reorder the items,
- // it doesn't do weird things to the RNG (so 0 maps to 0, 1 to
- // 1, internally; modulo a modulo operation).
+ // WeightedChoice. It may fail when the implementation in
+ // `distributions::uniform::UniformInt` changes.
macro_rules! t {
($items:expr, $expected:expr) => {{
let mut items = $items;
+ let mut total_weight = 0;
+ for item in &items { total_weight += item.weight; }
+
let wc = WeightedChoice::new(&mut items);
let expected = $expected;
- let mut rng = CountingRng { i: 0 };
+ // Use extremely large steps between the random numbers, because
+ // we test with small ranges and `UniformInt` is designed to prefer
+ // the most significant bits.
+ let mut rng = StepRng::new(0, !0 / (total_weight as u64));
for &val in expected.iter() {
- assert_eq!(wc.ind_sample(&mut rng), val)
+ assert_eq!(wc.sample(&mut rng), val)
}
}}
}
- t!(vec!(Weighted { weight: 1, item: 10}), [10]);
+ t!([Weighted { weight: 1, item: 10}], [10]);
// skip some
- t!(vec!(Weighted { weight: 0, item: 20},
- Weighted { weight: 2, item: 21},
- Weighted { weight: 0, item: 22},
- Weighted { weight: 1, item: 23}),
- [21,21, 23]);
+ t!([Weighted { weight: 0, item: 20},
+ Weighted { weight: 2, item: 21},
+ Weighted { weight: 0, item: 22},
+ Weighted { weight: 1, item: 23}],
+ [21, 21, 23]);
// different weights
- t!(vec!(Weighted { weight: 4, item: 30},
- Weighted { weight: 3, item: 31}),
- [30,30,30,30, 31,31,31]);
+ t!([Weighted { weight: 4, item: 30},
+ Weighted { weight: 3, item: 31}],
+ [30, 31, 30, 31, 30, 31, 30]);
// check that we're binary searching
// correctly with some vectors of odd
// length.
- t!(vec!(Weighted { weight: 1, item: 40},
- Weighted { weight: 1, item: 41},
- Weighted { weight: 1, item: 42},
- Weighted { weight: 1, item: 43},
- Weighted { weight: 1, item: 44}),
+ t!([Weighted { weight: 1, item: 40},
+ Weighted { weight: 1, item: 41},
+ Weighted { weight: 1, item: 42},
+ Weighted { weight: 1, item: 43},
+ Weighted { weight: 1, item: 44}],
[40, 41, 42, 43, 44]);
- t!(vec!(Weighted { weight: 1, item: 50},
- Weighted { weight: 1, item: 51},
- Weighted { weight: 1, item: 52},
- Weighted { weight: 1, item: 53},
- Weighted { weight: 1, item: 54},
- Weighted { weight: 1, item: 55},
- Weighted { weight: 1, item: 56}),
- [50, 51, 52, 53, 54, 55, 56]);
+ t!([Weighted { weight: 1, item: 50},
+ Weighted { weight: 1, item: 51},
+ Weighted { weight: 1, item: 52},
+ Weighted { weight: 1, item: 53},
+ Weighted { weight: 1, item: 54},
+ Weighted { weight: 1, item: 55},
+ Weighted { weight: 1, item: 56}],
+ [50, 54, 51, 55, 52, 56, 53]);
}
#[test]
+ #[allow(deprecated)]
fn test_weighted_clone_initialization() {
let initial : Weighted<u32> = Weighted {weight: 1, item: 1};
let clone = initial.clone();
@@ -373,6 +570,7 @@ mod tests {
}
#[test] #[should_panic]
+ #[allow(deprecated)]
fn test_weighted_clone_change_weight() {
let initial : Weighted<u32> = Weighted {weight: 1, item: 1};
let mut clone = initial.clone();
@@ -381,6 +579,7 @@ mod tests {
}
#[test] #[should_panic]
+ #[allow(deprecated)]
fn test_weighted_clone_change_item() {
let initial : Weighted<u32> = Weighted {weight: 1, item: 1};
let mut clone = initial.clone();
@@ -390,20 +589,33 @@ mod tests {
}
#[test] #[should_panic]
+ #[allow(deprecated)]
fn test_weighted_choice_no_items() {
WeightedChoice::<isize>::new(&mut []);
}
#[test] #[should_panic]
+ #[allow(deprecated)]
fn test_weighted_choice_zero_weight() {
WeightedChoice::new(&mut [Weighted { weight: 0, item: 0},
Weighted { weight: 0, item: 1}]);
}
#[test] #[should_panic]
+ #[allow(deprecated)]
fn test_weighted_choice_weight_overflows() {
- let x = ::std::u32::MAX / 2; // x + x + 2 is the overflow
+ let x = ::core::u32::MAX / 2; // x + x + 2 is the overflow
WeightedChoice::new(&mut [Weighted { weight: x, item: 0 },
Weighted { weight: 1, item: 1 },
Weighted { weight: x, item: 2 },
Weighted { weight: 1, item: 3 }]);
}
+
+ #[cfg(feature="std")]
+ #[test]
+ fn test_distributions_iter() {
+ use distributions::Normal;
+ let mut rng = ::test::rng(210);
+ let distr = Normal::new(10.0, 10.0);
+ let results: Vec<_> = distr.sample_iter(&mut rng).take(100).collect();
+ println!("{:?}", results);
+ }
}
diff --git a/rand/src/distributions/normal.rs b/rand/src/distributions/normal.rs
index 280613d..b8d632e 100644
--- a/rand/src/distributions/normal.rs
+++ b/rand/src/distributions/normal.rs
@@ -1,49 +1,50 @@
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
+// Copyright 2018 Developers of the Rand project.
+// Copyright 2013 The Rust Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! The normal and derived distributions.
-use {Rng, Rand, Open01};
-use distributions::{ziggurat, ziggurat_tables, Sample, IndependentSample};
+use Rng;
+use distributions::{ziggurat_tables, Distribution, Open01};
+use distributions::utils::ziggurat;
-/// A wrapper around an `f64` to generate N(0, 1) random numbers
-/// (a.k.a. a standard normal, or Gaussian).
+/// Samples floating-point numbers according to the normal distribution
+/// `N(0, 1)` (a.k.a. a standard normal, or Gaussian). This is equivalent to
+/// `Normal::new(0.0, 1.0)` but faster.
///
/// See `Normal` for the general normal distribution.
///
-/// Implemented via the ZIGNOR variant[1] of the Ziggurat method.
+/// Implemented via the ZIGNOR variant[^1] of the Ziggurat method.
///
-/// [1]: Jurgen A. Doornik (2005). [*An Improved Ziggurat Method to
-/// Generate Normal Random
-/// Samples*](http://www.doornik.com/research/ziggurat.pdf). Nuffield
-/// College, Oxford
+/// [^1]: Jurgen A. Doornik (2005). [*An Improved Ziggurat Method to
+/// Generate Normal Random Samples*](
+/// https://www.doornik.com/research/ziggurat.pdf).
+/// Nuffield College, Oxford
///
/// # Example
+/// ```
+/// use rand::prelude::*;
+/// use rand::distributions::StandardNormal;
///
-/// ```rust
-/// use rand::distributions::normal::StandardNormal;
-///
-/// let StandardNormal(x) = rand::random();
-/// println!("{}", x);
+/// let val: f64 = SmallRng::from_entropy().sample(StandardNormal);
+/// println!("{}", val);
/// ```
#[derive(Clone, Copy, Debug)]
-pub struct StandardNormal(pub f64);
+pub struct StandardNormal;
-impl Rand for StandardNormal {
- fn rand<R:Rng>(rng: &mut R) -> StandardNormal {
+impl Distribution<f64> for StandardNormal {
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
#[inline]
fn pdf(x: f64) -> f64 {
(-x*x/2.0).exp()
}
#[inline]
- fn zero_case<R:Rng>(rng: &mut R, u: f64) -> f64 {
+ fn zero_case<R: Rng + ?Sized>(rng: &mut R, u: f64) -> f64 {
// compute a random number in the tail by hand
// strange initial conditions, because the loop is not
@@ -54,8 +55,8 @@ impl Rand for StandardNormal {
let mut y = 0.0f64;
while -2.0 * y < x * x {
- let Open01(x_) = rng.gen::<Open01<f64>>();
- let Open01(y_) = rng.gen::<Open01<f64>>();
+ let x_: f64 = rng.sample(Open01);
+ let y_: f64 = rng.sample(Open01);
x = x_.ln() / ziggurat_tables::ZIG_NORM_R;
y = y_.ln();
@@ -64,30 +65,33 @@ impl Rand for StandardNormal {
if u < 0.0 { x - ziggurat_tables::ZIG_NORM_R } else { ziggurat_tables::ZIG_NORM_R - x }
}
- StandardNormal(ziggurat(
- rng,
- true, // this is symmetric
- &ziggurat_tables::ZIG_NORM_X,
- &ziggurat_tables::ZIG_NORM_F,
- pdf, zero_case))
+ ziggurat(rng, true, // this is symmetric
+ &ziggurat_tables::ZIG_NORM_X,
+ &ziggurat_tables::ZIG_NORM_F,
+ pdf, zero_case)
}
}
/// The normal distribution `N(mean, std_dev**2)`.
///
-/// This uses the ZIGNOR variant of the Ziggurat method, see
-/// `StandardNormal` for more details.
+/// This uses the ZIGNOR variant of the Ziggurat method, see [`StandardNormal`]
+/// for more details.
+///
+/// Note that [`StandardNormal`] is an optimised implementation for mean 0, and
+/// standard deviation 1.
///
/// # Example
///
-/// ```rust
-/// use rand::distributions::{Normal, IndependentSample};
+/// ```
+/// use rand::distributions::{Normal, Distribution};
///
/// // mean 2, standard deviation 3
/// let normal = Normal::new(2.0, 3.0);
-/// let v = normal.ind_sample(&mut rand::thread_rng());
+/// let v = normal.sample(&mut rand::thread_rng());
/// println!("{} is from a N(2, 9) distribution", v)
/// ```
+///
+/// [`StandardNormal`]: struct.StandardNormal.html
#[derive(Clone, Copy, Debug)]
pub struct Normal {
mean: f64,
@@ -105,17 +109,14 @@ impl Normal {
pub fn new(mean: f64, std_dev: f64) -> Normal {
assert!(std_dev >= 0.0, "Normal::new called with `std_dev` < 0");
Normal {
- mean: mean,
- std_dev: std_dev
+ mean,
+ std_dev
}
}
}
-impl Sample<f64> for Normal {
- fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
-}
-impl IndependentSample<f64> for Normal {
- fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
- let StandardNormal(n) = rng.gen::<StandardNormal>();
+impl Distribution<f64> for Normal {
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
+ let n = rng.sample(StandardNormal);
self.mean + self.std_dev * n
}
}
@@ -123,17 +124,17 @@ impl IndependentSample<f64> for Normal {
/// The log-normal distribution `ln N(mean, std_dev**2)`.
///
-/// If `X` is log-normal distributed, then `ln(X)` is `N(mean,
-/// std_dev**2)` distributed.
+/// If `X` is log-normal distributed, then `ln(X)` is `N(mean, std_dev**2)`
+/// distributed.
///
/// # Example
///
-/// ```rust
-/// use rand::distributions::{LogNormal, IndependentSample};
+/// ```
+/// use rand::distributions::{LogNormal, Distribution};
///
/// // mean 2, standard deviation 3
/// let log_normal = LogNormal::new(2.0, 3.0);
-/// let v = log_normal.ind_sample(&mut rand::thread_rng());
+/// let v = log_normal.sample(&mut rand::thread_rng());
/// println!("{} is from an ln N(2, 9) distribution", v)
/// ```
#[derive(Clone, Copy, Debug)]
@@ -154,27 +155,23 @@ impl LogNormal {
LogNormal { norm: Normal::new(mean, std_dev) }
}
}
-impl Sample<f64> for LogNormal {
- fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
-}
-impl IndependentSample<f64> for LogNormal {
- fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
- self.norm.ind_sample(rng).exp()
+impl Distribution<f64> for LogNormal {
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
+ self.norm.sample(rng).exp()
}
}
#[cfg(test)]
mod tests {
- use distributions::{Sample, IndependentSample};
+ use distributions::Distribution;
use super::{Normal, LogNormal};
#[test]
fn test_normal() {
- let mut norm = Normal::new(10.0, 10.0);
- let mut rng = ::test::rng();
+ let norm = Normal::new(10.0, 10.0);
+ let mut rng = ::test::rng(210);
for _ in 0..1000 {
norm.sample(&mut rng);
- norm.ind_sample(&mut rng);
}
}
#[test]
@@ -186,11 +183,10 @@ mod tests {
#[test]
fn test_log_normal() {
- let mut lnorm = LogNormal::new(10.0, 10.0);
- let mut rng = ::test::rng();
+ let lnorm = LogNormal::new(10.0, 10.0);
+ let mut rng = ::test::rng(211);
for _ in 0..1000 {
lnorm.sample(&mut rng);
- lnorm.ind_sample(&mut rng);
}
}
#[test]
diff --git a/rand/src/distributions/other.rs b/rand/src/distributions/other.rs
new file mode 100644
index 0000000..2295f79
--- /dev/null
+++ b/rand/src/distributions/other.rs
@@ -0,0 +1,219 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! The implementations of the `Standard` distribution for other built-in types.
+
+use core::char;
+use core::num::Wrapping;
+
+use {Rng};
+use distributions::{Distribution, Standard, Uniform};
+
+// ----- Sampling distributions -----
+
+/// Sample a `char`, uniformly distributed over ASCII letters and numbers:
+/// a-z, A-Z and 0-9.
+///
+/// # Example
+///
+/// ```
+/// use std::iter;
+/// use rand::{Rng, thread_rng};
+/// use rand::distributions::Alphanumeric;
+///
+/// let mut rng = thread_rng();
+/// let chars: String = iter::repeat(())
+/// .map(|()| rng.sample(Alphanumeric))
+/// .take(7)
+/// .collect();
+/// println!("Random chars: {}", chars);
+/// ```
+#[derive(Debug)]
+pub struct Alphanumeric;
+
+
+// ----- Implementations of distributions -----
+
+impl Distribution<char> for Standard {
+ #[inline]
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> char {
+ // A valid `char` is either in the interval `[0, 0xD800)` or
+ // `(0xDFFF, 0x11_0000)`. All `char`s must therefore be in
+ // `[0, 0x11_0000)` but not in the "gap" `[0xD800, 0xDFFF]` which is
+ // reserved for surrogates. This is the size of that gap.
+ const GAP_SIZE: u32 = 0xDFFF - 0xD800 + 1;
+
+ // Uniform::new(0, 0x11_0000 - GAP_SIZE) can also be used but it
+ // seemed slower.
+ let range = Uniform::new(GAP_SIZE, 0x11_0000);
+
+ let mut n = range.sample(rng);
+ if n <= 0xDFFF {
+ n -= GAP_SIZE;
+ }
+ unsafe { char::from_u32_unchecked(n) }
+ }
+}
+
+impl Distribution<char> for Alphanumeric {
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> char {
+ const RANGE: u32 = 26 + 26 + 10;
+ const GEN_ASCII_STR_CHARSET: &[u8] =
+ b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
+ abcdefghijklmnopqrstuvwxyz\
+ 0123456789";
+ // We can pick from 62 characters. This is so close to a power of 2, 64,
+ // that we can do better than `Uniform`. Use a simple bitshift and
+ // rejection sampling. We do not use a bitmask, because for small RNGs
+ // the most significant bits are usually of higher quality.
+ loop {
+ let var = rng.next_u32() >> (32 - 6);
+ if var < RANGE {
+ return GEN_ASCII_STR_CHARSET[var as usize] as char
+ }
+ }
+ }
+}
+
+impl Distribution<bool> for Standard {
+ #[inline]
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> bool {
+ // We can compare against an arbitrary bit of an u32 to get a bool.
+ // Because the least significant bits of a lower quality RNG can have
+ // simple patterns, we compare against the most significant bit. This is
+ // easiest done using a sign test.
+ (rng.next_u32() as i32) < 0
+ }
+}
+
+macro_rules! tuple_impl {
+ // use variables to indicate the arity of the tuple
+ ($($tyvar:ident),* ) => {
+ // the trailing commas are for the 1 tuple
+ impl< $( $tyvar ),* >
+ Distribution<( $( $tyvar ),* , )>
+ for Standard
+ where $( Standard: Distribution<$tyvar> ),*
+ {
+ #[inline]
+ fn sample<R: Rng + ?Sized>(&self, _rng: &mut R) -> ( $( $tyvar ),* , ) {
+ (
+ // use the $tyvar's to get the appropriate number of
+ // repeats (they're not actually needed)
+ $(
+ _rng.gen::<$tyvar>()
+ ),*
+ ,
+ )
+ }
+ }
+ }
+}
+
+impl Distribution<()> for Standard {
+ #[inline]
+ fn sample<R: Rng + ?Sized>(&self, _: &mut R) -> () { () }
+}
+tuple_impl!{A}
+tuple_impl!{A, B}
+tuple_impl!{A, B, C}
+tuple_impl!{A, B, C, D}
+tuple_impl!{A, B, C, D, E}
+tuple_impl!{A, B, C, D, E, F}
+tuple_impl!{A, B, C, D, E, F, G}
+tuple_impl!{A, B, C, D, E, F, G, H}
+tuple_impl!{A, B, C, D, E, F, G, H, I}
+tuple_impl!{A, B, C, D, E, F, G, H, I, J}
+tuple_impl!{A, B, C, D, E, F, G, H, I, J, K}
+tuple_impl!{A, B, C, D, E, F, G, H, I, J, K, L}
+
+macro_rules! array_impl {
+ // recursive, given at least one type parameter:
+ {$n:expr, $t:ident, $($ts:ident,)*} => {
+ array_impl!{($n - 1), $($ts,)*}
+
+ impl<T> Distribution<[T; $n]> for Standard where Standard: Distribution<T> {
+ #[inline]
+ fn sample<R: Rng + ?Sized>(&self, _rng: &mut R) -> [T; $n] {
+ [_rng.gen::<$t>(), $(_rng.gen::<$ts>()),*]
+ }
+ }
+ };
+ // empty case:
+ {$n:expr,} => {
+ impl<T> Distribution<[T; $n]> for Standard {
+ fn sample<R: Rng + ?Sized>(&self, _rng: &mut R) -> [T; $n] { [] }
+ }
+ };
+}
+
+array_impl!{32, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,}
+
+impl<T> Distribution<Option<T>> for Standard where Standard: Distribution<T> {
+ #[inline]
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Option<T> {
+ // UFCS is needed here: https://github.com/rust-lang/rust/issues/24066
+ if rng.gen::<bool>() {
+ Some(rng.gen())
+ } else {
+ None
+ }
+ }
+}
+
+impl<T> Distribution<Wrapping<T>> for Standard where Standard: Distribution<T> {
+ #[inline]
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Wrapping<T> {
+ Wrapping(rng.gen())
+ }
+}
+
+
+#[cfg(test)]
+mod tests {
+ use {Rng, RngCore, Standard};
+ use distributions::Alphanumeric;
+ #[cfg(all(not(feature="std"), feature="alloc"))] use alloc::string::String;
+
+ #[test]
+ fn test_misc() {
+ let rng: &mut RngCore = &mut ::test::rng(820);
+
+ rng.sample::<char, _>(Standard);
+ rng.sample::<bool, _>(Standard);
+ }
+
+ #[cfg(feature="alloc")]
+ #[test]
+ fn test_chars() {
+ use core::iter;
+ let mut rng = ::test::rng(805);
+
+ // Test by generating a relatively large number of chars, so we also
+ // take the rejection sampling path.
+ let word: String = iter::repeat(())
+ .map(|()| rng.gen::<char>()).take(1000).collect();
+ assert!(word.len() != 0);
+ }
+
+ #[test]
+ fn test_alphanumeric() {
+ let mut rng = ::test::rng(806);
+
+ // Test by generating a relatively large number of chars, so we also
+ // take the rejection sampling path.
+ let mut incorrect = false;
+ for _ in 0..100 {
+ let c = rng.sample(Alphanumeric);
+ incorrect |= !((c >= '0' && c <= '9') ||
+ (c >= 'A' && c <= 'Z') ||
+ (c >= 'a' && c <= 'z') );
+ }
+ assert!(incorrect == false);
+ }
+}
diff --git a/rand/src/distributions/pareto.rs b/rand/src/distributions/pareto.rs
new file mode 100644
index 0000000..744a157
--- /dev/null
+++ b/rand/src/distributions/pareto.rs
@@ -0,0 +1,74 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! The Pareto distribution.
+
+use Rng;
+use distributions::{Distribution, OpenClosed01};
+
+/// Samples floating-point numbers according to the Pareto distribution
+///
+/// # Example
+/// ```
+/// use rand::prelude::*;
+/// use rand::distributions::Pareto;
+///
+/// let val: f64 = SmallRng::from_entropy().sample(Pareto::new(1., 2.));
+/// println!("{}", val);
+/// ```
+#[derive(Clone, Copy, Debug)]
+pub struct Pareto {
+ scale: f64,
+ inv_neg_shape: f64,
+}
+
+impl Pareto {
+ /// Construct a new Pareto distribution with given `scale` and `shape`.
+ ///
+ /// In the literature, `scale` is commonly written as x<sub>m</sub> or k and
+ /// `shape` is often written as α.
+ ///
+ /// # Panics
+ ///
+ /// `scale` and `shape` have to be non-zero and positive.
+ pub fn new(scale: f64, shape: f64) -> Pareto {
+ assert!((scale > 0.) & (shape > 0.));
+ Pareto { scale, inv_neg_shape: -1.0 / shape }
+ }
+}
+
+impl Distribution<f64> for Pareto {
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
+ let u: f64 = rng.sample(OpenClosed01);
+ self.scale * u.powf(self.inv_neg_shape)
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use distributions::Distribution;
+ use super::Pareto;
+
+ #[test]
+ #[should_panic]
+ fn invalid() {
+ Pareto::new(0., 0.);
+ }
+
+ #[test]
+ fn sample() {
+ let scale = 1.0;
+ let shape = 2.0;
+ let d = Pareto::new(scale, shape);
+ let mut rng = ::test::rng(1);
+ for _ in 0..1000 {
+ let r = d.sample(&mut rng);
+ assert!(r >= scale);
+ }
+ }
+}
diff --git a/rand/src/distributions/poisson.rs b/rand/src/distributions/poisson.rs
new file mode 100644
index 0000000..1244caa
--- /dev/null
+++ b/rand/src/distributions/poisson.rs
@@ -0,0 +1,157 @@
+// Copyright 2018 Developers of the Rand project.
+// Copyright 2016-2017 The Rust Project Developers.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! The Poisson distribution.
+
+use Rng;
+use distributions::{Distribution, Cauchy};
+use distributions::utils::log_gamma;
+
+/// The Poisson distribution `Poisson(lambda)`.
+///
+/// This distribution has a density function:
+/// `f(k) = lambda^k * exp(-lambda) / k!` for `k >= 0`.
+///
+/// # Example
+///
+/// ```
+/// use rand::distributions::{Poisson, Distribution};
+///
+/// let poi = Poisson::new(2.0);
+/// let v = poi.sample(&mut rand::thread_rng());
+/// println!("{} is from a Poisson(2) distribution", v);
+/// ```
+#[derive(Clone, Copy, Debug)]
+pub struct Poisson {
+ lambda: f64,
+ // precalculated values
+ exp_lambda: f64,
+ log_lambda: f64,
+ sqrt_2lambda: f64,
+ magic_val: f64,
+}
+
+impl Poisson {
+ /// Construct a new `Poisson` with the given shape parameter
+ /// `lambda`. Panics if `lambda <= 0`.
+ pub fn new(lambda: f64) -> Poisson {
+ assert!(lambda > 0.0, "Poisson::new called with lambda <= 0");
+ let log_lambda = lambda.ln();
+ Poisson {
+ lambda,
+ exp_lambda: (-lambda).exp(),
+ log_lambda,
+ sqrt_2lambda: (2.0 * lambda).sqrt(),
+ magic_val: lambda * log_lambda - log_gamma(1.0 + lambda),
+ }
+ }
+}
+
+impl Distribution<u64> for Poisson {
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u64 {
+ // using the algorithm from Numerical Recipes in C
+
+ // for low expected values use the Knuth method
+ if self.lambda < 12.0 {
+ let mut result = 0;
+ let mut p = 1.0;
+ while p > self.exp_lambda {
+ p *= rng.gen::<f64>();
+ result += 1;
+ }
+ result - 1
+ }
+ // high expected values - rejection method
+ else {
+ let mut int_result: u64;
+
+ // we use the Cauchy distribution as the comparison distribution
+ // f(x) ~ 1/(1+x^2)
+ let cauchy = Cauchy::new(0.0, 1.0);
+
+ loop {
+ let mut result;
+ let mut comp_dev;
+
+ loop {
+ // draw from the Cauchy distribution
+ comp_dev = rng.sample(cauchy);
+ // shift the peak of the comparison ditribution
+ result = self.sqrt_2lambda * comp_dev + self.lambda;
+ // repeat the drawing until we are in the range of possible values
+ if result >= 0.0 {
+ break;
+ }
+ }
+ // now the result is a random variable greater than 0 with Cauchy distribution
+ // the result should be an integer value
+ result = result.floor();
+ int_result = result as u64;
+
+ // this is the ratio of the Poisson distribution to the comparison distribution
+ // the magic value scales the distribution function to a range of approximately 0-1
+ // since it is not exact, we multiply the ratio by 0.9 to avoid ratios greater than 1
+ // this doesn't change the resulting distribution, only increases the rate of failed drawings
+ let check = 0.9 * (1.0 + comp_dev * comp_dev)
+ * (result * self.log_lambda - log_gamma(1.0 + result) - self.magic_val).exp();
+
+ // check with uniform random value - if below the threshold, we are within the target distribution
+ if rng.gen::<f64>() <= check {
+ break;
+ }
+ }
+ int_result
+ }
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use distributions::Distribution;
+ use super::Poisson;
+
+ #[test]
+ fn test_poisson_10() {
+ let poisson = Poisson::new(10.0);
+ let mut rng = ::test::rng(123);
+ let mut sum = 0;
+ for _ in 0..1000 {
+ sum += poisson.sample(&mut rng);
+ }
+ let avg = (sum as f64) / 1000.0;
+ println!("Poisson average: {}", avg);
+ assert!((avg - 10.0).abs() < 0.5); // not 100% certain, but probable enough
+ }
+
+ #[test]
+ fn test_poisson_15() {
+ // Take the 'high expected values' path
+ let poisson = Poisson::new(15.0);
+ let mut rng = ::test::rng(123);
+ let mut sum = 0;
+ for _ in 0..1000 {
+ sum += poisson.sample(&mut rng);
+ }
+ let avg = (sum as f64) / 1000.0;
+ println!("Poisson average: {}", avg);
+ assert!((avg - 15.0).abs() < 0.5); // not 100% certain, but probable enough
+ }
+
+ #[test]
+ #[should_panic]
+ fn test_poisson_invalid_lambda_zero() {
+ Poisson::new(0.0);
+ }
+
+ #[test]
+ #[should_panic]
+ fn test_poisson_invalid_lambda_neg() {
+ Poisson::new(-10.0);
+ }
+}
diff --git a/rand/src/distributions/range.rs b/rand/src/distributions/range.rs
deleted file mode 100644
index 935a00a..0000000
--- a/rand/src/distributions/range.rs
+++ /dev/null
@@ -1,241 +0,0 @@
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Generating numbers between two others.
-
-// this is surprisingly complicated to be both generic & correct
-
-use core::num::Wrapping as w;
-
-use Rng;
-use distributions::{Sample, IndependentSample};
-
-/// Sample values uniformly between two bounds.
-///
-/// This gives a uniform distribution (assuming the RNG used to sample
-/// it is itself uniform & the `SampleRange` implementation for the
-/// given type is correct), even for edge cases like `low = 0u8`,
-/// `high = 170u8`, for which a naive modulo operation would return
-/// numbers less than 85 with double the probability to those greater
-/// than 85.
-///
-/// Types should attempt to sample in `[low, high)`, i.e., not
-/// including `high`, but this may be very difficult. All the
-/// primitive integer types satisfy this property, and the float types
-/// normally satisfy it, but rounding may mean `high` can occur.
-///
-/// # Example
-///
-/// ```rust
-/// use rand::distributions::{IndependentSample, Range};
-///
-/// fn main() {
-/// let between = Range::new(10, 10000);
-/// let mut rng = rand::thread_rng();
-/// let mut sum = 0;
-/// for _ in 0..1000 {
-/// sum += between.ind_sample(&mut rng);
-/// }
-/// println!("{}", sum);
-/// }
-/// ```
-#[derive(Clone, Copy, Debug)]
-pub struct Range<X> {
- low: X,
- range: X,
- accept_zone: X
-}
-
-impl<X: SampleRange + PartialOrd> Range<X> {
- /// Create a new `Range` instance that samples uniformly from
- /// `[low, high)`. Panics if `low >= high`.
- pub fn new(low: X, high: X) -> Range<X> {
- assert!(low < high, "Range::new called with `low >= high`");
- SampleRange::construct_range(low, high)
- }
-}
-
-impl<Sup: SampleRange> Sample<Sup> for Range<Sup> {
- #[inline]
- fn sample<R: Rng>(&mut self, rng: &mut R) -> Sup { self.ind_sample(rng) }
-}
-impl<Sup: SampleRange> IndependentSample<Sup> for Range<Sup> {
- fn ind_sample<R: Rng>(&self, rng: &mut R) -> Sup {
- SampleRange::sample_range(self, rng)
- }
-}
-
-/// The helper trait for types that have a sensible way to sample
-/// uniformly between two values. This should not be used directly,
-/// and is only to facilitate `Range`.
-pub trait SampleRange : Sized {
- /// Construct the `Range` object that `sample_range`
- /// requires. This should not ever be called directly, only via
- /// `Range::new`, which will check that `low < high`, so this
- /// function doesn't have to repeat the check.
- fn construct_range(low: Self, high: Self) -> Range<Self>;
-
- /// Sample a value from the given `Range` with the given `Rng` as
- /// a source of randomness.
- fn sample_range<R: Rng>(r: &Range<Self>, rng: &mut R) -> Self;
-}
-
-macro_rules! integer_impl {
- ($ty:ty, $unsigned:ident) => {
- impl SampleRange for $ty {
- // we play free and fast with unsigned vs signed here
- // (when $ty is signed), but that's fine, since the
- // contract of this macro is for $ty and $unsigned to be
- // "bit-equal", so casting between them is a no-op & a
- // bijection.
-
- #[inline]
- fn construct_range(low: $ty, high: $ty) -> Range<$ty> {
- let range = (w(high as $unsigned) - w(low as $unsigned)).0;
- let unsigned_max: $unsigned = ::core::$unsigned::MAX;
-
- // this is the largest number that fits into $unsigned
- // that `range` divides evenly, so, if we've sampled
- // `n` uniformly from this region, then `n % range` is
- // uniform in [0, range)
- let zone = unsigned_max - unsigned_max % range;
-
- Range {
- low: low,
- range: range as $ty,
- accept_zone: zone as $ty
- }
- }
-
- #[inline]
- fn sample_range<R: Rng>(r: &Range<$ty>, rng: &mut R) -> $ty {
- loop {
- // rejection sample
- let v = rng.gen::<$unsigned>();
- // until we find something that fits into the
- // region which r.range evenly divides (this will
- // be uniformly distributed)
- if v < r.accept_zone as $unsigned {
- // and return it, with some adjustments
- return (w(r.low) + w((v % r.range as $unsigned) as $ty)).0;
- }
- }
- }
- }
- }
-}
-
-integer_impl! { i8, u8 }
-integer_impl! { i16, u16 }
-integer_impl! { i32, u32 }
-integer_impl! { i64, u64 }
-#[cfg(feature = "i128_support")]
-integer_impl! { i128, u128 }
-integer_impl! { isize, usize }
-integer_impl! { u8, u8 }
-integer_impl! { u16, u16 }
-integer_impl! { u32, u32 }
-integer_impl! { u64, u64 }
-#[cfg(feature = "i128_support")]
-integer_impl! { u128, u128 }
-integer_impl! { usize, usize }
-
-macro_rules! float_impl {
- ($ty:ty) => {
- impl SampleRange for $ty {
- fn construct_range(low: $ty, high: $ty) -> Range<$ty> {
- Range {
- low: low,
- range: high - low,
- accept_zone: 0.0 // unused
- }
- }
- fn sample_range<R: Rng>(r: &Range<$ty>, rng: &mut R) -> $ty {
- r.low + r.range * rng.gen::<$ty>()
- }
- }
- }
-}
-
-float_impl! { f32 }
-float_impl! { f64 }
-
-#[cfg(test)]
-mod tests {
- use distributions::{Sample, IndependentSample};
- use super::Range as Range;
-
- #[should_panic]
- #[test]
- fn test_range_bad_limits_equal() {
- Range::new(10, 10);
- }
- #[should_panic]
- #[test]
- fn test_range_bad_limits_flipped() {
- Range::new(10, 5);
- }
-
- #[test]
- fn test_integers() {
- let mut rng = ::test::rng();
- macro_rules! t {
- ($($ty:ident),*) => {{
- $(
- let v: &[($ty, $ty)] = &[(0, 10),
- (10, 127),
- (::core::$ty::MIN, ::core::$ty::MAX)];
- for &(low, high) in v.iter() {
- let mut sampler: Range<$ty> = Range::new(low, high);
- for _ in 0..1000 {
- let v = sampler.sample(&mut rng);
- assert!(low <= v && v < high);
- let v = sampler.ind_sample(&mut rng);
- assert!(low <= v && v < high);
- }
- }
- )*
- }}
- }
- #[cfg(not(feature = "i128_support"))]
- t!(i8, i16, i32, i64, isize,
- u8, u16, u32, u64, usize);
- #[cfg(feature = "i128_support")]
- t!(i8, i16, i32, i64, i128, isize,
- u8, u16, u32, u64, u128, usize);
- }
-
- #[test]
- fn test_floats() {
- let mut rng = ::test::rng();
- macro_rules! t {
- ($($ty:ty),*) => {{
- $(
- let v: &[($ty, $ty)] = &[(0.0, 100.0),
- (-1e35, -1e25),
- (1e-35, 1e-25),
- (-1e35, 1e35)];
- for &(low, high) in v.iter() {
- let mut sampler: Range<$ty> = Range::new(low, high);
- for _ in 0..1000 {
- let v = sampler.sample(&mut rng);
- assert!(low <= v && v < high);
- let v = sampler.ind_sample(&mut rng);
- assert!(low <= v && v < high);
- }
- }
- )*
- }}
- }
-
- t!(f32, f64)
- }
-
-}
diff --git a/rand/src/distributions/triangular.rs b/rand/src/distributions/triangular.rs
new file mode 100644
index 0000000..a6eef5c
--- /dev/null
+++ b/rand/src/distributions/triangular.rs
@@ -0,0 +1,86 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+//! The triangular distribution.
+
+use Rng;
+use distributions::{Distribution, Standard};
+
+/// The triangular distribution.
+///
+/// # Example
+///
+/// ```rust
+/// use rand::distributions::{Triangular, Distribution};
+///
+/// let d = Triangular::new(0., 5., 2.5);
+/// let v = d.sample(&mut rand::thread_rng());
+/// println!("{} is from a triangular distribution", v);
+/// ```
+#[derive(Clone, Copy, Debug)]
+pub struct Triangular {
+ min: f64,
+ max: f64,
+ mode: f64,
+}
+
+impl Triangular {
+ /// Construct a new `Triangular` with minimum `min`, maximum `max` and mode
+ /// `mode`.
+ ///
+ /// # Panics
+ ///
+ /// If `max < mode`, `mode < max` or `max == min`.
+ ///
+ #[inline]
+ pub fn new(min: f64, max: f64, mode: f64) -> Triangular {
+ assert!(max >= mode);
+ assert!(mode >= min);
+ assert!(max != min);
+ Triangular { min, max, mode }
+ }
+}
+
+impl Distribution<f64> for Triangular {
+ #[inline]
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
+ let f: f64 = rng.sample(Standard);
+ let diff_mode_min = self.mode - self.min;
+ let diff_max_min = self.max - self.min;
+ if f * diff_max_min < diff_mode_min {
+ self.min + (f * diff_max_min * diff_mode_min).sqrt()
+ } else {
+ self.max - ((1. - f) * diff_max_min * (self.max - self.mode)).sqrt()
+ }
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use distributions::Distribution;
+ use super::Triangular;
+
+ #[test]
+ fn test_new() {
+ for &(min, max, mode) in &[
+ (-1., 1., 0.), (1., 2., 1.), (5., 25., 25.), (1e-5, 1e5, 1e-3),
+ (0., 1., 0.9), (-4., -0.5, -2.), (-13.039, 8.41, 1.17),
+ ] {
+ println!("{} {} {}", min, max, mode);
+ let _ = Triangular::new(min, max, mode);
+ }
+ }
+
+ #[test]
+ fn test_sample() {
+ let norm = Triangular::new(0., 1., 0.5);
+ let mut rng = ::test::rng(1);
+ for _ in 0..1000 {
+ norm.sample(&mut rng);
+ }
+ }
+}
diff --git a/rand/src/distributions/uniform.rs b/rand/src/distributions/uniform.rs
new file mode 100644
index 0000000..5fb89e3
--- /dev/null
+++ b/rand/src/distributions/uniform.rs
@@ -0,0 +1,1297 @@
+// Copyright 2018 Developers of the Rand project.
+// Copyright 2017 The Rust Project Developers.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! A distribution uniformly sampling numbers within a given range.
+//!
+//! [`Uniform`] is the standard distribution to sample uniformly from a range;
+//! e.g. `Uniform::new_inclusive(1, 6)` can sample integers from 1 to 6, like a
+//! standard die. [`Rng::gen_range`] supports any type supported by
+//! [`Uniform`].
+//!
+//! This distribution is provided with support for several primitive types
+//! (all integer and floating-point types) as well as `std::time::Duration`,
+//! and supports extension to user-defined types via a type-specific *back-end*
+//! implementation.
+//!
+//! The types [`UniformInt`], [`UniformFloat`] and [`UniformDuration`] are the
+//! back-ends supporting sampling from primitive integer and floating-point
+//! ranges as well as from `std::time::Duration`; these types do not normally
+//! need to be used directly (unless implementing a derived back-end).
+//!
+//! # Example usage
+//!
+//! ```
+//! use rand::{Rng, thread_rng};
+//! use rand::distributions::Uniform;
+//!
+//! let mut rng = thread_rng();
+//! let side = Uniform::new(-10.0, 10.0);
+//!
+//! // sample between 1 and 10 points
+//! for _ in 0..rng.gen_range(1, 11) {
+//! // sample a point from the square with sides -10 - 10 in two dimensions
+//! let (x, y) = (rng.sample(side), rng.sample(side));
+//! println!("Point: {}, {}", x, y);
+//! }
+//! ```
+//!
+//! # Extending `Uniform` to support a custom type
+//!
+//! To extend [`Uniform`] to support your own types, write a back-end which
+//! implements the [`UniformSampler`] trait, then implement the [`SampleUniform`]
+//! helper trait to "register" your back-end. See the `MyF32` example below.
+//!
+//! At a minimum, the back-end needs to store any parameters needed for sampling
+//! (e.g. the target range) and implement `new`, `new_inclusive` and `sample`.
+//! Those methods should include an assert to check the range is valid (i.e.
+//! `low < high`). The example below merely wraps another back-end.
+//!
+//! The `new`, `new_inclusive` and `sample_single` functions use arguments of
+//! type SampleBorrow<X> in order to support passing in values by reference or
+//! by value. In the implementation of these functions, you can choose to
+//! simply use the reference returned by [`SampleBorrow::borrow`], or you can choose
+//! to copy or clone the value, whatever is appropriate for your type.
+//!
+//! ```
+//! use rand::prelude::*;
+//! use rand::distributions::uniform::{Uniform, SampleUniform,
+//! UniformSampler, UniformFloat, SampleBorrow};
+//!
+//! struct MyF32(f32);
+//!
+//! #[derive(Clone, Copy, Debug)]
+//! struct UniformMyF32 {
+//! inner: UniformFloat<f32>,
+//! }
+//!
+//! impl UniformSampler for UniformMyF32 {
+//! type X = MyF32;
+//! fn new<B1, B2>(low: B1, high: B2) -> Self
+//! where B1: SampleBorrow<Self::X> + Sized,
+//! B2: SampleBorrow<Self::X> + Sized
+//! {
+//! UniformMyF32 {
+//! inner: UniformFloat::<f32>::new(low.borrow().0, high.borrow().0),
+//! }
+//! }
+//! fn new_inclusive<B1, B2>(low: B1, high: B2) -> Self
+//! where B1: SampleBorrow<Self::X> + Sized,
+//! B2: SampleBorrow<Self::X> + Sized
+//! {
+//! UniformSampler::new(low, high)
+//! }
+//! fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X {
+//! MyF32(self.inner.sample(rng))
+//! }
+//! }
+//!
+//! impl SampleUniform for MyF32 {
+//! type Sampler = UniformMyF32;
+//! }
+//!
+//! let (low, high) = (MyF32(17.0f32), MyF32(22.0f32));
+//! let uniform = Uniform::new(low, high);
+//! let x = uniform.sample(&mut thread_rng());
+//! ```
+//!
+//! [`Uniform`]: struct.Uniform.html
+//! [`Rng::gen_range`]: ../../trait.Rng.html#method.gen_range
+//! [`SampleUniform`]: trait.SampleUniform.html
+//! [`UniformSampler`]: trait.UniformSampler.html
+//! [`UniformInt`]: struct.UniformInt.html
+//! [`UniformFloat`]: struct.UniformFloat.html
+//! [`UniformDuration`]: struct.UniformDuration.html
+//! [`SampleBorrow::borrow`]: trait.SampleBorrow.html#method.borrow
+
+#[cfg(feature = "std")]
+use std::time::Duration;
+#[cfg(all(not(feature = "std"), rust_1_25))]
+use core::time::Duration;
+
+use Rng;
+use distributions::Distribution;
+use distributions::float::IntoFloat;
+use distributions::utils::{WideningMultiply, FloatSIMDUtils, FloatAsSIMD, BoolAsSIMD};
+
+#[cfg(not(feature = "std"))]
+#[allow(unused_imports)] // rustc doesn't detect that this is actually used
+use distributions::utils::Float;
+
+
+#[cfg(feature="simd_support")]
+use packed_simd::*;
+
+/// Sample values uniformly between two bounds.
+///
+/// [`Uniform::new`] and [`Uniform::new_inclusive`] construct a uniform
+/// distribution sampling from the given range; these functions may do extra
+/// work up front to make sampling of multiple values faster.
+///
+/// When sampling from a constant range, many calculations can happen at
+/// compile-time and all methods should be fast; for floating-point ranges and
+/// the full range of integer types this should have comparable performance to
+/// the `Standard` distribution.
+///
+/// Steps are taken to avoid bias which might be present in naive
+/// implementations; for example `rng.gen::<u8>() % 170` samples from the range
+/// `[0, 169]` but is twice as likely to select numbers less than 85 than other
+/// values. Further, the implementations here give more weight to the high-bits
+/// generated by the RNG than the low bits, since with some RNGs the low-bits
+/// are of lower quality than the high bits.
+///
+/// Implementations must sample in `[low, high)` range for
+/// `Uniform::new(low, high)`, i.e., excluding `high`. In particular care must
+/// be taken to ensure that rounding never results values `< low` or `>= high`.
+///
+/// # Example
+///
+/// ```
+/// use rand::distributions::{Distribution, Uniform};
+///
+/// fn main() {
+/// let between = Uniform::from(10..10000);
+/// let mut rng = rand::thread_rng();
+/// let mut sum = 0;
+/// for _ in 0..1000 {
+/// sum += between.sample(&mut rng);
+/// }
+/// println!("{}", sum);
+/// }
+/// ```
+///
+/// [`Uniform::new`]: struct.Uniform.html#method.new
+/// [`Uniform::new_inclusive`]: struct.Uniform.html#method.new_inclusive
+/// [`new`]: struct.Uniform.html#method.new
+/// [`new_inclusive`]: struct.Uniform.html#method.new_inclusive
+#[derive(Clone, Copy, Debug)]
+pub struct Uniform<X: SampleUniform> {
+ inner: X::Sampler,
+}
+
+impl<X: SampleUniform> Uniform<X> {
+ /// Create a new `Uniform` instance which samples uniformly from the half
+ /// open range `[low, high)` (excluding `high`). Panics if `low >= high`.
+ pub fn new<B1, B2>(low: B1, high: B2) -> Uniform<X>
+ where B1: SampleBorrow<X> + Sized,
+ B2: SampleBorrow<X> + Sized
+ {
+ Uniform { inner: X::Sampler::new(low, high) }
+ }
+
+ /// Create a new `Uniform` instance which samples uniformly from the closed
+ /// range `[low, high]` (inclusive). Panics if `low > high`.
+ pub fn new_inclusive<B1, B2>(low: B1, high: B2) -> Uniform<X>
+ where B1: SampleBorrow<X> + Sized,
+ B2: SampleBorrow<X> + Sized
+ {
+ Uniform { inner: X::Sampler::new_inclusive(low, high) }
+ }
+}
+
+impl<X: SampleUniform> Distribution<X> for Uniform<X> {
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> X {
+ self.inner.sample(rng)
+ }
+}
+
+/// Helper trait for creating objects using the correct implementation of
+/// [`UniformSampler`] for the sampling type.
+///
+/// See the [module documentation] on how to implement [`Uniform`] range
+/// sampling for a custom type.
+///
+/// [`UniformSampler`]: trait.UniformSampler.html
+/// [module documentation]: index.html
+/// [`Uniform`]: struct.Uniform.html
+pub trait SampleUniform: Sized {
+ /// The `UniformSampler` implementation supporting type `X`.
+ type Sampler: UniformSampler<X = Self>;
+}
+
+/// Helper trait handling actual uniform sampling.
+///
+/// See the [module documentation] on how to implement [`Uniform`] range
+/// sampling for a custom type.
+///
+/// Implementation of [`sample_single`] is optional, and is only useful when
+/// the implementation can be faster than `Self::new(low, high).sample(rng)`.
+///
+/// [module documentation]: index.html
+/// [`Uniform`]: struct.Uniform.html
+/// [`sample_single`]: trait.UniformSampler.html#method.sample_single
+pub trait UniformSampler: Sized {
+ /// The type sampled by this implementation.
+ type X;
+
+ /// Construct self, with inclusive lower bound and exclusive upper bound
+ /// `[low, high)`.
+ ///
+ /// Usually users should not call this directly but instead use
+ /// `Uniform::new`, which asserts that `low < high` before calling this.
+ fn new<B1, B2>(low: B1, high: B2) -> Self
+ where B1: SampleBorrow<Self::X> + Sized,
+ B2: SampleBorrow<Self::X> + Sized;
+
+ /// Construct self, with inclusive bounds `[low, high]`.
+ ///
+ /// Usually users should not call this directly but instead use
+ /// `Uniform::new_inclusive`, which asserts that `low <= high` before
+ /// calling this.
+ fn new_inclusive<B1, B2>(low: B1, high: B2) -> Self
+ where B1: SampleBorrow<Self::X> + Sized,
+ B2: SampleBorrow<Self::X> + Sized;
+
+ /// Sample a value.
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X;
+
+ /// Sample a single value uniformly from a range with inclusive lower bound
+ /// and exclusive upper bound `[low, high)`.
+ ///
+ /// Usually users should not call this directly but instead use
+ /// `Uniform::sample_single`, which asserts that `low < high` before calling
+ /// this.
+ ///
+ /// Via this method, implementations can provide a method optimized for
+ /// sampling only a single value from the specified range. The default
+ /// implementation simply calls `UniformSampler::new` then `sample` on the
+ /// result.
+ fn sample_single<R: Rng + ?Sized, B1, B2>(low: B1, high: B2, rng: &mut R)
+ -> Self::X
+ where B1: SampleBorrow<Self::X> + Sized,
+ B2: SampleBorrow<Self::X> + Sized
+ {
+ let uniform: Self = UniformSampler::new(low, high);
+ uniform.sample(rng)
+ }
+}
+
+impl<X: SampleUniform> From<::core::ops::Range<X>> for Uniform<X> {
+ fn from(r: ::core::ops::Range<X>) -> Uniform<X> {
+ Uniform::new(r.start, r.end)
+ }
+}
+
+#[cfg(rust_1_27)]
+impl<X: SampleUniform> From<::core::ops::RangeInclusive<X>> for Uniform<X> {
+ fn from(r: ::core::ops::RangeInclusive<X>) -> Uniform<X> {
+ Uniform::new_inclusive(r.start(), r.end())
+ }
+}
+
+/// Helper trait similar to [`Borrow`] but implemented
+/// only for SampleUniform and references to SampleUniform in
+/// order to resolve ambiguity issues.
+///
+/// [`Borrow`]: https://doc.rust-lang.org/std/borrow/trait.Borrow.html
+pub trait SampleBorrow<Borrowed> {
+ /// Immutably borrows from an owned value. See [`Borrow::borrow`]
+ ///
+ /// [`Borrow::borrow`]: https://doc.rust-lang.org/std/borrow/trait.Borrow.html#tymethod.borrow
+ fn borrow(&self) -> &Borrowed;
+}
+impl<Borrowed> SampleBorrow<Borrowed> for Borrowed where Borrowed: SampleUniform {
+ #[inline(always)]
+ fn borrow(&self) -> &Borrowed { self }
+}
+impl<'a, Borrowed> SampleBorrow<Borrowed> for &'a Borrowed where Borrowed: SampleUniform {
+ #[inline(always)]
+ fn borrow(&self) -> &Borrowed { *self }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+// What follows are all back-ends.
+
+
+/// The back-end implementing [`UniformSampler`] for integer types.
+///
+/// Unless you are implementing [`UniformSampler`] for your own type, this type
+/// should not be used directly, use [`Uniform`] instead.
+///
+/// # Implementation notes
+///
+/// For a closed range, the number of possible numbers we should generate is
+/// `range = (high - low + 1)`. It is not possible to end up with a uniform
+/// distribution if we map *all* the random integers that can be generated to
+/// this range. We have to map integers from a `zone` that is a multiple of the
+/// range. The rest of the integers, that cause a bias, are rejected.
+///
+/// The problem with `range` is that to cover the full range of the type, it has
+/// to store `unsigned_max + 1`, which can't be represented. But if the range
+/// covers the full range of the type, no modulus is needed. A range of size 0
+/// can't exist, so we use that to represent this special case. Wrapping
+/// arithmetic even makes representing `unsigned_max + 1` as 0 simple.
+///
+/// We don't calculate `zone` directly, but first calculate the number of
+/// integers to reject. To handle `unsigned_max + 1` not fitting in the type,
+/// we use:
+/// `ints_to_reject = (unsigned_max + 1) % range;`
+/// `ints_to_reject = (unsigned_max - range + 1) % range;`
+///
+/// The smallest integer PRNGs generate is `u32`. That is why for small integer
+/// sizes (`i8`/`u8` and `i16`/`u16`) there is an optimization: don't pick the
+/// largest zone that can fit in the small type, but pick the largest zone that
+/// can fit in an `u32`. `ints_to_reject` is always less than half the size of
+/// the small integer. This means the first bit of `zone` is always 1, and so
+/// are all the other preceding bits of a larger integer. The easiest way to
+/// grow the `zone` for the larger type is to simply sign extend it.
+///
+/// An alternative to using a modulus is widening multiply: After a widening
+/// multiply by `range`, the result is in the high word. Then comparing the low
+/// word against `zone` makes sure our distribution is uniform.
+///
+/// [`UniformSampler`]: trait.UniformSampler.html
+/// [`Uniform`]: struct.Uniform.html
+#[derive(Clone, Copy, Debug)]
+pub struct UniformInt<X> {
+ low: X,
+ range: X,
+ zone: X,
+}
+
+macro_rules! uniform_int_impl {
+ ($ty:ty, $signed:ty, $unsigned:ident,
+ $i_large:ident, $u_large:ident) => {
+ impl SampleUniform for $ty {
+ type Sampler = UniformInt<$ty>;
+ }
+
+ impl UniformSampler for UniformInt<$ty> {
+ // We play free and fast with unsigned vs signed here
+ // (when $ty is signed), but that's fine, since the
+ // contract of this macro is for $ty and $unsigned to be
+ // "bit-equal", so casting between them is a no-op.
+
+ type X = $ty;
+
+ #[inline] // if the range is constant, this helps LLVM to do the
+ // calculations at compile-time.
+ fn new<B1, B2>(low_b: B1, high_b: B2) -> Self
+ where B1: SampleBorrow<Self::X> + Sized,
+ B2: SampleBorrow<Self::X> + Sized
+ {
+ let low = *low_b.borrow();
+ let high = *high_b.borrow();
+ assert!(low < high, "Uniform::new called with `low >= high`");
+ UniformSampler::new_inclusive(low, high - 1)
+ }
+
+ #[inline] // if the range is constant, this helps LLVM to do the
+ // calculations at compile-time.
+ fn new_inclusive<B1, B2>(low_b: B1, high_b: B2) -> Self
+ where B1: SampleBorrow<Self::X> + Sized,
+ B2: SampleBorrow<Self::X> + Sized
+ {
+ let low = *low_b.borrow();
+ let high = *high_b.borrow();
+ assert!(low <= high,
+ "Uniform::new_inclusive called with `low > high`");
+ let unsigned_max = ::core::$unsigned::MAX;
+
+ let range = high.wrapping_sub(low).wrapping_add(1) as $unsigned;
+ let ints_to_reject =
+ if range > 0 {
+ (unsigned_max - range + 1) % range
+ } else {
+ 0
+ };
+ let zone = unsigned_max - ints_to_reject;
+
+ UniformInt {
+ low: low,
+ // These are really $unsigned values, but store as $ty:
+ range: range as $ty,
+ zone: zone as $ty
+ }
+ }
+
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X {
+ let range = self.range as $unsigned as $u_large;
+ if range > 0 {
+ // Grow `zone` to fit a type of at least 32 bits, by
+ // sign-extending it (the first bit is always 1, so are all
+ // the preceding bits of the larger type).
+ // For types that already have the right size, all the
+ // casting is a no-op.
+ let zone = self.zone as $signed as $i_large as $u_large;
+ loop {
+ let v: $u_large = rng.gen();
+ let (hi, lo) = v.wmul(range);
+ if lo <= zone {
+ return self.low.wrapping_add(hi as $ty);
+ }
+ }
+ } else {
+ // Sample from the entire integer range.
+ rng.gen()
+ }
+ }
+
+ fn sample_single<R: Rng + ?Sized, B1, B2>(low_b: B1, high_b: B2, rng: &mut R)
+ -> Self::X
+ where B1: SampleBorrow<Self::X> + Sized,
+ B2: SampleBorrow<Self::X> + Sized
+ {
+ let low = *low_b.borrow();
+ let high = *high_b.borrow();
+ assert!(low < high,
+ "Uniform::sample_single called with low >= high");
+ let range = high.wrapping_sub(low) as $unsigned as $u_large;
+ let zone =
+ if ::core::$unsigned::MAX <= ::core::u16::MAX as $unsigned {
+ // Using a modulus is faster than the approximation for
+ // i8 and i16. I suppose we trade the cost of one
+ // modulus for near-perfect branch prediction.
+ let unsigned_max: $u_large = ::core::$u_large::MAX;
+ let ints_to_reject = (unsigned_max - range + 1) % range;
+ unsigned_max - ints_to_reject
+ } else {
+ // conservative but fast approximation
+ range << range.leading_zeros()
+ };
+
+ loop {
+ let v: $u_large = rng.gen();
+ let (hi, lo) = v.wmul(range);
+ if lo <= zone {
+ return low.wrapping_add(hi as $ty);
+ }
+ }
+ }
+ }
+ }
+}
+
+uniform_int_impl! { i8, i8, u8, i32, u32 }
+uniform_int_impl! { i16, i16, u16, i32, u32 }
+uniform_int_impl! { i32, i32, u32, i32, u32 }
+uniform_int_impl! { i64, i64, u64, i64, u64 }
+#[cfg(rust_1_26)]
+uniform_int_impl! { i128, i128, u128, u128, u128 }
+uniform_int_impl! { isize, isize, usize, isize, usize }
+uniform_int_impl! { u8, i8, u8, i32, u32 }
+uniform_int_impl! { u16, i16, u16, i32, u32 }
+uniform_int_impl! { u32, i32, u32, i32, u32 }
+uniform_int_impl! { u64, i64, u64, i64, u64 }
+uniform_int_impl! { usize, isize, usize, isize, usize }
+#[cfg(rust_1_26)]
+uniform_int_impl! { u128, u128, u128, i128, u128 }
+
+#[cfg(all(feature = "simd_support", feature = "nightly"))]
+macro_rules! uniform_simd_int_impl {
+ ($ty:ident, $unsigned:ident, $u_scalar:ident) => {
+ // The "pick the largest zone that can fit in an `u32`" optimization
+ // is less useful here. Multiple lanes complicate things, we don't
+ // know the PRNG's minimal output size, and casting to a larger vector
+ // is generally a bad idea for SIMD performance. The user can still
+ // implement it manually.
+
+ // TODO: look into `Uniform::<u32x4>::new(0u32, 100)` functionality
+ // perhaps `impl SampleUniform for $u_scalar`?
+ impl SampleUniform for $ty {
+ type Sampler = UniformInt<$ty>;
+ }
+
+ impl UniformSampler for UniformInt<$ty> {
+ type X = $ty;
+
+ #[inline] // if the range is constant, this helps LLVM to do the
+ // calculations at compile-time.
+ fn new<B1, B2>(low_b: B1, high_b: B2) -> Self
+ where B1: SampleBorrow<Self::X> + Sized,
+ B2: SampleBorrow<Self::X> + Sized
+ {
+ let low = *low_b.borrow();
+ let high = *high_b.borrow();
+ assert!(low.lt(high).all(), "Uniform::new called with `low >= high`");
+ UniformSampler::new_inclusive(low, high - 1)
+ }
+
+ #[inline] // if the range is constant, this helps LLVM to do the
+ // calculations at compile-time.
+ fn new_inclusive<B1, B2>(low_b: B1, high_b: B2) -> Self
+ where B1: SampleBorrow<Self::X> + Sized,
+ B2: SampleBorrow<Self::X> + Sized
+ {
+ let low = *low_b.borrow();
+ let high = *high_b.borrow();
+ assert!(low.le(high).all(),
+ "Uniform::new_inclusive called with `low > high`");
+ let unsigned_max = ::core::$u_scalar::MAX;
+
+ // NOTE: these may need to be replaced with explicitly
+ // wrapping operations if `packed_simd` changes
+ let range: $unsigned = ((high - low) + 1).cast();
+ // `% 0` will panic at runtime.
+ let not_full_range = range.gt($unsigned::splat(0));
+ // replacing 0 with `unsigned_max` allows a faster `select`
+ // with bitwise OR
+ let modulo = not_full_range.select(range, $unsigned::splat(unsigned_max));
+ // wrapping addition
+ let ints_to_reject = (unsigned_max - range + 1) % modulo;
+ // When `range` is 0, `lo` of `v.wmul(range)` will always be
+ // zero which means only one sample is needed.
+ let zone = unsigned_max - ints_to_reject;
+
+ UniformInt {
+ low: low,
+ // These are really $unsigned values, but store as $ty:
+ range: range.cast(),
+ zone: zone.cast(),
+ }
+ }
+
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X {
+ let range: $unsigned = self.range.cast();
+ let zone: $unsigned = self.zone.cast();
+
+ // This might seem very slow, generating a whole new
+ // SIMD vector for every sample rejection. For most uses
+ // though, the chance of rejection is small and provides good
+ // general performance. With multiple lanes, that chance is
+ // multiplied. To mitigate this, we replace only the lanes of
+ // the vector which fail, iteratively reducing the chance of
+ // rejection. The replacement method does however add a little
+ // overhead. Benchmarking or calculating probabilities might
+ // reveal contexts where this replacement method is slower.
+ let mut v: $unsigned = rng.gen();
+ loop {
+ let (hi, lo) = v.wmul(range);
+ let mask = lo.le(zone);
+ if mask.all() {
+ let hi: $ty = hi.cast();
+ // wrapping addition
+ let result = self.low + hi;
+ // `select` here compiles to a blend operation
+ // When `range.eq(0).none()` the compare and blend
+ // operations are avoided.
+ let v: $ty = v.cast();
+ return range.gt($unsigned::splat(0)).select(result, v);
+ }
+ // Replace only the failing lanes
+ v = mask.select(v, rng.gen());
+ }
+ }
+ }
+ };
+
+ // bulk implementation
+ ($(($unsigned:ident, $signed:ident),)+ $u_scalar:ident) => {
+ $(
+ uniform_simd_int_impl!($unsigned, $unsigned, $u_scalar);
+ uniform_simd_int_impl!($signed, $unsigned, $u_scalar);
+ )+
+ };
+}
+
+#[cfg(all(feature = "simd_support", feature = "nightly"))]
+uniform_simd_int_impl! {
+ (u64x2, i64x2),
+ (u64x4, i64x4),
+ (u64x8, i64x8),
+ u64
+}
+
+#[cfg(all(feature = "simd_support", feature = "nightly"))]
+uniform_simd_int_impl! {
+ (u32x2, i32x2),
+ (u32x4, i32x4),
+ (u32x8, i32x8),
+ (u32x16, i32x16),
+ u32
+}
+
+#[cfg(all(feature = "simd_support", feature = "nightly"))]
+uniform_simd_int_impl! {
+ (u16x2, i16x2),
+ (u16x4, i16x4),
+ (u16x8, i16x8),
+ (u16x16, i16x16),
+ (u16x32, i16x32),
+ u16
+}
+
+#[cfg(all(feature = "simd_support", feature = "nightly"))]
+uniform_simd_int_impl! {
+ (u8x2, i8x2),
+ (u8x4, i8x4),
+ (u8x8, i8x8),
+ (u8x16, i8x16),
+ (u8x32, i8x32),
+ (u8x64, i8x64),
+ u8
+}
+
+
+/// The back-end implementing [`UniformSampler`] for floating-point types.
+///
+/// Unless you are implementing [`UniformSampler`] for your own type, this type
+/// should not be used directly, use [`Uniform`] instead.
+///
+/// # Implementation notes
+///
+/// Instead of generating a float in the `[0, 1)` range using [`Standard`], the
+/// `UniformFloat` implementation converts the output of an PRNG itself. This
+/// way one or two steps can be optimized out.
+///
+/// The floats are first converted to a value in the `[1, 2)` interval using a
+/// transmute-based method, and then mapped to the expected range with a
+/// multiply and addition. Values produced this way have what equals 22 bits of
+/// random digits for an `f32`, and 52 for an `f64`.
+///
+/// [`UniformSampler`]: trait.UniformSampler.html
+/// [`new`]: trait.UniformSampler.html#tymethod.new
+/// [`new_inclusive`]: trait.UniformSampler.html#tymethod.new_inclusive
+/// [`Uniform`]: struct.Uniform.html
+/// [`Standard`]: ../struct.Standard.html
+#[derive(Clone, Copy, Debug)]
+pub struct UniformFloat<X> {
+ low: X,
+ scale: X,
+}
+
+macro_rules! uniform_float_impl {
+ ($ty:ty, $uty:ident, $f_scalar:ident, $u_scalar:ident, $bits_to_discard:expr) => {
+ impl SampleUniform for $ty {
+ type Sampler = UniformFloat<$ty>;
+ }
+
+ impl UniformSampler for UniformFloat<$ty> {
+ type X = $ty;
+
+ fn new<B1, B2>(low_b: B1, high_b: B2) -> Self
+ where B1: SampleBorrow<Self::X> + Sized,
+ B2: SampleBorrow<Self::X> + Sized
+ {
+ let low = *low_b.borrow();
+ let high = *high_b.borrow();
+ assert!(low.all_lt(high),
+ "Uniform::new called with `low >= high`");
+ assert!(low.all_finite() && high.all_finite(),
+ "Uniform::new called with non-finite boundaries");
+ let max_rand = <$ty>::splat((::core::$u_scalar::MAX >> $bits_to_discard)
+ .into_float_with_exponent(0) - 1.0);
+
+ let mut scale = high - low;
+
+ loop {
+ let mask = (scale * max_rand + low).ge_mask(high);
+ if mask.none() {
+ break;
+ }
+ scale = scale.decrease_masked(mask);
+ }
+
+ debug_assert!(<$ty>::splat(0.0).all_le(scale));
+
+ UniformFloat { low, scale }
+ }
+
+ fn new_inclusive<B1, B2>(low_b: B1, high_b: B2) -> Self
+ where B1: SampleBorrow<Self::X> + Sized,
+ B2: SampleBorrow<Self::X> + Sized
+ {
+ let low = *low_b.borrow();
+ let high = *high_b.borrow();
+ assert!(low.all_le(high),
+ "Uniform::new_inclusive called with `low > high`");
+ assert!(low.all_finite() && high.all_finite(),
+ "Uniform::new_inclusive called with non-finite boundaries");
+ let max_rand = <$ty>::splat((::core::$u_scalar::MAX >> $bits_to_discard)
+ .into_float_with_exponent(0) - 1.0);
+
+ let mut scale = (high - low) / max_rand;
+
+ loop {
+ let mask = (scale * max_rand + low).gt_mask(high);
+ if mask.none() {
+ break;
+ }
+ scale = scale.decrease_masked(mask);
+ }
+
+ debug_assert!(<$ty>::splat(0.0).all_le(scale));
+
+ UniformFloat { low, scale }
+ }
+
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X {
+ // Generate a value in the range [1, 2)
+ let value1_2 = (rng.gen::<$uty>() >> $bits_to_discard)
+ .into_float_with_exponent(0);
+
+ // Get a value in the range [0, 1) in order to avoid
+ // overflowing into infinity when multiplying with scale
+ let value0_1 = value1_2 - 1.0;
+
+ // We don't use `f64::mul_add`, because it is not available with
+ // `no_std`. Furthermore, it is slower for some targets (but
+ // faster for others). However, the order of multiplication and
+ // addition is important, because on some platforms (e.g. ARM)
+ // it will be optimized to a single (non-FMA) instruction.
+ value0_1 * self.scale + self.low
+ }
+
+ #[inline]
+ fn sample_single<R: Rng + ?Sized, B1, B2>(low_b: B1, high_b: B2, rng: &mut R)
+ -> Self::X
+ where B1: SampleBorrow<Self::X> + Sized,
+ B2: SampleBorrow<Self::X> + Sized
+ {
+ let low = *low_b.borrow();
+ let high = *high_b.borrow();
+ assert!(low.all_lt(high),
+ "Uniform::sample_single called with low >= high");
+ let mut scale = high - low;
+
+ loop {
+ // Generate a value in the range [1, 2)
+ let value1_2 = (rng.gen::<$uty>() >> $bits_to_discard)
+ .into_float_with_exponent(0);
+
+ // Get a value in the range [0, 1) in order to avoid
+ // overflowing into infinity when multiplying with scale
+ let value0_1 = value1_2 - 1.0;
+
+ // Doing multiply before addition allows some architectures
+ // to use a single instruction.
+ let res = value0_1 * scale + low;
+
+ debug_assert!(low.all_le(res) || !scale.all_finite());
+ if res.all_lt(high) {
+ return res;
+ }
+
+ // This handles a number of edge cases.
+ // * `low` or `high` is NaN. In this case `scale` and
+ // `res` are going to end up as NaN.
+ // * `low` is negative infinity and `high` is finite.
+ // `scale` is going to be infinite and `res` will be
+ // NaN.
+ // * `high` is positive infinity and `low` is finite.
+ // `scale` is going to be infinite and `res` will
+ // be infinite or NaN (if value0_1 is 0).
+ // * `low` is negative infinity and `high` is positive
+ // infinity. `scale` will be infinite and `res` will
+ // be NaN.
+ // * `low` and `high` are finite, but `high - low`
+ // overflows to infinite. `scale` will be infinite
+ // and `res` will be infinite or NaN (if value0_1 is 0).
+ // So if `high` or `low` are non-finite, we are guaranteed
+ // to fail the `res < high` check above and end up here.
+ //
+ // While we technically should check for non-finite `low`
+ // and `high` before entering the loop, by doing the checks
+ // here instead, we allow the common case to avoid these
+ // checks. But we are still guaranteed that if `low` or
+ // `high` are non-finite we'll end up here and can do the
+ // appropriate checks.
+ //
+ // Likewise `high - low` overflowing to infinity is also
+ // rare, so handle it here after the common case.
+ let mask = !scale.finite_mask();
+ if mask.any() {
+ assert!(low.all_finite() && high.all_finite(),
+ "Uniform::sample_single called with non-finite boundaries");
+ scale = scale.decrease_masked(mask);
+ }
+ }
+ }
+ }
+ }
+}
+
+uniform_float_impl! { f32, u32, f32, u32, 32 - 23 }
+uniform_float_impl! { f64, u64, f64, u64, 64 - 52 }
+
+#[cfg(feature="simd_support")]
+uniform_float_impl! { f32x2, u32x2, f32, u32, 32 - 23 }
+#[cfg(feature="simd_support")]
+uniform_float_impl! { f32x4, u32x4, f32, u32, 32 - 23 }
+#[cfg(feature="simd_support")]
+uniform_float_impl! { f32x8, u32x8, f32, u32, 32 - 23 }
+#[cfg(feature="simd_support")]
+uniform_float_impl! { f32x16, u32x16, f32, u32, 32 - 23 }
+
+#[cfg(feature="simd_support")]
+uniform_float_impl! { f64x2, u64x2, f64, u64, 64 - 52 }
+#[cfg(feature="simd_support")]
+uniform_float_impl! { f64x4, u64x4, f64, u64, 64 - 52 }
+#[cfg(feature="simd_support")]
+uniform_float_impl! { f64x8, u64x8, f64, u64, 64 - 52 }
+
+
+
+/// The back-end implementing [`UniformSampler`] for `Duration`.
+///
+/// Unless you are implementing [`UniformSampler`] for your own types, this type
+/// should not be used directly, use [`Uniform`] instead.
+///
+/// [`UniformSampler`]: trait.UniformSampler.html
+/// [`Uniform`]: struct.Uniform.html
+#[cfg(any(feature = "std", rust_1_25))]
+#[derive(Clone, Copy, Debug)]
+pub struct UniformDuration {
+ mode: UniformDurationMode,
+ offset: u32,
+}
+
+#[cfg(any(feature = "std", rust_1_25))]
+#[derive(Debug, Copy, Clone)]
+enum UniformDurationMode {
+ Small {
+ secs: u64,
+ nanos: Uniform<u32>,
+ },
+ Medium {
+ nanos: Uniform<u64>,
+ },
+ Large {
+ max_secs: u64,
+ max_nanos: u32,
+ secs: Uniform<u64>,
+ }
+}
+
+#[cfg(any(feature = "std", rust_1_25))]
+impl SampleUniform for Duration {
+ type Sampler = UniformDuration;
+}
+
+#[cfg(any(feature = "std", rust_1_25))]
+impl UniformSampler for UniformDuration {
+ type X = Duration;
+
+ #[inline]
+ fn new<B1, B2>(low_b: B1, high_b: B2) -> Self
+ where B1: SampleBorrow<Self::X> + Sized,
+ B2: SampleBorrow<Self::X> + Sized
+ {
+ let low = *low_b.borrow();
+ let high = *high_b.borrow();
+ assert!(low < high, "Uniform::new called with `low >= high`");
+ UniformDuration::new_inclusive(low, high - Duration::new(0, 1))
+ }
+
+ #[inline]
+ fn new_inclusive<B1, B2>(low_b: B1, high_b: B2) -> Self
+ where B1: SampleBorrow<Self::X> + Sized,
+ B2: SampleBorrow<Self::X> + Sized
+ {
+ let low = *low_b.borrow();
+ let high = *high_b.borrow();
+ assert!(low <= high, "Uniform::new_inclusive called with `low > high`");
+
+ let low_s = low.as_secs();
+ let low_n = low.subsec_nanos();
+ let mut high_s = high.as_secs();
+ let mut high_n = high.subsec_nanos();
+
+ if high_n < low_n {
+ high_s = high_s - 1;
+ high_n = high_n + 1_000_000_000;
+ }
+
+ let mode = if low_s == high_s {
+ UniformDurationMode::Small {
+ secs: low_s,
+ nanos: Uniform::new_inclusive(low_n, high_n),
+ }
+ } else {
+ let max = high_s
+ .checked_mul(1_000_000_000)
+ .and_then(|n| n.checked_add(high_n as u64));
+
+ if let Some(higher_bound) = max {
+ let lower_bound = low_s * 1_000_000_000 + low_n as u64;
+ UniformDurationMode::Medium {
+ nanos: Uniform::new_inclusive(lower_bound, higher_bound),
+ }
+ } else {
+ // An offset is applied to simplify generation of nanoseconds
+ let max_nanos = high_n - low_n;
+ UniformDurationMode::Large {
+ max_secs: high_s,
+ max_nanos,
+ secs: Uniform::new_inclusive(low_s, high_s),
+ }
+ }
+ };
+ UniformDuration {
+ mode,
+ offset: low_n,
+ }
+ }
+
+ #[inline]
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Duration {
+ match self.mode {
+ UniformDurationMode::Small { secs, nanos } => {
+ let n = nanos.sample(rng);
+ Duration::new(secs, n)
+ }
+ UniformDurationMode::Medium { nanos } => {
+ let nanos = nanos.sample(rng);
+ Duration::new(nanos / 1_000_000_000, (nanos % 1_000_000_000) as u32)
+ }
+ UniformDurationMode::Large { max_secs, max_nanos, secs } => {
+ // constant folding means this is at least as fast as `gen_range`
+ let nano_range = Uniform::new(0, 1_000_000_000);
+ loop {
+ let s = secs.sample(rng);
+ let n = nano_range.sample(rng);
+ if !(s == max_secs && n > max_nanos) {
+ let sum = n + self.offset;
+ break Duration::new(s, sum);
+ }
+ }
+ }
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use Rng;
+ use rngs::mock::StepRng;
+ use distributions::uniform::Uniform;
+ use distributions::utils::FloatAsSIMD;
+ #[cfg(feature="simd_support")] use packed_simd::*;
+
+ #[should_panic]
+ #[test]
+ fn test_uniform_bad_limits_equal_int() {
+ Uniform::new(10, 10);
+ }
+
+ #[test]
+ fn test_uniform_good_limits_equal_int() {
+ let mut rng = ::test::rng(804);
+ let dist = Uniform::new_inclusive(10, 10);
+ for _ in 0..20 {
+ assert_eq!(rng.sample(dist), 10);
+ }
+ }
+
+ #[should_panic]
+ #[test]
+ fn test_uniform_bad_limits_flipped_int() {
+ Uniform::new(10, 5);
+ }
+
+ #[test]
+ fn test_integers() {
+ use core::{i8, i16, i32, i64, isize};
+ use core::{u8, u16, u32, u64, usize};
+ #[cfg(rust_1_26)]
+ use core::{i128, u128};
+
+ let mut rng = ::test::rng(251);
+ macro_rules! t {
+ ($ty:ident, $v:expr, $le:expr, $lt:expr) => {{
+ for &(low, high) in $v.iter() {
+ let my_uniform = Uniform::new(low, high);
+ for _ in 0..1000 {
+ let v: $ty = rng.sample(my_uniform);
+ assert!($le(low, v) && $lt(v, high));
+ }
+
+ let my_uniform = Uniform::new_inclusive(low, high);
+ for _ in 0..1000 {
+ let v: $ty = rng.sample(my_uniform);
+ assert!($le(low, v) && $le(v, high));
+ }
+
+ let my_uniform = Uniform::new(&low, high);
+ for _ in 0..1000 {
+ let v: $ty = rng.sample(my_uniform);
+ assert!($le(low, v) && $lt(v, high));
+ }
+
+ let my_uniform = Uniform::new_inclusive(&low, &high);
+ for _ in 0..1000 {
+ let v: $ty = rng.sample(my_uniform);
+ assert!($le(low, v) && $le(v, high));
+ }
+
+ for _ in 0..1000 {
+ let v: $ty = rng.gen_range(low, high);
+ assert!($le(low, v) && $lt(v, high));
+ }
+ }
+ }};
+
+ // scalar bulk
+ ($($ty:ident),*) => {{
+ $(t!(
+ $ty,
+ [(0, 10), (10, 127), ($ty::MIN, $ty::MAX)],
+ |x, y| x <= y,
+ |x, y| x < y
+ );)*
+ }};
+
+ // simd bulk
+ ($($ty:ident),* => $scalar:ident) => {{
+ $(t!(
+ $ty,
+ [
+ ($ty::splat(0), $ty::splat(10)),
+ ($ty::splat(10), $ty::splat(127)),
+ ($ty::splat($scalar::MIN), $ty::splat($scalar::MAX)),
+ ],
+ |x: $ty, y| x.le(y).all(),
+ |x: $ty, y| x.lt(y).all()
+ );)*
+ }};
+ }
+ t!(i8, i16, i32, i64, isize,
+ u8, u16, u32, u64, usize);
+ #[cfg(rust_1_26)]
+ t!(i128, u128);
+
+ #[cfg(all(feature = "simd_support", feature = "nightly"))]
+ {
+ t!(u8x2, u8x4, u8x8, u8x16, u8x32, u8x64 => u8);
+ t!(i8x2, i8x4, i8x8, i8x16, i8x32, i8x64 => i8);
+ t!(u16x2, u16x4, u16x8, u16x16, u16x32 => u16);
+ t!(i16x2, i16x4, i16x8, i16x16, i16x32 => i16);
+ t!(u32x2, u32x4, u32x8, u32x16 => u32);
+ t!(i32x2, i32x4, i32x8, i32x16 => i32);
+ t!(u64x2, u64x4, u64x8 => u64);
+ t!(i64x2, i64x4, i64x8 => i64);
+ }
+ }
+
+ #[test]
+ fn test_floats() {
+ let mut rng = ::test::rng(252);
+ let mut zero_rng = StepRng::new(0, 0);
+ let mut max_rng = StepRng::new(0xffff_ffff_ffff_ffff, 0);
+ macro_rules! t {
+ ($ty:ty, $f_scalar:ident, $bits_shifted:expr) => {{
+ let v: &[($f_scalar, $f_scalar)]=
+ &[(0.0, 100.0),
+ (-1e35, -1e25),
+ (1e-35, 1e-25),
+ (-1e35, 1e35),
+ (<$f_scalar>::from_bits(0), <$f_scalar>::from_bits(3)),
+ (-<$f_scalar>::from_bits(10), -<$f_scalar>::from_bits(1)),
+ (-<$f_scalar>::from_bits(5), 0.0),
+ (-<$f_scalar>::from_bits(7), -0.0),
+ (10.0, ::core::$f_scalar::MAX),
+ (-100.0, ::core::$f_scalar::MAX),
+ (-::core::$f_scalar::MAX / 5.0, ::core::$f_scalar::MAX),
+ (-::core::$f_scalar::MAX, ::core::$f_scalar::MAX / 5.0),
+ (-::core::$f_scalar::MAX * 0.8, ::core::$f_scalar::MAX * 0.7),
+ (-::core::$f_scalar::MAX, ::core::$f_scalar::MAX),
+ ];
+ for &(low_scalar, high_scalar) in v.iter() {
+ for lane in 0..<$ty>::lanes() {
+ let low = <$ty>::splat(0.0 as $f_scalar).replace(lane, low_scalar);
+ let high = <$ty>::splat(1.0 as $f_scalar).replace(lane, high_scalar);
+ let my_uniform = Uniform::new(low, high);
+ let my_incl_uniform = Uniform::new_inclusive(low, high);
+ for _ in 0..100 {
+ let v = rng.sample(my_uniform).extract(lane);
+ assert!(low_scalar <= v && v < high_scalar);
+ let v = rng.sample(my_incl_uniform).extract(lane);
+ assert!(low_scalar <= v && v <= high_scalar);
+ let v = rng.gen_range(low, high).extract(lane);
+ assert!(low_scalar <= v && v < high_scalar);
+ }
+
+ assert_eq!(rng.sample(Uniform::new_inclusive(low, low)).extract(lane), low_scalar);
+
+ assert_eq!(zero_rng.sample(my_uniform).extract(lane), low_scalar);
+ assert_eq!(zero_rng.sample(my_incl_uniform).extract(lane), low_scalar);
+ assert_eq!(zero_rng.gen_range(low, high).extract(lane), low_scalar);
+ assert!(max_rng.sample(my_uniform).extract(lane) < high_scalar);
+ assert!(max_rng.sample(my_incl_uniform).extract(lane) <= high_scalar);
+
+ // Don't run this test for really tiny differences between high and low
+ // since for those rounding might result in selecting high for a very
+ // long time.
+ if (high_scalar - low_scalar) > 0.0001 {
+ let mut lowering_max_rng =
+ StepRng::new(0xffff_ffff_ffff_ffff,
+ (-1i64 << $bits_shifted) as u64);
+ assert!(lowering_max_rng.gen_range(low, high).extract(lane) < high_scalar);
+ }
+ }
+ }
+
+ assert_eq!(rng.sample(Uniform::new_inclusive(::core::$f_scalar::MAX,
+ ::core::$f_scalar::MAX)),
+ ::core::$f_scalar::MAX);
+ assert_eq!(rng.sample(Uniform::new_inclusive(-::core::$f_scalar::MAX,
+ -::core::$f_scalar::MAX)),
+ -::core::$f_scalar::MAX);
+ }}
+ }
+
+ t!(f32, f32, 32 - 23);
+ t!(f64, f64, 64 - 52);
+ #[cfg(feature="simd_support")]
+ {
+ t!(f32x2, f32, 32 - 23);
+ t!(f32x4, f32, 32 - 23);
+ t!(f32x8, f32, 32 - 23);
+ t!(f32x16, f32, 32 - 23);
+ t!(f64x2, f64, 64 - 52);
+ t!(f64x4, f64, 64 - 52);
+ t!(f64x8, f64, 64 - 52);
+ }
+ }
+
+ #[test]
+ #[cfg(all(feature="std",
+ not(target_arch = "wasm32"),
+ not(target_arch = "asmjs")))]
+ fn test_float_assertions() {
+ use std::panic::catch_unwind;
+ use super::SampleUniform;
+ fn range<T: SampleUniform>(low: T, high: T) {
+ let mut rng = ::test::rng(253);
+ rng.gen_range(low, high);
+ }
+
+ macro_rules! t {
+ ($ty:ident, $f_scalar:ident) => {{
+ let v: &[($f_scalar, $f_scalar)] =
+ &[(::std::$f_scalar::NAN, 0.0),
+ (1.0, ::std::$f_scalar::NAN),
+ (::std::$f_scalar::NAN, ::std::$f_scalar::NAN),
+ (1.0, 0.5),
+ (::std::$f_scalar::MAX, -::std::$f_scalar::MAX),
+ (::std::$f_scalar::INFINITY, ::std::$f_scalar::INFINITY),
+ (::std::$f_scalar::NEG_INFINITY, ::std::$f_scalar::NEG_INFINITY),
+ (::std::$f_scalar::NEG_INFINITY, 5.0),
+ (5.0, ::std::$f_scalar::INFINITY),
+ (::std::$f_scalar::NAN, ::std::$f_scalar::INFINITY),
+ (::std::$f_scalar::NEG_INFINITY, ::std::$f_scalar::NAN),
+ (::std::$f_scalar::NEG_INFINITY, ::std::$f_scalar::INFINITY),
+ ];
+ for &(low_scalar, high_scalar) in v.iter() {
+ for lane in 0..<$ty>::lanes() {
+ let low = <$ty>::splat(0.0 as $f_scalar).replace(lane, low_scalar);
+ let high = <$ty>::splat(1.0 as $f_scalar).replace(lane, high_scalar);
+ assert!(catch_unwind(|| range(low, high)).is_err());
+ assert!(catch_unwind(|| Uniform::new(low, high)).is_err());
+ assert!(catch_unwind(|| Uniform::new_inclusive(low, high)).is_err());
+ assert!(catch_unwind(|| range(low, low)).is_err());
+ assert!(catch_unwind(|| Uniform::new(low, low)).is_err());
+ }
+ }
+ }}
+ }
+
+ t!(f32, f32);
+ t!(f64, f64);
+ #[cfg(feature="simd_support")]
+ {
+ t!(f32x2, f32);
+ t!(f32x4, f32);
+ t!(f32x8, f32);
+ t!(f32x16, f32);
+ t!(f64x2, f64);
+ t!(f64x4, f64);
+ t!(f64x8, f64);
+ }
+ }
+
+
+ #[test]
+ #[cfg(any(feature = "std", rust_1_25))]
+ fn test_durations() {
+ #[cfg(feature = "std")]
+ use std::time::Duration;
+ #[cfg(all(not(feature = "std"), rust_1_25))]
+ use core::time::Duration;
+
+ let mut rng = ::test::rng(253);
+
+ let v = &[(Duration::new(10, 50000), Duration::new(100, 1234)),
+ (Duration::new(0, 100), Duration::new(1, 50)),
+ (Duration::new(0, 0), Duration::new(u64::max_value(), 999_999_999))];
+ for &(low, high) in v.iter() {
+ let my_uniform = Uniform::new(low, high);
+ for _ in 0..1000 {
+ let v = rng.sample(my_uniform);
+ assert!(low <= v && v < high);
+ }
+ }
+ }
+
+ #[test]
+ fn test_custom_uniform() {
+ use distributions::uniform::{UniformSampler, UniformFloat, SampleUniform, SampleBorrow};
+ #[derive(Clone, Copy, PartialEq, PartialOrd)]
+ struct MyF32 {
+ x: f32,
+ }
+ #[derive(Clone, Copy, Debug)]
+ struct UniformMyF32 {
+ inner: UniformFloat<f32>,
+ }
+ impl UniformSampler for UniformMyF32 {
+ type X = MyF32;
+ fn new<B1, B2>(low: B1, high: B2) -> Self
+ where B1: SampleBorrow<Self::X> + Sized,
+ B2: SampleBorrow<Self::X> + Sized
+ {
+ UniformMyF32 {
+ inner: UniformFloat::<f32>::new(low.borrow().x, high.borrow().x),
+ }
+ }
+ fn new_inclusive<B1, B2>(low: B1, high: B2) -> Self
+ where B1: SampleBorrow<Self::X> + Sized,
+ B2: SampleBorrow<Self::X> + Sized
+ {
+ UniformSampler::new(low, high)
+ }
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X {
+ MyF32 { x: self.inner.sample(rng) }
+ }
+ }
+ impl SampleUniform for MyF32 {
+ type Sampler = UniformMyF32;
+ }
+
+ let (low, high) = (MyF32{ x: 17.0f32 }, MyF32{ x: 22.0f32 });
+ let uniform = Uniform::new(low, high);
+ let mut rng = ::test::rng(804);
+ for _ in 0..100 {
+ let x: MyF32 = rng.sample(uniform);
+ assert!(low <= x && x < high);
+ }
+ }
+
+ #[test]
+ fn test_uniform_from_std_range() {
+ let r = Uniform::from(2u32..7);
+ assert_eq!(r.inner.low, 2);
+ assert_eq!(r.inner.range, 5);
+ let r = Uniform::from(2.0f64..7.0);
+ assert_eq!(r.inner.low, 2.0);
+ assert_eq!(r.inner.scale, 5.0);
+ }
+
+ #[cfg(rust_1_27)]
+ #[test]
+ fn test_uniform_from_std_range_inclusive() {
+ let r = Uniform::from(2u32..=6);
+ assert_eq!(r.inner.low, 2);
+ assert_eq!(r.inner.range, 5);
+ let r = Uniform::from(2.0f64..=7.0);
+ assert_eq!(r.inner.low, 2.0);
+ assert!(r.inner.scale > 5.0);
+ assert!(r.inner.scale < 5.0 + 1e-14);
+ }
+}
diff --git a/rand/src/distributions/unit_circle.rs b/rand/src/distributions/unit_circle.rs
new file mode 100644
index 0000000..abb36dc
--- /dev/null
+++ b/rand/src/distributions/unit_circle.rs
@@ -0,0 +1,102 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use Rng;
+use distributions::{Distribution, Uniform};
+
+/// Samples uniformly from the edge of the unit circle in two dimensions.
+///
+/// Implemented via a method by von Neumann[^1].
+///
+///
+/// # Example
+///
+/// ```
+/// use rand::distributions::{UnitCircle, Distribution};
+///
+/// let circle = UnitCircle::new();
+/// let v = circle.sample(&mut rand::thread_rng());
+/// println!("{:?} is from the unit circle.", v)
+/// ```
+///
+/// [^1]: von Neumann, J. (1951) [*Various Techniques Used in Connection with
+/// Random Digits.*](https://mcnp.lanl.gov/pdf_files/nbs_vonneumann.pdf)
+/// NBS Appl. Math. Ser., No. 12. Washington, DC: U.S. Government Printing
+/// Office, pp. 36-38.
+#[derive(Clone, Copy, Debug)]
+pub struct UnitCircle {
+ uniform: Uniform<f64>,
+}
+
+impl UnitCircle {
+ /// Construct a new `UnitCircle` distribution.
+ #[inline]
+ pub fn new() -> UnitCircle {
+ UnitCircle { uniform: Uniform::new(-1., 1.) }
+ }
+}
+
+impl Distribution<[f64; 2]> for UnitCircle {
+ #[inline]
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> [f64; 2] {
+ let mut x1;
+ let mut x2;
+ let mut sum;
+ loop {
+ x1 = self.uniform.sample(rng);
+ x2 = self.uniform.sample(rng);
+ sum = x1*x1 + x2*x2;
+ if sum < 1. {
+ break;
+ }
+ }
+ let diff = x1*x1 - x2*x2;
+ [diff / sum, 2.*x1*x2 / sum]
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use distributions::Distribution;
+ use super::UnitCircle;
+
+ /// Assert that two numbers are almost equal to each other.
+ ///
+ /// On panic, this macro will print the values of the expressions with their
+ /// debug representations.
+ macro_rules! assert_almost_eq {
+ ($a:expr, $b:expr, $prec:expr) => (
+ let diff = ($a - $b).abs();
+ if diff > $prec {
+ panic!(format!(
+ "assertion failed: `abs(left - right) = {:.1e} < {:e}`, \
+ (left: `{}`, right: `{}`)",
+ diff, $prec, $a, $b));
+ }
+ );
+ }
+
+ #[test]
+ fn norm() {
+ let mut rng = ::test::rng(1);
+ let dist = UnitCircle::new();
+ for _ in 0..1000 {
+ let x = dist.sample(&mut rng);
+ assert_almost_eq!(x[0]*x[0] + x[1]*x[1], 1., 1e-15);
+ }
+ }
+
+ #[test]
+ fn value_stability() {
+ let mut rng = ::test::rng(2);
+ let dist = UnitCircle::new();
+ assert_eq!(dist.sample(&mut rng), [-0.8032118336637037, 0.5956935036263119]);
+ assert_eq!(dist.sample(&mut rng), [-0.4742919588505423, -0.880367615130018]);
+ assert_eq!(dist.sample(&mut rng), [0.9297328981467168, 0.368234623716601]);
+ }
+}
diff --git a/rand/src/distributions/unit_sphere.rs b/rand/src/distributions/unit_sphere.rs
new file mode 100644
index 0000000..61cbda5
--- /dev/null
+++ b/rand/src/distributions/unit_sphere.rs
@@ -0,0 +1,100 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use Rng;
+use distributions::{Distribution, Uniform};
+
+/// Samples uniformly from the surface of the unit sphere in three dimensions.
+///
+/// Implemented via a method by Marsaglia[^1].
+///
+///
+/// # Example
+///
+/// ```
+/// use rand::distributions::{UnitSphereSurface, Distribution};
+///
+/// let sphere = UnitSphereSurface::new();
+/// let v = sphere.sample(&mut rand::thread_rng());
+/// println!("{:?} is from the unit sphere surface.", v)
+/// ```
+///
+/// [^1]: Marsaglia, George (1972). [*Choosing a Point from the Surface of a
+/// Sphere.*](https://doi.org/10.1214/aoms/1177692644)
+/// Ann. Math. Statist. 43, no. 2, 645--646.
+#[derive(Clone, Copy, Debug)]
+pub struct UnitSphereSurface {
+ uniform: Uniform<f64>,
+}
+
+impl UnitSphereSurface {
+ /// Construct a new `UnitSphereSurface` distribution.
+ #[inline]
+ pub fn new() -> UnitSphereSurface {
+ UnitSphereSurface { uniform: Uniform::new(-1., 1.) }
+ }
+}
+
+impl Distribution<[f64; 3]> for UnitSphereSurface {
+ #[inline]
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> [f64; 3] {
+ loop {
+ let (x1, x2) = (self.uniform.sample(rng), self.uniform.sample(rng));
+ let sum = x1*x1 + x2*x2;
+ if sum >= 1. {
+ continue;
+ }
+ let factor = 2. * (1.0_f64 - sum).sqrt();
+ return [x1 * factor, x2 * factor, 1. - 2.*sum];
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use distributions::Distribution;
+ use super::UnitSphereSurface;
+
+ /// Assert that two numbers are almost equal to each other.
+ ///
+ /// On panic, this macro will print the values of the expressions with their
+ /// debug representations.
+ macro_rules! assert_almost_eq {
+ ($a:expr, $b:expr, $prec:expr) => (
+ let diff = ($a - $b).abs();
+ if diff > $prec {
+ panic!(format!(
+ "assertion failed: `abs(left - right) = {:.1e} < {:e}`, \
+ (left: `{}`, right: `{}`)",
+ diff, $prec, $a, $b));
+ }
+ );
+ }
+
+ #[test]
+ fn norm() {
+ let mut rng = ::test::rng(1);
+ let dist = UnitSphereSurface::new();
+ for _ in 0..1000 {
+ let x = dist.sample(&mut rng);
+ assert_almost_eq!(x[0]*x[0] + x[1]*x[1] + x[2]*x[2], 1., 1e-15);
+ }
+ }
+
+ #[test]
+ fn value_stability() {
+ let mut rng = ::test::rng(2);
+ let dist = UnitSphereSurface::new();
+ assert_eq!(dist.sample(&mut rng),
+ [-0.24950027180862533, -0.7552572587896719, 0.6060825747478084]);
+ assert_eq!(dist.sample(&mut rng),
+ [0.47604534507233487, -0.797200864987207, -0.3712837328763685]);
+ assert_eq!(dist.sample(&mut rng),
+ [0.9795722330927367, 0.18692349236651176, 0.07414747571708524]);
+ }
+}
diff --git a/rand/src/distributions/utils.rs b/rand/src/distributions/utils.rs
new file mode 100644
index 0000000..a2112fd
--- /dev/null
+++ b/rand/src/distributions/utils.rs
@@ -0,0 +1,504 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Math helper functions
+
+#[cfg(feature="simd_support")]
+use packed_simd::*;
+#[cfg(feature="std")]
+use distributions::ziggurat_tables;
+#[cfg(feature="std")]
+use Rng;
+
+
+pub trait WideningMultiply<RHS = Self> {
+ type Output;
+
+ fn wmul(self, x: RHS) -> Self::Output;
+}
+
+macro_rules! wmul_impl {
+ ($ty:ty, $wide:ty, $shift:expr) => {
+ impl WideningMultiply for $ty {
+ type Output = ($ty, $ty);
+
+ #[inline(always)]
+ fn wmul(self, x: $ty) -> Self::Output {
+ let tmp = (self as $wide) * (x as $wide);
+ ((tmp >> $shift) as $ty, tmp as $ty)
+ }
+ }
+ };
+
+ // simd bulk implementation
+ ($(($ty:ident, $wide:ident),)+, $shift:expr) => {
+ $(
+ impl WideningMultiply for $ty {
+ type Output = ($ty, $ty);
+
+ #[inline(always)]
+ fn wmul(self, x: $ty) -> Self::Output {
+ // For supported vectors, this should compile to a couple
+ // supported multiply & swizzle instructions (no actual
+ // casting).
+ // TODO: optimize
+ let y: $wide = self.cast();
+ let x: $wide = x.cast();
+ let tmp = y * x;
+ let hi: $ty = (tmp >> $shift).cast();
+ let lo: $ty = tmp.cast();
+ (hi, lo)
+ }
+ }
+ )+
+ };
+}
+wmul_impl! { u8, u16, 8 }
+wmul_impl! { u16, u32, 16 }
+wmul_impl! { u32, u64, 32 }
+#[cfg(rust_1_26)]
+wmul_impl! { u64, u128, 64 }
+
+// This code is a translation of the __mulddi3 function in LLVM's
+// compiler-rt. It is an optimised variant of the common method
+// `(a + b) * (c + d) = ac + ad + bc + bd`.
+//
+// For some reason LLVM can optimise the C version very well, but
+// keeps shuffling registers in this Rust translation.
+macro_rules! wmul_impl_large {
+ ($ty:ty, $half:expr) => {
+ impl WideningMultiply for $ty {
+ type Output = ($ty, $ty);
+
+ #[inline(always)]
+ fn wmul(self, b: $ty) -> Self::Output {
+ const LOWER_MASK: $ty = !0 >> $half;
+ let mut low = (self & LOWER_MASK).wrapping_mul(b & LOWER_MASK);
+ let mut t = low >> $half;
+ low &= LOWER_MASK;
+ t += (self >> $half).wrapping_mul(b & LOWER_MASK);
+ low += (t & LOWER_MASK) << $half;
+ let mut high = t >> $half;
+ t = low >> $half;
+ low &= LOWER_MASK;
+ t += (b >> $half).wrapping_mul(self & LOWER_MASK);
+ low += (t & LOWER_MASK) << $half;
+ high += t >> $half;
+ high += (self >> $half).wrapping_mul(b >> $half);
+
+ (high, low)
+ }
+ }
+ };
+
+ // simd bulk implementation
+ (($($ty:ty,)+) $scalar:ty, $half:expr) => {
+ $(
+ impl WideningMultiply for $ty {
+ type Output = ($ty, $ty);
+
+ #[inline(always)]
+ fn wmul(self, b: $ty) -> Self::Output {
+ // needs wrapping multiplication
+ const LOWER_MASK: $scalar = !0 >> $half;
+ let mut low = (self & LOWER_MASK) * (b & LOWER_MASK);
+ let mut t = low >> $half;
+ low &= LOWER_MASK;
+ t += (self >> $half) * (b & LOWER_MASK);
+ low += (t & LOWER_MASK) << $half;
+ let mut high = t >> $half;
+ t = low >> $half;
+ low &= LOWER_MASK;
+ t += (b >> $half) * (self & LOWER_MASK);
+ low += (t & LOWER_MASK) << $half;
+ high += t >> $half;
+ high += (self >> $half) * (b >> $half);
+
+ (high, low)
+ }
+ }
+ )+
+ };
+}
+#[cfg(not(rust_1_26))]
+wmul_impl_large! { u64, 32 }
+#[cfg(rust_1_26)]
+wmul_impl_large! { u128, 64 }
+
+macro_rules! wmul_impl_usize {
+ ($ty:ty) => {
+ impl WideningMultiply for usize {
+ type Output = (usize, usize);
+
+ #[inline(always)]
+ fn wmul(self, x: usize) -> Self::Output {
+ let (high, low) = (self as $ty).wmul(x as $ty);
+ (high as usize, low as usize)
+ }
+ }
+ }
+}
+#[cfg(target_pointer_width = "32")]
+wmul_impl_usize! { u32 }
+#[cfg(target_pointer_width = "64")]
+wmul_impl_usize! { u64 }
+
+#[cfg(all(feature = "simd_support", feature = "nightly"))]
+mod simd_wmul {
+ #[cfg(target_arch = "x86")]
+ use core::arch::x86::*;
+ #[cfg(target_arch = "x86_64")]
+ use core::arch::x86_64::*;
+ use super::*;
+
+ wmul_impl! {
+ (u8x2, u16x2),
+ (u8x4, u16x4),
+ (u8x8, u16x8),
+ (u8x16, u16x16),
+ (u8x32, u16x32),,
+ 8
+ }
+
+ wmul_impl! { (u16x2, u32x2),, 16 }
+ #[cfg(not(target_feature = "sse2"))]
+ wmul_impl! { (u16x4, u32x4),, 16 }
+ #[cfg(not(target_feature = "sse4.2"))]
+ wmul_impl! { (u16x8, u32x8),, 16 }
+ #[cfg(not(target_feature = "avx2"))]
+ wmul_impl! { (u16x16, u32x16),, 16 }
+
+ // 16-bit lane widths allow use of the x86 `mulhi` instructions, which
+ // means `wmul` can be implemented with only two instructions.
+ #[allow(unused_macros)]
+ macro_rules! wmul_impl_16 {
+ ($ty:ident, $intrinsic:ident, $mulhi:ident, $mullo:ident) => {
+ impl WideningMultiply for $ty {
+ type Output = ($ty, $ty);
+
+ #[inline(always)]
+ fn wmul(self, x: $ty) -> Self::Output {
+ let b = $intrinsic::from_bits(x);
+ let a = $intrinsic::from_bits(self);
+ let hi = $ty::from_bits(unsafe { $mulhi(a, b) });
+ let lo = $ty::from_bits(unsafe { $mullo(a, b) });
+ (hi, lo)
+ }
+ }
+ };
+ }
+
+ #[cfg(target_feature = "sse2")]
+ wmul_impl_16! { u16x4, __m64, _mm_mulhi_pu16, _mm_mullo_pi16 }
+ #[cfg(target_feature = "sse4.2")]
+ wmul_impl_16! { u16x8, __m128i, _mm_mulhi_epu16, _mm_mullo_epi16 }
+ #[cfg(target_feature = "avx2")]
+ wmul_impl_16! { u16x16, __m256i, _mm256_mulhi_epu16, _mm256_mullo_epi16 }
+ // FIXME: there are no `__m512i` types in stdsimd yet, so `wmul::<u16x32>`
+ // cannot use the same implementation.
+
+ wmul_impl! {
+ (u32x2, u64x2),
+ (u32x4, u64x4),
+ (u32x8, u64x8),,
+ 32
+ }
+
+ // TODO: optimize, this seems to seriously slow things down
+ wmul_impl_large! { (u8x64,) u8, 4 }
+ wmul_impl_large! { (u16x32,) u16, 8 }
+ wmul_impl_large! { (u32x16,) u32, 16 }
+ wmul_impl_large! { (u64x2, u64x4, u64x8,) u64, 32 }
+}
+#[cfg(all(feature = "simd_support", feature = "nightly"))]
+pub use self::simd_wmul::*;
+
+
+/// Helper trait when dealing with scalar and SIMD floating point types.
+pub(crate) trait FloatSIMDUtils {
+ // `PartialOrd` for vectors compares lexicographically. We want to compare all
+ // the individual SIMD lanes instead, and get the combined result over all
+ // lanes. This is possible using something like `a.lt(b).all()`, but we
+ // implement it as a trait so we can write the same code for `f32` and `f64`.
+ // Only the comparison functions we need are implemented.
+ fn all_lt(self, other: Self) -> bool;
+ fn all_le(self, other: Self) -> bool;
+ fn all_finite(self) -> bool;
+
+ type Mask;
+ fn finite_mask(self) -> Self::Mask;
+ fn gt_mask(self, other: Self) -> Self::Mask;
+ fn ge_mask(self, other: Self) -> Self::Mask;
+
+ // Decrease all lanes where the mask is `true` to the next lower value
+ // representable by the floating-point type. At least one of the lanes
+ // must be set.
+ fn decrease_masked(self, mask: Self::Mask) -> Self;
+
+ // Convert from int value. Conversion is done while retaining the numerical
+ // value, not by retaining the binary representation.
+ type UInt;
+ fn cast_from_int(i: Self::UInt) -> Self;
+}
+
+/// Implement functions available in std builds but missing from core primitives
+#[cfg(not(std))]
+pub(crate) trait Float : Sized {
+ type Bits;
+
+ fn is_nan(self) -> bool;
+ fn is_infinite(self) -> bool;
+ fn is_finite(self) -> bool;
+ fn to_bits(self) -> Self::Bits;
+ fn from_bits(v: Self::Bits) -> Self;
+}
+
+/// Implement functions on f32/f64 to give them APIs similar to SIMD types
+pub(crate) trait FloatAsSIMD : Sized {
+ #[inline(always)]
+ fn lanes() -> usize { 1 }
+ #[inline(always)]
+ fn splat(scalar: Self) -> Self { scalar }
+ #[inline(always)]
+ fn extract(self, index: usize) -> Self { debug_assert_eq!(index, 0); self }
+ #[inline(always)]
+ fn replace(self, index: usize, new_value: Self) -> Self { debug_assert_eq!(index, 0); new_value }
+}
+
+pub(crate) trait BoolAsSIMD : Sized {
+ fn any(self) -> bool;
+ fn all(self) -> bool;
+ fn none(self) -> bool;
+}
+
+impl BoolAsSIMD for bool {
+ #[inline(always)]
+ fn any(self) -> bool { self }
+ #[inline(always)]
+ fn all(self) -> bool { self }
+ #[inline(always)]
+ fn none(self) -> bool { !self }
+}
+
+macro_rules! scalar_float_impl {
+ ($ty:ident, $uty:ident) => {
+ #[cfg(not(std))]
+ impl Float for $ty {
+ type Bits = $uty;
+
+ #[inline]
+ fn is_nan(self) -> bool {
+ self != self
+ }
+
+ #[inline]
+ fn is_infinite(self) -> bool {
+ self == ::core::$ty::INFINITY || self == ::core::$ty::NEG_INFINITY
+ }
+
+ #[inline]
+ fn is_finite(self) -> bool {
+ !(self.is_nan() || self.is_infinite())
+ }
+
+ #[inline]
+ fn to_bits(self) -> Self::Bits {
+ unsafe { ::core::mem::transmute(self) }
+ }
+
+ #[inline]
+ fn from_bits(v: Self::Bits) -> Self {
+ // It turns out the safety issues with sNaN were overblown! Hooray!
+ unsafe { ::core::mem::transmute(v) }
+ }
+ }
+
+ impl FloatSIMDUtils for $ty {
+ type Mask = bool;
+ #[inline(always)]
+ fn all_lt(self, other: Self) -> bool { self < other }
+ #[inline(always)]
+ fn all_le(self, other: Self) -> bool { self <= other }
+ #[inline(always)]
+ fn all_finite(self) -> bool { self.is_finite() }
+ #[inline(always)]
+ fn finite_mask(self) -> Self::Mask { self.is_finite() }
+ #[inline(always)]
+ fn gt_mask(self, other: Self) -> Self::Mask { self > other }
+ #[inline(always)]
+ fn ge_mask(self, other: Self) -> Self::Mask { self >= other }
+ #[inline(always)]
+ fn decrease_masked(self, mask: Self::Mask) -> Self {
+ debug_assert!(mask, "At least one lane must be set");
+ <$ty>::from_bits(self.to_bits() - 1)
+ }
+ type UInt = $uty;
+ fn cast_from_int(i: Self::UInt) -> Self { i as $ty }
+ }
+
+ impl FloatAsSIMD for $ty {}
+ }
+}
+
+scalar_float_impl!(f32, u32);
+scalar_float_impl!(f64, u64);
+
+
+#[cfg(feature="simd_support")]
+macro_rules! simd_impl {
+ ($ty:ident, $f_scalar:ident, $mty:ident, $uty:ident) => {
+ impl FloatSIMDUtils for $ty {
+ type Mask = $mty;
+ #[inline(always)]
+ fn all_lt(self, other: Self) -> bool { self.lt(other).all() }
+ #[inline(always)]
+ fn all_le(self, other: Self) -> bool { self.le(other).all() }
+ #[inline(always)]
+ fn all_finite(self) -> bool { self.finite_mask().all() }
+ #[inline(always)]
+ fn finite_mask(self) -> Self::Mask {
+ // This can possibly be done faster by checking bit patterns
+ let neg_inf = $ty::splat(::core::$f_scalar::NEG_INFINITY);
+ let pos_inf = $ty::splat(::core::$f_scalar::INFINITY);
+ self.gt(neg_inf) & self.lt(pos_inf)
+ }
+ #[inline(always)]
+ fn gt_mask(self, other: Self) -> Self::Mask { self.gt(other) }
+ #[inline(always)]
+ fn ge_mask(self, other: Self) -> Self::Mask { self.ge(other) }
+ #[inline(always)]
+ fn decrease_masked(self, mask: Self::Mask) -> Self {
+ // Casting a mask into ints will produce all bits set for
+ // true, and 0 for false. Adding that to the binary
+ // representation of a float means subtracting one from
+ // the binary representation, resulting in the next lower
+ // value representable by $ty. This works even when the
+ // current value is infinity.
+ debug_assert!(mask.any(), "At least one lane must be set");
+ <$ty>::from_bits(<$uty>::from_bits(self) + <$uty>::from_bits(mask))
+ }
+ type UInt = $uty;
+ fn cast_from_int(i: Self::UInt) -> Self { i.cast() }
+ }
+ }
+}
+
+#[cfg(feature="simd_support")] simd_impl! { f32x2, f32, m32x2, u32x2 }
+#[cfg(feature="simd_support")] simd_impl! { f32x4, f32, m32x4, u32x4 }
+#[cfg(feature="simd_support")] simd_impl! { f32x8, f32, m32x8, u32x8 }
+#[cfg(feature="simd_support")] simd_impl! { f32x16, f32, m32x16, u32x16 }
+#[cfg(feature="simd_support")] simd_impl! { f64x2, f64, m64x2, u64x2 }
+#[cfg(feature="simd_support")] simd_impl! { f64x4, f64, m64x4, u64x4 }
+#[cfg(feature="simd_support")] simd_impl! { f64x8, f64, m64x8, u64x8 }
+
+/// Calculates ln(gamma(x)) (natural logarithm of the gamma
+/// function) using the Lanczos approximation.
+///
+/// The approximation expresses the gamma function as:
+/// `gamma(z+1) = sqrt(2*pi)*(z+g+0.5)^(z+0.5)*exp(-z-g-0.5)*Ag(z)`
+/// `g` is an arbitrary constant; we use the approximation with `g=5`.
+///
+/// Noting that `gamma(z+1) = z*gamma(z)` and applying `ln` to both sides:
+/// `ln(gamma(z)) = (z+0.5)*ln(z+g+0.5)-(z+g+0.5) + ln(sqrt(2*pi)*Ag(z)/z)`
+///
+/// `Ag(z)` is an infinite series with coefficients that can be calculated
+/// ahead of time - we use just the first 6 terms, which is good enough
+/// for most purposes.
+#[cfg(feature="std")]
+pub fn log_gamma(x: f64) -> f64 {
+ // precalculated 6 coefficients for the first 6 terms of the series
+ let coefficients: [f64; 6] = [
+ 76.18009172947146,
+ -86.50532032941677,
+ 24.01409824083091,
+ -1.231739572450155,
+ 0.1208650973866179e-2,
+ -0.5395239384953e-5,
+ ];
+
+ // (x+0.5)*ln(x+g+0.5)-(x+g+0.5)
+ let tmp = x + 5.5;
+ let log = (x + 0.5) * tmp.ln() - tmp;
+
+ // the first few terms of the series for Ag(x)
+ let mut a = 1.000000000190015;
+ let mut denom = x;
+ for coeff in &coefficients {
+ denom += 1.0;
+ a += coeff / denom;
+ }
+
+ // get everything together
+ // a is Ag(x)
+ // 2.5066... is sqrt(2pi)
+ log + (2.5066282746310005 * a / x).ln()
+}
+
+/// Sample a random number using the Ziggurat method (specifically the
+/// ZIGNOR variant from Doornik 2005). Most of the arguments are
+/// directly from the paper:
+///
+/// * `rng`: source of randomness
+/// * `symmetric`: whether this is a symmetric distribution, or one-sided with P(x < 0) = 0.
+/// * `X`: the $x_i$ abscissae.
+/// * `F`: precomputed values of the PDF at the $x_i$, (i.e. $f(x_i)$)
+/// * `F_DIFF`: precomputed values of $f(x_i) - f(x_{i+1})$
+/// * `pdf`: the probability density function
+/// * `zero_case`: manual sampling from the tail when we chose the
+/// bottom box (i.e. i == 0)
+
+// the perf improvement (25-50%) is definitely worth the extra code
+// size from force-inlining.
+#[cfg(feature="std")]
+#[inline(always)]
+pub fn ziggurat<R: Rng + ?Sized, P, Z>(
+ rng: &mut R,
+ symmetric: bool,
+ x_tab: ziggurat_tables::ZigTable,
+ f_tab: ziggurat_tables::ZigTable,
+ mut pdf: P,
+ mut zero_case: Z)
+ -> f64 where P: FnMut(f64) -> f64, Z: FnMut(&mut R, f64) -> f64 {
+ use distributions::float::IntoFloat;
+ loop {
+ // As an optimisation we re-implement the conversion to a f64.
+ // From the remaining 12 most significant bits we use 8 to construct `i`.
+ // This saves us generating a whole extra random number, while the added
+ // precision of using 64 bits for f64 does not buy us much.
+ let bits = rng.next_u64();
+ let i = bits as usize & 0xff;
+
+ let u = if symmetric {
+ // Convert to a value in the range [2,4) and substract to get [-1,1)
+ // We can't convert to an open range directly, that would require
+ // substracting `3.0 - EPSILON`, which is not representable.
+ // It is possible with an extra step, but an open range does not
+ // seem neccesary for the ziggurat algorithm anyway.
+ (bits >> 12).into_float_with_exponent(1) - 3.0
+ } else {
+ // Convert to a value in the range [1,2) and substract to get (0,1)
+ (bits >> 12).into_float_with_exponent(0)
+ - (1.0 - ::core::f64::EPSILON / 2.0)
+ };
+ let x = u * x_tab[i];
+
+ let test_x = if symmetric { x.abs() } else {x};
+
+ // algebraically equivalent to |u| < x_tab[i+1]/x_tab[i] (or u < x_tab[i+1]/x_tab[i])
+ if test_x < x_tab[i + 1] {
+ return x;
+ }
+ if i == 0 {
+ return zero_case(rng, u);
+ }
+ // algebraically equivalent to f1 + DRanU()*(f0 - f1) < 1
+ if f_tab[i + 1] + (f_tab[i] - f_tab[i + 1]) * rng.gen::<f64>() < pdf(x) {
+ return x;
+ }
+ }
+}
diff --git a/rand/src/distributions/weibull.rs b/rand/src/distributions/weibull.rs
new file mode 100644
index 0000000..5fbe10a
--- /dev/null
+++ b/rand/src/distributions/weibull.rs
@@ -0,0 +1,71 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! The Weibull distribution.
+
+use Rng;
+use distributions::{Distribution, OpenClosed01};
+
+/// Samples floating-point numbers according to the Weibull distribution
+///
+/// # Example
+/// ```
+/// use rand::prelude::*;
+/// use rand::distributions::Weibull;
+///
+/// let val: f64 = SmallRng::from_entropy().sample(Weibull::new(1., 10.));
+/// println!("{}", val);
+/// ```
+#[derive(Clone, Copy, Debug)]
+pub struct Weibull {
+ inv_shape: f64,
+ scale: f64,
+}
+
+impl Weibull {
+ /// Construct a new `Weibull` distribution with given `scale` and `shape`.
+ ///
+ /// # Panics
+ ///
+ /// `scale` and `shape` have to be non-zero and positive.
+ pub fn new(scale: f64, shape: f64) -> Weibull {
+ assert!((scale > 0.) & (shape > 0.));
+ Weibull { inv_shape: 1./shape, scale }
+ }
+}
+
+impl Distribution<f64> for Weibull {
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
+ let x: f64 = rng.sample(OpenClosed01);
+ self.scale * (-x.ln()).powf(self.inv_shape)
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use distributions::Distribution;
+ use super::Weibull;
+
+ #[test]
+ #[should_panic]
+ fn invalid() {
+ Weibull::new(0., 0.);
+ }
+
+ #[test]
+ fn sample() {
+ let scale = 1.0;
+ let shape = 2.0;
+ let d = Weibull::new(scale, shape);
+ let mut rng = ::test::rng(1);
+ for _ in 0..1000 {
+ let r = d.sample(&mut rng);
+ assert!(r >= 0.);
+ }
+ }
+}
diff --git a/rand/src/distributions/weighted.rs b/rand/src/distributions/weighted.rs
new file mode 100644
index 0000000..01c8fe6
--- /dev/null
+++ b/rand/src/distributions/weighted.rs
@@ -0,0 +1,232 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use Rng;
+use distributions::Distribution;
+use distributions::uniform::{UniformSampler, SampleUniform, SampleBorrow};
+use ::core::cmp::PartialOrd;
+use core::fmt;
+
+// Note that this whole module is only imported if feature="alloc" is enabled.
+#[cfg(not(feature="std"))] use alloc::vec::Vec;
+
+/// A distribution using weighted sampling to pick a discretely selected
+/// item.
+///
+/// Sampling a `WeightedIndex` distribution returns the index of a randomly
+/// selected element from the iterator used when the `WeightedIndex` was
+/// created. The chance of a given element being picked is proportional to the
+/// value of the element. The weights can use any type `X` for which an
+/// implementation of [`Uniform<X>`] exists.
+///
+/// # Performance
+///
+/// A `WeightedIndex<X>` contains a `Vec<X>` and a [`Uniform<X>`] and so its
+/// size is the sum of the size of those objects, possibly plus some alignment.
+///
+/// Creating a `WeightedIndex<X>` will allocate enough space to hold `N - 1`
+/// weights of type `X`, where `N` is the number of weights. However, since
+/// `Vec` doesn't guarantee a particular growth strategy, additional memory
+/// might be allocated but not used. Since the `WeightedIndex` object also
+/// contains, this might cause additional allocations, though for primitive
+/// types, ['Uniform<X>`] doesn't allocate any memory.
+///
+/// Time complexity of sampling from `WeightedIndex` is `O(log N)` where
+/// `N` is the number of weights.
+///
+/// Sampling from `WeightedIndex` will result in a single call to
+/// [`Uniform<X>::sample`], which typically will request a single value from
+/// the underlying [`RngCore`], though the exact number depends on the
+/// implementaiton of [`Uniform<X>::sample`].
+///
+/// # Example
+///
+/// ```
+/// use rand::prelude::*;
+/// use rand::distributions::WeightedIndex;
+///
+/// let choices = ['a', 'b', 'c'];
+/// let weights = [2, 1, 1];
+/// let dist = WeightedIndex::new(&weights).unwrap();
+/// let mut rng = thread_rng();
+/// for _ in 0..100 {
+/// // 50% chance to print 'a', 25% chance to print 'b', 25% chance to print 'c'
+/// println!("{}", choices[dist.sample(&mut rng)]);
+/// }
+///
+/// let items = [('a', 0), ('b', 3), ('c', 7)];
+/// let dist2 = WeightedIndex::new(items.iter().map(|item| item.1)).unwrap();
+/// for _ in 0..100 {
+/// // 0% chance to print 'a', 30% chance to print 'b', 70% chance to print 'c'
+/// println!("{}", items[dist2.sample(&mut rng)].0);
+/// }
+/// ```
+///
+/// [`Uniform<X>`]: struct.Uniform.html
+/// [`Uniform<X>::sample`]: struct.Uniform.html#method.sample
+/// [`RngCore`]: ../trait.RngCore.html
+#[derive(Debug, Clone)]
+pub struct WeightedIndex<X: SampleUniform + PartialOrd> {
+ cumulative_weights: Vec<X>,
+ weight_distribution: X::Sampler,
+}
+
+impl<X: SampleUniform + PartialOrd> WeightedIndex<X> {
+ /// Creates a new a `WeightedIndex` [`Distribution`] using the values
+ /// in `weights`. The weights can use any type `X` for which an
+ /// implementation of [`Uniform<X>`] exists.
+ ///
+ /// Returns an error if the iterator is empty, if any weight is `< 0`, or
+ /// if its total value is 0.
+ ///
+ /// [`Distribution`]: trait.Distribution.html
+ /// [`Uniform<X>`]: struct.Uniform.html
+ pub fn new<I>(weights: I) -> Result<WeightedIndex<X>, WeightedError>
+ where I: IntoIterator,
+ I::Item: SampleBorrow<X>,
+ X: for<'a> ::core::ops::AddAssign<&'a X> +
+ Clone +
+ Default {
+ let mut iter = weights.into_iter();
+ let mut total_weight: X = iter.next()
+ .ok_or(WeightedError::NoItem)?
+ .borrow()
+ .clone();
+
+ let zero = <X as Default>::default();
+ if total_weight < zero {
+ return Err(WeightedError::NegativeWeight);
+ }
+
+ let mut weights = Vec::<X>::with_capacity(iter.size_hint().0);
+ for w in iter {
+ if *w.borrow() < zero {
+ return Err(WeightedError::NegativeWeight);
+ }
+ weights.push(total_weight.clone());
+ total_weight += w.borrow();
+ }
+
+ if total_weight == zero {
+ return Err(WeightedError::AllWeightsZero);
+ }
+ let distr = X::Sampler::new(zero, total_weight);
+
+ Ok(WeightedIndex { cumulative_weights: weights, weight_distribution: distr })
+ }
+}
+
+impl<X> Distribution<usize> for WeightedIndex<X> where
+ X: SampleUniform + PartialOrd {
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> usize {
+ use ::core::cmp::Ordering;
+ let chosen_weight = self.weight_distribution.sample(rng);
+ // Find the first item which has a weight *higher* than the chosen weight.
+ self.cumulative_weights.binary_search_by(
+ |w| if *w <= chosen_weight { Ordering::Less } else { Ordering::Greater }).unwrap_err()
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+
+ #[test]
+ fn test_weightedindex() {
+ let mut r = ::test::rng(700);
+ const N_REPS: u32 = 5000;
+ let weights = [1u32, 2, 3, 0, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7];
+ let total_weight = weights.iter().sum::<u32>() as f32;
+
+ let verify = |result: [i32; 14]| {
+ for (i, count) in result.iter().enumerate() {
+ let exp = (weights[i] * N_REPS) as f32 / total_weight;
+ let mut err = (*count as f32 - exp).abs();
+ if err != 0.0 {
+ err /= exp;
+ }
+ assert!(err <= 0.25);
+ }
+ };
+
+ // WeightedIndex from vec
+ let mut chosen = [0i32; 14];
+ let distr = WeightedIndex::new(weights.to_vec()).unwrap();
+ for _ in 0..N_REPS {
+ chosen[distr.sample(&mut r)] += 1;
+ }
+ verify(chosen);
+
+ // WeightedIndex from slice
+ chosen = [0i32; 14];
+ let distr = WeightedIndex::new(&weights[..]).unwrap();
+ for _ in 0..N_REPS {
+ chosen[distr.sample(&mut r)] += 1;
+ }
+ verify(chosen);
+
+ // WeightedIndex from iterator
+ chosen = [0i32; 14];
+ let distr = WeightedIndex::new(weights.iter()).unwrap();
+ for _ in 0..N_REPS {
+ chosen[distr.sample(&mut r)] += 1;
+ }
+ verify(chosen);
+
+ for _ in 0..5 {
+ assert_eq!(WeightedIndex::new(&[0, 1]).unwrap().sample(&mut r), 1);
+ assert_eq!(WeightedIndex::new(&[1, 0]).unwrap().sample(&mut r), 0);
+ assert_eq!(WeightedIndex::new(&[0, 0, 0, 0, 10, 0]).unwrap().sample(&mut r), 4);
+ }
+
+ assert_eq!(WeightedIndex::new(&[10][0..0]).unwrap_err(), WeightedError::NoItem);
+ assert_eq!(WeightedIndex::new(&[0]).unwrap_err(), WeightedError::AllWeightsZero);
+ assert_eq!(WeightedIndex::new(&[10, 20, -1, 30]).unwrap_err(), WeightedError::NegativeWeight);
+ assert_eq!(WeightedIndex::new(&[-10, 20, 1, 30]).unwrap_err(), WeightedError::NegativeWeight);
+ assert_eq!(WeightedIndex::new(&[-10]).unwrap_err(), WeightedError::NegativeWeight);
+ }
+}
+
+/// Error type returned from `WeightedIndex::new`.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum WeightedError {
+ /// The provided iterator contained no items.
+ NoItem,
+
+ /// A weight lower than zero was used.
+ NegativeWeight,
+
+ /// All items in the provided iterator had a weight of zero.
+ AllWeightsZero,
+}
+
+impl WeightedError {
+ fn msg(&self) -> &str {
+ match *self {
+ WeightedError::NoItem => "No items found",
+ WeightedError::NegativeWeight => "Item has negative weight",
+ WeightedError::AllWeightsZero => "All items had weight zero",
+ }
+ }
+}
+
+#[cfg(feature="std")]
+impl ::std::error::Error for WeightedError {
+ fn description(&self) -> &str {
+ self.msg()
+ }
+ fn cause(&self) -> Option<&::std::error::Error> {
+ None
+ }
+}
+
+impl fmt::Display for WeightedError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{}", self.msg())
+ }
+}
diff --git a/rand/src/distributions/ziggurat_tables.rs b/rand/src/distributions/ziggurat_tables.rs
index b6de4bf..ca1ce30 100644
--- a/rand/src/distributions/ziggurat_tables.rs
+++ b/rand/src/distributions/ziggurat_tables.rs
@@ -1,10 +1,9 @@
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
+// Copyright 2018 Developers of the Rand project.
+// Copyright 2013 The Rust Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
diff --git a/rand/src/lib.rs b/rand/src/lib.rs
index 7b22dd4..d364bd1 100644
--- a/rand/src/lib.rs
+++ b/rand/src/lib.rs
@@ -1,921 +1,673 @@
-// Copyright 2013-2017 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
+// Copyright 2018 Developers of the Rand project.
+// Copyright 2013-2017 The Rust Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Utilities for random number generation
//!
-//! The key functions are `random()` and `Rng::gen()`. These are polymorphic and
-//! so can be used to generate any type that implements `Rand`. Type inference
-//! means that often a simple call to `rand::random()` or `rng.gen()` will
-//! suffice, but sometimes an annotation is required, e.g.
-//! `rand::random::<f64>()`.
+//! Rand provides utilities to generate random numbers, to convert them to
+//! useful types and distributions, and some randomness-related algorithms.
//!
-//! See the `distributions` submodule for sampling random numbers from
-//! distributions like normal and exponential.
+//! # Quick Start
+//!
+//! To get you started quickly, the easiest and highest-level way to get
+//! a random value is to use [`random()`]; alternatively you can use
+//! [`thread_rng()`]. The [`Rng`] trait provides a useful API on all RNGs, while
+//! the [`distributions` module] and [`seq` module] provide further
+//! functionality on top of RNGs.
//!
-//! # Usage
-//!
-//! This crate is [on crates.io](https://crates.io/crates/rand) and can be
-//! used by adding `rand` to the dependencies in your project's `Cargo.toml`.
-//!
-//! ```toml
-//! [dependencies]
-//! rand = "0.4"
-//! ```
-//!
-//! and this to your crate root:
-//!
-//! ```rust
-//! extern crate rand;
//! ```
-//!
-//! # Thread-local RNG
-//!
-//! There is built-in support for a RNG associated with each thread stored
-//! in thread-local storage. This RNG can be accessed via `thread_rng`, or
-//! used implicitly via `random`. This RNG is normally randomly seeded
-//! from an operating-system source of randomness, e.g. `/dev/urandom` on
-//! Unix systems, and will automatically reseed itself from this source
-//! after generating 32 KiB of random data.
-//!
-//! # Cryptographic security
-//!
-//! An application that requires an entropy source for cryptographic purposes
-//! must use `OsRng`, which reads randomness from the source that the operating
-//! system provides (e.g. `/dev/urandom` on Unixes or `CryptGenRandom()` on
-//! Windows).
-//! The other random number generators provided by this module are not suitable
-//! for such purposes.
-//!
-//! *Note*: many Unix systems provide `/dev/random` as well as `/dev/urandom`.
-//! This module uses `/dev/urandom` for the following reasons:
-//!
-//! - On Linux, `/dev/random` may block if entropy pool is empty;
-//! `/dev/urandom` will not block. This does not mean that `/dev/random`
-//! provides better output than `/dev/urandom`; the kernel internally runs a
-//! cryptographically secure pseudorandom number generator (CSPRNG) based on
-//! entropy pool for random number generation, so the "quality" of
-//! `/dev/random` is not better than `/dev/urandom` in most cases. However,
-//! this means that `/dev/urandom` can yield somewhat predictable randomness
-//! if the entropy pool is very small, such as immediately after first
-//! booting. Linux 3.17 added the `getrandom(2)` system call which solves
-//! the issue: it blocks if entropy pool is not initialized yet, but it does
-//! not block once initialized. `OsRng` tries to use `getrandom(2)` if
-//! available, and use `/dev/urandom` fallback if not. If an application
-//! does not have `getrandom` and likely to be run soon after first booting,
-//! or on a system with very few entropy sources, one should consider using
-//! `/dev/random` via `ReadRng`.
-//! - On some systems (e.g. FreeBSD, OpenBSD and Mac OS X) there is no
-//! difference between the two sources. (Also note that, on some systems
-//! e.g. FreeBSD, both `/dev/random` and `/dev/urandom` may block once if
-//! the CSPRNG has not seeded yet.)
-//!
-//! # Examples
-//!
-//! ```rust
-//! use rand::Rng;
-//!
-//! let mut rng = rand::thread_rng();
-//! if rng.gen() { // random bool
-//! println!("i32: {}, u32: {}", rng.gen::<i32>(), rng.gen::<u32>())
+//! use rand::prelude::*;
+//!
+//! if rand::random() { // generates a boolean
+//! // Try printing a random unicode code point (probably a bad idea)!
+//! println!("char: {}", rand::random::<char>());
//! }
-//! ```
-//!
-//! ```rust
-//! let tuple = rand::random::<(f64, char)>();
-//! println!("{:?}", tuple)
-//! ```
-//!
-//! ## Monte Carlo estimation of π
-//!
-//! For this example, imagine we have a square with sides of length 2 and a unit
-//! circle, both centered at the origin. Since the area of a unit circle is π,
-//! we have:
-//!
-//! ```text
-//! (area of unit circle) / (area of square) = π / 4
-//! ```
//!
-//! So if we sample many points randomly from the square, roughly π / 4 of them
-//! should be inside the circle.
-//!
-//! We can use the above fact to estimate the value of π: pick many points in
-//! the square at random, calculate the fraction that fall within the circle,
-//! and multiply this fraction by 4.
-//!
-//! ```
-//! use rand::distributions::{IndependentSample, Range};
-//!
-//! fn main() {
-//! let between = Range::new(-1f64, 1.);
-//! let mut rng = rand::thread_rng();
-//!
-//! let total = 1_000_000;
-//! let mut in_circle = 0;
-//!
-//! for _ in 0..total {
-//! let a = between.ind_sample(&mut rng);
-//! let b = between.ind_sample(&mut rng);
-//! if a*a + b*b <= 1. {
-//! in_circle += 1;
-//! }
-//! }
-//!
-//! // prints something close to 3.14159...
-//! println!("{}", 4. * (in_circle as f64) / (total as f64));
-//! }
-//! ```
-//!
-//! ## Monty Hall Problem
-//!
-//! This is a simulation of the [Monty Hall Problem][]:
-//!
-//! > Suppose you're on a game show, and you're given the choice of three doors:
-//! > Behind one door is a car; behind the others, goats. You pick a door, say
-//! > No. 1, and the host, who knows what's behind the doors, opens another
-//! > door, say No. 3, which has a goat. He then says to you, "Do you want to
-//! > pick door No. 2?" Is it to your advantage to switch your choice?
-//!
-//! The rather unintuitive answer is that you will have a 2/3 chance of winning
-//! if you switch and a 1/3 chance of winning if you don't, so it's better to
-//! switch.
-//!
-//! This program will simulate the game show and with large enough simulation
-//! steps it will indeed confirm that it is better to switch.
-//!
-//! [Monty Hall Problem]: http://en.wikipedia.org/wiki/Monty_Hall_problem
+//! let mut rng = rand::thread_rng();
+//! let y: f64 = rng.gen(); // generates a float between 0 and 1
//!
+//! let mut nums: Vec<i32> = (1..100).collect();
+//! nums.shuffle(&mut rng);
//! ```
-//! use rand::Rng;
-//! use rand::distributions::{IndependentSample, Range};
-//!
-//! struct SimulationResult {
-//! win: bool,
-//! switch: bool,
-//! }
-//!
-//! // Run a single simulation of the Monty Hall problem.
-//! fn simulate<R: Rng>(random_door: &Range<u32>, rng: &mut R)
-//! -> SimulationResult {
-//! let car = random_door.ind_sample(rng);
-//!
-//! // This is our initial choice
-//! let mut choice = random_door.ind_sample(rng);
-//!
-//! // The game host opens a door
-//! let open = game_host_open(car, choice, rng);
//!
-//! // Shall we switch?
-//! let switch = rng.gen();
-//! if switch {
-//! choice = switch_door(choice, open);
-//! }
+//! # The Book
+//!
+//! For the user guide and futher documentation, please read
+//! [The Rust Rand Book](https://rust-random.github.io/book).
//!
-//! SimulationResult { win: choice == car, switch: switch }
-//! }
-//!
-//! // Returns the door the game host opens given our choice and knowledge of
-//! // where the car is. The game host will never open the door with the car.
-//! fn game_host_open<R: Rng>(car: u32, choice: u32, rng: &mut R) -> u32 {
-//! let choices = free_doors(&[car, choice]);
-//! rand::seq::sample_slice(rng, &choices, 1)[0]
-//! }
-//!
-//! // Returns the door we switch to, given our current choice and
-//! // the open door. There will only be one valid door.
-//! fn switch_door(choice: u32, open: u32) -> u32 {
-//! free_doors(&[choice, open])[0]
-//! }
-//!
-//! fn free_doors(blocked: &[u32]) -> Vec<u32> {
-//! (0..3).filter(|x| !blocked.contains(x)).collect()
-//! }
-//!
-//! fn main() {
-//! // The estimation will be more accurate with more simulations
-//! let num_simulations = 10000;
-//!
-//! let mut rng = rand::thread_rng();
-//! let random_door = Range::new(0, 3);
-//!
-//! let (mut switch_wins, mut switch_losses) = (0, 0);
-//! let (mut keep_wins, mut keep_losses) = (0, 0);
-//!
-//! println!("Running {} simulations...", num_simulations);
-//! for _ in 0..num_simulations {
-//! let result = simulate(&random_door, &mut rng);
-//!
-//! match (result.win, result.switch) {
-//! (true, true) => switch_wins += 1,
-//! (true, false) => keep_wins += 1,
-//! (false, true) => switch_losses += 1,
-//! (false, false) => keep_losses += 1,
-//! }
-//! }
-//!
-//! let total_switches = switch_wins + switch_losses;
-//! let total_keeps = keep_wins + keep_losses;
-//!
-//! println!("Switched door {} times with {} wins and {} losses",
-//! total_switches, switch_wins, switch_losses);
-//!
-//! println!("Kept our choice {} times with {} wins and {} losses",
-//! total_keeps, keep_wins, keep_losses);
-//!
-//! // With a large number of simulations, the values should converge to
-//! // 0.667 and 0.333 respectively.
-//! println!("Estimated chance to win if we switch: {}",
-//! switch_wins as f32 / total_switches as f32);
-//! println!("Estimated chance to win if we don't: {}",
-//! keep_wins as f32 / total_keeps as f32);
-//! }
-//! ```
+//! [`distributions` module]: distributions/index.html
+//! [`random()`]: fn.random.html
+//! [`Rng`]: trait.Rng.html
+//! [`seq` module]: seq/index.html
+//! [`thread_rng()`]: fn.thread_rng.html
+
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png",
html_favicon_url = "https://www.rust-lang.org/favicon.ico",
- html_root_url = "https://docs.rs/rand/0.4")]
+ html_root_url = "https://rust-random.github.io/rand/")]
+#![deny(missing_docs)]
#![deny(missing_debug_implementations)]
+#![doc(test(attr(allow(unused_variables), deny(warnings))))]
#![cfg_attr(not(feature="std"), no_std)]
#![cfg_attr(all(feature="alloc", not(feature="std")), feature(alloc))]
-#![cfg_attr(feature = "i128_support", feature(i128_type, i128))]
+#![cfg_attr(all(feature="simd_support", feature="nightly"), feature(stdsimd))]
+#![cfg_attr(feature = "stdweb", recursion_limit="128")]
-#[cfg(feature="std")] extern crate std as core;
-#[cfg(all(feature = "alloc", not(feature="std")))] extern crate alloc;
+#[cfg(feature = "std")] extern crate core;
+#[cfg(all(feature = "alloc", not(feature="std")))] #[macro_use] extern crate alloc;
-use core::marker;
-use core::mem;
-#[cfg(feature="std")] use std::cell::RefCell;
-#[cfg(feature="std")] use std::io;
-#[cfg(feature="std")] use std::rc::Rc;
+#[cfg(feature="simd_support")] extern crate packed_simd;
-// external rngs
-pub use jitter::JitterRng;
-#[cfg(feature="std")] pub use os::OsRng;
+#[cfg(all(target_arch="wasm32", not(target_os="emscripten"), feature="stdweb"))]
+#[macro_use]
+extern crate stdweb;
-// pseudo rngs
-pub use isaac::{IsaacRng, Isaac64Rng};
-pub use chacha::ChaChaRng;
-pub use prng::XorShiftRng;
+#[cfg(all(target_arch = "wasm32", feature = "wasm-bindgen"))]
+extern crate wasm_bindgen;
-// local use declarations
-#[cfg(target_pointer_width = "32")]
-use prng::IsaacRng as IsaacWordRng;
-#[cfg(target_pointer_width = "64")]
-use prng::Isaac64Rng as IsaacWordRng;
+extern crate rand_core;
+extern crate rand_isaac; // only for deprecations
+extern crate rand_chacha; // only for deprecations
+extern crate rand_hc;
+extern crate rand_pcg;
+extern crate rand_xorshift;
-use distributions::{Range, IndependentSample};
-use distributions::range::SampleRange;
+#[cfg(feature = "log")] #[macro_use] extern crate log;
+#[allow(unused)]
+#[cfg(not(feature = "log"))] macro_rules! trace { ($($x:tt)*) => () }
+#[allow(unused)]
+#[cfg(not(feature = "log"))] macro_rules! debug { ($($x:tt)*) => () }
+#[allow(unused)]
+#[cfg(not(feature = "log"))] macro_rules! info { ($($x:tt)*) => () }
+#[allow(unused)]
+#[cfg(not(feature = "log"))] macro_rules! warn { ($($x:tt)*) => () }
+#[allow(unused)]
+#[cfg(not(feature = "log"))] macro_rules! error { ($($x:tt)*) => () }
-// public modules
-pub mod distributions;
-pub mod jitter;
-#[cfg(feature="std")] pub mod os;
-#[cfg(feature="std")] pub mod read;
-pub mod reseeding;
-#[cfg(any(feature="std", feature = "alloc"))] pub mod seq;
-// These tiny modules are here to avoid API breakage, probably only temporarily
+// Re-exports from rand_core
+pub use rand_core::{RngCore, CryptoRng, SeedableRng};
+pub use rand_core::{ErrorKind, Error};
+
+// Public exports
+#[cfg(feature="std")] pub use rngs::thread::thread_rng;
+
+// Public modules
+pub mod distributions;
+pub mod prelude;
+#[deprecated(since="0.6.0")]
+pub mod prng;
+pub mod rngs;
+pub mod seq;
+
+////////////////////////////////////////////////////////////////////////////////
+// Compatibility re-exports. Documentation is hidden; will be removed eventually.
+
+#[doc(hidden)] mod deprecated;
+
+#[allow(deprecated)]
+#[doc(hidden)] pub use deprecated::ReseedingRng;
+
+#[allow(deprecated)]
+#[cfg(feature="std")] #[doc(hidden)] pub use deprecated::EntropyRng;
+
+#[allow(deprecated)]
+#[cfg(all(feature="std",
+ any(target_os = "linux", target_os = "android",
+ target_os = "netbsd",
+ target_os = "dragonfly",
+ target_os = "haiku",
+ target_os = "emscripten",
+ target_os = "solaris",
+ target_os = "cloudabi",
+ target_os = "macos", target_os = "ios",
+ target_os = "freebsd",
+ target_os = "openbsd", target_os = "bitrig",
+ target_os = "redox",
+ target_os = "fuchsia",
+ windows,
+ all(target_arch = "wasm32", feature = "stdweb"),
+ all(target_arch = "wasm32", feature = "wasm-bindgen"),
+)))]
+#[doc(hidden)]
+pub use deprecated::OsRng;
+
+#[allow(deprecated)]
+#[doc(hidden)] pub use deprecated::{ChaChaRng, IsaacRng, Isaac64Rng, XorShiftRng};
+#[allow(deprecated)]
+#[doc(hidden)] pub use deprecated::StdRng;
+
+
+#[allow(deprecated)]
+#[doc(hidden)]
+pub mod jitter {
+ pub use deprecated::JitterRng;
+ pub use rngs::TimerError;
+}
+#[allow(deprecated)]
+#[cfg(all(feature="std",
+ any(target_os = "linux", target_os = "android",
+ target_os = "netbsd",
+ target_os = "dragonfly",
+ target_os = "haiku",
+ target_os = "emscripten",
+ target_os = "solaris",
+ target_os = "cloudabi",
+ target_os = "macos", target_os = "ios",
+ target_os = "freebsd",
+ target_os = "openbsd", target_os = "bitrig",
+ target_os = "redox",
+ target_os = "fuchsia",
+ windows,
+ all(target_arch = "wasm32", feature = "stdweb"),
+ all(target_arch = "wasm32", feature = "wasm-bindgen"),
+)))]
+#[doc(hidden)]
+pub mod os {
+ pub use deprecated::OsRng;
+}
+#[allow(deprecated)]
+#[doc(hidden)]
pub mod chacha {
- //! The ChaCha random number generator.
- pub use prng::ChaChaRng;
+ pub use deprecated::ChaChaRng;
}
+#[allow(deprecated)]
+#[doc(hidden)]
pub mod isaac {
- //! The ISAAC random number generator.
- pub use prng::{IsaacRng, Isaac64Rng};
+ pub use deprecated::{IsaacRng, Isaac64Rng};
}
+#[allow(deprecated)]
+#[cfg(feature="std")]
+#[doc(hidden)]
+pub mod read {
+ pub use deprecated::ReadRng;
+}
+
+#[allow(deprecated)]
+#[cfg(feature="std")] #[doc(hidden)] pub use deprecated::ThreadRng;
-// private modules
-mod rand_impls;
-mod prng;
+////////////////////////////////////////////////////////////////////////////////
-/// A type that can be randomly generated using an `Rng`.
+use core::{mem, slice};
+use distributions::{Distribution, Standard};
+use distributions::uniform::{SampleUniform, UniformSampler, SampleBorrow};
+
+/// An automatically-implemented extension trait on [`RngCore`] providing high-level
+/// generic methods for sampling values and other convenience methods.
///
-/// ## Built-in Implementations
+/// This is the primary trait to use when generating random values.
///
-/// This crate implements `Rand` for various primitive types. Assuming the
-/// provided `Rng` is well-behaved, these implementations generate values with
-/// the following ranges and distributions:
+/// # Generic usage
///
-/// * Integers (`i32`, `u32`, `isize`, `usize`, etc.): Uniformly distributed
-/// over all values of the type.
-/// * `char`: Uniformly distributed over all Unicode scalar values, i.e. all
-/// code points in the range `0...0x10_FFFF`, except for the range
-/// `0xD800...0xDFFF` (the surrogate code points). This includes
-/// unassigned/reserved code points.
-/// * `bool`: Generates `false` or `true`, each with probability 0.5.
-/// * Floating point types (`f32` and `f64`): Uniformly distributed in the
-/// half-open range `[0, 1)`. (The [`Open01`], [`Closed01`], [`Exp1`], and
-/// [`StandardNormal`] wrapper types produce floating point numbers with
-/// alternative ranges or distributions.)
+/// The basic pattern is `fn foo<R: Rng + ?Sized>(rng: &mut R)`. Some
+/// things are worth noting here:
///
-/// [`Open01`]: struct.Open01.html
-/// [`Closed01`]: struct.Closed01.html
-/// [`Exp1`]: distributions/exponential/struct.Exp1.html
-/// [`StandardNormal`]: distributions/normal/struct.StandardNormal.html
+/// - Since `Rng: RngCore` and every `RngCore` implements `Rng`, it makes no
+/// difference whether we use `R: Rng` or `R: RngCore`.
+/// - The `+ ?Sized` un-bounding allows functions to be called directly on
+/// type-erased references; i.e. `foo(r)` where `r: &mut RngCore`. Without
+/// this it would be necessary to write `foo(&mut r)`.
///
-/// The following aggregate types also implement `Rand` as long as their
-/// component types implement it:
+/// An alternative pattern is possible: `fn foo<R: Rng>(rng: R)`. This has some
+/// trade-offs. It allows the argument to be consumed directly without a `&mut`
+/// (which is how `from_rng(thread_rng())` works); also it still works directly
+/// on references (including type-erased references). Unfortunately within the
+/// function `foo` it is not known whether `rng` is a reference type or not,
+/// hence many uses of `rng` require an extra reference, either explicitly
+/// (`distr.sample(&mut rng)`) or implicitly (`rng.gen()`); one may hope the
+/// optimiser can remove redundant references later.
///
-/// * Tuples and arrays: Each element of the tuple or array is generated
-/// independently, using its own `Rand` implementation.
-/// * `Option<T>`: Returns `None` with probability 0.5; otherwise generates a
-/// random `T` and returns `Some(T)`.
-pub trait Rand : Sized {
- /// Generates a random instance of this type using the specified source of
- /// randomness.
- fn rand<R: Rng>(rng: &mut R) -> Self;
-}
-
-/// A random number generator.
-pub trait Rng {
- /// Return the next random u32.
- ///
- /// This rarely needs to be called directly, prefer `r.gen()` to
- /// `r.next_u32()`.
- // FIXME #rust-lang/rfcs#628: Should be implemented in terms of next_u64
- fn next_u32(&mut self) -> u32;
-
- /// Return the next random u64.
- ///
- /// By default this is implemented in terms of `next_u32`. An
- /// implementation of this trait must provide at least one of
- /// these two methods. Similarly to `next_u32`, this rarely needs
- /// to be called directly, prefer `r.gen()` to `r.next_u64()`.
- fn next_u64(&mut self) -> u64 {
- ((self.next_u32() as u64) << 32) | (self.next_u32() as u64)
- }
-
- /// Return the next random f32 selected from the half-open
- /// interval `[0, 1)`.
- ///
- /// This uses a technique described by Saito and Matsumoto at
- /// MCQMC'08. Given that the IEEE floating point numbers are
- /// uniformly distributed over [1,2), we generate a number in
- /// this range and then offset it onto the range [0,1). Our
- /// choice of bits (masking v. shifting) is arbitrary and
- /// should be immaterial for high quality generators. For low
- /// quality generators (ex. LCG), prefer bitshifting due to
- /// correlation between sequential low order bits.
- ///
- /// See:
- /// A PRNG specialized in double precision floating point numbers using
- /// an affine transition
- ///
- /// * <http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/ARTICLES/dSFMT.pdf>
- /// * <http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/dSFMT-slide-e.pdf>
+/// Example:
+///
+/// ```
+/// # use rand::thread_rng;
+/// use rand::Rng;
+///
+/// fn foo<R: Rng + ?Sized>(rng: &mut R) -> f32 {
+/// rng.gen()
+/// }
+///
+/// # let v = foo(&mut thread_rng());
+/// ```
+///
+/// [`RngCore`]: trait.RngCore.html
+pub trait Rng: RngCore {
+ /// Return a random value supporting the [`Standard`] distribution.
///
- /// By default this is implemented in terms of `next_u32`, but a
- /// random number generator which can generate numbers satisfying
- /// the requirements directly can overload this for performance.
- /// It is required that the return value lies in `[0, 1)`.
+ /// [`Standard`]: distributions/struct.Standard.html
///
- /// See `Closed01` for the closed interval `[0,1]`, and
- /// `Open01` for the open interval `(0,1)`.
- fn next_f32(&mut self) -> f32 {
- const UPPER_MASK: u32 = 0x3F800000;
- const LOWER_MASK: u32 = 0x7FFFFF;
- let tmp = UPPER_MASK | (self.next_u32() & LOWER_MASK);
- let result: f32 = unsafe { mem::transmute(tmp) };
- result - 1.0
- }
-
- /// Return the next random f64 selected from the half-open
- /// interval `[0, 1)`.
+ /// # Example
///
- /// By default this is implemented in terms of `next_u64`, but a
- /// random number generator which can generate numbers satisfying
- /// the requirements directly can overload this for performance.
- /// It is required that the return value lies in `[0, 1)`.
+ /// ```
+ /// use rand::{thread_rng, Rng};
///
- /// See `Closed01` for the closed interval `[0,1]`, and
- /// `Open01` for the open interval `(0,1)`.
- fn next_f64(&mut self) -> f64 {
- const UPPER_MASK: u64 = 0x3FF0000000000000;
- const LOWER_MASK: u64 = 0xFFFFFFFFFFFFF;
- let tmp = UPPER_MASK | (self.next_u64() & LOWER_MASK);
- let result: f64 = unsafe { mem::transmute(tmp) };
- result - 1.0
+ /// let mut rng = thread_rng();
+ /// let x: u32 = rng.gen();
+ /// println!("{}", x);
+ /// println!("{:?}", rng.gen::<(f64, bool)>());
+ /// ```
+ #[inline]
+ fn gen<T>(&mut self) -> T where Standard: Distribution<T> {
+ Standard.sample(self)
}
- /// Fill `dest` with random data.
+ /// Generate a random value in the range [`low`, `high`), i.e. inclusive of
+ /// `low` and exclusive of `high`.
///
- /// This has a default implementation in terms of `next_u64` and
- /// `next_u32`, but should be overridden by implementations that
- /// offer a more efficient solution than just calling those
- /// methods repeatedly.
+ /// This function is optimised for the case that only a single sample is
+ /// made from the given range. See also the [`Uniform`] distribution
+ /// type which may be faster if sampling from the same range repeatedly.
///
- /// This method does *not* have a requirement to bear any fixed
- /// relationship to the other methods, for example, it does *not*
- /// have to result in the same output as progressively filling
- /// `dest` with `self.gen::<u8>()`, and any such behaviour should
- /// not be relied upon.
+ /// # Panics
///
- /// This method should guarantee that `dest` is entirely filled
- /// with new data, and may panic if this is impossible
- /// (e.g. reading past the end of a file that is being used as the
- /// source of randomness).
+ /// Panics if `low >= high`.
///
/// # Example
///
- /// ```rust
+ /// ```
/// use rand::{thread_rng, Rng};
///
- /// let mut v = [0u8; 13579];
- /// thread_rng().fill_bytes(&mut v);
- /// println!("{:?}", &v[..]);
+ /// let mut rng = thread_rng();
+ /// let n: u32 = rng.gen_range(0, 10);
+ /// println!("{}", n);
+ /// let m: f64 = rng.gen_range(-40.0f64, 1.3e5f64);
+ /// println!("{}", m);
/// ```
- fn fill_bytes(&mut self, dest: &mut [u8]) {
- // this could, in theory, be done by transmuting dest to a
- // [u64], but this is (1) likely to be undefined behaviour for
- // LLVM, (2) has to be very careful about alignment concerns,
- // (3) adds more `unsafe` that needs to be checked, (4)
- // probably doesn't give much performance gain if
- // optimisations are on.
- let mut count = 0;
- let mut num = 0;
- for byte in dest.iter_mut() {
- if count == 0 {
- // we could micro-optimise here by generating a u32 if
- // we only need a few more bytes to fill the vector
- // (i.e. at most 4).
- num = self.next_u64();
- count = 8;
- }
-
- *byte = (num & 0xff) as u8;
- num >>= 8;
- count -= 1;
- }
+ ///
+ /// [`Uniform`]: distributions/uniform/struct.Uniform.html
+ fn gen_range<T: SampleUniform, B1, B2>(&mut self, low: B1, high: B2) -> T
+ where B1: SampleBorrow<T> + Sized,
+ B2: SampleBorrow<T> + Sized {
+ T::Sampler::sample_single(low, high, self)
}
- /// Return a random value of a `Rand` type.
+ /// Sample a new value, using the given distribution.
///
- /// # Example
+ /// ### Example
///
- /// ```rust
+ /// ```
/// use rand::{thread_rng, Rng};
+ /// use rand::distributions::Uniform;
///
/// let mut rng = thread_rng();
- /// let x: u32 = rng.gen();
- /// println!("{}", x);
- /// println!("{:?}", rng.gen::<(f64, bool)>());
+ /// let x = rng.sample(Uniform::new(10u32, 15));
+ /// // Type annotation requires two types, the type and distribution; the
+ /// // distribution can be inferred.
+ /// let y = rng.sample::<u16, _>(Uniform::new(10, 15));
/// ```
- #[inline(always)]
- fn gen<T: Rand>(&mut self) -> T where Self: Sized {
- Rand::rand(self)
+ fn sample<T, D: Distribution<T>>(&mut self, distr: D) -> T {
+ distr.sample(self)
}
- /// Return an iterator that will yield an infinite number of randomly
- /// generated items.
+ /// Create an iterator that generates values using the given distribution.
///
/// # Example
///
/// ```
/// use rand::{thread_rng, Rng};
+ /// use rand::distributions::{Alphanumeric, Uniform, Standard};
///
/// let mut rng = thread_rng();
- /// let x = rng.gen_iter::<u32>().take(10).collect::<Vec<u32>>();
- /// println!("{:?}", x);
- /// println!("{:?}", rng.gen_iter::<(f64, bool)>().take(5)
- /// .collect::<Vec<(f64, bool)>>());
- /// ```
- fn gen_iter<'a, T: Rand>(&'a mut self) -> Generator<'a, T, Self> where Self: Sized {
- Generator { rng: self, _marker: marker::PhantomData }
- }
-
- /// Generate a random value in the range [`low`, `high`).
- ///
- /// This is a convenience wrapper around
- /// `distributions::Range`. If this function will be called
- /// repeatedly with the same arguments, one should use `Range`, as
- /// that will amortize the computations that allow for perfect
- /// uniformity, as they only happen on initialization.
- ///
- /// # Panics
///
- /// Panics if `low >= high`.
+ /// // Vec of 16 x f32:
+ /// let v: Vec<f32> = thread_rng().sample_iter(&Standard).take(16).collect();
///
- /// # Example
+ /// // String:
+ /// let s: String = rng.sample_iter(&Alphanumeric).take(7).collect();
///
- /// ```rust
- /// use rand::{thread_rng, Rng};
+ /// // Combined values
+ /// println!("{:?}", thread_rng().sample_iter(&Standard).take(5)
+ /// .collect::<Vec<(f64, bool)>>());
///
- /// let mut rng = thread_rng();
- /// let n: u32 = rng.gen_range(0, 10);
- /// println!("{}", n);
- /// let m: f64 = rng.gen_range(-40.0f64, 1.3e5f64);
- /// println!("{}", m);
+ /// // Dice-rolling:
+ /// let die_range = Uniform::new_inclusive(1, 6);
+ /// let mut roll_die = rng.sample_iter(&die_range);
+ /// while roll_die.next().unwrap() != 6 {
+ /// println!("Not a 6; rolling again!");
+ /// }
/// ```
- fn gen_range<T: PartialOrd + SampleRange>(&mut self, low: T, high: T) -> T where Self: Sized {
- assert!(low < high, "Rng.gen_range called with low >= high");
- Range::new(low, high).ind_sample(self)
+ fn sample_iter<'a, T, D: Distribution<T>>(&'a mut self, distr: &'a D)
+ -> distributions::DistIter<'a, D, Self, T> where Self: Sized
+ {
+ distr.sample_iter(self)
}
- /// Return a bool with a 1 in n chance of true
+ /// Fill `dest` entirely with random bytes (uniform value distribution),
+ /// where `dest` is any type supporting [`AsByteSliceMut`], namely slices
+ /// and arrays over primitive integer types (`i8`, `i16`, `u32`, etc.).
+ ///
+ /// On big-endian platforms this performs byte-swapping to ensure
+ /// portability of results from reproducible generators.
+ ///
+ /// This uses [`fill_bytes`] internally which may handle some RNG errors
+ /// implicitly (e.g. waiting if the OS generator is not ready), but panics
+ /// on other errors. See also [`try_fill`] which returns errors.
///
/// # Example
///
- /// ```rust
+ /// ```
/// use rand::{thread_rng, Rng};
///
- /// let mut rng = thread_rng();
- /// println!("{}", rng.gen_weighted_bool(3));
+ /// let mut arr = [0i8; 20];
+ /// thread_rng().fill(&mut arr[..]);
/// ```
- fn gen_weighted_bool(&mut self, n: u32) -> bool where Self: Sized {
- n <= 1 || self.gen_range(0, n) == 0
+ ///
+ /// [`fill_bytes`]: trait.RngCore.html#method.fill_bytes
+ /// [`try_fill`]: trait.Rng.html#method.try_fill
+ /// [`AsByteSliceMut`]: trait.AsByteSliceMut.html
+ fn fill<T: AsByteSliceMut + ?Sized>(&mut self, dest: &mut T) {
+ self.fill_bytes(dest.as_byte_slice_mut());
+ dest.to_le();
}
- /// Return an iterator of random characters from the set A-Z,a-z,0-9.
+ /// Fill `dest` entirely with random bytes (uniform value distribution),
+ /// where `dest` is any type supporting [`AsByteSliceMut`], namely slices
+ /// and arrays over primitive integer types (`i8`, `i16`, `u32`, etc.).
+ ///
+ /// On big-endian platforms this performs byte-swapping to ensure
+ /// portability of results from reproducible generators.
+ ///
+ /// This uses [`try_fill_bytes`] internally and forwards all RNG errors. In
+ /// some cases errors may be resolvable; see [`ErrorKind`] and
+ /// documentation for the RNG in use. If you do not plan to handle these
+ /// errors you may prefer to use [`fill`].
///
/// # Example
///
- /// ```rust
+ /// ```
+ /// # use rand::Error;
/// use rand::{thread_rng, Rng};
///
- /// let s: String = thread_rng().gen_ascii_chars().take(10).collect();
- /// println!("{}", s);
+ /// # fn try_inner() -> Result<(), Error> {
+ /// let mut arr = [0u64; 4];
+ /// thread_rng().try_fill(&mut arr[..])?;
+ /// # Ok(())
+ /// # }
+ ///
+ /// # try_inner().unwrap()
/// ```
- fn gen_ascii_chars<'a>(&'a mut self) -> AsciiGenerator<'a, Self> where Self: Sized {
- AsciiGenerator { rng: self }
+ ///
+ /// [`ErrorKind`]: enum.ErrorKind.html
+ /// [`try_fill_bytes`]: trait.RngCore.html#method.try_fill_bytes
+ /// [`fill`]: trait.Rng.html#method.fill
+ /// [`AsByteSliceMut`]: trait.AsByteSliceMut.html
+ fn try_fill<T: AsByteSliceMut + ?Sized>(&mut self, dest: &mut T) -> Result<(), Error> {
+ self.try_fill_bytes(dest.as_byte_slice_mut())?;
+ dest.to_le();
+ Ok(())
}
- /// Return a random element from `values`.
+ /// Return a bool with a probability `p` of being true.
///
- /// Return `None` if `values` is empty.
+ /// See also the [`Bernoulli`] distribution, which may be faster if
+ /// sampling from the same probability repeatedly.
///
/// # Example
///
/// ```
/// use rand::{thread_rng, Rng};
///
- /// let choices = [1, 2, 4, 8, 16, 32];
/// let mut rng = thread_rng();
- /// println!("{:?}", rng.choose(&choices));
- /// assert_eq!(rng.choose(&choices[..0]), None);
+ /// println!("{}", rng.gen_bool(1.0 / 3.0));
/// ```
- fn choose<'a, T>(&mut self, values: &'a [T]) -> Option<&'a T> where Self: Sized {
- if values.is_empty() {
- None
- } else {
- Some(&values[self.gen_range(0, values.len())])
- }
- }
-
- /// Return a mutable pointer to a random element from `values`.
///
- /// Return `None` if `values` is empty.
- fn choose_mut<'a, T>(&mut self, values: &'a mut [T]) -> Option<&'a mut T> where Self: Sized {
- if values.is_empty() {
- None
- } else {
- let len = values.len();
- Some(&mut values[self.gen_range(0, len)])
- }
+ /// # Panics
+ ///
+ /// If `p < 0` or `p > 1`.
+ ///
+ /// [`Bernoulli`]: distributions/bernoulli/struct.Bernoulli.html
+ #[inline]
+ fn gen_bool(&mut self, p: f64) -> bool {
+ let d = distributions::Bernoulli::new(p);
+ self.sample(d)
}
- /// Shuffle a mutable slice in place.
+ /// Return a bool with a probability of `numerator/denominator` of being
+ /// true. I.e. `gen_ratio(2, 3)` has chance of 2 in 3, or about 67%, of
+ /// returning true. If `numerator == denominator`, then the returned value
+ /// is guaranteed to be `true`. If `numerator == 0`, then the returned
+ /// value is guaranteed to be `false`.
+ ///
+ /// See also the [`Bernoulli`] distribution, which may be faster if
+ /// sampling from the same `numerator` and `denominator` repeatedly.
///
- /// This applies Durstenfeld's algorithm for the [Fisher–Yates shuffle](https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#The_modern_algorithm)
- /// which produces an unbiased permutation.
+ /// # Panics
+ ///
+ /// If `denominator == 0` or `numerator > denominator`.
///
/// # Example
///
- /// ```rust
+ /// ```
/// use rand::{thread_rng, Rng};
///
/// let mut rng = thread_rng();
- /// let mut y = [1, 2, 3];
- /// rng.shuffle(&mut y);
- /// println!("{:?}", y);
- /// rng.shuffle(&mut y);
- /// println!("{:?}", y);
+ /// println!("{}", rng.gen_ratio(2, 3));
/// ```
- fn shuffle<T>(&mut self, values: &mut [T]) where Self: Sized {
- let mut i = values.len();
- while i >= 2 {
- // invariant: elements with index >= i have been locked in place.
- i -= 1;
- // lock element i in place.
- values.swap(i, self.gen_range(0, i + 1));
- }
- }
-}
-
-impl<'a, R: ?Sized> Rng for &'a mut R where R: Rng {
- fn next_u32(&mut self) -> u32 {
- (**self).next_u32()
- }
-
- fn next_u64(&mut self) -> u64 {
- (**self).next_u64()
+ ///
+ /// [`Bernoulli`]: distributions/bernoulli/struct.Bernoulli.html
+ #[inline]
+ fn gen_ratio(&mut self, numerator: u32, denominator: u32) -> bool {
+ let d = distributions::Bernoulli::from_ratio(numerator, denominator);
+ self.sample(d)
}
- fn next_f32(&mut self) -> f32 {
- (**self).next_f32()
+ /// Return a random element from `values`.
+ ///
+ /// Deprecated: use [`SliceRandom::choose`] instead.
+ ///
+ /// [`SliceRandom::choose`]: seq/trait.SliceRandom.html#method.choose
+ #[deprecated(since="0.6.0", note="use SliceRandom::choose instead")]
+ fn choose<'a, T>(&mut self, values: &'a [T]) -> Option<&'a T> {
+ use seq::SliceRandom;
+ values.choose(self)
}
- fn next_f64(&mut self) -> f64 {
- (**self).next_f64()
+ /// Return a mutable pointer to a random element from `values`.
+ ///
+ /// Deprecated: use [`SliceRandom::choose_mut`] instead.
+ ///
+ /// [`SliceRandom::choose_mut`]: seq/trait.SliceRandom.html#method.choose_mut
+ #[deprecated(since="0.6.0", note="use SliceRandom::choose_mut instead")]
+ fn choose_mut<'a, T>(&mut self, values: &'a mut [T]) -> Option<&'a mut T> {
+ use seq::SliceRandom;
+ values.choose_mut(self)
}
- fn fill_bytes(&mut self, dest: &mut [u8]) {
- (**self).fill_bytes(dest)
+ /// Shuffle a mutable slice in place.
+ ///
+ /// Deprecated: use [`SliceRandom::shuffle`] instead.
+ ///
+ /// [`SliceRandom::shuffle`]: seq/trait.SliceRandom.html#method.shuffle
+ #[deprecated(since="0.6.0", note="use SliceRandom::shuffle instead")]
+ fn shuffle<T>(&mut self, values: &mut [T]) {
+ use seq::SliceRandom;
+ values.shuffle(self)
}
}
-#[cfg(feature="std")]
-impl<R: ?Sized> Rng for Box<R> where R: Rng {
- fn next_u32(&mut self) -> u32 {
- (**self).next_u32()
- }
-
- fn next_u64(&mut self) -> u64 {
- (**self).next_u64()
- }
-
- fn next_f32(&mut self) -> f32 {
- (**self).next_f32()
- }
-
- fn next_f64(&mut self) -> f64 {
- (**self).next_f64()
- }
-
- fn fill_bytes(&mut self, dest: &mut [u8]) {
- (**self).fill_bytes(dest)
- }
-}
+impl<R: RngCore + ?Sized> Rng for R {}
-/// Iterator which will generate a stream of random items.
+/// Trait for casting types to byte slices
///
-/// This iterator is created via the [`gen_iter`] method on [`Rng`].
+/// This is used by the [`fill`] and [`try_fill`] methods.
///
-/// [`gen_iter`]: trait.Rng.html#method.gen_iter
-/// [`Rng`]: trait.Rng.html
-#[derive(Debug)]
-pub struct Generator<'a, T, R:'a> {
- rng: &'a mut R,
- _marker: marker::PhantomData<fn() -> T>,
-}
-
-impl<'a, T: Rand, R: Rng> Iterator for Generator<'a, T, R> {
- type Item = T;
+/// [`fill`]: trait.Rng.html#method.fill
+/// [`try_fill`]: trait.Rng.html#method.try_fill
+pub trait AsByteSliceMut {
+ /// Return a mutable reference to self as a byte slice
+ fn as_byte_slice_mut(&mut self) -> &mut [u8];
- fn next(&mut self) -> Option<T> {
- Some(self.rng.gen())
- }
-}
-
-/// Iterator which will continuously generate random ascii characters.
-///
-/// This iterator is created via the [`gen_ascii_chars`] method on [`Rng`].
-///
-/// [`gen_ascii_chars`]: trait.Rng.html#method.gen_ascii_chars
-/// [`Rng`]: trait.Rng.html
-#[derive(Debug)]
-pub struct AsciiGenerator<'a, R:'a> {
- rng: &'a mut R,
+ /// Call `to_le` on each element (i.e. byte-swap on Big Endian platforms).
+ fn to_le(&mut self);
}
-impl<'a, R: Rng> Iterator for AsciiGenerator<'a, R> {
- type Item = char;
-
- fn next(&mut self) -> Option<char> {
- const GEN_ASCII_STR_CHARSET: &'static [u8] =
- b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
- abcdefghijklmnopqrstuvwxyz\
- 0123456789";
- Some(*self.rng.choose(GEN_ASCII_STR_CHARSET).unwrap() as char)
+impl AsByteSliceMut for [u8] {
+ fn as_byte_slice_mut(&mut self) -> &mut [u8] {
+ self
}
-}
-/// A random number generator that can be explicitly seeded to produce
-/// the same stream of randomness multiple times.
-pub trait SeedableRng<Seed>: Rng {
- /// Reseed an RNG with the given seed.
- ///
- /// # Example
- ///
- /// ```rust
- /// use rand::{Rng, SeedableRng, StdRng};
- ///
- /// let seed: &[_] = &[1, 2, 3, 4];
- /// let mut rng: StdRng = SeedableRng::from_seed(seed);
- /// println!("{}", rng.gen::<f64>());
- /// rng.reseed(&[5, 6, 7, 8]);
- /// println!("{}", rng.gen::<f64>());
- /// ```
- fn reseed(&mut self, Seed);
-
- /// Create a new RNG with the given seed.
- ///
- /// # Example
- ///
- /// ```rust
- /// use rand::{Rng, SeedableRng, StdRng};
- ///
- /// let seed: &[_] = &[1, 2, 3, 4];
- /// let mut rng: StdRng = SeedableRng::from_seed(seed);
- /// println!("{}", rng.gen::<f64>());
- /// ```
- fn from_seed(seed: Seed) -> Self;
-}
-
-/// A wrapper for generating floating point numbers uniformly in the
-/// open interval `(0,1)` (not including either endpoint).
-///
-/// Use `Closed01` for the closed interval `[0,1]`, and the default
-/// `Rand` implementation for `f32` and `f64` for the half-open
-/// `[0,1)`.
-///
-/// # Example
-/// ```rust
-/// use rand::{random, Open01};
-///
-/// let Open01(val) = random::<Open01<f32>>();
-/// println!("f32 from (0,1): {}", val);
-/// ```
-#[derive(Debug)]
-pub struct Open01<F>(pub F);
-
-/// A wrapper for generating floating point numbers uniformly in the
-/// closed interval `[0,1]` (including both endpoints).
-///
-/// Use `Open01` for the closed interval `(0,1)`, and the default
-/// `Rand` implementation of `f32` and `f64` for the half-open
-/// `[0,1)`.
-///
-/// # Example
-///
-/// ```rust
-/// use rand::{random, Closed01};
-///
-/// let Closed01(val) = random::<Closed01<f32>>();
-/// println!("f32 from [0,1]: {}", val);
-/// ```
-#[derive(Debug)]
-pub struct Closed01<F>(pub F);
-
-/// The standard RNG. This is designed to be efficient on the current
-/// platform.
-#[derive(Copy, Clone, Debug)]
-pub struct StdRng {
- rng: IsaacWordRng,
+ fn to_le(&mut self) {}
}
-impl StdRng {
- /// Create a randomly seeded instance of `StdRng`.
- ///
- /// This is a very expensive operation as it has to read
- /// randomness from the operating system and use this in an
- /// expensive seeding operation. If one is only generating a small
- /// number of random numbers, or doesn't need the utmost speed for
- /// generating each number, `thread_rng` and/or `random` may be more
- /// appropriate.
- ///
- /// Reading the randomness from the OS may fail, and any error is
- /// propagated via the `io::Result` return value.
- #[cfg(feature="std")]
- pub fn new() -> io::Result<StdRng> {
- match OsRng::new() {
- Ok(mut r) => Ok(StdRng { rng: r.gen() }),
- Err(e1) => {
- match JitterRng::new() {
- Ok(mut r) => Ok(StdRng { rng: r.gen() }),
- Err(_) => {
- Err(e1)
+macro_rules! impl_as_byte_slice {
+ ($t:ty) => {
+ impl AsByteSliceMut for [$t] {
+ fn as_byte_slice_mut(&mut self) -> &mut [u8] {
+ if self.len() == 0 {
+ unsafe {
+ // must not use null pointer
+ slice::from_raw_parts_mut(0x1 as *mut u8, 0)
+ }
+ } else {
+ unsafe {
+ slice::from_raw_parts_mut(&mut self[0]
+ as *mut $t
+ as *mut u8,
+ self.len() * mem::size_of::<$t>()
+ )
}
}
}
- }
- }
-}
-impl Rng for StdRng {
- #[inline]
- fn next_u32(&mut self) -> u32 {
- self.rng.next_u32()
- }
-
- #[inline]
- fn next_u64(&mut self) -> u64 {
- self.rng.next_u64()
- }
-}
-
-impl<'a> SeedableRng<&'a [usize]> for StdRng {
- fn reseed(&mut self, seed: &'a [usize]) {
- // the internal RNG can just be seeded from the above
- // randomness.
- self.rng.reseed(unsafe {mem::transmute(seed)})
- }
-
- fn from_seed(seed: &'a [usize]) -> StdRng {
- StdRng { rng: SeedableRng::from_seed(unsafe {mem::transmute(seed)}) }
+ fn to_le(&mut self) {
+ for x in self {
+ *x = x.to_le();
+ }
+ }
+ }
}
}
-/// Create a weak random number generator with a default algorithm and seed.
-///
-/// It returns the fastest `Rng` algorithm currently available in Rust without
-/// consideration for cryptography or security. If you require a specifically
-/// seeded `Rng` for consistency over time you should pick one algorithm and
-/// create the `Rng` yourself.
-///
-/// This will seed the generator with randomness from thread_rng.
-#[cfg(feature="std")]
-pub fn weak_rng() -> XorShiftRng {
- thread_rng().gen()
-}
+impl_as_byte_slice!(u16);
+impl_as_byte_slice!(u32);
+impl_as_byte_slice!(u64);
+#[cfg(rust_1_26)] impl_as_byte_slice!(u128);
+impl_as_byte_slice!(usize);
+impl_as_byte_slice!(i8);
+impl_as_byte_slice!(i16);
+impl_as_byte_slice!(i32);
+impl_as_byte_slice!(i64);
+#[cfg(rust_1_26)] impl_as_byte_slice!(i128);
+impl_as_byte_slice!(isize);
+
+macro_rules! impl_as_byte_slice_arrays {
+ ($n:expr,) => {};
+ ($n:expr, $N:ident, $($NN:ident,)*) => {
+ impl_as_byte_slice_arrays!($n - 1, $($NN,)*);
+
+ impl<T> AsByteSliceMut for [T; $n] where [T]: AsByteSliceMut {
+ fn as_byte_slice_mut(&mut self) -> &mut [u8] {
+ self[..].as_byte_slice_mut()
+ }
-/// Controls how the thread-local RNG is reseeded.
-#[cfg(feature="std")]
-#[derive(Debug)]
-struct ThreadRngReseeder;
+ fn to_le(&mut self) {
+ self[..].to_le()
+ }
+ }
+ };
+ (!div $n:expr,) => {};
+ (!div $n:expr, $N:ident, $($NN:ident,)*) => {
+ impl_as_byte_slice_arrays!(!div $n / 2, $($NN,)*);
+
+ impl<T> AsByteSliceMut for [T; $n] where [T]: AsByteSliceMut {
+ fn as_byte_slice_mut(&mut self) -> &mut [u8] {
+ self[..].as_byte_slice_mut()
+ }
-#[cfg(feature="std")]
-impl reseeding::Reseeder<StdRng> for ThreadRngReseeder {
- fn reseed(&mut self, rng: &mut StdRng) {
- match StdRng::new() {
- Ok(r) => *rng = r,
- Err(e) => panic!("No entropy available: {}", e),
+ fn to_le(&mut self) {
+ self[..].to_le()
+ }
}
- }
+ };
}
-#[cfg(feature="std")]
-const THREAD_RNG_RESEED_THRESHOLD: u64 = 32_768;
-#[cfg(feature="std")]
-type ThreadRngInner = reseeding::ReseedingRng<StdRng, ThreadRngReseeder>;
+impl_as_byte_slice_arrays!(32, N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,);
+impl_as_byte_slice_arrays!(!div 4096, N,N,N,N,N,N,N,);
-/// The thread-local RNG.
-#[cfg(feature="std")]
-#[derive(Clone, Debug)]
-pub struct ThreadRng {
- rng: Rc<RefCell<ThreadRngInner>>,
-}
-/// Retrieve the lazily-initialized thread-local random number
-/// generator, seeded by the system. Intended to be used in method
-/// chaining style, e.g. `thread_rng().gen::<i32>()`.
+/// A convenience extension to [`SeedableRng`] allowing construction from fresh
+/// entropy. This trait is automatically implemented for any PRNG implementing
+/// [`SeedableRng`] and is not intended to be implemented by users.
+///
+/// This is equivalent to using `SeedableRng::from_rng(EntropyRng::new())` then
+/// unwrapping the result.
+///
+/// Since this is convenient and secure, it is the recommended way to create
+/// PRNGs, though two alternatives may be considered:
+///
+/// * Deterministic creation using [`SeedableRng::from_seed`] with a fixed seed
+/// * Seeding from `thread_rng`: `SeedableRng::from_rng(thread_rng())?`;
+/// this will usually be faster and should also be secure, but requires
+/// trusting one extra component.
///
-/// After generating a certain amount of randomness, the RNG will reseed itself
-/// from the operating system or, if the operating system RNG returns an error,
-/// a seed based on the current system time.
+/// ## Example
///
-/// The internal RNG used is platform and architecture dependent, even
-/// if the operating system random number generator is rigged to give
-/// the same sequence always. If absolute consistency is required,
-/// explicitly select an RNG, e.g. `IsaacRng` or `Isaac64Rng`.
+/// ```
+/// use rand::{Rng, FromEntropy};
+/// use rand::rngs::StdRng;
+///
+/// let mut rng = StdRng::from_entropy();
+/// println!("Random die roll: {}", rng.gen_range(1, 7));
+/// ```
+///
+/// [`EntropyRng`]: rngs/struct.EntropyRng.html
+/// [`SeedableRng`]: trait.SeedableRng.html
+/// [`SeedableRng::from_seed`]: trait.SeedableRng.html#tymethod.from_seed
#[cfg(feature="std")]
-pub fn thread_rng() -> ThreadRng {
- // used to make space in TLS for a random number generator
- thread_local!(static THREAD_RNG_KEY: Rc<RefCell<ThreadRngInner>> = {
- let r = match StdRng::new() {
- Ok(r) => r,
- Err(e) => panic!("No entropy available: {}", e),
- };
- let rng = reseeding::ReseedingRng::new(r,
- THREAD_RNG_RESEED_THRESHOLD,
- ThreadRngReseeder);
- Rc::new(RefCell::new(rng))
- });
-
- ThreadRng { rng: THREAD_RNG_KEY.with(|t| t.clone()) }
+pub trait FromEntropy: SeedableRng {
+ /// Creates a new instance, automatically seeded with fresh entropy.
+ ///
+ /// Normally this will use `OsRng`, but if that fails `JitterRng` will be
+ /// used instead. Both should be suitable for cryptography. It is possible
+ /// that both entropy sources will fail though unlikely; failures would
+ /// almost certainly be platform limitations or build issues, i.e. most
+ /// applications targetting PC/mobile platforms should not need to worry
+ /// about this failing.
+ ///
+ /// # Panics
+ ///
+ /// If all entropy sources fail this will panic. If you need to handle
+ /// errors, use the following code, equivalent aside from error handling:
+ ///
+ /// ```
+ /// # use rand::Error;
+ /// use rand::prelude::*;
+ /// use rand::rngs::EntropyRng;
+ ///
+ /// # fn try_inner() -> Result<(), Error> {
+ /// // This uses StdRng, but is valid for any R: SeedableRng
+ /// let mut rng = StdRng::from_rng(EntropyRng::new())?;
+ ///
+ /// println!("random number: {}", rng.gen_range(1, 10));
+ /// # Ok(())
+ /// # }
+ ///
+ /// # try_inner().unwrap()
+ /// ```
+ fn from_entropy() -> Self;
}
#[cfg(feature="std")]
-impl Rng for ThreadRng {
- fn next_u32(&mut self) -> u32 {
- self.rng.borrow_mut().next_u32()
- }
-
- fn next_u64(&mut self) -> u64 {
- self.rng.borrow_mut().next_u64()
- }
-
- #[inline]
- fn fill_bytes(&mut self, bytes: &mut [u8]) {
- self.rng.borrow_mut().fill_bytes(bytes)
+impl<R: SeedableRng> FromEntropy for R {
+ fn from_entropy() -> R {
+ R::from_rng(rngs::EntropyRng::new()).unwrap_or_else(|err|
+ panic!("FromEntropy::from_entropy() failed: {}", err))
}
}
+
/// Generates a random value using the thread-local random number generator.
///
-/// `random()` can generate various types of random things, and so may require
-/// type hinting to generate the specific type you want.
-///
-/// This function uses the thread local random number generator. This means
-/// that if you're calling `random()` in a loop, caching the generator can
-/// increase performance. An example is shown below.
+/// This is simply a shortcut for `thread_rng().gen()`. See [`thread_rng`] for
+/// documentation of the entropy source and [`Standard`] for documentation of
+/// distributions and type-specific generation.
///
/// # Examples
///
@@ -931,7 +683,8 @@ impl Rng for ThreadRng {
/// }
/// ```
///
-/// Caching the thread local random number generator:
+/// If you're calling `random()` in a loop, caching the generator as in the
+/// following example can increase performance.
///
/// ```
/// use rand::Rng;
@@ -950,93 +703,109 @@ impl Rng for ThreadRng {
/// *x = rng.gen();
/// }
/// ```
+///
+/// [`thread_rng`]: fn.thread_rng.html
+/// [`Standard`]: distributions/struct.Standard.html
#[cfg(feature="std")]
#[inline]
-pub fn random<T: Rand>() -> T {
+pub fn random<T>() -> T where Standard: Distribution<T> {
thread_rng().gen()
}
-/// DEPRECATED: use `seq::sample_iter` instead.
-///
-/// Randomly sample up to `amount` elements from a finite iterator.
-/// The order of elements in the sample is not random.
-///
-/// # Example
-///
-/// ```rust
-/// use rand::{thread_rng, sample};
-///
-/// let mut rng = thread_rng();
-/// let sample = sample(&mut rng, 1..100, 5);
-/// println!("{:?}", sample);
-/// ```
-#[cfg(feature="std")]
-#[inline(always)]
-#[deprecated(since="0.4.0", note="renamed to seq::sample_iter")]
-pub fn sample<T, I, R>(rng: &mut R, iterable: I, amount: usize) -> Vec<T>
- where I: IntoIterator<Item=T>,
- R: Rng,
-{
- // the legacy sample didn't care whether amount was met
- seq::sample_iter(rng, iterable, amount)
- .unwrap_or_else(|e| e)
+// Due to rustwasm/wasm-bindgen#201 this can't be defined in the inner os
+// modules, so hack around it for now and place it at the root.
+#[cfg(all(feature = "wasm-bindgen", target_arch = "wasm32"))]
+#[doc(hidden)]
+#[allow(missing_debug_implementations)]
+pub mod __wbg_shims {
+
+ // `extern { type Foo; }` isn't supported on 1.22 syntactically, so use a
+ // macro to work around that.
+ macro_rules! rust_122_compat {
+ ($($t:tt)*) => ($($t)*)
+ }
+
+ rust_122_compat! {
+ extern crate wasm_bindgen;
+
+ pub use wasm_bindgen::prelude::*;
+
+ #[wasm_bindgen]
+ extern "C" {
+ pub type Function;
+ #[wasm_bindgen(constructor)]
+ pub fn new(s: &str) -> Function;
+ #[wasm_bindgen(method)]
+ pub fn call(this: &Function, self_: &JsValue) -> JsValue;
+
+ pub type This;
+ #[wasm_bindgen(method, getter, structural, js_name = self)]
+ pub fn self_(me: &This) -> JsValue;
+ #[wasm_bindgen(method, getter, structural)]
+ pub fn crypto(me: &This) -> JsValue;
+
+ #[derive(Clone, Debug)]
+ pub type BrowserCrypto;
+
+ // TODO: these `structural` annotations here ideally wouldn't be here to
+ // avoid a JS shim, but for now with feature detection they're
+ // unavoidable.
+ #[wasm_bindgen(method, js_name = getRandomValues, structural, getter)]
+ pub fn get_random_values_fn(me: &BrowserCrypto) -> JsValue;
+ #[wasm_bindgen(method, js_name = getRandomValues, structural)]
+ pub fn get_random_values(me: &BrowserCrypto, buf: &mut [u8]);
+
+ #[wasm_bindgen(js_name = require)]
+ pub fn node_require(s: &str) -> NodeCrypto;
+
+ #[derive(Clone, Debug)]
+ pub type NodeCrypto;
+
+ #[wasm_bindgen(method, js_name = randomFillSync, structural)]
+ pub fn random_fill_sync(me: &NodeCrypto, buf: &mut [u8]);
+ }
+ }
}
#[cfg(test)]
mod test {
- use super::{Rng, thread_rng, random, SeedableRng, StdRng, weak_rng};
- use std::iter::repeat;
+ use rngs::mock::StepRng;
+ use rngs::StdRng;
+ use super::*;
+ #[cfg(all(not(feature="std"), feature="alloc"))] use alloc::boxed::Box;
- pub struct MyRng<R> { inner: R }
+ pub struct TestRng<R> { inner: R }
- impl<R: Rng> Rng for MyRng<R> {
+ impl<R: RngCore> RngCore for TestRng<R> {
fn next_u32(&mut self) -> u32 {
- fn next<T: Rng>(t: &mut T) -> u32 {
- t.next_u32()
- }
- next(&mut self.inner)
+ self.inner.next_u32()
+ }
+ fn next_u64(&mut self) -> u64 {
+ self.inner.next_u64()
+ }
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
+ self.inner.fill_bytes(dest)
+ }
+ fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ self.inner.try_fill_bytes(dest)
}
}
- pub fn rng() -> MyRng<::ThreadRng> {
- MyRng { inner: ::thread_rng() }
- }
-
- struct ConstRng { i: u64 }
- impl Rng for ConstRng {
- fn next_u32(&mut self) -> u32 { self.i as u32 }
- fn next_u64(&mut self) -> u64 { self.i }
-
- // no fill_bytes on purpose
- }
-
- pub fn iter_eq<I, J>(i: I, j: J) -> bool
- where I: IntoIterator,
- J: IntoIterator<Item=I::Item>,
- I::Item: Eq
- {
- // make sure the iterators have equal length
- let mut i = i.into_iter();
- let mut j = j.into_iter();
- loop {
- match (i.next(), j.next()) {
- (Some(ref ei), Some(ref ej)) if ei == ej => { }
- (None, None) => return true,
- _ => return false,
- }
- }
+ pub fn rng(seed: u64) -> TestRng<StdRng> {
+ TestRng { inner: StdRng::seed_from_u64(seed) }
}
#[test]
fn test_fill_bytes_default() {
- let mut r = ConstRng { i: 0x11_22_33_44_55_66_77_88 };
+ let mut r = StepRng::new(0x11_22_33_44_55_66_77_88, 0);
// check every remainder mod 8, both in small and big vectors.
let lengths = [0, 1, 2, 3, 4, 5, 6, 7,
80, 81, 82, 83, 84, 85, 86, 87];
for &n in lengths.iter() {
- let mut v = repeat(0u8).take(n).collect::<Vec<_>>();
- r.fill_bytes(&mut v);
+ let mut buffer = [0u8; 87];
+ let v = &mut buffer[0..n];
+ r.fill_bytes(v);
// use this to get nicer error messages.
for (i, &byte) in v.iter().enumerate() {
@@ -1048,127 +817,100 @@ mod test {
}
#[test]
- fn test_gen_range() {
- let mut r = thread_rng();
- for _ in 0..1000 {
- let a = r.gen_range(-3, 42);
- assert!(a >= -3 && a < 42);
- assert_eq!(r.gen_range(0, 1), 0);
- assert_eq!(r.gen_range(-12, -11), -12);
- }
+ fn test_fill() {
+ let x = 9041086907909331047; // a random u64
+ let mut rng = StepRng::new(x, 0);
+
+ // Convert to byte sequence and back to u64; byte-swap twice if BE.
+ let mut array = [0u64; 2];
+ rng.fill(&mut array[..]);
+ assert_eq!(array, [x, x]);
+ assert_eq!(rng.next_u64(), x);
+ // Convert to bytes then u32 in LE order
+ let mut array = [0u32; 2];
+ rng.fill(&mut array[..]);
+ assert_eq!(array, [x as u32, (x >> 32) as u32]);
+ assert_eq!(rng.next_u32(), x as u32);
+ }
+
+ #[test]
+ fn test_fill_empty() {
+ let mut array = [0u32; 0];
+ let mut rng = StepRng::new(0, 1);
+ rng.fill(&mut array);
+ rng.fill(&mut array[..]);
+ }
+
+ #[test]
+ fn test_gen_range() {
+ let mut r = rng(101);
for _ in 0..1000 {
- let a = r.gen_range(10, 42);
- assert!(a >= 10 && a < 42);
- assert_eq!(r.gen_range(0, 1), 0);
+ let a = r.gen_range(-4711, 17);
+ assert!(a >= -4711 && a < 17);
+ let a = r.gen_range(-3i8, 42);
+ assert!(a >= -3i8 && a < 42i8);
+ let a = r.gen_range(&10u16, 99);
+ assert!(a >= 10u16 && a < 99u16);
+ let a = r.gen_range(-100i32, &2000);
+ assert!(a >= -100i32 && a < 2000i32);
+ let a = r.gen_range(&12u32, &24u32);
+ assert!(a >= 12u32 && a < 24u32);
+
+ assert_eq!(r.gen_range(0u32, 1), 0u32);
+ assert_eq!(r.gen_range(-12i64, -11), -12i64);
assert_eq!(r.gen_range(3_000_000, 3_000_001), 3_000_000);
}
-
}
#[test]
#[should_panic]
fn test_gen_range_panic_int() {
- let mut r = thread_rng();
+ let mut r = rng(102);
r.gen_range(5, -2);
}
#[test]
#[should_panic]
fn test_gen_range_panic_usize() {
- let mut r = thread_rng();
+ let mut r = rng(103);
r.gen_range(5, 2);
}
#[test]
- fn test_gen_weighted_bool() {
- let mut r = thread_rng();
- assert_eq!(r.gen_weighted_bool(0), true);
- assert_eq!(r.gen_weighted_bool(1), true);
- }
-
- #[test]
- fn test_gen_ascii_str() {
- let mut r = thread_rng();
- assert_eq!(r.gen_ascii_chars().take(0).count(), 0);
- assert_eq!(r.gen_ascii_chars().take(10).count(), 10);
- assert_eq!(r.gen_ascii_chars().take(16).count(), 16);
- }
-
- #[test]
- fn test_gen_vec() {
- let mut r = thread_rng();
- assert_eq!(r.gen_iter::<u8>().take(0).count(), 0);
- assert_eq!(r.gen_iter::<u8>().take(10).count(), 10);
- assert_eq!(r.gen_iter::<f64>().take(16).count(), 16);
- }
-
- #[test]
- fn test_choose() {
- let mut r = thread_rng();
- assert_eq!(r.choose(&[1, 1, 1]).map(|&x|x), Some(1));
-
- let v: &[isize] = &[];
- assert_eq!(r.choose(v), None);
- }
-
- #[test]
- fn test_shuffle() {
- let mut r = thread_rng();
- let empty: &mut [isize] = &mut [];
- r.shuffle(empty);
- let mut one = [1];
- r.shuffle(&mut one);
- let b: &[_] = &[1];
- assert_eq!(one, b);
-
- let mut two = [1, 2];
- r.shuffle(&mut two);
- assert!(two == [1, 2] || two == [2, 1]);
-
- let mut x = [1, 1, 1];
- r.shuffle(&mut x);
- let b: &[_] = &[1, 1, 1];
- assert_eq!(x, b);
+ fn test_gen_bool() {
+ let mut r = rng(105);
+ for _ in 0..5 {
+ assert_eq!(r.gen_bool(0.0), false);
+ assert_eq!(r.gen_bool(1.0), true);
+ }
}
#[test]
- fn test_thread_rng() {
- let mut r = thread_rng();
+ fn test_rng_trait_object() {
+ use distributions::{Distribution, Standard};
+ let mut rng = rng(109);
+ let mut r = &mut rng as &mut RngCore;
+ r.next_u32();
r.gen::<i32>();
- let mut v = [1, 1, 1];
- r.shuffle(&mut v);
- let b: &[_] = &[1, 1, 1];
- assert_eq!(v, b);
assert_eq!(r.gen_range(0, 1), 0);
+ let _c: u8 = Standard.sample(&mut r);
}
#[test]
- fn test_rng_trait_object() {
- let mut rng = thread_rng();
- {
- let mut r = &mut rng as &mut Rng;
- r.next_u32();
- (&mut r).gen::<i32>();
- let mut v = [1, 1, 1];
- (&mut r).shuffle(&mut v);
- let b: &[_] = &[1, 1, 1];
- assert_eq!(v, b);
- assert_eq!((&mut r).gen_range(0, 1), 0);
- }
- {
- let mut r = Box::new(rng) as Box<Rng>;
- r.next_u32();
- r.gen::<i32>();
- let mut v = [1, 1, 1];
- r.shuffle(&mut v);
- let b: &[_] = &[1, 1, 1];
- assert_eq!(v, b);
- assert_eq!(r.gen_range(0, 1), 0);
- }
+ #[cfg(feature="alloc")]
+ fn test_rng_boxed_trait() {
+ use distributions::{Distribution, Standard};
+ let rng = rng(110);
+ let mut r = Box::new(rng) as Box<RngCore>;
+ r.next_u32();
+ r.gen::<i32>();
+ assert_eq!(r.gen_range(0, 1), 0);
+ let _c: u8 = Standard.sample(&mut r);
}
#[test]
+ #[cfg(feature="std")]
fn test_random() {
// not sure how to test this aside from just getting some values
let _n : usize = random();
@@ -1183,32 +925,20 @@ mod test {
}
#[test]
- fn test_std_rng_seeded() {
- let s = thread_rng().gen_iter::<usize>().take(256).collect::<Vec<usize>>();
- let mut ra: StdRng = SeedableRng::from_seed(&s[..]);
- let mut rb: StdRng = SeedableRng::from_seed(&s[..]);
- assert!(iter_eq(ra.gen_ascii_chars().take(100),
- rb.gen_ascii_chars().take(100)));
- }
-
- #[test]
- fn test_std_rng_reseed() {
- let s = thread_rng().gen_iter::<usize>().take(256).collect::<Vec<usize>>();
- let mut r: StdRng = SeedableRng::from_seed(&s[..]);
- let string1 = r.gen_ascii_chars().take(100).collect::<String>();
-
- r.reseed(&s);
-
- let string2 = r.gen_ascii_chars().take(100).collect::<String>();
- assert_eq!(string1, string2);
- }
-
- #[test]
- fn test_weak_rng() {
- let s = weak_rng().gen_iter::<usize>().take(256).collect::<Vec<usize>>();
- let mut ra: StdRng = SeedableRng::from_seed(&s[..]);
- let mut rb: StdRng = SeedableRng::from_seed(&s[..]);
- assert!(iter_eq(ra.gen_ascii_chars().take(100),
- rb.gen_ascii_chars().take(100)));
+ fn test_gen_ratio_average() {
+ const NUM: u32 = 3;
+ const DENOM: u32 = 10;
+ const N: u32 = 100_000;
+
+ let mut sum: u32 = 0;
+ let mut rng = rng(111);
+ for _ in 0..N {
+ if rng.gen_ratio(NUM, DENOM) {
+ sum += 1;
+ }
+ }
+ // Have Binomial(N, NUM/DENOM) distribution
+ let expected = (NUM * N) / DENOM; // exact integer
+ assert!(((sum - expected) as i32).abs() < 500);
}
}
diff --git a/rand/src/os.rs b/rand/src/os.rs
deleted file mode 100644
index 10022fb..0000000
--- a/rand/src/os.rs
+++ /dev/null
@@ -1,617 +0,0 @@
-// Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Interfaces to the operating system provided random number
-//! generators.
-
-use std::{io, mem, fmt};
-use Rng;
-
-/// A random number generator that retrieves randomness straight from
-/// the operating system. Platform sources:
-///
-/// - Unix-like systems (Linux, Android, Mac OSX): read directly from
-/// `/dev/urandom`, or from `getrandom(2)` system call if available.
-/// - OpenBSD: calls `getentropy(2)`
-/// - FreeBSD: uses the `kern.arandom` `sysctl(2)` mib
-/// - Windows: calls `RtlGenRandom`, exported from `advapi32.dll` as
-/// `SystemFunction036`.
-/// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
-/// - PNaCl: calls into the `nacl-irt-random-0.1` IRT interface.
-///
-/// This usually does not block. On some systems (e.g. FreeBSD, OpenBSD,
-/// Max OS X, and modern Linux) this may block very early in the init
-/// process, if the CSPRNG has not been seeded yet.[1]
-///
-/// [1] See <https://www.python.org/dev/peps/pep-0524/> for a more
-/// in-depth discussion.
-pub struct OsRng(imp::OsRng);
-
-impl OsRng {
- /// Create a new `OsRng`.
- pub fn new() -> io::Result<OsRng> {
- imp::OsRng::new().map(OsRng)
- }
-}
-
-impl Rng for OsRng {
- fn next_u32(&mut self) -> u32 { self.0.next_u32() }
- fn next_u64(&mut self) -> u64 { self.0.next_u64() }
- fn fill_bytes(&mut self, v: &mut [u8]) { self.0.fill_bytes(v) }
-}
-
-impl fmt::Debug for OsRng {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "OsRng {{}}")
- }
-}
-
-fn next_u32(fill_buf: &mut FnMut(&mut [u8])) -> u32 {
- let mut buf: [u8; 4] = [0; 4];
- fill_buf(&mut buf);
- unsafe { mem::transmute::<[u8; 4], u32>(buf) }
-}
-
-fn next_u64(fill_buf: &mut FnMut(&mut [u8])) -> u64 {
- let mut buf: [u8; 8] = [0; 8];
- fill_buf(&mut buf);
- unsafe { mem::transmute::<[u8; 8], u64>(buf) }
-}
-
-#[cfg(all(unix, not(target_os = "ios"),
- not(target_os = "nacl"),
- not(target_os = "freebsd"),
- not(target_os = "fuchsia"),
- not(target_os = "openbsd"),
- not(target_os = "redox")))]
-mod imp {
- extern crate libc;
-
- use super::{next_u32, next_u64};
- use self::OsRngInner::*;
-
- use std::io;
- use std::fs::File;
- use Rng;
- use read::ReadRng;
-
- #[cfg(all(target_os = "linux",
- any(target_arch = "x86_64",
- target_arch = "x86",
- target_arch = "arm",
- target_arch = "aarch64",
- target_arch = "powerpc")))]
- fn getrandom(buf: &mut [u8]) -> libc::c_long {
- extern "C" {
- fn syscall(number: libc::c_long, ...) -> libc::c_long;
- }
-
- #[cfg(target_arch = "x86_64")]
- const NR_GETRANDOM: libc::c_long = 318;
- #[cfg(target_arch = "x86")]
- const NR_GETRANDOM: libc::c_long = 355;
- #[cfg(target_arch = "arm")]
- const NR_GETRANDOM: libc::c_long = 384;
- #[cfg(target_arch = "aarch64")]
- const NR_GETRANDOM: libc::c_long = 278;
- #[cfg(target_arch = "powerpc")]
- const NR_GETRANDOM: libc::c_long = 359;
-
- unsafe {
- syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), 0)
- }
- }
-
- #[cfg(not(all(target_os = "linux",
- any(target_arch = "x86_64",
- target_arch = "x86",
- target_arch = "arm",
- target_arch = "aarch64",
- target_arch = "powerpc"))))]
- fn getrandom(_buf: &mut [u8]) -> libc::c_long { -1 }
-
- fn getrandom_fill_bytes(v: &mut [u8]) {
- let mut read = 0;
- let len = v.len();
- while read < len {
- let result = getrandom(&mut v[read..]);
- if result == -1 {
- let err = io::Error::last_os_error();
- if err.kind() == io::ErrorKind::Interrupted {
- continue
- } else {
- panic!("unexpected getrandom error: {}", err);
- }
- } else {
- read += result as usize;
- }
- }
- }
-
- #[cfg(all(target_os = "linux",
- any(target_arch = "x86_64",
- target_arch = "x86",
- target_arch = "arm",
- target_arch = "aarch64",
- target_arch = "powerpc")))]
- fn is_getrandom_available() -> bool {
- use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};
- use std::sync::{Once, ONCE_INIT};
-
- static CHECKER: Once = ONCE_INIT;
- static AVAILABLE: AtomicBool = ATOMIC_BOOL_INIT;
-
- CHECKER.call_once(|| {
- let mut buf: [u8; 0] = [];
- let result = getrandom(&mut buf);
- let available = if result == -1 {
- let err = io::Error::last_os_error().raw_os_error();
- err != Some(libc::ENOSYS)
- } else {
- true
- };
- AVAILABLE.store(available, Ordering::Relaxed);
- });
-
- AVAILABLE.load(Ordering::Relaxed)
- }
-
- #[cfg(not(all(target_os = "linux",
- any(target_arch = "x86_64",
- target_arch = "x86",
- target_arch = "arm",
- target_arch = "aarch64",
- target_arch = "powerpc"))))]
- fn is_getrandom_available() -> bool { false }
-
- pub struct OsRng {
- inner: OsRngInner,
- }
-
- enum OsRngInner {
- OsGetrandomRng,
- OsReadRng(ReadRng<File>),
- }
-
- impl OsRng {
- pub fn new() -> io::Result<OsRng> {
- if is_getrandom_available() {
- return Ok(OsRng { inner: OsGetrandomRng });
- }
-
- let reader = try!(File::open("/dev/urandom"));
- let reader_rng = ReadRng::new(reader);
-
- Ok(OsRng { inner: OsReadRng(reader_rng) })
- }
- }
-
- impl Rng for OsRng {
- fn next_u32(&mut self) -> u32 {
- match self.inner {
- OsGetrandomRng => next_u32(&mut getrandom_fill_bytes),
- OsReadRng(ref mut rng) => rng.next_u32(),
- }
- }
- fn next_u64(&mut self) -> u64 {
- match self.inner {
- OsGetrandomRng => next_u64(&mut getrandom_fill_bytes),
- OsReadRng(ref mut rng) => rng.next_u64(),
- }
- }
- fn fill_bytes(&mut self, v: &mut [u8]) {
- match self.inner {
- OsGetrandomRng => getrandom_fill_bytes(v),
- OsReadRng(ref mut rng) => rng.fill_bytes(v)
- }
- }
- }
-}
-
-#[cfg(target_os = "ios")]
-mod imp {
- extern crate libc;
-
- use super::{next_u32, next_u64};
-
- use std::io;
- use Rng;
- use self::libc::{c_int, size_t};
-
- #[derive(Debug)]
- pub struct OsRng;
-
- enum SecRandom {}
-
- #[allow(non_upper_case_globals)]
- const kSecRandomDefault: *const SecRandom = 0 as *const SecRandom;
-
- #[link(name = "Security", kind = "framework")]
- extern {
- fn SecRandomCopyBytes(rnd: *const SecRandom,
- count: size_t, bytes: *mut u8) -> c_int;
- }
-
- impl OsRng {
- pub fn new() -> io::Result<OsRng> {
- Ok(OsRng)
- }
- }
-
- impl Rng for OsRng {
- fn next_u32(&mut self) -> u32 {
- next_u32(&mut |v| self.fill_bytes(v))
- }
- fn next_u64(&mut self) -> u64 {
- next_u64(&mut |v| self.fill_bytes(v))
- }
- fn fill_bytes(&mut self, v: &mut [u8]) {
- let ret = unsafe {
- SecRandomCopyBytes(kSecRandomDefault, v.len() as size_t, v.as_mut_ptr())
- };
- if ret == -1 {
- panic!("couldn't generate random bytes: {}", io::Error::last_os_error());
- }
- }
- }
-}
-
-#[cfg(target_os = "freebsd")]
-mod imp {
- extern crate libc;
-
- use std::{io, ptr};
- use Rng;
-
- use super::{next_u32, next_u64};
-
- #[derive(Debug)]
- pub struct OsRng;
-
- impl OsRng {
- pub fn new() -> io::Result<OsRng> {
- Ok(OsRng)
- }
- }
-
- impl Rng for OsRng {
- fn next_u32(&mut self) -> u32 {
- next_u32(&mut |v| self.fill_bytes(v))
- }
- fn next_u64(&mut self) -> u64 {
- next_u64(&mut |v| self.fill_bytes(v))
- }
- fn fill_bytes(&mut self, v: &mut [u8]) {
- let mib = [libc::CTL_KERN, libc::KERN_ARND];
- // kern.arandom permits a maximum buffer size of 256 bytes
- for s in v.chunks_mut(256) {
- let mut s_len = s.len();
- let ret = unsafe {
- libc::sysctl(mib.as_ptr(), mib.len() as libc::c_uint,
- s.as_mut_ptr() as *mut _, &mut s_len,
- ptr::null(), 0)
- };
- if ret == -1 || s_len != s.len() {
- panic!("kern.arandom sysctl failed! (returned {}, s.len() {}, oldlenp {})",
- ret, s.len(), s_len);
- }
- }
- }
- }
-}
-
-#[cfg(target_os = "openbsd")]
-mod imp {
- extern crate libc;
-
- use std::io;
- use Rng;
-
- use super::{next_u32, next_u64};
-
- #[derive(Debug)]
- pub struct OsRng;
-
- impl OsRng {
- pub fn new() -> io::Result<OsRng> {
- Ok(OsRng)
- }
- }
-
- impl Rng for OsRng {
- fn next_u32(&mut self) -> u32 {
- next_u32(&mut |v| self.fill_bytes(v))
- }
- fn next_u64(&mut self) -> u64 {
- next_u64(&mut |v| self.fill_bytes(v))
- }
- fn fill_bytes(&mut self, v: &mut [u8]) {
- // getentropy(2) permits a maximum buffer size of 256 bytes
- for s in v.chunks_mut(256) {
- let ret = unsafe {
- libc::getentropy(s.as_mut_ptr() as *mut libc::c_void, s.len())
- };
- if ret == -1 {
- let err = io::Error::last_os_error();
- panic!("getentropy failed: {}", err);
- }
- }
- }
- }
-}
-
-#[cfg(target_os = "redox")]
-mod imp {
- use std::io;
- use std::fs::File;
- use Rng;
- use read::ReadRng;
-
- #[derive(Debug)]
- pub struct OsRng {
- inner: ReadRng<File>,
- }
-
- impl OsRng {
- pub fn new() -> io::Result<OsRng> {
- let reader = try!(File::open("rand:"));
- let reader_rng = ReadRng::new(reader);
-
- Ok(OsRng { inner: reader_rng })
- }
- }
-
- impl Rng for OsRng {
- fn next_u32(&mut self) -> u32 {
- self.inner.next_u32()
- }
- fn next_u64(&mut self) -> u64 {
- self.inner.next_u64()
- }
- fn fill_bytes(&mut self, v: &mut [u8]) {
- self.inner.fill_bytes(v)
- }
- }
-}
-
-#[cfg(target_os = "fuchsia")]
-mod imp {
- extern crate fuchsia_zircon;
-
- use std::io;
- use Rng;
-
- use super::{next_u32, next_u64};
-
- #[derive(Debug)]
- pub struct OsRng;
-
- impl OsRng {
- pub fn new() -> io::Result<OsRng> {
- Ok(OsRng)
- }
- }
-
- impl Rng for OsRng {
- fn next_u32(&mut self) -> u32 {
- next_u32(&mut |v| self.fill_bytes(v))
- }
- fn next_u64(&mut self) -> u64 {
- next_u64(&mut |v| self.fill_bytes(v))
- }
- fn fill_bytes(&mut self, v: &mut [u8]) {
- for s in v.chunks_mut(fuchsia_zircon::sys::ZX_CPRNG_DRAW_MAX_LEN) {
- let mut filled = 0;
- while filled < s.len() {
- match fuchsia_zircon::cprng_draw(&mut s[filled..]) {
- Ok(actual) => filled += actual,
- Err(e) => panic!("cprng_draw failed: {:?}", e),
- };
- }
- }
- }
- }
-}
-
-#[cfg(windows)]
-mod imp {
- extern crate winapi;
-
- use std::io;
- use Rng;
-
- use super::{next_u32, next_u64};
-
- use self::winapi::shared::minwindef::ULONG;
- use self::winapi::um::ntsecapi::RtlGenRandom;
- use self::winapi::um::winnt::PVOID;
-
- #[derive(Debug)]
- pub struct OsRng;
-
- impl OsRng {
- pub fn new() -> io::Result<OsRng> {
- Ok(OsRng)
- }
- }
-
- impl Rng for OsRng {
- fn next_u32(&mut self) -> u32 {
- next_u32(&mut |v| self.fill_bytes(v))
- }
- fn next_u64(&mut self) -> u64 {
- next_u64(&mut |v| self.fill_bytes(v))
- }
- fn fill_bytes(&mut self, v: &mut [u8]) {
- // RtlGenRandom takes an ULONG (u32) for the length so we need to
- // split up the buffer.
- for slice in v.chunks_mut(<ULONG>::max_value() as usize) {
- let ret = unsafe {
- RtlGenRandom(slice.as_mut_ptr() as PVOID, slice.len() as ULONG)
- };
- if ret == 0 {
- panic!("couldn't generate random bytes: {}",
- io::Error::last_os_error());
- }
- }
- }
- }
-}
-
-#[cfg(target_os = "nacl")]
-mod imp {
- extern crate libc;
-
- use std::io;
- use std::mem;
- use Rng;
-
- use super::{next_u32, next_u64};
-
- #[derive(Debug)]
- pub struct OsRng(extern fn(dest: *mut libc::c_void,
- bytes: libc::size_t,
- read: *mut libc::size_t) -> libc::c_int);
-
- extern {
- fn nacl_interface_query(name: *const libc::c_char,
- table: *mut libc::c_void,
- table_size: libc::size_t) -> libc::size_t;
- }
-
- const INTERFACE: &'static [u8] = b"nacl-irt-random-0.1\0";
-
- #[repr(C)]
- struct NaClIRTRandom {
- get_random_bytes: Option<extern fn(dest: *mut libc::c_void,
- bytes: libc::size_t,
- read: *mut libc::size_t) -> libc::c_int>,
- }
-
- impl OsRng {
- pub fn new() -> io::Result<OsRng> {
- let mut iface = NaClIRTRandom {
- get_random_bytes: None,
- };
- let result = unsafe {
- nacl_interface_query(INTERFACE.as_ptr() as *const _,
- mem::transmute(&mut iface),
- mem::size_of::<NaClIRTRandom>() as libc::size_t)
- };
- if result != 0 {
- assert!(iface.get_random_bytes.is_some());
- let result = OsRng(iface.get_random_bytes.take().unwrap());
- Ok(result)
- } else {
- let error = io::ErrorKind::NotFound;
- let error = io::Error::new(error, "IRT random interface missing");
- Err(error)
- }
- }
- }
-
- impl Rng for OsRng {
- fn next_u32(&mut self) -> u32 {
- next_u32(&mut |v| self.fill_bytes(v))
- }
- fn next_u64(&mut self) -> u64 {
- next_u64(&mut |v| self.fill_bytes(v))
- }
- fn fill_bytes(&mut self, v: &mut [u8]) {
- let mut read = 0;
- loop {
- let mut r: libc::size_t = 0;
- let len = v.len();
- let error = (self.0)(v[read..].as_mut_ptr() as *mut _,
- (len - read) as libc::size_t,
- &mut r as *mut _);
- assert!(error == 0, "`get_random_bytes` failed!");
- read += r as usize;
-
- if read >= v.len() { break; }
- }
- }
- }
-}
-
-#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
-mod imp {
- use std::io;
- use Rng;
-
- #[derive(Debug)]
- pub struct OsRng;
-
- impl OsRng {
- pub fn new() -> io::Result<OsRng> {
- Err(io::Error::new(io::ErrorKind::Other, "Not supported"))
- }
- }
-
- impl Rng for OsRng {
- fn next_u32(&mut self) -> u32 {
- panic!("Not supported")
- }
- }
-}
-
-#[cfg(test)]
-mod test {
- use std::sync::mpsc::channel;
- use Rng;
- use OsRng;
- use std::thread;
-
- #[test]
- fn test_os_rng() {
- let mut r = OsRng::new().unwrap();
-
- r.next_u32();
- r.next_u64();
-
- let mut v = [0u8; 1000];
- r.fill_bytes(&mut v);
- }
-
- #[test]
- fn test_os_rng_tasks() {
-
- let mut txs = vec!();
- for _ in 0..20 {
- let (tx, rx) = channel();
- txs.push(tx);
-
- thread::spawn(move|| {
- // wait until all the tasks are ready to go.
- rx.recv().unwrap();
-
- // deschedule to attempt to interleave things as much
- // as possible (XXX: is this a good test?)
- let mut r = OsRng::new().unwrap();
- thread::yield_now();
- let mut v = [0u8; 1000];
-
- for _ in 0..100 {
- r.next_u32();
- thread::yield_now();
- r.next_u64();
- thread::yield_now();
- r.fill_bytes(&mut v);
- thread::yield_now();
- }
- });
- }
-
- // start all the tasks
- for tx in txs.iter() {
- tx.send(()).unwrap();
- }
- }
-}
diff --git a/rand/src/prelude.rs b/rand/src/prelude.rs
new file mode 100644
index 0000000..5d8a0e9
--- /dev/null
+++ b/rand/src/prelude.rs
@@ -0,0 +1,27 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Convenience re-export of common members
+//!
+//! Like the standard library's prelude, this module simplifies importing of
+//! common items. Unlike the standard prelude, the contents of this module must
+//! be imported manually:
+//!
+//! ```
+//! use rand::prelude::*;
+//! # let _ = StdRng::from_entropy();
+//! # let mut r = SmallRng::from_rng(thread_rng()).unwrap();
+//! # let _: f32 = r.gen();
+//! ```
+
+#[doc(no_inline)] pub use distributions::Distribution;
+#[doc(no_inline)] pub use rngs::{SmallRng, StdRng};
+#[doc(no_inline)] #[cfg(feature="std")] pub use rngs::ThreadRng;
+#[doc(no_inline)] pub use {Rng, RngCore, CryptoRng, SeedableRng};
+#[doc(no_inline)] #[cfg(feature="std")] pub use {FromEntropy, random, thread_rng};
+#[doc(no_inline)] pub use seq::{SliceRandom, IteratorRandom};
diff --git a/rand/src/prng/chacha.rs b/rand/src/prng/chacha.rs
deleted file mode 100644
index a73e8e7..0000000
--- a/rand/src/prng/chacha.rs
+++ /dev/null
@@ -1,321 +0,0 @@
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! The ChaCha random number generator.
-
-use core::num::Wrapping as w;
-use {Rng, SeedableRng, Rand};
-
-#[allow(bad_style)]
-type w32 = w<u32>;
-
-const KEY_WORDS : usize = 8; // 8 words for the 256-bit key
-const STATE_WORDS : usize = 16;
-const CHACHA_ROUNDS: u32 = 20; // Cryptographically secure from 8 upwards as of this writing
-
-/// A random number generator that uses the ChaCha20 algorithm [1].
-///
-/// The ChaCha algorithm is widely accepted as suitable for
-/// cryptographic purposes, but this implementation has not been
-/// verified as such. Prefer a generator like `OsRng` that defers to
-/// the operating system for cases that need high security.
-///
-/// [1]: D. J. Bernstein, [*ChaCha, a variant of
-/// Salsa20*](http://cr.yp.to/chacha.html)
-#[derive(Copy, Clone, Debug)]
-pub struct ChaChaRng {
- buffer: [w32; STATE_WORDS], // Internal buffer of output
- state: [w32; STATE_WORDS], // Initial state
- index: usize, // Index into state
-}
-
-static EMPTY: ChaChaRng = ChaChaRng {
- buffer: [w(0); STATE_WORDS],
- state: [w(0); STATE_WORDS],
- index: STATE_WORDS
-};
-
-
-macro_rules! quarter_round{
- ($a: expr, $b: expr, $c: expr, $d: expr) => {{
- $a = $a + $b; $d = $d ^ $a; $d = w($d.0.rotate_left(16));
- $c = $c + $d; $b = $b ^ $c; $b = w($b.0.rotate_left(12));
- $a = $a + $b; $d = $d ^ $a; $d = w($d.0.rotate_left( 8));
- $c = $c + $d; $b = $b ^ $c; $b = w($b.0.rotate_left( 7));
- }}
-}
-
-macro_rules! double_round{
- ($x: expr) => {{
- // Column round
- quarter_round!($x[ 0], $x[ 4], $x[ 8], $x[12]);
- quarter_round!($x[ 1], $x[ 5], $x[ 9], $x[13]);
- quarter_round!($x[ 2], $x[ 6], $x[10], $x[14]);
- quarter_round!($x[ 3], $x[ 7], $x[11], $x[15]);
- // Diagonal round
- quarter_round!($x[ 0], $x[ 5], $x[10], $x[15]);
- quarter_round!($x[ 1], $x[ 6], $x[11], $x[12]);
- quarter_round!($x[ 2], $x[ 7], $x[ 8], $x[13]);
- quarter_round!($x[ 3], $x[ 4], $x[ 9], $x[14]);
- }}
-}
-
-#[inline]
-fn core(output: &mut [w32; STATE_WORDS], input: &[w32; STATE_WORDS]) {
- *output = *input;
-
- for _ in 0..CHACHA_ROUNDS / 2 {
- double_round!(output);
- }
-
- for i in 0..STATE_WORDS {
- output[i] = output[i] + input[i];
- }
-}
-
-impl ChaChaRng {
-
- /// Create an ChaCha random number generator using the default
- /// fixed key of 8 zero words.
- ///
- /// # Examples
- ///
- /// ```rust
- /// use rand::{Rng, ChaChaRng};
- ///
- /// let mut ra = ChaChaRng::new_unseeded();
- /// println!("{:?}", ra.next_u32());
- /// println!("{:?}", ra.next_u32());
- /// ```
- ///
- /// Since this equivalent to a RNG with a fixed seed, repeated executions
- /// of an unseeded RNG will produce the same result. This code sample will
- /// consistently produce:
- ///
- /// - 2917185654
- /// - 2419978656
- pub fn new_unseeded() -> ChaChaRng {
- let mut rng = EMPTY;
- rng.init(&[0; KEY_WORDS]);
- rng
- }
-
- /// Sets the internal 128-bit ChaCha counter to
- /// a user-provided value. This permits jumping
- /// arbitrarily ahead (or backwards) in the pseudorandom stream.
- ///
- /// Since the nonce words are used to extend the counter to 128 bits,
- /// users wishing to obtain the conventional ChaCha pseudorandom stream
- /// associated with a particular nonce can call this function with
- /// arguments `0, desired_nonce`.
- ///
- /// # Examples
- ///
- /// ```rust
- /// use rand::{Rng, ChaChaRng};
- ///
- /// let mut ra = ChaChaRng::new_unseeded();
- /// ra.set_counter(0u64, 1234567890u64);
- /// println!("{:?}", ra.next_u32());
- /// println!("{:?}", ra.next_u32());
- /// ```
- pub fn set_counter(&mut self, counter_low: u64, counter_high: u64) {
- self.state[12] = w((counter_low >> 0) as u32);
- self.state[13] = w((counter_low >> 32) as u32);
- self.state[14] = w((counter_high >> 0) as u32);
- self.state[15] = w((counter_high >> 32) as u32);
- self.index = STATE_WORDS; // force recomputation
- }
-
- /// Initializes `self.state` with the appropriate key and constants
- ///
- /// We deviate slightly from the ChaCha specification regarding
- /// the nonce, which is used to extend the counter to 128 bits.
- /// This is provably as strong as the original cipher, though,
- /// since any distinguishing attack on our variant also works
- /// against ChaCha with a chosen-nonce. See the XSalsa20 [1]
- /// security proof for a more involved example of this.
- ///
- /// The modified word layout is:
- /// ```text
- /// constant constant constant constant
- /// key key key key
- /// key key key key
- /// counter counter counter counter
- /// ```
- /// [1]: Daniel J. Bernstein. [*Extending the Salsa20
- /// nonce.*](http://cr.yp.to/papers.html#xsalsa)
- fn init(&mut self, key: &[u32; KEY_WORDS]) {
- self.state[0] = w(0x61707865);
- self.state[1] = w(0x3320646E);
- self.state[2] = w(0x79622D32);
- self.state[3] = w(0x6B206574);
-
- for i in 0..KEY_WORDS {
- self.state[4+i] = w(key[i]);
- }
-
- self.state[12] = w(0);
- self.state[13] = w(0);
- self.state[14] = w(0);
- self.state[15] = w(0);
-
- self.index = STATE_WORDS;
- }
-
- /// Refill the internal output buffer (`self.buffer`)
- fn update(&mut self) {
- core(&mut self.buffer, &self.state);
- self.index = 0;
- // update 128-bit counter
- self.state[12] = self.state[12] + w(1);
- if self.state[12] != w(0) { return };
- self.state[13] = self.state[13] + w(1);
- if self.state[13] != w(0) { return };
- self.state[14] = self.state[14] + w(1);
- if self.state[14] != w(0) { return };
- self.state[15] = self.state[15] + w(1);
- }
-}
-
-impl Rng for ChaChaRng {
- #[inline]
- fn next_u32(&mut self) -> u32 {
- if self.index == STATE_WORDS {
- self.update();
- }
-
- let value = self.buffer[self.index % STATE_WORDS];
- self.index += 1;
- value.0
- }
-}
-
-impl<'a> SeedableRng<&'a [u32]> for ChaChaRng {
-
- fn reseed(&mut self, seed: &'a [u32]) {
- // reset state
- self.init(&[0u32; KEY_WORDS]);
- // set key in place
- let key = &mut self.state[4 .. 4+KEY_WORDS];
- for (k, s) in key.iter_mut().zip(seed.iter()) {
- *k = w(*s);
- }
- }
-
- /// Create a ChaCha generator from a seed,
- /// obtained from a variable-length u32 array.
- /// Only up to 8 words are used; if less than 8
- /// words are used, the remaining are set to zero.
- fn from_seed(seed: &'a [u32]) -> ChaChaRng {
- let mut rng = EMPTY;
- rng.reseed(seed);
- rng
- }
-}
-
-impl Rand for ChaChaRng {
- fn rand<R: Rng>(other: &mut R) -> ChaChaRng {
- let mut key : [u32; KEY_WORDS] = [0; KEY_WORDS];
- for word in key.iter_mut() {
- *word = other.gen();
- }
- SeedableRng::from_seed(&key[..])
- }
-}
-
-
-#[cfg(test)]
-mod test {
- use {Rng, SeedableRng};
- use super::ChaChaRng;
-
- #[test]
- fn test_rng_rand_seeded() {
- let s = ::test::rng().gen_iter::<u32>().take(8).collect::<Vec<u32>>();
- let mut ra: ChaChaRng = SeedableRng::from_seed(&s[..]);
- let mut rb: ChaChaRng = SeedableRng::from_seed(&s[..]);
- assert!(::test::iter_eq(ra.gen_ascii_chars().take(100),
- rb.gen_ascii_chars().take(100)));
- }
-
- #[test]
- fn test_rng_seeded() {
- let seed : &[_] = &[0,1,2,3,4,5,6,7];
- let mut ra: ChaChaRng = SeedableRng::from_seed(seed);
- let mut rb: ChaChaRng = SeedableRng::from_seed(seed);
- assert!(::test::iter_eq(ra.gen_ascii_chars().take(100),
- rb.gen_ascii_chars().take(100)));
- }
-
- #[test]
- fn test_rng_reseed() {
- let s = ::test::rng().gen_iter::<u32>().take(8).collect::<Vec<u32>>();
- let mut r: ChaChaRng = SeedableRng::from_seed(&s[..]);
- let string1: String = r.gen_ascii_chars().take(100).collect();
-
- r.reseed(&s);
-
- let string2: String = r.gen_ascii_chars().take(100).collect();
- assert_eq!(string1, string2);
- }
-
- #[test]
- fn test_rng_true_values() {
- // Test vectors 1 and 2 from
- // http://tools.ietf.org/html/draft-nir-cfrg-chacha20-poly1305-04
- let seed : &[_] = &[0u32; 8];
- let mut ra: ChaChaRng = SeedableRng::from_seed(seed);
-
- let v = (0..16).map(|_| ra.next_u32()).collect::<Vec<_>>();
- assert_eq!(v,
- vec!(0xade0b876, 0x903df1a0, 0xe56a5d40, 0x28bd8653,
- 0xb819d2bd, 0x1aed8da0, 0xccef36a8, 0xc70d778b,
- 0x7c5941da, 0x8d485751, 0x3fe02477, 0x374ad8b8,
- 0xf4b8436a, 0x1ca11815, 0x69b687c3, 0x8665eeb2));
-
- let v = (0..16).map(|_| ra.next_u32()).collect::<Vec<_>>();
- assert_eq!(v,
- vec!(0xbee7079f, 0x7a385155, 0x7c97ba98, 0x0d082d73,
- 0xa0290fcb, 0x6965e348, 0x3e53c612, 0xed7aee32,
- 0x7621b729, 0x434ee69c, 0xb03371d5, 0xd539d874,
- 0x281fed31, 0x45fb0a51, 0x1f0ae1ac, 0x6f4d794b));
-
-
- let seed : &[_] = &[0,1,2,3,4,5,6,7];
- let mut ra: ChaChaRng = SeedableRng::from_seed(seed);
-
- // Store the 17*i-th 32-bit word,
- // i.e., the i-th word of the i-th 16-word block
- let mut v : Vec<u32> = Vec::new();
- for _ in 0..16 {
- v.push(ra.next_u32());
- for _ in 0..16 {
- ra.next_u32();
- }
- }
-
- assert_eq!(v,
- vec!(0xf225c81a, 0x6ab1be57, 0x04d42951, 0x70858036,
- 0x49884684, 0x64efec72, 0x4be2d186, 0x3615b384,
- 0x11cfa18e, 0xd3c50049, 0x75c775f6, 0x434c6530,
- 0x2c5bad8f, 0x898881dc, 0x5f1c86d9, 0xc1f8e7f4));
- }
-
- #[test]
- fn test_rng_clone() {
- let seed : &[_] = &[0u32; 8];
- let mut rng: ChaChaRng = SeedableRng::from_seed(seed);
- let mut clone = rng.clone();
- for _ in 0..16 {
- assert_eq!(rng.next_u64(), clone.next_u64());
- }
- }
-}
diff --git a/rand/src/prng/isaac.rs b/rand/src/prng/isaac.rs
deleted file mode 100644
index cf5eb67..0000000
--- a/rand/src/prng/isaac.rs
+++ /dev/null
@@ -1,328 +0,0 @@
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! The ISAAC random number generator.
-
-#![allow(non_camel_case_types)]
-
-use core::slice;
-use core::iter::repeat;
-use core::num::Wrapping as w;
-use core::fmt;
-
-use {Rng, SeedableRng, Rand};
-
-#[allow(bad_style)]
-type w32 = w<u32>;
-
-const RAND_SIZE_LEN: usize = 8;
-const RAND_SIZE: u32 = 1 << RAND_SIZE_LEN;
-const RAND_SIZE_USIZE: usize = 1 << RAND_SIZE_LEN;
-
-/// A random number generator that uses the ISAAC algorithm[1].
-///
-/// The ISAAC algorithm is generally accepted as suitable for
-/// cryptographic purposes, but this implementation has not be
-/// verified as such. Prefer a generator like `OsRng` that defers to
-/// the operating system for cases that need high security.
-///
-/// [1]: Bob Jenkins, [*ISAAC: A fast cryptographic random number
-/// generator*](http://www.burtleburtle.net/bob/rand/isaacafa.html)
-#[derive(Copy)]
-pub struct IsaacRng {
- cnt: u32,
- rsl: [w32; RAND_SIZE_USIZE],
- mem: [w32; RAND_SIZE_USIZE],
- a: w32,
- b: w32,
- c: w32,
-}
-
-static EMPTY: IsaacRng = IsaacRng {
- cnt: 0,
- rsl: [w(0); RAND_SIZE_USIZE],
- mem: [w(0); RAND_SIZE_USIZE],
- a: w(0), b: w(0), c: w(0),
-};
-
-impl IsaacRng {
-
- /// Create an ISAAC random number generator using the default
- /// fixed seed.
- pub fn new_unseeded() -> IsaacRng {
- let mut rng = EMPTY;
- rng.init(false);
- rng
- }
-
- /// Initialises `self`. If `use_rsl` is true, then use the current value
- /// of `rsl` as a seed, otherwise construct one algorithmically (not
- /// randomly).
- fn init(&mut self, use_rsl: bool) {
- let mut a = w(0x9e3779b9);
- let mut b = a;
- let mut c = a;
- let mut d = a;
- let mut e = a;
- let mut f = a;
- let mut g = a;
- let mut h = a;
-
- macro_rules! mix {
- () => {{
- a=a^(b<<11); d=d+a; b=b+c;
- b=b^(c>>2); e=e+b; c=c+d;
- c=c^(d<<8); f=f+c; d=d+e;
- d=d^(e>>16); g=g+d; e=e+f;
- e=e^(f<<10); h=h+e; f=f+g;
- f=f^(g>>4); a=a+f; g=g+h;
- g=g^(h<<8); b=b+g; h=h+a;
- h=h^(a>>9); c=c+h; a=a+b;
- }}
- }
-
- for _ in 0..4 {
- mix!();
- }
-
- if use_rsl {
- macro_rules! memloop {
- ($arr:expr) => {{
- for i in (0..RAND_SIZE_USIZE/8).map(|i| i * 8) {
- a=a+$arr[i ]; b=b+$arr[i+1];
- c=c+$arr[i+2]; d=d+$arr[i+3];
- e=e+$arr[i+4]; f=f+$arr[i+5];
- g=g+$arr[i+6]; h=h+$arr[i+7];
- mix!();
- self.mem[i ]=a; self.mem[i+1]=b;
- self.mem[i+2]=c; self.mem[i+3]=d;
- self.mem[i+4]=e; self.mem[i+5]=f;
- self.mem[i+6]=g; self.mem[i+7]=h;
- }
- }}
- }
-
- memloop!(self.rsl);
- memloop!(self.mem);
- } else {
- for i in (0..RAND_SIZE_USIZE/8).map(|i| i * 8) {
- mix!();
- self.mem[i ]=a; self.mem[i+1]=b;
- self.mem[i+2]=c; self.mem[i+3]=d;
- self.mem[i+4]=e; self.mem[i+5]=f;
- self.mem[i+6]=g; self.mem[i+7]=h;
- }
- }
-
- self.isaac();
- }
-
- /// Refills the output buffer (`self.rsl`)
- #[inline]
- fn isaac(&mut self) {
- self.c = self.c + w(1);
- // abbreviations
- let mut a = self.a;
- let mut b = self.b + self.c;
-
- const MIDPOINT: usize = RAND_SIZE_USIZE / 2;
-
- macro_rules! ind {
- ($x:expr) => ( self.mem[($x >> 2usize).0 as usize & (RAND_SIZE_USIZE - 1)] )
- }
-
- let r = [(0, MIDPOINT), (MIDPOINT, 0)];
- for &(mr_offset, m2_offset) in r.iter() {
-
- macro_rules! rngstepp {
- ($j:expr, $shift:expr) => {{
- let base = $j;
- let mix = a << $shift;
-
- let x = self.mem[base + mr_offset];
- a = (a ^ mix) + self.mem[base + m2_offset];
- let y = ind!(x) + a + b;
- self.mem[base + mr_offset] = y;
-
- b = ind!(y >> RAND_SIZE_LEN) + x;
- self.rsl[base + mr_offset] = b;
- }}
- }
-
- macro_rules! rngstepn {
- ($j:expr, $shift:expr) => {{
- let base = $j;
- let mix = a >> $shift;
-
- let x = self.mem[base + mr_offset];
- a = (a ^ mix) + self.mem[base + m2_offset];
- let y = ind!(x) + a + b;
- self.mem[base + mr_offset] = y;
-
- b = ind!(y >> RAND_SIZE_LEN) + x;
- self.rsl[base + mr_offset] = b;
- }}
- }
-
- for i in (0..MIDPOINT/4).map(|i| i * 4) {
- rngstepp!(i + 0, 13);
- rngstepn!(i + 1, 6);
- rngstepp!(i + 2, 2);
- rngstepn!(i + 3, 16);
- }
- }
-
- self.a = a;
- self.b = b;
- self.cnt = RAND_SIZE;
- }
-}
-
-// Cannot be derived because [u32; 256] does not implement Clone
-impl Clone for IsaacRng {
- fn clone(&self) -> IsaacRng {
- *self
- }
-}
-
-impl Rng for IsaacRng {
- #[inline]
- fn next_u32(&mut self) -> u32 {
- if self.cnt == 0 {
- // make some more numbers
- self.isaac();
- }
- self.cnt -= 1;
-
- // self.cnt is at most RAND_SIZE, but that is before the
- // subtraction above. We want to index without bounds
- // checking, but this could lead to incorrect code if someone
- // misrefactors, so we check, sometimes.
- //
- // (Changes here should be reflected in Isaac64Rng.next_u64.)
- debug_assert!(self.cnt < RAND_SIZE);
-
- // (the % is cheaply telling the optimiser that we're always
- // in bounds, without unsafe. NB. this is a power of two, so
- // it optimises to a bitwise mask).
- self.rsl[(self.cnt % RAND_SIZE) as usize].0
- }
-}
-
-impl<'a> SeedableRng<&'a [u32]> for IsaacRng {
- fn reseed(&mut self, seed: &'a [u32]) {
- // make the seed into [seed[0], seed[1], ..., seed[seed.len()
- // - 1], 0, 0, ...], to fill rng.rsl.
- let seed_iter = seed.iter().map(|&x| x).chain(repeat(0u32));
-
- for (rsl_elem, seed_elem) in self.rsl.iter_mut().zip(seed_iter) {
- *rsl_elem = w(seed_elem);
- }
- self.cnt = 0;
- self.a = w(0);
- self.b = w(0);
- self.c = w(0);
-
- self.init(true);
- }
-
- /// Create an ISAAC random number generator with a seed. This can
- /// be any length, although the maximum number of elements used is
- /// 256 and any more will be silently ignored. A generator
- /// constructed with a given seed will generate the same sequence
- /// of values as all other generators constructed with that seed.
- fn from_seed(seed: &'a [u32]) -> IsaacRng {
- let mut rng = EMPTY;
- rng.reseed(seed);
- rng
- }
-}
-
-impl Rand for IsaacRng {
- fn rand<R: Rng>(other: &mut R) -> IsaacRng {
- let mut ret = EMPTY;
- unsafe {
- let ptr = ret.rsl.as_mut_ptr() as *mut u8;
-
- let slice = slice::from_raw_parts_mut(ptr, RAND_SIZE_USIZE * 4);
- other.fill_bytes(slice);
- }
- ret.cnt = 0;
- ret.a = w(0);
- ret.b = w(0);
- ret.c = w(0);
-
- ret.init(true);
- return ret;
- }
-}
-
-impl fmt::Debug for IsaacRng {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "IsaacRng {{}}")
- }
-}
-
-#[cfg(test)]
-mod test {
- use {Rng, SeedableRng};
- use super::IsaacRng;
-
- #[test]
- fn test_rng_32_rand_seeded() {
- let s = ::test::rng().gen_iter::<u32>().take(256).collect::<Vec<u32>>();
- let mut ra: IsaacRng = SeedableRng::from_seed(&s[..]);
- let mut rb: IsaacRng = SeedableRng::from_seed(&s[..]);
- assert!(::test::iter_eq(ra.gen_ascii_chars().take(100),
- rb.gen_ascii_chars().take(100)));
- }
-
- #[test]
- fn test_rng_32_seeded() {
- let seed: &[_] = &[1, 23, 456, 7890, 12345];
- let mut ra: IsaacRng = SeedableRng::from_seed(seed);
- let mut rb: IsaacRng = SeedableRng::from_seed(seed);
- assert!(::test::iter_eq(ra.gen_ascii_chars().take(100),
- rb.gen_ascii_chars().take(100)));
- }
-
- #[test]
- fn test_rng_32_reseed() {
- let s = ::test::rng().gen_iter::<u32>().take(256).collect::<Vec<u32>>();
- let mut r: IsaacRng = SeedableRng::from_seed(&s[..]);
- let string1: String = r.gen_ascii_chars().take(100).collect();
-
- r.reseed(&s[..]);
-
- let string2: String = r.gen_ascii_chars().take(100).collect();
- assert_eq!(string1, string2);
- }
-
- #[test]
- fn test_rng_32_true_values() {
- let seed: &[_] = &[1, 23, 456, 7890, 12345];
- let mut ra: IsaacRng = SeedableRng::from_seed(seed);
- // Regression test that isaac is actually using the above vector
- let v = (0..10).map(|_| ra.next_u32()).collect::<Vec<_>>();
- assert_eq!(v,
- vec!(2558573138, 873787463, 263499565, 2103644246, 3595684709,
- 4203127393, 264982119, 2765226902, 2737944514, 3900253796));
-
- let seed: &[_] = &[12345, 67890, 54321, 9876];
- let mut rb: IsaacRng = SeedableRng::from_seed(seed);
- // skip forward to the 10000th number
- for _ in 0..10000 { rb.next_u32(); }
-
- let v = (0..10).map(|_| rb.next_u32()).collect::<Vec<_>>();
- assert_eq!(v,
- vec!(3676831399, 3183332890, 2834741178, 3854698763, 2717568474,
- 1576568959, 3507990155, 179069555, 141456972, 2478885421));
- }
-}
diff --git a/rand/src/prng/isaac64.rs b/rand/src/prng/isaac64.rs
deleted file mode 100644
index b98e3fe..0000000
--- a/rand/src/prng/isaac64.rs
+++ /dev/null
@@ -1,340 +0,0 @@
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! The ISAAC-64 random number generator.
-
-use core::slice;
-use core::iter::repeat;
-use core::num::Wrapping as w;
-use core::fmt;
-
-use {Rng, SeedableRng, Rand};
-
-#[allow(bad_style)]
-type w64 = w<u64>;
-
-const RAND_SIZE_64_LEN: usize = 8;
-const RAND_SIZE_64: usize = 1 << RAND_SIZE_64_LEN;
-
-/// A random number generator that uses ISAAC-64[1], the 64-bit
-/// variant of the ISAAC algorithm.
-///
-/// The ISAAC algorithm is generally accepted as suitable for
-/// cryptographic purposes, but this implementation has not be
-/// verified as such. Prefer a generator like `OsRng` that defers to
-/// the operating system for cases that need high security.
-///
-/// [1]: Bob Jenkins, [*ISAAC: A fast cryptographic random number
-/// generator*](http://www.burtleburtle.net/bob/rand/isaacafa.html)
-#[derive(Copy)]
-pub struct Isaac64Rng {
- cnt: usize,
- rsl: [w64; RAND_SIZE_64],
- mem: [w64; RAND_SIZE_64],
- a: w64,
- b: w64,
- c: w64,
-}
-
-static EMPTY_64: Isaac64Rng = Isaac64Rng {
- cnt: 0,
- rsl: [w(0); RAND_SIZE_64],
- mem: [w(0); RAND_SIZE_64],
- a: w(0), b: w(0), c: w(0),
-};
-
-impl Isaac64Rng {
- /// Create a 64-bit ISAAC random number generator using the
- /// default fixed seed.
- pub fn new_unseeded() -> Isaac64Rng {
- let mut rng = EMPTY_64;
- rng.init(false);
- rng
- }
-
- /// Initialises `self`. If `use_rsl` is true, then use the current value
- /// of `rsl` as a seed, otherwise construct one algorithmically (not
- /// randomly).
- fn init(&mut self, use_rsl: bool) {
- macro_rules! init {
- ($var:ident) => (
- let mut $var = w(0x9e3779b97f4a7c13);
- )
- }
- init!(a); init!(b); init!(c); init!(d);
- init!(e); init!(f); init!(g); init!(h);
-
- macro_rules! mix {
- () => {{
- a=a-e; f=f^(h>>9); h=h+a;
- b=b-f; g=g^(a<<9); a=a+b;
- c=c-g; h=h^(b>>23); b=b+c;
- d=d-h; a=a^(c<<15); c=c+d;
- e=e-a; b=b^(d>>14); d=d+e;
- f=f-b; c=c^(e<<20); e=e+f;
- g=g-c; d=d^(f>>17); f=f+g;
- h=h-d; e=e^(g<<14); g=g+h;
- }}
- }
-
- for _ in 0..4 {
- mix!();
- }
-
- if use_rsl {
- macro_rules! memloop {
- ($arr:expr) => {{
- for i in (0..RAND_SIZE_64 / 8).map(|i| i * 8) {
- a=a+$arr[i ]; b=b+$arr[i+1];
- c=c+$arr[i+2]; d=d+$arr[i+3];
- e=e+$arr[i+4]; f=f+$arr[i+5];
- g=g+$arr[i+6]; h=h+$arr[i+7];
- mix!();
- self.mem[i ]=a; self.mem[i+1]=b;
- self.mem[i+2]=c; self.mem[i+3]=d;
- self.mem[i+4]=e; self.mem[i+5]=f;
- self.mem[i+6]=g; self.mem[i+7]=h;
- }
- }}
- }
-
- memloop!(self.rsl);
- memloop!(self.mem);
- } else {
- for i in (0..RAND_SIZE_64 / 8).map(|i| i * 8) {
- mix!();
- self.mem[i ]=a; self.mem[i+1]=b;
- self.mem[i+2]=c; self.mem[i+3]=d;
- self.mem[i+4]=e; self.mem[i+5]=f;
- self.mem[i+6]=g; self.mem[i+7]=h;
- }
- }
-
- self.isaac64();
- }
-
- /// Refills the output buffer (`self.rsl`)
- fn isaac64(&mut self) {
- self.c = self.c + w(1);
- // abbreviations
- let mut a = self.a;
- let mut b = self.b + self.c;
- const MIDPOINT: usize = RAND_SIZE_64 / 2;
- const MP_VEC: [(usize, usize); 2] = [(0,MIDPOINT), (MIDPOINT, 0)];
- macro_rules! ind {
- ($x:expr) => {
- *self.mem.get_unchecked((($x >> 3usize).0 as usize) & (RAND_SIZE_64 - 1))
- }
- }
-
- for &(mr_offset, m2_offset) in MP_VEC.iter() {
- for base in (0..MIDPOINT / 4).map(|i| i * 4) {
-
- macro_rules! rngstepp {
- ($j:expr, $shift:expr) => {{
- let base = base + $j;
- let mix = a ^ (a << $shift);
- let mix = if $j == 0 {!mix} else {mix};
-
- unsafe {
- let x = *self.mem.get_unchecked(base + mr_offset);
- a = mix + *self.mem.get_unchecked(base + m2_offset);
- let y = ind!(x) + a + b;
- *self.mem.get_unchecked_mut(base + mr_offset) = y;
-
- b = ind!(y >> RAND_SIZE_64_LEN) + x;
- *self.rsl.get_unchecked_mut(base + mr_offset) = b;
- }
- }}
- }
-
- macro_rules! rngstepn {
- ($j:expr, $shift:expr) => {{
- let base = base + $j;
- let mix = a ^ (a >> $shift);
- let mix = if $j == 0 {!mix} else {mix};
-
- unsafe {
- let x = *self.mem.get_unchecked(base + mr_offset);
- a = mix + *self.mem.get_unchecked(base + m2_offset);
- let y = ind!(x) + a + b;
- *self.mem.get_unchecked_mut(base + mr_offset) = y;
-
- b = ind!(y >> RAND_SIZE_64_LEN) + x;
- *self.rsl.get_unchecked_mut(base + mr_offset) = b;
- }
- }}
- }
-
- rngstepp!(0, 21);
- rngstepn!(1, 5);
- rngstepp!(2, 12);
- rngstepn!(3, 33);
- }
- }
-
- self.a = a;
- self.b = b;
- self.cnt = RAND_SIZE_64;
- }
-}
-
-// Cannot be derived because [u32; 256] does not implement Clone
-impl Clone for Isaac64Rng {
- fn clone(&self) -> Isaac64Rng {
- *self
- }
-}
-
-impl Rng for Isaac64Rng {
- #[inline]
- fn next_u32(&mut self) -> u32 {
- self.next_u64() as u32
- }
-
- #[inline]
- fn next_u64(&mut self) -> u64 {
- if self.cnt == 0 {
- // make some more numbers
- self.isaac64();
- }
- self.cnt -= 1;
-
- // See corresponding location in IsaacRng.next_u32 for
- // explanation.
- debug_assert!(self.cnt < RAND_SIZE_64);
- self.rsl[(self.cnt % RAND_SIZE_64) as usize].0
- }
-}
-
-impl<'a> SeedableRng<&'a [u64]> for Isaac64Rng {
- fn reseed(&mut self, seed: &'a [u64]) {
- // make the seed into [seed[0], seed[1], ..., seed[seed.len()
- // - 1], 0, 0, ...], to fill rng.rsl.
- let seed_iter = seed.iter().map(|&x| x).chain(repeat(0u64));
-
- for (rsl_elem, seed_elem) in self.rsl.iter_mut().zip(seed_iter) {
- *rsl_elem = w(seed_elem);
- }
- self.cnt = 0;
- self.a = w(0);
- self.b = w(0);
- self.c = w(0);
-
- self.init(true);
- }
-
- /// Create an ISAAC random number generator with a seed. This can
- /// be any length, although the maximum number of elements used is
- /// 256 and any more will be silently ignored. A generator
- /// constructed with a given seed will generate the same sequence
- /// of values as all other generators constructed with that seed.
- fn from_seed(seed: &'a [u64]) -> Isaac64Rng {
- let mut rng = EMPTY_64;
- rng.reseed(seed);
- rng
- }
-}
-
-impl Rand for Isaac64Rng {
- fn rand<R: Rng>(other: &mut R) -> Isaac64Rng {
- let mut ret = EMPTY_64;
- unsafe {
- let ptr = ret.rsl.as_mut_ptr() as *mut u8;
-
- let slice = slice::from_raw_parts_mut(ptr, RAND_SIZE_64 * 8);
- other.fill_bytes(slice);
- }
- ret.cnt = 0;
- ret.a = w(0);
- ret.b = w(0);
- ret.c = w(0);
-
- ret.init(true);
- return ret;
- }
-}
-
-impl fmt::Debug for Isaac64Rng {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "Isaac64Rng {{}}")
- }
-}
-
-#[cfg(test)]
-mod test {
- use {Rng, SeedableRng};
- use super::Isaac64Rng;
-
- #[test]
- fn test_rng_64_rand_seeded() {
- let s = ::test::rng().gen_iter::<u64>().take(256).collect::<Vec<u64>>();
- let mut ra: Isaac64Rng = SeedableRng::from_seed(&s[..]);
- let mut rb: Isaac64Rng = SeedableRng::from_seed(&s[..]);
- assert!(::test::iter_eq(ra.gen_ascii_chars().take(100),
- rb.gen_ascii_chars().take(100)));
- }
-
- #[test]
- fn test_rng_64_seeded() {
- let seed: &[_] = &[1, 23, 456, 7890, 12345];
- let mut ra: Isaac64Rng = SeedableRng::from_seed(seed);
- let mut rb: Isaac64Rng = SeedableRng::from_seed(seed);
- assert!(::test::iter_eq(ra.gen_ascii_chars().take(100),
- rb.gen_ascii_chars().take(100)));
- }
-
- #[test]
- fn test_rng_64_reseed() {
- let s = ::test::rng().gen_iter::<u64>().take(256).collect::<Vec<u64>>();
- let mut r: Isaac64Rng = SeedableRng::from_seed(&s[..]);
- let string1: String = r.gen_ascii_chars().take(100).collect();
-
- r.reseed(&s[..]);
-
- let string2: String = r.gen_ascii_chars().take(100).collect();
- assert_eq!(string1, string2);
- }
-
- #[test]
- fn test_rng_64_true_values() {
- let seed: &[_] = &[1, 23, 456, 7890, 12345];
- let mut ra: Isaac64Rng = SeedableRng::from_seed(seed);
- // Regression test that isaac is actually using the above vector
- let v = (0..10).map(|_| ra.next_u64()).collect::<Vec<_>>();
- assert_eq!(v,
- vec!(547121783600835980, 14377643087320773276, 17351601304698403469,
- 1238879483818134882, 11952566807690396487, 13970131091560099343,
- 4469761996653280935, 15552757044682284409, 6860251611068737823,
- 13722198873481261842));
-
- let seed: &[_] = &[12345, 67890, 54321, 9876];
- let mut rb: Isaac64Rng = SeedableRng::from_seed(seed);
- // skip forward to the 10000th number
- for _ in 0..10000 { rb.next_u64(); }
-
- let v = (0..10).map(|_| rb.next_u64()).collect::<Vec<_>>();
- assert_eq!(v,
- vec!(18143823860592706164, 8491801882678285927, 2699425367717515619,
- 17196852593171130876, 2606123525235546165, 15790932315217671084,
- 596345674630742204, 9947027391921273664, 11788097613744130851,
- 10391409374914919106));
- }
-
- #[test]
- fn test_rng_clone() {
- let seed: &[_] = &[1, 23, 456, 7890, 12345];
- let mut rng: Isaac64Rng = SeedableRng::from_seed(seed);
- let mut clone = rng.clone();
- for _ in 0..16 {
- assert_eq!(rng.next_u64(), clone.next_u64());
- }
- }
-}
diff --git a/rand/src/prng/mod.rs b/rand/src/prng/mod.rs
index ed3e018..3c0d27b 100644
--- a/rand/src/prng/mod.rs
+++ b/rand/src/prng/mod.rs
@@ -1,51 +1,37 @@
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
+// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-//! Pseudo random number generators are algorithms to produce *apparently
-//! random* numbers deterministically, and usually fairly quickly.
+//! Pseudo-random number generators.
+//!
+//! This module is deprecated:
//!
-//! So long as the algorithm is computationally secure, is initialised with
-//! sufficient entropy (i.e. unknown by an attacker), and its internal state is
-//! also protected (unknown to an attacker), the output will also be
-//! *computationally secure*. Computationally Secure Pseudo Random Number
-//! Generators (CSPRNGs) are thus suitable sources of random numbers for
-//! cryptography. There are a couple of gotchas here, however. First, the seed
-//! used for initialisation must be unknown. Usually this should be provided by
-//! the operating system and should usually be secure, however this may not
-//! always be the case (especially soon after startup). Second, user-space
-//! memory may be vulnerable, for example when written to swap space, and after
-//! forking a child process should reinitialise any user-space PRNGs. For this
-//! reason it may be preferable to source random numbers directly from the OS
-//! for cryptographic applications.
-//!
-//! PRNGs are also widely used for non-cryptographic uses: randomised
-//! algorithms, simulations, games. In these applications it is usually not
-//! important for numbers to be cryptographically *unguessable*, but even
-//! distribution and independence from other samples (from the point of view
-//! of someone unaware of the algorithm used, at least) may still be important.
-//! Good PRNGs should satisfy these properties, but do not take them for
-//! granted; Wikipedia's article on
-//! [Pseudorandom number generators](https://en.wikipedia.org/wiki/Pseudorandom_number_generator)
-//! provides some background on this topic.
-//!
-//! Care should be taken when seeding (initialising) PRNGs. Some PRNGs have
-//! short periods for some seeds. If one PRNG is seeded from another using the
-//! same algorithm, it is possible that both will yield the same sequence of
-//! values (with some lag).
-
-mod chacha;
-mod isaac;
-mod isaac64;
-mod xorshift;
+//! - documentation has moved to
+//! [The Book](https://rust-random.github.io/book/guide-rngs.html),
+//! - PRNGs have moved to other `rand_*` crates.
-pub use self::chacha::ChaChaRng;
-pub use self::isaac::IsaacRng;
-pub use self::isaac64::Isaac64Rng;
-pub use self::xorshift::XorShiftRng;
+// Deprecations (to be removed in 0.7)
+#[doc(hidden)] #[allow(deprecated)]
+pub use deprecated::XorShiftRng;
+#[doc(hidden)] pub mod isaac {
+ // Note: we miss `IsaacCore` here but probably unimportant.
+ #[allow(deprecated)] pub use deprecated::IsaacRng;
+}
+#[doc(hidden)] pub mod isaac64 {
+ #[allow(deprecated)] pub use deprecated::Isaac64Rng;
+}
+#[doc(hidden)] #[allow(deprecated)] pub use deprecated::{IsaacRng, Isaac64Rng};
+#[doc(hidden)] pub mod chacha {
+ // Note: we miss `ChaChaCore` here but probably unimportant.
+ #[allow(deprecated)] pub use deprecated::ChaChaRng;
+}
+#[doc(hidden)] #[allow(deprecated)] pub use deprecated::ChaChaRng;
+#[doc(hidden)] pub mod hc128 {
+ // Note: we miss `Hc128Core` here but probably unimportant.
+ #[allow(deprecated)] pub use deprecated::Hc128Rng;
+}
+#[doc(hidden)] #[allow(deprecated)] pub use deprecated::Hc128Rng;
diff --git a/rand/src/prng/xorshift.rs b/rand/src/prng/xorshift.rs
deleted file mode 100644
index dd367e9..0000000
--- a/rand/src/prng/xorshift.rs
+++ /dev/null
@@ -1,101 +0,0 @@
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Xorshift generators
-
-use core::num::Wrapping as w;
-use {Rng, SeedableRng, Rand};
-
-/// An Xorshift[1] random number
-/// generator.
-///
-/// The Xorshift algorithm is not suitable for cryptographic purposes
-/// but is very fast. If you do not know for sure that it fits your
-/// requirements, use a more secure one such as `IsaacRng` or `OsRng`.
-///
-/// [1]: Marsaglia, George (July 2003). ["Xorshift
-/// RNGs"](http://www.jstatsoft.org/v08/i14/paper). *Journal of
-/// Statistical Software*. Vol. 8 (Issue 14).
-#[allow(missing_copy_implementations)]
-#[derive(Clone, Debug)]
-pub struct XorShiftRng {
- x: w<u32>,
- y: w<u32>,
- z: w<u32>,
- w: w<u32>,
-}
-
-impl XorShiftRng {
- /// Creates a new XorShiftRng instance which is not seeded.
- ///
- /// The initial values of this RNG are constants, so all generators created
- /// by this function will yield the same stream of random numbers. It is
- /// highly recommended that this is created through `SeedableRng` instead of
- /// this function
- pub fn new_unseeded() -> XorShiftRng {
- XorShiftRng {
- x: w(0x193a6754),
- y: w(0xa8a7d469),
- z: w(0x97830e05),
- w: w(0x113ba7bb),
- }
- }
-}
-
-impl Rng for XorShiftRng {
- #[inline]
- fn next_u32(&mut self) -> u32 {
- let x = self.x;
- let t = x ^ (x << 11);
- self.x = self.y;
- self.y = self.z;
- self.z = self.w;
- let w_ = self.w;
- self.w = w_ ^ (w_ >> 19) ^ (t ^ (t >> 8));
- self.w.0
- }
-}
-
-impl SeedableRng<[u32; 4]> for XorShiftRng {
- /// Reseed an XorShiftRng. This will panic if `seed` is entirely 0.
- fn reseed(&mut self, seed: [u32; 4]) {
- assert!(!seed.iter().all(|&x| x == 0),
- "XorShiftRng.reseed called with an all zero seed.");
-
- self.x = w(seed[0]);
- self.y = w(seed[1]);
- self.z = w(seed[2]);
- self.w = w(seed[3]);
- }
-
- /// Create a new XorShiftRng. This will panic if `seed` is entirely 0.
- fn from_seed(seed: [u32; 4]) -> XorShiftRng {
- assert!(!seed.iter().all(|&x| x == 0),
- "XorShiftRng::from_seed called with an all zero seed.");
-
- XorShiftRng {
- x: w(seed[0]),
- y: w(seed[1]),
- z: w(seed[2]),
- w: w(seed[3]),
- }
- }
-}
-
-impl Rand for XorShiftRng {
- fn rand<R: Rng>(rng: &mut R) -> XorShiftRng {
- let mut tuple: (u32, u32, u32, u32) = rng.gen();
- while tuple == (0, 0, 0, 0) {
- tuple = rng.gen();
- }
- let (x, y, z, w_) = tuple;
- XorShiftRng { x: w(x), y: w(y), z: w(z), w: w(w_) }
- }
-}
diff --git a/rand/src/rand_impls.rs b/rand/src/rand_impls.rs
deleted file mode 100644
index a865bb6..0000000
--- a/rand/src/rand_impls.rs
+++ /dev/null
@@ -1,299 +0,0 @@
-// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! The implementations of `Rand` for the built-in types.
-
-use core::{char, mem};
-
-use {Rand,Rng};
-
-impl Rand for isize {
- #[inline]
- fn rand<R: Rng>(rng: &mut R) -> isize {
- if mem::size_of::<isize>() == 4 {
- rng.gen::<i32>() as isize
- } else {
- rng.gen::<i64>() as isize
- }
- }
-}
-
-impl Rand for i8 {
- #[inline]
- fn rand<R: Rng>(rng: &mut R) -> i8 {
- rng.next_u32() as i8
- }
-}
-
-impl Rand for i16 {
- #[inline]
- fn rand<R: Rng>(rng: &mut R) -> i16 {
- rng.next_u32() as i16
- }
-}
-
-impl Rand for i32 {
- #[inline]
- fn rand<R: Rng>(rng: &mut R) -> i32 {
- rng.next_u32() as i32
- }
-}
-
-impl Rand for i64 {
- #[inline]
- fn rand<R: Rng>(rng: &mut R) -> i64 {
- rng.next_u64() as i64
- }
-}
-
-#[cfg(feature = "i128_support")]
-impl Rand for i128 {
- #[inline]
- fn rand<R: Rng>(rng: &mut R) -> i128 {
- rng.gen::<u128>() as i128
- }
-}
-
-impl Rand for usize {
- #[inline]
- fn rand<R: Rng>(rng: &mut R) -> usize {
- if mem::size_of::<usize>() == 4 {
- rng.gen::<u32>() as usize
- } else {
- rng.gen::<u64>() as usize
- }
- }
-}
-
-impl Rand for u8 {
- #[inline]
- fn rand<R: Rng>(rng: &mut R) -> u8 {
- rng.next_u32() as u8
- }
-}
-
-impl Rand for u16 {
- #[inline]
- fn rand<R: Rng>(rng: &mut R) -> u16 {
- rng.next_u32() as u16
- }
-}
-
-impl Rand for u32 {
- #[inline]
- fn rand<R: Rng>(rng: &mut R) -> u32 {
- rng.next_u32()
- }
-}
-
-impl Rand for u64 {
- #[inline]
- fn rand<R: Rng>(rng: &mut R) -> u64 {
- rng.next_u64()
- }
-}
-
-#[cfg(feature = "i128_support")]
-impl Rand for u128 {
- #[inline]
- fn rand<R: Rng>(rng: &mut R) -> u128 {
- ((rng.next_u64() as u128) << 64) | (rng.next_u64() as u128)
- }
-}
-
-
-macro_rules! float_impls {
- ($mod_name:ident, $ty:ty, $mantissa_bits:expr, $method_name:ident) => {
- mod $mod_name {
- use {Rand, Rng, Open01, Closed01};
-
- const SCALE: $ty = (1u64 << $mantissa_bits) as $ty;
-
- impl Rand for $ty {
- /// Generate a floating point number in the half-open
- /// interval `[0,1)`.
- ///
- /// See `Closed01` for the closed interval `[0,1]`,
- /// and `Open01` for the open interval `(0,1)`.
- #[inline]
- fn rand<R: Rng>(rng: &mut R) -> $ty {
- rng.$method_name()
- }
- }
- impl Rand for Open01<$ty> {
- #[inline]
- fn rand<R: Rng>(rng: &mut R) -> Open01<$ty> {
- // add a small amount (specifically 2 bits below
- // the precision of f64/f32 at 1.0), so that small
- // numbers are larger than 0, but large numbers
- // aren't pushed to/above 1.
- Open01(rng.$method_name() + 0.25 / SCALE)
- }
- }
- impl Rand for Closed01<$ty> {
- #[inline]
- fn rand<R: Rng>(rng: &mut R) -> Closed01<$ty> {
- // rescale so that 1.0 - epsilon becomes 1.0
- // precisely.
- Closed01(rng.$method_name() * SCALE / (SCALE - 1.0))
- }
- }
- }
- }
-}
-float_impls! { f64_rand_impls, f64, 53, next_f64 }
-float_impls! { f32_rand_impls, f32, 24, next_f32 }
-
-impl Rand for char {
- #[inline]
- fn rand<R: Rng>(rng: &mut R) -> char {
- // a char is 21 bits
- const CHAR_MASK: u32 = 0x001f_ffff;
- loop {
- // Rejection sampling. About 0.2% of numbers with at most
- // 21-bits are invalid codepoints (surrogates), so this
- // will succeed first go almost every time.
- match char::from_u32(rng.next_u32() & CHAR_MASK) {
- Some(c) => return c,
- None => {}
- }
- }
- }
-}
-
-impl Rand for bool {
- #[inline]
- fn rand<R: Rng>(rng: &mut R) -> bool {
- rng.gen::<u8>() & 1 == 1
- }
-}
-
-macro_rules! tuple_impl {
- // use variables to indicate the arity of the tuple
- ($($tyvar:ident),* ) => {
- // the trailing commas are for the 1 tuple
- impl<
- $( $tyvar : Rand ),*
- > Rand for ( $( $tyvar ),* , ) {
-
- #[inline]
- fn rand<R: Rng>(_rng: &mut R) -> ( $( $tyvar ),* , ) {
- (
- // use the $tyvar's to get the appropriate number of
- // repeats (they're not actually needed)
- $(
- _rng.gen::<$tyvar>()
- ),*
- ,
- )
- }
- }
- }
-}
-
-impl Rand for () {
- #[inline]
- fn rand<R: Rng>(_: &mut R) -> () { () }
-}
-tuple_impl!{A}
-tuple_impl!{A, B}
-tuple_impl!{A, B, C}
-tuple_impl!{A, B, C, D}
-tuple_impl!{A, B, C, D, E}
-tuple_impl!{A, B, C, D, E, F}
-tuple_impl!{A, B, C, D, E, F, G}
-tuple_impl!{A, B, C, D, E, F, G, H}
-tuple_impl!{A, B, C, D, E, F, G, H, I}
-tuple_impl!{A, B, C, D, E, F, G, H, I, J}
-tuple_impl!{A, B, C, D, E, F, G, H, I, J, K}
-tuple_impl!{A, B, C, D, E, F, G, H, I, J, K, L}
-
-macro_rules! array_impl {
- {$n:expr, $t:ident, $($ts:ident,)*} => {
- array_impl!{($n - 1), $($ts,)*}
-
- impl<T> Rand for [T; $n] where T: Rand {
- #[inline]
- fn rand<R: Rng>(_rng: &mut R) -> [T; $n] {
- [_rng.gen::<$t>(), $(_rng.gen::<$ts>()),*]
- }
- }
- };
- {$n:expr,} => {
- impl<T> Rand for [T; $n] {
- fn rand<R: Rng>(_rng: &mut R) -> [T; $n] { [] }
- }
- };
-}
-
-array_impl!{32, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,}
-
-impl<T:Rand> Rand for Option<T> {
- #[inline]
- fn rand<R: Rng>(rng: &mut R) -> Option<T> {
- if rng.gen() {
- Some(rng.gen())
- } else {
- None
- }
- }
-}
-
-#[cfg(test)]
-mod tests {
- use {Rng, thread_rng, Open01, Closed01};
-
- struct ConstantRng(u64);
- impl Rng for ConstantRng {
- fn next_u32(&mut self) -> u32 {
- let ConstantRng(v) = *self;
- v as u32
- }
- fn next_u64(&mut self) -> u64 {
- let ConstantRng(v) = *self;
- v
- }
- }
-
- #[test]
- fn floating_point_edge_cases() {
- // the test for exact equality is correct here.
- assert!(ConstantRng(0xffff_ffff).gen::<f32>() != 1.0);
- assert!(ConstantRng(0xffff_ffff_ffff_ffff).gen::<f64>() != 1.0);
- }
-
- #[test]
- fn rand_open() {
- // this is unlikely to catch an incorrect implementation that
- // generates exactly 0 or 1, but it keeps it sane.
- let mut rng = thread_rng();
- for _ in 0..1_000 {
- // strict inequalities
- let Open01(f) = rng.gen::<Open01<f64>>();
- assert!(0.0 < f && f < 1.0);
-
- let Open01(f) = rng.gen::<Open01<f32>>();
- assert!(0.0 < f && f < 1.0);
- }
- }
-
- #[test]
- fn rand_closed() {
- let mut rng = thread_rng();
- for _ in 0..1_000 {
- // strict inequalities
- let Closed01(f) = rng.gen::<Closed01<f64>>();
- assert!(0.0 <= f && f <= 1.0);
-
- let Closed01(f) = rng.gen::<Closed01<f32>>();
- assert!(0.0 <= f && f <= 1.0);
- }
- }
-}
diff --git a/rand/src/read.rs b/rand/src/read.rs
deleted file mode 100644
index c7351b7..0000000
--- a/rand/src/read.rs
+++ /dev/null
@@ -1,123 +0,0 @@
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! A wrapper around any Read to treat it as an RNG.
-
-use std::io::{self, Read};
-use std::mem;
-use Rng;
-
-/// An RNG that reads random bytes straight from a `Read`. This will
-/// work best with an infinite reader, but this is not required.
-///
-/// # Panics
-///
-/// It will panic if it there is insufficient data to fulfill a request.
-///
-/// # Example
-///
-/// ```rust
-/// use rand::{read, Rng};
-///
-/// let data = vec![1, 2, 3, 4, 5, 6, 7, 8];
-/// let mut rng = read::ReadRng::new(&data[..]);
-/// println!("{:x}", rng.gen::<u32>());
-/// ```
-#[derive(Debug)]
-pub struct ReadRng<R> {
- reader: R
-}
-
-impl<R: Read> ReadRng<R> {
- /// Create a new `ReadRng` from a `Read`.
- pub fn new(r: R) -> ReadRng<R> {
- ReadRng {
- reader: r
- }
- }
-}
-
-impl<R: Read> Rng for ReadRng<R> {
- fn next_u32(&mut self) -> u32 {
- // This is designed for speed: reading a LE integer on a LE
- // platform just involves blitting the bytes into the memory
- // of the u32, similarly for BE on BE; avoiding byteswapping.
- let mut buf = [0; 4];
- fill(&mut self.reader, &mut buf).unwrap();
- unsafe { *(buf.as_ptr() as *const u32) }
- }
- fn next_u64(&mut self) -> u64 {
- // see above for explanation.
- let mut buf = [0; 8];
- fill(&mut self.reader, &mut buf).unwrap();
- unsafe { *(buf.as_ptr() as *const u64) }
- }
- fn fill_bytes(&mut self, v: &mut [u8]) {
- if v.len() == 0 { return }
- fill(&mut self.reader, v).unwrap();
- }
-}
-
-fn fill(r: &mut Read, mut buf: &mut [u8]) -> io::Result<()> {
- while buf.len() > 0 {
- match try!(r.read(buf)) {
- 0 => return Err(io::Error::new(io::ErrorKind::Other,
- "end of file reached")),
- n => buf = &mut mem::replace(&mut buf, &mut [])[n..],
- }
- }
- Ok(())
-}
-
-#[cfg(test)]
-mod test {
- use super::ReadRng;
- use Rng;
-
- #[test]
- fn test_reader_rng_u64() {
- // transmute from the target to avoid endianness concerns.
- let v = vec![0u8, 0, 0, 0, 0, 0, 0, 1,
- 0 , 0, 0, 0, 0, 0, 0, 2,
- 0, 0, 0, 0, 0, 0, 0, 3];
- let mut rng = ReadRng::new(&v[..]);
-
- assert_eq!(rng.next_u64(), 1_u64.to_be());
- assert_eq!(rng.next_u64(), 2_u64.to_be());
- assert_eq!(rng.next_u64(), 3_u64.to_be());
- }
- #[test]
- fn test_reader_rng_u32() {
- let v = vec![0u8, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3];
- let mut rng = ReadRng::new(&v[..]);
-
- assert_eq!(rng.next_u32(), 1_u32.to_be());
- assert_eq!(rng.next_u32(), 2_u32.to_be());
- assert_eq!(rng.next_u32(), 3_u32.to_be());
- }
- #[test]
- fn test_reader_rng_fill_bytes() {
- let v = [1u8, 2, 3, 4, 5, 6, 7, 8];
- let mut w = [0u8; 8];
-
- let mut rng = ReadRng::new(&v[..]);
- rng.fill_bytes(&mut w);
-
- assert!(v == w);
- }
-
- #[test]
- #[should_panic]
- fn test_reader_rng_insufficient_bytes() {
- let mut rng = ReadRng::new(&[][..]);
- let mut v = [0u8; 3];
- rng.fill_bytes(&mut v);
- }
-}
diff --git a/rand/src/reseeding.rs b/rand/src/reseeding.rs
deleted file mode 100644
index 1f24e20..0000000
--- a/rand/src/reseeding.rs
+++ /dev/null
@@ -1,229 +0,0 @@
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! A wrapper around another RNG that reseeds it after it
-//! generates a certain number of random bytes.
-
-use core::default::Default;
-
-use {Rng, SeedableRng};
-
-/// How many bytes of entropy the underling RNG is allowed to generate
-/// before it is reseeded
-const DEFAULT_GENERATION_THRESHOLD: u64 = 32 * 1024;
-
-/// A wrapper around any RNG which reseeds the underlying RNG after it
-/// has generated a certain number of random bytes.
-#[derive(Debug)]
-pub struct ReseedingRng<R, Rsdr> {
- rng: R,
- generation_threshold: u64,
- bytes_generated: u64,
- /// Controls the behaviour when reseeding the RNG.
- pub reseeder: Rsdr,
-}
-
-impl<R: Rng, Rsdr: Reseeder<R>> ReseedingRng<R, Rsdr> {
- /// Create a new `ReseedingRng` with the given parameters.
- ///
- /// # Arguments
- ///
- /// * `rng`: the random number generator to use.
- /// * `generation_threshold`: the number of bytes of entropy at which to reseed the RNG.
- /// * `reseeder`: the reseeding object to use.
- pub fn new(rng: R, generation_threshold: u64, reseeder: Rsdr) -> ReseedingRng<R,Rsdr> {
- ReseedingRng {
- rng: rng,
- generation_threshold: generation_threshold,
- bytes_generated: 0,
- reseeder: reseeder
- }
- }
-
- /// Reseed the internal RNG if the number of bytes that have been
- /// generated exceed the threshold.
- pub fn reseed_if_necessary(&mut self) {
- if self.bytes_generated >= self.generation_threshold {
- self.reseeder.reseed(&mut self.rng);
- self.bytes_generated = 0;
- }
- }
-}
-
-
-impl<R: Rng, Rsdr: Reseeder<R>> Rng for ReseedingRng<R, Rsdr> {
- fn next_u32(&mut self) -> u32 {
- self.reseed_if_necessary();
- self.bytes_generated += 4;
- self.rng.next_u32()
- }
-
- fn next_u64(&mut self) -> u64 {
- self.reseed_if_necessary();
- self.bytes_generated += 8;
- self.rng.next_u64()
- }
-
- fn fill_bytes(&mut self, dest: &mut [u8]) {
- self.reseed_if_necessary();
- self.bytes_generated += dest.len() as u64;
- self.rng.fill_bytes(dest)
- }
-}
-
-impl<S, R: SeedableRng<S>, Rsdr: Reseeder<R> + Default>
- SeedableRng<(Rsdr, S)> for ReseedingRng<R, Rsdr> {
- fn reseed(&mut self, (rsdr, seed): (Rsdr, S)) {
- self.rng.reseed(seed);
- self.reseeder = rsdr;
- self.bytes_generated = 0;
- }
-
- /// Create a new `ReseedingRng` from the given reseeder and
- /// seed. This uses a default value for `generation_threshold`.
- fn from_seed((rsdr, seed): (Rsdr, S)) -> ReseedingRng<R, Rsdr> {
- ReseedingRng {
- rng: SeedableRng::from_seed(seed),
- generation_threshold: DEFAULT_GENERATION_THRESHOLD,
- bytes_generated: 0,
- reseeder: rsdr
- }
- }
-}
-
-/// Something that can be used to reseed an RNG via `ReseedingRng`.
-///
-/// # Example
-///
-/// ```rust
-/// use rand::{Rng, SeedableRng, StdRng};
-/// use rand::reseeding::{Reseeder, ReseedingRng};
-///
-/// struct TickTockReseeder { tick: bool }
-/// impl Reseeder<StdRng> for TickTockReseeder {
-/// fn reseed(&mut self, rng: &mut StdRng) {
-/// let val = if self.tick {0} else {1};
-/// rng.reseed(&[val]);
-/// self.tick = !self.tick;
-/// }
-/// }
-/// fn main() {
-/// let rsdr = TickTockReseeder { tick: true };
-///
-/// let inner = StdRng::new().unwrap();
-/// let mut rng = ReseedingRng::new(inner, 10, rsdr);
-///
-/// // this will repeat, because it gets reseeded very regularly.
-/// let s: String = rng.gen_ascii_chars().take(100).collect();
-/// println!("{}", s);
-/// }
-///
-/// ```
-pub trait Reseeder<R> {
- /// Reseed the given RNG.
- fn reseed(&mut self, rng: &mut R);
-}
-
-/// Reseed an RNG using a `Default` instance. This reseeds by
-/// replacing the RNG with the result of a `Default::default` call.
-#[derive(Clone, Copy, Debug)]
-pub struct ReseedWithDefault;
-
-impl<R: Rng + Default> Reseeder<R> for ReseedWithDefault {
- fn reseed(&mut self, rng: &mut R) {
- *rng = Default::default();
- }
-}
-impl Default for ReseedWithDefault {
- fn default() -> ReseedWithDefault { ReseedWithDefault }
-}
-
-#[cfg(test)]
-mod test {
- use std::default::Default;
- use std::iter::repeat;
- use super::{ReseedingRng, ReseedWithDefault};
- use {SeedableRng, Rng};
-
- struct Counter {
- i: u32
- }
-
- impl Rng for Counter {
- fn next_u32(&mut self) -> u32 {
- self.i += 1;
- // very random
- self.i - 1
- }
- }
- impl Default for Counter {
- fn default() -> Counter {
- Counter { i: 0 }
- }
- }
- impl SeedableRng<u32> for Counter {
- fn reseed(&mut self, seed: u32) {
- self.i = seed;
- }
- fn from_seed(seed: u32) -> Counter {
- Counter { i: seed }
- }
- }
- type MyRng = ReseedingRng<Counter, ReseedWithDefault>;
-
- #[test]
- fn test_reseeding() {
- let mut rs = ReseedingRng::new(Counter {i:0}, 400, ReseedWithDefault);
-
- let mut i = 0;
- for _ in 0..1000 {
- assert_eq!(rs.next_u32(), i % 100);
- i += 1;
- }
- }
-
- #[test]
- fn test_rng_seeded() {
- let mut ra: MyRng = SeedableRng::from_seed((ReseedWithDefault, 2));
- let mut rb: MyRng = SeedableRng::from_seed((ReseedWithDefault, 2));
- assert!(::test::iter_eq(ra.gen_ascii_chars().take(100),
- rb.gen_ascii_chars().take(100)));
- }
-
- #[test]
- fn test_rng_reseed() {
- let mut r: MyRng = SeedableRng::from_seed((ReseedWithDefault, 3));
- let string1: String = r.gen_ascii_chars().take(100).collect();
-
- r.reseed((ReseedWithDefault, 3));
-
- let string2: String = r.gen_ascii_chars().take(100).collect();
- assert_eq!(string1, string2);
- }
-
- const FILL_BYTES_V_LEN: usize = 13579;
- #[test]
- fn test_rng_fill_bytes() {
- let mut v = repeat(0u8).take(FILL_BYTES_V_LEN).collect::<Vec<_>>();
- ::test::rng().fill_bytes(&mut v);
-
- // Sanity test: if we've gotten here, `fill_bytes` has not infinitely
- // recursed.
- assert_eq!(v.len(), FILL_BYTES_V_LEN);
-
- // To test that `fill_bytes` actually did something, check that the
- // average of `v` is not 0.
- let mut sum = 0.0;
- for &x in v.iter() {
- sum += x as f64;
- }
- assert!(sum / v.len() as f64 != 0.0);
- }
-}
diff --git a/rand/src/rngs/adapter/mod.rs b/rand/src/rngs/adapter/mod.rs
new file mode 100644
index 0000000..60b832e
--- /dev/null
+++ b/rand/src/rngs/adapter/mod.rs
@@ -0,0 +1,15 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Wrappers / adapters forming RNGs
+
+#[cfg(feature="std")] #[doc(hidden)] pub mod read;
+mod reseeding;
+
+#[cfg(feature="std")] pub use self::read::ReadRng;
+pub use self::reseeding::ReseedingRng;
diff --git a/rand/src/rngs/adapter/read.rs b/rand/src/rngs/adapter/read.rs
new file mode 100644
index 0000000..30b6de6
--- /dev/null
+++ b/rand/src/rngs/adapter/read.rs
@@ -0,0 +1,137 @@
+// Copyright 2018 Developers of the Rand project.
+// Copyright 2013 The Rust Project Developers.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! A wrapper around any Read to treat it as an RNG.
+
+use std::io::Read;
+
+use rand_core::{RngCore, Error, ErrorKind, impls};
+
+
+/// An RNG that reads random bytes straight from any type supporting
+/// `std::io::Read`, for example files.
+///
+/// This will work best with an infinite reader, but that is not required.
+///
+/// This can be used with `/dev/urandom` on Unix but it is recommended to use
+/// [`OsRng`] instead.
+///
+/// # Panics
+///
+/// `ReadRng` uses `std::io::read_exact`, which retries on interrupts. All other
+/// errors from the underlying reader, including when it does not have enough
+/// data, will only be reported through [`try_fill_bytes`]. The other
+/// [`RngCore`] methods will panic in case of an error.
+///
+/// # Example
+///
+/// ```
+/// use rand::Rng;
+/// use rand::rngs::adapter::ReadRng;
+///
+/// let data = vec![1, 2, 3, 4, 5, 6, 7, 8];
+/// let mut rng = ReadRng::new(&data[..]);
+/// println!("{:x}", rng.gen::<u32>());
+/// ```
+///
+/// [`OsRng`]: ../struct.OsRng.html
+/// [`RngCore`]: ../../trait.RngCore.html
+/// [`try_fill_bytes`]: ../../trait.RngCore.html#method.tymethod.try_fill_bytes
+#[derive(Debug)]
+pub struct ReadRng<R> {
+ reader: R
+}
+
+impl<R: Read> ReadRng<R> {
+ /// Create a new `ReadRng` from a `Read`.
+ pub fn new(r: R) -> ReadRng<R> {
+ ReadRng {
+ reader: r
+ }
+ }
+}
+
+impl<R: Read> RngCore for ReadRng<R> {
+ fn next_u32(&mut self) -> u32 {
+ impls::next_u32_via_fill(self)
+ }
+
+ fn next_u64(&mut self) -> u64 {
+ impls::next_u64_via_fill(self)
+ }
+
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
+ self.try_fill_bytes(dest).unwrap_or_else(|err|
+ panic!("reading random bytes from Read implementation failed; error: {}", err));
+ }
+
+ fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ if dest.len() == 0 { return Ok(()); }
+ // Use `std::io::read_exact`, which retries on `ErrorKind::Interrupted`.
+ self.reader.read_exact(dest).map_err(|err| {
+ match err.kind() {
+ ::std::io::ErrorKind::UnexpectedEof => Error::with_cause(
+ ErrorKind::Unavailable,
+ "not enough bytes available, reached end of source", err),
+ _ => Error::with_cause(ErrorKind::Unavailable,
+ "error reading from Read source", err)
+ }
+ })
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::ReadRng;
+ use {RngCore, ErrorKind};
+
+ #[test]
+ fn test_reader_rng_u64() {
+ // transmute from the target to avoid endianness concerns.
+ let v = vec![0u8, 0, 0, 0, 0, 0, 0, 1,
+ 0 , 0, 0, 0, 0, 0, 0, 2,
+ 0, 0, 0, 0, 0, 0, 0, 3];
+ let mut rng = ReadRng::new(&v[..]);
+
+ assert_eq!(rng.next_u64(), 1_u64.to_be());
+ assert_eq!(rng.next_u64(), 2_u64.to_be());
+ assert_eq!(rng.next_u64(), 3_u64.to_be());
+ }
+
+ #[test]
+ fn test_reader_rng_u32() {
+ let v = vec![0u8, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3];
+ let mut rng = ReadRng::new(&v[..]);
+
+ assert_eq!(rng.next_u32(), 1_u32.to_be());
+ assert_eq!(rng.next_u32(), 2_u32.to_be());
+ assert_eq!(rng.next_u32(), 3_u32.to_be());
+ }
+
+ #[test]
+ fn test_reader_rng_fill_bytes() {
+ let v = [1u8, 2, 3, 4, 5, 6, 7, 8];
+ let mut w = [0u8; 8];
+
+ let mut rng = ReadRng::new(&v[..]);
+ rng.fill_bytes(&mut w);
+
+ assert!(v == w);
+ }
+
+ #[test]
+ fn test_reader_rng_insufficient_bytes() {
+ let v = [1u8, 2, 3, 4, 5, 6, 7, 8];
+ let mut w = [0u8; 9];
+
+ let mut rng = ReadRng::new(&v[..]);
+
+ assert!(rng.try_fill_bytes(&mut w).err().unwrap().kind == ErrorKind::Unavailable);
+ }
+}
diff --git a/rand/src/rngs/adapter/reseeding.rs b/rand/src/rngs/adapter/reseeding.rs
new file mode 100644
index 0000000..016afab
--- /dev/null
+++ b/rand/src/rngs/adapter/reseeding.rs
@@ -0,0 +1,370 @@
+// Copyright 2018 Developers of the Rand project.
+// Copyright 2013 The Rust Project Developers.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! A wrapper around another PRNG that reseeds it after it
+//! generates a certain number of random bytes.
+
+use core::mem::size_of;
+
+use rand_core::{RngCore, CryptoRng, SeedableRng, Error, ErrorKind};
+use rand_core::block::{BlockRngCore, BlockRng};
+
+/// A wrapper around any PRNG that implements [`BlockRngCore`], that adds the
+/// ability to reseed it.
+///
+/// `ReseedingRng` reseeds the underlying PRNG in the following cases:
+///
+/// - On a manual call to [`reseed()`].
+/// - After `clone()`, the clone will be reseeded on first use.
+/// - After a process is forked, the RNG in the child process is reseeded within
+/// the next few generated values, depending on the block size of the
+/// underlying PRNG. For [`ChaChaCore`] and [`Hc128Core`] this is a maximum of
+/// 15 `u32` values before reseeding.
+/// - After the PRNG has generated a configurable number of random bytes.
+///
+/// # When should reseeding after a fixed number of generated bytes be used?
+///
+/// Reseeding after a fixed number of generated bytes is never strictly
+/// *necessary*. Cryptographic PRNGs don't have a limited number of bytes they
+/// can output, or at least not a limit reachable in any practical way. There is
+/// no such thing as 'running out of entropy'.
+///
+/// Occasionally reseeding can be seen as some form of 'security in depth'. Even
+/// if in the future a cryptographic weakness is found in the CSPRNG being used,
+/// or a flaw in the implementation, occasionally reseeding should make
+/// exploiting it much more difficult or even impossible.
+///
+/// Use [`ReseedingRng::new`] with a `threshold` of `0` to disable reseeding
+/// after a fixed number of generated bytes.
+///
+/// # Error handling
+///
+/// Although unlikely, reseeding the wrapped PRNG can fail. `ReseedingRng` will
+/// never panic but try to handle the error intelligently through some
+/// combination of retrying and delaying reseeding until later.
+/// If handling the source error fails `ReseedingRng` will continue generating
+/// data from the wrapped PRNG without reseeding.
+///
+/// Manually calling [`reseed()`] will not have this retry or delay logic, but
+/// reports the error.
+///
+/// # Example
+///
+/// ```
+/// # extern crate rand;
+/// # extern crate rand_chacha;
+/// # fn main() {
+/// use rand::prelude::*;
+/// use rand_chacha::ChaChaCore; // Internal part of ChaChaRng that
+/// // implements BlockRngCore
+/// use rand::rngs::OsRng;
+/// use rand::rngs::adapter::ReseedingRng;
+///
+/// let prng = ChaChaCore::from_entropy();
+// FIXME: it is better to use EntropyRng as reseeder, but that doesn't implement
+// clone yet.
+/// let reseeder = OsRng::new().unwrap();
+/// let mut reseeding_rng = ReseedingRng::new(prng, 0, reseeder);
+///
+/// println!("{}", reseeding_rng.gen::<u64>());
+///
+/// let mut cloned_rng = reseeding_rng.clone();
+/// assert!(reseeding_rng.gen::<u64>() != cloned_rng.gen::<u64>());
+/// # }
+/// ```
+///
+/// [`ChaChaCore`]: ../../../rand_chacha/struct.ChaChaCore.html
+/// [`Hc128Core`]: ../../../rand_hc/struct.Hc128Core.html
+/// [`BlockRngCore`]: ../../../rand_core/block/trait.BlockRngCore.html
+/// [`ReseedingRng::new`]: struct.ReseedingRng.html#method.new
+/// [`reseed()`]: struct.ReseedingRng.html#method.reseed
+#[derive(Debug)]
+pub struct ReseedingRng<R, Rsdr>(BlockRng<ReseedingCore<R, Rsdr>>)
+where R: BlockRngCore + SeedableRng,
+ Rsdr: RngCore;
+
+impl<R, Rsdr> ReseedingRng<R, Rsdr>
+where R: BlockRngCore + SeedableRng,
+ Rsdr: RngCore
+{
+ /// Create a new `ReseedingRng` from an existing PRNG, combined with a RNG
+ /// to use as reseeder.
+ ///
+ /// `threshold` sets the number of generated bytes after which to reseed the
+ /// PRNG. Set it to zero to never reseed based on the number of generated
+ /// values.
+ pub fn new(rng: R, threshold: u64, reseeder: Rsdr) -> Self {
+ ReseedingRng(BlockRng::new(ReseedingCore::new(rng, threshold, reseeder)))
+ }
+
+ /// Reseed the internal PRNG.
+ pub fn reseed(&mut self) -> Result<(), Error> {
+ self.0.core.reseed()
+ }
+}
+
+// TODO: this should be implemented for any type where the inner type
+// implements RngCore, but we can't specify that because ReseedingCore is private
+impl<R, Rsdr: RngCore> RngCore for ReseedingRng<R, Rsdr>
+where R: BlockRngCore<Item = u32> + SeedableRng,
+ <R as BlockRngCore>::Results: AsRef<[u32]> + AsMut<[u32]>
+{
+ #[inline(always)]
+ fn next_u32(&mut self) -> u32 {
+ self.0.next_u32()
+ }
+
+ #[inline(always)]
+ fn next_u64(&mut self) -> u64 {
+ self.0.next_u64()
+ }
+
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
+ self.0.fill_bytes(dest)
+ }
+
+ fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ self.0.try_fill_bytes(dest)
+ }
+}
+
+impl<R, Rsdr> Clone for ReseedingRng<R, Rsdr>
+where R: BlockRngCore + SeedableRng + Clone,
+ Rsdr: RngCore + Clone
+{
+ fn clone(&self) -> ReseedingRng<R, Rsdr> {
+ // Recreating `BlockRng` seems easier than cloning it and resetting
+ // the index.
+ ReseedingRng(BlockRng::new(self.0.core.clone()))
+ }
+}
+
+impl<R, Rsdr> CryptoRng for ReseedingRng<R, Rsdr>
+where R: BlockRngCore + SeedableRng + CryptoRng,
+ Rsdr: RngCore + CryptoRng {}
+
+#[derive(Debug)]
+struct ReseedingCore<R, Rsdr> {
+ inner: R,
+ reseeder: Rsdr,
+ threshold: i64,
+ bytes_until_reseed: i64,
+ fork_counter: usize,
+}
+
+impl<R, Rsdr> BlockRngCore for ReseedingCore<R, Rsdr>
+where R: BlockRngCore + SeedableRng,
+ Rsdr: RngCore
+{
+ type Item = <R as BlockRngCore>::Item;
+ type Results = <R as BlockRngCore>::Results;
+
+ fn generate(&mut self, results: &mut Self::Results) {
+ let global_fork_counter = fork::get_fork_counter();
+ if self.bytes_until_reseed <= 0 ||
+ self.is_forked(global_fork_counter) {
+ // We get better performance by not calling only `reseed` here
+ // and continuing with the rest of the function, but by directly
+ // returning from a non-inlined function.
+ return self.reseed_and_generate(results, global_fork_counter);
+ }
+ let num_bytes = results.as_ref().len() * size_of::<Self::Item>();
+ self.bytes_until_reseed -= num_bytes as i64;
+ self.inner.generate(results);
+ }
+}
+
+impl<R, Rsdr> ReseedingCore<R, Rsdr>
+where R: BlockRngCore + SeedableRng,
+ Rsdr: RngCore
+{
+ /// Create a new `ReseedingCore`.
+ fn new(rng: R, threshold: u64, reseeder: Rsdr) -> Self {
+ use ::core::i64::MAX;
+ fork::register_fork_handler();
+
+ // Because generating more values than `i64::MAX` takes centuries on
+ // current hardware, we just clamp to that value.
+ // Also we set a threshold of 0, which indicates no limit, to that
+ // value.
+ let threshold =
+ if threshold == 0 { MAX }
+ else if threshold <= MAX as u64 { threshold as i64 }
+ else { MAX };
+
+ ReseedingCore {
+ inner: rng,
+ reseeder,
+ threshold: threshold as i64,
+ bytes_until_reseed: threshold as i64,
+ fork_counter: 0,
+ }
+ }
+
+ /// Reseed the internal PRNG.
+ fn reseed(&mut self) -> Result<(), Error> {
+ R::from_rng(&mut self.reseeder).map(|result| {
+ self.bytes_until_reseed = self.threshold;
+ self.inner = result
+ })
+ }
+
+ fn is_forked(&self, global_fork_counter: usize) -> bool {
+ // In theory, on 32-bit platforms, it is possible for
+ // `global_fork_counter` to wrap around after ~4e9 forks.
+ //
+ // This check will detect a fork in the normal case where
+ // `fork_counter < global_fork_counter`, and also when the difference
+ // between both is greater than `isize::MAX` (wrapped around).
+ //
+ // It will still fail to detect a fork if there have been more than
+ // `isize::MAX` forks, without any reseed in between. Seems unlikely
+ // enough.
+ (self.fork_counter.wrapping_sub(global_fork_counter) as isize) < 0
+ }
+
+ #[inline(never)]
+ fn reseed_and_generate(&mut self,
+ results: &mut <Self as BlockRngCore>::Results,
+ global_fork_counter: usize)
+ {
+ if self.is_forked(global_fork_counter) {
+ info!("Fork detected, reseeding RNG");
+ } else {
+ trace!("Reseeding RNG (periodic reseed)");
+ }
+
+ let num_bytes =
+ results.as_ref().len() * size_of::<<R as BlockRngCore>::Item>();
+
+ let threshold = if let Err(e) = self.reseed() {
+ let delay = match e.kind {
+ ErrorKind::Transient => num_bytes as i64,
+ kind @ _ if kind.should_retry() => self.threshold >> 8,
+ _ => self.threshold,
+ };
+ warn!("Reseeding RNG delayed reseeding by {} bytes due to \
+ error from source: {}", delay, e);
+ delay
+ } else {
+ self.fork_counter = global_fork_counter;
+ self.threshold
+ };
+
+ self.bytes_until_reseed = threshold - num_bytes as i64;
+ self.inner.generate(results);
+ }
+}
+
+impl<R, Rsdr> Clone for ReseedingCore<R, Rsdr>
+where R: BlockRngCore + SeedableRng + Clone,
+ Rsdr: RngCore + Clone
+{
+ fn clone(&self) -> ReseedingCore<R, Rsdr> {
+ ReseedingCore {
+ inner: self.inner.clone(),
+ reseeder: self.reseeder.clone(),
+ threshold: self.threshold,
+ bytes_until_reseed: 0, // reseed clone on first use
+ fork_counter: self.fork_counter,
+ }
+ }
+}
+
+impl<R, Rsdr> CryptoRng for ReseedingCore<R, Rsdr>
+where R: BlockRngCore + SeedableRng + CryptoRng,
+ Rsdr: RngCore + CryptoRng {}
+
+
+#[cfg(all(feature="std", unix, not(target_os="emscripten")))]
+mod fork {
+ extern crate libc;
+
+ use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
+ use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT};
+
+ // Fork protection
+ //
+ // We implement fork protection on Unix using `pthread_atfork`.
+ // When the process is forked, we increment `RESEEDING_RNG_FORK_COUNTER`.
+ // Every `ReseedingRng` stores the last known value of the static in
+ // `fork_counter`. If the cached `fork_counter` is less than
+ // `RESEEDING_RNG_FORK_COUNTER`, it is time to reseed this RNG.
+ //
+ // If reseeding fails, we don't deal with this by setting a delay, but just
+ // don't update `fork_counter`, so a reseed is attempted as soon as
+ // possible.
+
+ static RESEEDING_RNG_FORK_COUNTER: AtomicUsize = ATOMIC_USIZE_INIT;
+
+ pub fn get_fork_counter() -> usize {
+ RESEEDING_RNG_FORK_COUNTER.load(Ordering::Relaxed)
+ }
+
+ static FORK_HANDLER_REGISTERED: AtomicBool = ATOMIC_BOOL_INIT;
+
+ extern fn fork_handler() {
+ // Note: fetch_add is defined to wrap on overflow
+ // (which is what we want).
+ RESEEDING_RNG_FORK_COUNTER.fetch_add(1, Ordering::Relaxed);
+ }
+
+ pub fn register_fork_handler() {
+ if FORK_HANDLER_REGISTERED.load(Ordering::Relaxed) == false {
+ unsafe { libc::pthread_atfork(None, None, Some(fork_handler)) };
+ FORK_HANDLER_REGISTERED.store(true, Ordering::Relaxed);
+ }
+ }
+}
+
+#[cfg(not(all(feature="std", unix, not(target_os="emscripten"))))]
+mod fork {
+ pub fn get_fork_counter() -> usize { 0 }
+ pub fn register_fork_handler() {}
+}
+
+
+#[cfg(test)]
+mod test {
+ use {Rng, SeedableRng};
+ use rand_chacha::ChaChaCore;
+ use rngs::mock::StepRng;
+ use super::ReseedingRng;
+
+ #[test]
+ fn test_reseeding() {
+ let mut zero = StepRng::new(0, 0);
+ let rng = ChaChaCore::from_rng(&mut zero).unwrap();
+ let mut reseeding = ReseedingRng::new(rng, 32*4, zero);
+
+ // Currently we only support for arrays up to length 32.
+ // TODO: cannot generate seq via Rng::gen because it uses different alg
+ let mut buf = [0u32; 32]; // Needs to be a multiple of the RNGs result
+ // size to test exactly.
+ reseeding.fill(&mut buf);
+ let seq = buf;
+ for _ in 0..10 {
+ reseeding.fill(&mut buf);
+ assert_eq!(buf, seq);
+ }
+ }
+
+ #[test]
+ fn test_clone_reseeding() {
+ let mut zero = StepRng::new(0, 0);
+ let rng = ChaChaCore::from_rng(&mut zero).unwrap();
+ let mut rng1 = ReseedingRng::new(rng, 32*4, zero);
+
+ let first: u32 = rng1.gen();
+ for _ in 0..10 { let _ = rng1.gen::<u32>(); }
+
+ let mut rng2 = rng1.clone();
+ assert_eq!(first, rng2.gen::<u32>());
+ }
+}
diff --git a/rand/src/rngs/entropy.rs b/rand/src/rngs/entropy.rs
new file mode 100644
index 0000000..8736324
--- /dev/null
+++ b/rand/src/rngs/entropy.rs
@@ -0,0 +1,297 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Entropy generator, or wrapper around external generators
+
+use rand_core::{RngCore, CryptoRng, Error, ErrorKind, impls};
+#[allow(unused)]
+use rngs;
+
+/// An interface returning random data from external source(s), provided
+/// specifically for securely seeding algorithmic generators (PRNGs).
+///
+/// Where possible, `EntropyRng` retrieves random data from the operating
+/// system's interface for random numbers ([`OsRng`]); if that fails it will
+/// fall back to the [`JitterRng`] entropy collector. In the latter case it will
+/// still try to use [`OsRng`] on the next usage.
+///
+/// If no secure source of entropy is available `EntropyRng` will panic on use;
+/// i.e. it should never output predictable data.
+///
+/// This is either a little slow ([`OsRng`] requires a system call) or extremely
+/// slow ([`JitterRng`] must use significant CPU time to generate sufficient
+/// jitter); for better performance it is common to seed a local PRNG from
+/// external entropy then primarily use the local PRNG ([`thread_rng`] is
+/// provided as a convenient, local, automatically-seeded CSPRNG).
+///
+/// # Panics
+///
+/// On most systems, like Windows, Linux, macOS and *BSD on common hardware, it
+/// is highly unlikely for both [`OsRng`] and [`JitterRng`] to fail. But on
+/// combinations like webassembly without Emscripten or stdweb both sources are
+/// unavailable. If both sources fail, only [`try_fill_bytes`] is able to
+/// report the error, and only the one from `OsRng`. The other [`RngCore`]
+/// methods will panic in case of an error.
+///
+/// [`OsRng`]: struct.OsRng.html
+/// [`JitterRng`]: jitter/struct.JitterRng.html
+/// [`thread_rng`]: ../fn.thread_rng.html
+/// [`RngCore`]: ../trait.RngCore.html
+/// [`try_fill_bytes`]: ../trait.RngCore.html#method.tymethod.try_fill_bytes
+#[derive(Debug)]
+pub struct EntropyRng {
+ source: Source,
+}
+
+#[derive(Debug)]
+enum Source {
+ Os(Os),
+ Custom(Custom),
+ Jitter(Jitter),
+ None,
+}
+
+impl EntropyRng {
+ /// Create a new `EntropyRng`.
+ ///
+ /// This method will do no system calls or other initialization routines,
+ /// those are done on first use. This is done to make `new` infallible,
+ /// and `try_fill_bytes` the only place to report errors.
+ pub fn new() -> Self {
+ EntropyRng { source: Source::None }
+ }
+}
+
+impl Default for EntropyRng {
+ fn default() -> Self {
+ EntropyRng::new()
+ }
+}
+
+impl RngCore for EntropyRng {
+ fn next_u32(&mut self) -> u32 {
+ impls::next_u32_via_fill(self)
+ }
+
+ fn next_u64(&mut self) -> u64 {
+ impls::next_u64_via_fill(self)
+ }
+
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
+ self.try_fill_bytes(dest).unwrap_or_else(|err|
+ panic!("all entropy sources failed; first error: {}", err))
+ }
+
+ fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ let mut reported_error = None;
+
+ if let Source::Os(ref mut os_rng) = self.source {
+ match os_rng.fill(dest) {
+ Ok(()) => return Ok(()),
+ Err(err) => {
+ warn!("EntropyRng: OsRng failed \
+ [trying other entropy sources]: {}", err);
+ reported_error = Some(err);
+ },
+ }
+ } else if Os::is_supported() {
+ match Os::new_and_fill(dest) {
+ Ok(os_rng) => {
+ debug!("EntropyRng: using OsRng");
+ self.source = Source::Os(os_rng);
+ return Ok(());
+ },
+ Err(err) => { reported_error = reported_error.or(Some(err)) },
+ }
+ }
+
+ if let Source::Custom(ref mut rng) = self.source {
+ match rng.fill(dest) {
+ Ok(()) => return Ok(()),
+ Err(err) => {
+ warn!("EntropyRng: custom entropy source failed \
+ [trying other entropy sources]: {}", err);
+ reported_error = Some(err);
+ },
+ }
+ } else if Custom::is_supported() {
+ match Custom::new_and_fill(dest) {
+ Ok(custom) => {
+ debug!("EntropyRng: using custom entropy source");
+ self.source = Source::Custom(custom);
+ return Ok(());
+ },
+ Err(err) => { reported_error = reported_error.or(Some(err)) },
+ }
+ }
+
+ if let Source::Jitter(ref mut jitter_rng) = self.source {
+ match jitter_rng.fill(dest) {
+ Ok(()) => return Ok(()),
+ Err(err) => {
+ warn!("EntropyRng: JitterRng failed: {}", err);
+ reported_error = Some(err);
+ },
+ }
+ } else if Jitter::is_supported() {
+ match Jitter::new_and_fill(dest) {
+ Ok(jitter_rng) => {
+ debug!("EntropyRng: using JitterRng");
+ self.source = Source::Jitter(jitter_rng);
+ return Ok(());
+ },
+ Err(err) => { reported_error = reported_error.or(Some(err)) },
+ }
+ }
+
+ if let Some(err) = reported_error {
+ Err(Error::with_cause(ErrorKind::Unavailable,
+ "All entropy sources failed",
+ err))
+ } else {
+ Err(Error::new(ErrorKind::Unavailable,
+ "No entropy sources available"))
+ }
+ }
+}
+
+impl CryptoRng for EntropyRng {}
+
+
+
+trait EntropySource {
+ fn new_and_fill(dest: &mut [u8]) -> Result<Self, Error>
+ where Self: Sized;
+
+ fn fill(&mut self, dest: &mut [u8]) -> Result<(), Error>;
+
+ fn is_supported() -> bool { true }
+}
+
+#[allow(unused)]
+#[derive(Clone, Debug)]
+struct NoSource;
+
+#[allow(unused)]
+impl EntropySource for NoSource {
+ fn new_and_fill(dest: &mut [u8]) -> Result<Self, Error> {
+ Err(Error::new(ErrorKind::Unavailable, "Source not supported"))
+ }
+
+ fn fill(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ unreachable!()
+ }
+
+ fn is_supported() -> bool { false }
+}
+
+
+#[cfg(all(feature="std",
+ any(target_os = "linux", target_os = "android",
+ target_os = "netbsd",
+ target_os = "dragonfly",
+ target_os = "haiku",
+ target_os = "emscripten",
+ target_os = "solaris",
+ target_os = "cloudabi",
+ target_os = "macos", target_os = "ios",
+ target_os = "freebsd",
+ target_os = "openbsd", target_os = "bitrig",
+ target_os = "redox",
+ target_os = "fuchsia",
+ windows,
+ all(target_arch = "wasm32", feature = "stdweb"),
+ all(target_arch = "wasm32", feature = "wasm-bindgen"),
+)))]
+#[derive(Clone, Debug)]
+pub struct Os(rngs::OsRng);
+
+#[cfg(all(feature="std",
+ any(target_os = "linux", target_os = "android",
+ target_os = "netbsd",
+ target_os = "dragonfly",
+ target_os = "haiku",
+ target_os = "emscripten",
+ target_os = "solaris",
+ target_os = "cloudabi",
+ target_os = "macos", target_os = "ios",
+ target_os = "freebsd",
+ target_os = "openbsd", target_os = "bitrig",
+ target_os = "redox",
+ target_os = "fuchsia",
+ windows,
+ all(target_arch = "wasm32", feature = "stdweb"),
+ all(target_arch = "wasm32", feature = "wasm-bindgen"),
+)))]
+impl EntropySource for Os {
+ fn new_and_fill(dest: &mut [u8]) -> Result<Self, Error> {
+ let mut rng = rngs::OsRng::new()?;
+ rng.try_fill_bytes(dest)?;
+ Ok(Os(rng))
+ }
+
+ fn fill(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ self.0.try_fill_bytes(dest)
+ }
+}
+
+#[cfg(not(all(feature="std",
+ any(target_os = "linux", target_os = "android",
+ target_os = "netbsd",
+ target_os = "dragonfly",
+ target_os = "haiku",
+ target_os = "emscripten",
+ target_os = "solaris",
+ target_os = "cloudabi",
+ target_os = "macos", target_os = "ios",
+ target_os = "freebsd",
+ target_os = "openbsd", target_os = "bitrig",
+ target_os = "redox",
+ target_os = "fuchsia",
+ windows,
+ all(target_arch = "wasm32", feature = "stdweb"),
+ all(target_arch = "wasm32", feature = "wasm-bindgen"),
+))))]
+type Os = NoSource;
+
+
+type Custom = NoSource;
+
+
+#[cfg(not(target_arch = "wasm32"))]
+#[derive(Clone, Debug)]
+pub struct Jitter(rngs::JitterRng);
+
+#[cfg(not(target_arch = "wasm32"))]
+impl EntropySource for Jitter {
+ fn new_and_fill(dest: &mut [u8]) -> Result<Self, Error> {
+ let mut rng = rngs::JitterRng::new()?;
+ rng.try_fill_bytes(dest)?;
+ Ok(Jitter(rng))
+ }
+
+ fn fill(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ self.0.try_fill_bytes(dest)
+ }
+}
+
+#[cfg(target_arch = "wasm32")]
+type Jitter = NoSource;
+
+
+#[cfg(test)]
+mod test {
+ use super::*;
+
+ #[test]
+ fn test_entropy() {
+ let mut rng = EntropyRng::new();
+ let n = (rng.next_u32() ^ rng.next_u32()).count_ones();
+ assert!(n >= 2); // p(failure) approx 1e-7
+ }
+}
diff --git a/rand/src/jitter.rs b/rand/src/rngs/jitter.rs
index 3693481..3e93477 100644
--- a/rand/src/jitter.rs
+++ b/rand/src/rngs/jitter.rs
@@ -1,10 +1,8 @@
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
+// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//
@@ -16,10 +14,15 @@
//! Non-physical true random number generator based on timing jitter.
-use Rng;
+// Note: the C implementation of `Jitterentropy` relies on being compiled
+// without optimizations. This implementation goes through lengths to make the
+// compiler not optimize out code which does influence timing jitter, but is
+// technically dead code.
+
+use rand_core::{RngCore, CryptoRng, Error, ErrorKind, impls};
use core::{fmt, mem, ptr};
-#[cfg(feature="std")]
+#[cfg(all(feature="std", not(target_arch = "wasm32")))]
use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
const MEMORY_BLOCKS: usize = 64;
@@ -31,8 +34,8 @@ const MEMORY_SIZE: usize = MEMORY_BLOCKS * MEMORY_BLOCKSIZE;
///
/// This is a true random number generator, as opposed to pseudo-random
/// generators. Random numbers generated by `JitterRng` can be seen as fresh
-/// entropy. A consequence is that is orders of magnitude slower than `OsRng`
-/// and PRNGs (about 10^3 .. 10^6 slower).
+/// entropy. A consequence is that is orders of magnitude slower than [`OsRng`]
+/// and PRNGs (about 10<sup>3</sup>..10<sup>6</sup> slower).
///
/// There are very few situations where using this RNG is appropriate. Only very
/// few applications require true entropy. A normal PRNG can be statistically
@@ -40,29 +43,155 @@ const MEMORY_SIZE: usize = MEMORY_BLOCKS * MEMORY_BLOCKSIZE;
/// predict.
///
/// Use of `JitterRng` is recommended for initializing cryptographic PRNGs when
-/// `OsRng` is not available.
+/// [`OsRng`] is not available.
+///
+/// `JitterRng` can be used without the standard library, but not conveniently,
+/// you must provide a high-precision timer and carefully have to follow the
+/// instructions of [`new_with_timer`].
///
/// This implementation is based on
/// [Jitterentropy](http://www.chronox.de/jent.html) version 2.1.0.
-//
-// Note: the C implementation relies on being compiled without optimizations.
-// This implementation goes through lengths to make the compiler not optimise
-// out what is technically dead code, but that does influence timing jitter.
+///
+/// Note: There is no accurate timer available on Wasm platforms, to help
+/// prevent fingerprinting or timing side-channel attacks. Therefore
+/// [`JitterRng::new()`] is not available on Wasm.
+///
+/// # Quality testing
+///
+/// [`JitterRng::new()`] has build-in, but limited, quality testing, however
+/// before using `JitterRng` on untested hardware, or after changes that could
+/// effect how the code is optimized (such as a new LLVM version), it is
+/// recommend to run the much more stringent
+/// [NIST SP 800-90B Entropy Estimation Suite](
+/// https://github.com/usnistgov/SP800-90B_EntropyAssessment).
+///
+/// Use the following code using [`timer_stats`] to collect the data:
+///
+/// ```no_run
+/// use rand::rngs::JitterRng;
+/// #
+/// # use std::error::Error;
+/// # use std::fs::File;
+/// # use std::io::Write;
+/// #
+/// # fn try_main() -> Result<(), Box<Error>> {
+/// let mut rng = JitterRng::new()?;
+///
+/// // 1_000_000 results are required for the
+/// // NIST SP 800-90B Entropy Estimation Suite
+/// const ROUNDS: usize = 1_000_000;
+/// let mut deltas_variable: Vec<u8> = Vec::with_capacity(ROUNDS);
+/// let mut deltas_minimal: Vec<u8> = Vec::with_capacity(ROUNDS);
+///
+/// for _ in 0..ROUNDS {
+/// deltas_variable.push(rng.timer_stats(true) as u8);
+/// deltas_minimal.push(rng.timer_stats(false) as u8);
+/// }
+///
+/// // Write out after the statistics collection loop, to not disturb the
+/// // test results.
+/// File::create("jitter_rng_var.bin")?.write(&deltas_variable)?;
+/// File::create("jitter_rng_min.bin")?.write(&deltas_minimal)?;
+/// #
+/// # Ok(())
+/// # }
+/// #
+/// # fn main() {
+/// # try_main().unwrap();
+/// # }
+/// ```
+///
+/// This will produce two files: `jitter_rng_var.bin` and `jitter_rng_min.bin`.
+/// Run the Entropy Estimation Suite in three configurations, as outlined below.
+/// Every run has two steps. One step to produce an estimation, another to
+/// validate the estimation.
+///
+/// 1. Estimate the expected amount of entropy that is at least available with
+/// each round of the entropy collector. This number should be greater than
+/// the amount estimated with `64 / test_timer()`.
+/// ```sh
+/// python noniid_main.py -v jitter_rng_var.bin 8
+/// restart.py -v jitter_rng_var.bin 8 <min-entropy>
+/// ```
+/// 2. Estimate the expected amount of entropy that is available in the last 4
+/// bits of the timer delta after running noice sources. Note that a value of
+/// `3.70` is the minimum estimated entropy for true randomness.
+/// ```sh
+/// python noniid_main.py -v -u 4 jitter_rng_var.bin 4
+/// restart.py -v -u 4 jitter_rng_var.bin 4 <min-entropy>
+/// ```
+/// 3. Estimate the expected amount of entropy that is available to the entropy
+/// collector if both noice sources only run their minimal number of times.
+/// This measures the absolute worst-case, and gives a lower bound for the
+/// available entropy.
+/// ```sh
+/// python noniid_main.py -v -u 4 jitter_rng_min.bin 4
+/// restart.py -v -u 4 jitter_rng_min.bin 4 <min-entropy>
+/// ```
+///
+/// [`OsRng`]: struct.OsRng.html
+/// [`JitterRng::new()`]: struct.JitterRng.html#method.new
+/// [`new_with_timer`]: struct.JitterRng.html#method.new_with_timer
+/// [`timer_stats`]: struct.JitterRng.html#method.timer_stats
pub struct JitterRng {
data: u64, // Actual random number
// Number of rounds to run the entropy collector per 64 bits
- rounds: u32,
- // Timer and previous time stamp, used by `measure_jitter`
+ rounds: u8,
+ // Timer used by `measure_jitter`
timer: fn() -> u64,
+ // Memory for the Memory Access noise source
+ mem_prev_index: u16,
+ // Make `next_u32` not waste 32 bits
+ data_half_used: bool,
+}
+
+// Note: `JitterRng` maintains a small 64-bit entropy pool. With every
+// `generate` 64 new bits should be integrated in the pool. If a round of
+// `generate` were to collect less than the expected 64 bit, then the returned
+// value, and the new state of the entropy pool, would be in some way related to
+// the initial state. It is therefore better if the initial state of the entropy
+// pool is different on each call to `generate`. This has a few implications:
+// - `generate` should be called once before using `JitterRng` to produce the
+// first usable value (this is done by default in `new`);
+// - We do not zero the entropy pool after generating a result. The reference
+// implementation also does not support zeroing, but recommends generating a
+// new value without using it if you want to protect a previously generated
+// 'secret' value from someone inspecting the memory;
+// - Implementing `Clone` seems acceptable, as it would not cause the systematic
+// bias a constant might cause. Only instead of one value that could be
+// potentially related to the same initial state, there are now two.
+
+// Entropy collector state.
+// These values are not necessary to preserve across runs.
+struct EcState {
+ // Previous time stamp to determine the timer delta
prev_time: u64,
// Deltas used for the stuck test
- last_delta: i64,
- last_delta2: i64,
+ last_delta: i32,
+ last_delta2: i32,
// Memory for the Memory Access noise source
- mem_prev_index: usize,
mem: [u8; MEMORY_SIZE],
- // Make `next_u32` not waste 32 bits
- data_remaining: Option<u32>,
+}
+
+impl EcState {
+ // Stuck test by checking the:
+ // - 1st derivation of the jitter measurement (time delta)
+ // - 2nd derivation of the jitter measurement (delta of time deltas)
+ // - 3rd derivation of the jitter measurement (delta of delta of time
+ // deltas)
+ //
+ // All values must always be non-zero.
+ // This test is a heuristic to see whether the last measurement holds
+ // entropy.
+ fn stuck(&mut self, current_delta: i32) -> bool {
+ let delta2 = self.last_delta - current_delta;
+ let delta3 = delta2 - self.last_delta2;
+
+ self.last_delta = current_delta;
+ self.last_delta2 = delta2;
+
+ current_delta == 0 || delta2 == 0 || delta3 == 0
+ }
}
// Custom Debug implementation that does not expose the internal state
@@ -72,7 +201,23 @@ impl fmt::Debug for JitterRng {
}
}
-/// An error that can occur when `test_timer` fails.
+impl Clone for JitterRng {
+ fn clone(&self) -> JitterRng {
+ JitterRng {
+ data: self.data,
+ rounds: self.rounds,
+ timer: self.timer,
+ mem_prev_index: self.mem_prev_index,
+ // The 32 bits that may still be unused from the previous round are
+ // for the original to use, not for the clone.
+ data_half_used: false,
+ }
+ }
+}
+
+/// An error that can occur when [`JitterRng::test_timer`] fails.
+///
+/// [`JitterRng::test_timer`]: struct.JitterRng.html#method.test_timer
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum TimerError {
/// No timer available.
@@ -115,29 +260,43 @@ impl ::std::error::Error for TimerError {
}
}
+impl From<TimerError> for Error {
+ fn from(err: TimerError) -> Error {
+ // Timer check is already quite permissive of failures so we don't
+ // expect false-positive failures, i.e. any error is irrecoverable.
+ Error::with_cause(ErrorKind::Unavailable,
+ "timer jitter failed basic quality tests", err)
+ }
+}
+
// Initialise to zero; must be positive
-#[cfg(feature="std")]
+#[cfg(all(feature="std", not(target_arch = "wasm32")))]
static JITTER_ROUNDS: AtomicUsize = ATOMIC_USIZE_INIT;
impl JitterRng {
- /// Create a new `JitterRng`.
- /// Makes use of `std::time` for a timer.
+ /// Create a new `JitterRng`. Makes use of `std::time` for a timer, or a
+ /// platform-specific function with higher accuracy if necessary and
+ /// available.
///
/// During initialization CPU execution timing jitter is measured a few
/// hundred times. If this does not pass basic quality tests, an error is
/// returned. The test result is cached to make subsequent calls faster.
- #[cfg(feature="std")]
+ #[cfg(all(feature="std", not(target_arch = "wasm32")))]
pub fn new() -> Result<JitterRng, TimerError> {
- let mut ec = JitterRng::new_with_timer(platform::get_nstime);
- let mut rounds = JITTER_ROUNDS.load(Ordering::Relaxed) as u32;
+ let mut state = JitterRng::new_with_timer(platform::get_nstime);
+ let mut rounds = JITTER_ROUNDS.load(Ordering::Relaxed) as u8;
if rounds == 0 {
// No result yet: run test.
// This allows the timer test to run multiple times; we don't care.
- rounds = ec.test_timer()?;
+ rounds = state.test_timer()?;
JITTER_ROUNDS.store(rounds as usize, Ordering::Relaxed);
+ info!("JitterRng: using {} rounds per u64 output", rounds);
}
- ec.set_rounds(rounds);
- Ok(ec)
+ state.set_rounds(rounds);
+
+ // Fill `data` with a non-zero value.
+ state.gen_entropy();
+ Ok(state)
}
/// Create a new `JitterRng`.
@@ -147,44 +306,65 @@ impl JitterRng {
/// The timer must have nanosecond precision.
///
/// This method is more low-level than `new()`. It is the responsibility of
- /// the caller to run `test_timer` before using any numbers generated with
- /// `JitterRng`, and optionally call `set_rounds()`.
+ /// the caller to run [`test_timer`] before using any numbers generated with
+ /// `JitterRng`, and optionally call [`set_rounds`]. Also it is important to
+ /// consume at least one `u64` before using the first result to initialize
+ /// the entropy collection pool.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// # use rand::{Rng, Error};
+ /// use rand::rngs::JitterRng;
+ ///
+ /// # fn try_inner() -> Result<(), Error> {
+ /// fn get_nstime() -> u64 {
+ /// use std::time::{SystemTime, UNIX_EPOCH};
+ ///
+ /// let dur = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
+ /// // The correct way to calculate the current time is
+ /// // `dur.as_secs() * 1_000_000_000 + dur.subsec_nanos() as u64`
+ /// // But this is faster, and the difference in terms of entropy is
+ /// // negligible (log2(10^9) == 29.9).
+ /// dur.as_secs() << 30 | dur.subsec_nanos() as u64
+ /// }
+ ///
+ /// let mut rng = JitterRng::new_with_timer(get_nstime);
+ /// let rounds = rng.test_timer()?;
+ /// rng.set_rounds(rounds); // optional
+ /// let _ = rng.gen::<u64>();
+ ///
+ /// // Ready for use
+ /// let v: u64 = rng.gen();
+ /// # Ok(())
+ /// # }
+ ///
+ /// # let _ = try_inner();
+ /// ```
+ ///
+ /// [`test_timer`]: struct.JitterRng.html#method.test_timer
+ /// [`set_rounds`]: struct.JitterRng.html#method.set_rounds
pub fn new_with_timer(timer: fn() -> u64) -> JitterRng {
- let mut ec = JitterRng {
+ JitterRng {
data: 0,
rounds: 64,
- timer: timer,
- prev_time: 0,
- last_delta: 0,
- last_delta2: 0,
+ timer,
mem_prev_index: 0,
- mem: [0; MEMORY_SIZE],
- data_remaining: None,
- };
-
- // Fill `data`, `prev_time`, `last_delta` and `last_delta2` with
- // non-zero values.
- ec.prev_time = timer();
- ec.gen_entropy();
-
- // Do a single read from `self.mem` to make sure the Memory Access noise
- // source is not optimised out.
- // Note: this read is important, it effects optimisations for the entire
- // module!
- black_box(ec.mem[0]);
-
- ec
+ data_half_used: false,
+ }
}
/// Configures how many rounds are used to generate each 64-bit value.
/// This must be greater than zero, and has a big impact on performance
/// and output quality.
///
- /// `new_with_timer` conservatively uses 64 rounds, but often less rounds
+ /// [`new_with_timer`] conservatively uses 64 rounds, but often less rounds
/// can be used. The `test_timer()` function returns the minimum number of
/// rounds required for full strength (platform dependent), so one may use
/// `rng.set_rounds(rng.test_timer()?);` or cache the value.
- pub fn set_rounds(&mut self, rounds: u32) {
+ ///
+ /// [`new_with_timer`]: struct.JitterRng.html#method.new_with_timer
+ pub fn set_rounds(&mut self, rounds: u8) {
assert!(rounds > 0);
self.rounds = rounds;
}
@@ -212,7 +392,7 @@ impl JitterRng {
let mask = (1 << n_bits) - 1;
for _ in 0..folds {
rounds ^= time & mask;
- time = time >> n_bits;
+ time >>= n_bits;
}
rounds as u32
@@ -233,7 +413,7 @@ impl JitterRng {
fn lfsr(mut data: u64, time: u64) -> u64{
for i in 1..65 {
let mut tmp = time << (64 - i);
- tmp = tmp >> (64 - 1);
+ tmp >>= 64 - 1;
// Fibonacci LSFR with polynomial of
// x^64 + x^61 + x^56 + x^31 + x^28 + x^23 + 1 which is
@@ -288,11 +468,11 @@ impl JitterRng {
// range of wait states. However, to reliably access either L3 or memory,
// the `self.mem` memory must be quite large which is usually not desirable.
#[inline(never)]
- fn memaccess(&mut self, var_rounds: bool) {
+ fn memaccess(&mut self, mem: &mut [u8; MEMORY_SIZE], var_rounds: bool) {
let mut acc_loop_cnt = 128;
if var_rounds { acc_loop_cnt += self.random_loop_cnt(4) };
- let mut index = self.mem_prev_index;
+ let mut index = self.mem_prev_index as usize;
for _ in 0..acc_loop_cnt {
// Addition of memblocksize - 1 to index with wrap around logic to
// ensure that every memory location is hit evenly.
@@ -302,42 +482,21 @@ impl JitterRng {
// memory access: just add 1 to one byte
// memory access implies read from and write to memory location
- let tmp = self.mem[index];
- self.mem[index] = tmp.wrapping_add(1);
+ mem[index] = mem[index].wrapping_add(1);
}
- self.mem_prev_index = index;
- }
-
-
- // Stuck test by checking the:
- // - 1st derivation of the jitter measurement (time delta)
- // - 2nd derivation of the jitter measurement (delta of time deltas)
- // - 3rd derivation of the jitter measurement (delta of delta of time
- // deltas)
- //
- // All values must always be non-zero.
- // This test is a heuristic to see whether the last measurement holds
- // entropy.
- fn stuck(&mut self, current_delta: i64) -> bool {
- let delta2 = self.last_delta - current_delta;
- let delta3 = delta2 - self.last_delta2;
-
- self.last_delta = current_delta;
- self.last_delta2 = delta2;
-
- current_delta == 0 || delta2 == 0 || delta3 == 0
+ self.mem_prev_index = index as u16;
}
// This is the heart of the entropy generation: calculate time deltas and
// use the CPU jitter in the time deltas. The jitter is injected into the
// entropy pool.
//
- // Ensure that `self.prev_time` is primed before using the output of this
+ // Ensure that `ec.prev_time` is primed before using the output of this
// function. This can be done by calling this function and not using its
// result.
- fn measure_jitter(&mut self) -> Option<()> {
+ fn measure_jitter(&mut self, ec: &mut EcState) -> Option<()> {
// Invoke one noise source before time measurement to add variations
- self.memaccess(true);
+ self.memaccess(&mut ec.mem, true);
// Get time stamp and calculate time delta to previous
// invocation to measure the timing variations
@@ -345,15 +504,15 @@ impl JitterRng {
// Note: wrapping_sub combined with a cast to `i64` generates a correct
// delta, even in the unlikely case this is a timer that is not strictly
// monotonic.
- let current_delta = time.wrapping_sub(self.prev_time) as i64;
- self.prev_time = time;
+ let current_delta = time.wrapping_sub(ec.prev_time) as i64 as i32;
+ ec.prev_time = time;
// Call the next noise source which also injects the data
self.lfsr_time(current_delta as u64, true);
// Check whether we have a stuck measurement (i.e. does the last
// measurement holds entropy?).
- if self.stuck(current_delta) { return None };
+ if ec.stuck(current_delta) { return None };
// Rotate the data buffer by a prime number (any odd number would
// do) to ensure that every bit position of the input time stamp
@@ -415,35 +574,47 @@ impl JitterRng {
}
fn gen_entropy(&mut self) -> u64 {
- // Prime `self.prev_time`, and run the noice sources to make sure the
+ trace!("JitterRng: collecting entropy");
+
+ // Prime `ec.prev_time`, and run the noice sources to make sure the
// first loop round collects the expected entropy.
- let _ = self.measure_jitter();
+ let mut ec = EcState {
+ prev_time: (self.timer)(),
+ last_delta: 0,
+ last_delta2: 0,
+ mem: [0; MEMORY_SIZE],
+ };
+ let _ = self.measure_jitter(&mut ec);
for _ in 0..self.rounds {
// If a stuck measurement is received, repeat measurement
// Note: we do not guard against an infinite loop, that would mean
// the timer suddenly became broken.
- while self.measure_jitter().is_none() {}
+ while self.measure_jitter(&mut ec).is_none() {}
}
+ // Do a single read from `self.mem` to make sure the Memory Access noise
+ // source is not optimised out.
+ black_box(ec.mem[0]);
+
self.stir_pool();
self.data
}
-
+
/// Basic quality tests on the timer, by measuring CPU timing jitter a few
/// hundred times.
///
/// If succesful, this will return the estimated number of rounds necessary
- /// to collect 64 bits of entropy. Otherwise a `TimerError` with the cause
+ /// to collect 64 bits of entropy. Otherwise a [`TimerError`] with the cause
/// of the failure will be returned.
- pub fn test_timer(&mut self) -> Result<u32, TimerError> {
+ ///
+ /// [`TimerError`]: enum.TimerError.html
+ pub fn test_timer(&mut self) -> Result<u8, TimerError> {
+ debug!("JitterRng: testing timer ...");
// We could add a check for system capabilities such as `clock_getres`
// or check for `CONFIG_X86_TSC`, but it does not make much sense as the
// following sanity checks verify that we have a high-resolution timer.
- #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
- return Err(TimerError::NoTimer);
-
let mut delta_sum = 0;
let mut old_delta = 0;
@@ -451,6 +622,13 @@ impl JitterRng {
let mut count_mod = 0;
let mut count_stuck = 0;
+ let mut ec = EcState {
+ prev_time: (self.timer)(),
+ last_delta: 0,
+ last_delta2: 0,
+ mem: [0; MEMORY_SIZE],
+ };
+
// TESTLOOPCOUNT needs some loops to identify edge systems.
// 100 is definitely too little.
const TESTLOOPCOUNT: u64 = 300;
@@ -459,7 +637,7 @@ impl JitterRng {
for i in 0..(CLEARCACHE + TESTLOOPCOUNT) {
// Measure time delta of core entropy collection logic
let time = (self.timer)();
- self.memaccess(true);
+ self.memaccess(&mut ec.mem, true);
self.lfsr_time(time, true);
let time2 = (self.timer)();
@@ -467,7 +645,7 @@ impl JitterRng {
if time == 0 || time2 == 0 {
return Err(TimerError::NoTimer);
}
- let delta = time2.wrapping_sub(time) as i64;
+ let delta = time2.wrapping_sub(time) as i64 as i32;
// Test whether timer is fine grained enough to provide delta even
// when called shortly after each other -- this implies that we also
@@ -483,7 +661,7 @@ impl JitterRng {
// measurements.
if i < CLEARCACHE { continue; }
- if self.stuck(delta) { count_stuck += 1; }
+ if ec.stuck(delta) { count_stuck += 1; }
// Test whether we have an increasing timer.
if !(time2 > time) { time_backwards += 1; }
@@ -499,6 +677,10 @@ impl JitterRng {
old_delta = delta;
}
+ // Do a single read from `self.mem` to make sure the Memory Access noise
+ // source is not optimised out.
+ black_box(ec.mem[0]);
+
// We allow the time to run backwards for up to three times.
// This can happen if the clock is being adjusted by NTP operations.
// If such an operation just happens to interfere with our test, it
@@ -539,140 +721,69 @@ impl JitterRng {
// available bits of entropy per round here for two reasons:
// 1. Simple estimates of the available bits (like Shannon entropy) are
// too optimistic.
- // 2) Unless we want to waste a lot of time during intialization, there
- // only a small number of samples are available.
+ // 2. Unless we want to waste a lot of time during intialization, there
+ // only a small number of samples are available.
//
// Therefore we use a very simple and conservative estimate:
// `let bits_of_entropy = log2(delta_average) / 2`.
//
// The number of rounds `measure_jitter` should run to collect 64 bits
// of entropy is `64 / bits_of_entropy`.
- //
- // To have smaller rounding errors, intermediate values are multiplied
- // by `FACTOR`. To compensate for `log2` and division rounding down,
- // add 1.
let delta_average = delta_sum / TESTLOOPCOUNT;
- // println!("delta_average: {}", delta_average);
-
- const FACTOR: u32 = 3;
- fn log2(x: u64) -> u32 { 64 - x.leading_zeros() }
- // pow(δ, FACTOR) must be representable; if you have overflow reduce FACTOR
- Ok(64 * 2 * FACTOR / (log2(delta_average.pow(FACTOR)) + 1))
+ if delta_average >= 16 {
+ let log2 = 64 - delta_average.leading_zeros();
+ // Do something similar to roundup(64/(log2/2)):
+ Ok( ((64u32 * 2 + log2 - 1) / log2) as u8)
+ } else {
+ // For values < 16 the rounding error becomes too large, use a
+ // lookup table.
+ // Values 0 and 1 are invalid, and filtered out by the
+ // `delta_sum < TESTLOOPCOUNT` test above.
+ let log2_lookup = [0, 0, 128, 81, 64, 56, 50, 46,
+ 43, 41, 39, 38, 36, 35, 34, 33];
+ Ok(log2_lookup[delta_average as usize])
+ }
}
/// Statistical test: return the timer delta of one normal run of the
- /// `JitterEntropy` entropy collector.
+ /// `JitterRng` entropy collector.
///
/// Setting `var_rounds` to `true` will execute the memory access and the
/// CPU jitter noice sources a variable amount of times (just like a real
- /// `JitterEntropy` round).
+ /// `JitterRng` round).
///
/// Setting `var_rounds` to `false` will execute the noice sources the
/// minimal number of times. This can be used to measure the minimum amount
- /// of entropy one round of entropy collector can collect in the worst case.
- ///
- /// # Example
- ///
- /// Use `timer_stats` to run the [NIST SP 800-90B Entropy Estimation Suite]
- /// (https://github.com/usnistgov/SP800-90B_EntropyAssessment).
- ///
- /// This is the recommended way to test the quality of `JitterRng`. It
- /// should be run before using the RNG on untested hardware, after changes
- /// that could effect how the code is optimised, and after major compiler
- /// compiler changes, like a new LLVM version.
- ///
- /// First generate two files `jitter_rng_var.bin` and `jitter_rng_var.min`.
- ///
- /// Execute `python noniid_main.py -v jitter_rng_var.bin 8`, and validate it
- /// with `restart.py -v jitter_rng_var.bin 8 <min-entropy>`.
- /// This number is the expected amount of entropy that is at least available
- /// for each round of the entropy collector. This number should be greater
- /// than the amount estimated with `64 / test_timer()`.
- ///
- /// Execute `python noniid_main.py -v -u 4 jitter_rng_var.bin 4`, and
- /// validate it with `restart.py -v -u 4 jitter_rng_var.bin 4 <min-entropy>`.
- /// This number is the expected amount of entropy that is available in the
- /// last 4 bits of the timer delta after running noice sources. Note that
- /// a value of 3.70 is the minimum estimated entropy for true randomness.
- ///
- /// Execute `python noniid_main.py -v -u 4 jitter_rng_var.bin 4`, and
- /// validate it with `restart.py -v -u 4 jitter_rng_var.bin 4 <min-entropy>`.
- /// This number is the expected amount of entropy that is available to the
- /// entropy collecter if both noice sources only run their minimal number of
- /// times. This measures the absolute worst-case, and gives a lower bound
- /// for the available entropy.
- ///
- /// ```rust,no_run
- /// use rand::JitterRng;
- ///
- /// # use std::error::Error;
- /// # use std::fs::File;
- /// # use std::io::Write;
- /// #
- /// # fn try_main() -> Result<(), Box<Error>> {
- /// fn get_nstime() -> u64 {
- /// use std::time::{SystemTime, UNIX_EPOCH};
- ///
- /// let dur = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
- /// // The correct way to calculate the current time is
- /// // `dur.as_secs() * 1_000_000_000 + dur.subsec_nanos() as u64`
- /// // But this is faster, and the difference in terms of entropy is
- /// // negligible (log2(10^9) == 29.9).
- /// dur.as_secs() << 30 | dur.subsec_nanos() as u64
- /// }
- ///
- /// // Do not initialize with `JitterRng::new`, but with `new_with_timer`.
- /// // 'new' always runst `test_timer`, and can therefore fail to
- /// // initialize. We want to be able to get the statistics even when the
- /// // timer test fails.
- /// let mut rng = JitterRng::new_with_timer(get_nstime);
- ///
- /// // 1_000_000 results are required for the NIST SP 800-90B Entropy
- /// // Estimation Suite
- /// // FIXME: this number is smaller here, otherwise the Doc-test is too slow
- /// const ROUNDS: usize = 10_000;
- /// let mut deltas_variable: Vec<u8> = Vec::with_capacity(ROUNDS);
- /// let mut deltas_minimal: Vec<u8> = Vec::with_capacity(ROUNDS);
+ /// of entropy one round of the entropy collector can collect in the worst
+ /// case.
///
- /// for _ in 0..ROUNDS {
- /// deltas_variable.push(rng.timer_stats(true) as u8);
- /// deltas_minimal.push(rng.timer_stats(false) as u8);
- /// }
- ///
- /// // Write out after the statistics collection loop, to not disturb the
- /// // test results.
- /// File::create("jitter_rng_var.bin")?.write(&deltas_variable)?;
- /// File::create("jitter_rng_min.bin")?.write(&deltas_minimal)?;
- /// #
- /// # Ok(())
- /// # }
- /// #
- /// # fn main() {
- /// # try_main().unwrap();
- /// # }
- /// ```
- #[cfg(feature="std")]
+ /// See [Quality testing](struct.JitterRng.html#quality-testing) on how to
+ /// use `timer_stats` to test the quality of `JitterRng`.
pub fn timer_stats(&mut self, var_rounds: bool) -> i64 {
- let time = platform::get_nstime();
- self.memaccess(var_rounds);
+ let mut mem = [0; MEMORY_SIZE];
+
+ let time = (self.timer)();
+ self.memaccess(&mut mem, var_rounds);
self.lfsr_time(time, var_rounds);
- let time2 = platform::get_nstime();
+ let time2 = (self.timer)();
time2.wrapping_sub(time) as i64
}
}
#[cfg(feature="std")]
mod platform {
- #[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "windows", all(target_arch = "wasm32", not(target_os = "emscripten")))))]
+ #[cfg(not(any(target_os = "macos", target_os = "ios",
+ target_os = "windows",
+ target_arch = "wasm32")))]
pub fn get_nstime() -> u64 {
use std::time::{SystemTime, UNIX_EPOCH};
let dur = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
// The correct way to calculate the current time is
// `dur.as_secs() * 1_000_000_000 + dur.subsec_nanos() as u64`
- // But this is faster, and the difference in terms of entropy is negligible
- // (log2(10^9) == 29.9).
+ // But this is faster, and the difference in terms of entropy is
+ // negligible (log2(10^9) == 29.9).
dur.as_secs() << 30 | dur.subsec_nanos() as u64
}
@@ -680,11 +791,11 @@ mod platform {
pub fn get_nstime() -> u64 {
extern crate libc;
// On Mac OS and iOS std::time::SystemTime only has 1000ns resolution.
- // We use `mach_absolute_time` instead. This provides a CPU dependent unit,
- // to get real nanoseconds the result should by multiplied by numer/denom
- // from `mach_timebase_info`.
- // But we are not interested in the exact nanoseconds, just entropy. So we
- // use the raw result.
+ // We use `mach_absolute_time` instead. This provides a CPU dependent
+ // unit, to get real nanoseconds the result should by multiplied by
+ // numer/denom from `mach_timebase_info`.
+ // But we are not interested in the exact nanoseconds, just entropy. So
+ // we use the raw result.
unsafe { libc::mach_absolute_time() }
}
@@ -697,11 +808,6 @@ mod platform {
*t.QuadPart() as u64
}
}
-
- #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
- pub fn get_nstime() -> u64 {
- unreachable!()
- }
}
// A function that is opaque to the optimizer to assist in avoiding dead-code
@@ -714,41 +820,66 @@ fn black_box<T>(dummy: T) -> T {
}
}
-impl Rng for JitterRng {
+impl RngCore for JitterRng {
fn next_u32(&mut self) -> u32 {
// We want to use both parts of the generated entropy
- if let Some(high) = self.data_remaining.take() {
- high
+ if self.data_half_used {
+ self.data_half_used = false;
+ (self.data >> 32) as u32
} else {
- let data = self.next_u64();
- self.data_remaining = Some((data >> 32) as u32);
- data as u32
+ self.data = self.next_u64();
+ self.data_half_used = true;
+ self.data as u32
}
}
fn next_u64(&mut self) -> u64 {
+ self.data_half_used = false;
self.gen_entropy()
}
fn fill_bytes(&mut self, dest: &mut [u8]) {
- let mut left = dest;
- while left.len() >= 8 {
- let (l, r) = {left}.split_at_mut(8);
- left = r;
- let chunk: [u8; 8] = unsafe {
- mem::transmute(self.next_u64().to_le())
- };
- l.copy_from_slice(&chunk);
- }
- let n = left.len();
- if n > 0 {
- let chunk: [u8; 8] = unsafe {
- mem::transmute(self.next_u64().to_le())
- };
- left.copy_from_slice(&chunk[..n]);
- }
+ // Fill using `next_u32`. This is faster for filling small slices (four
+ // bytes or less), while the overhead is negligible.
+ //
+ // This is done especially for wrappers that implement `next_u32`
+ // themselves via `fill_bytes`.
+ impls::fill_bytes_via_next(self, dest)
+ }
+
+ fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ Ok(self.fill_bytes(dest))
}
}
-// There are no tests included because (1) this is an "external" RNG, so output
-// is not reproducible and (2) `test_timer` *will* fail on some platforms.
+impl CryptoRng for JitterRng {}
+
+#[cfg(test)]
+mod test_jitter_init {
+ use super::JitterRng;
+
+ #[cfg(all(feature="std", not(target_arch = "wasm32")))]
+ #[test]
+ fn test_jitter_init() {
+ use RngCore;
+ // Because this is a debug build, measurements here are not representive
+ // of the final release build.
+ // Don't fail this test if initializing `JitterRng` fails because of a
+ // bad timer (the timer from the standard library may not have enough
+ // accuracy on all platforms).
+ match JitterRng::new() {
+ Ok(ref mut rng) => {
+ // false positives are possible, but extremely unlikely
+ assert!(rng.next_u32() | rng.next_u32() != 0);
+ },
+ Err(_) => {},
+ }
+ }
+
+ #[test]
+ fn test_jitter_bad_timer() {
+ fn bad_timer() -> u64 { 0 }
+ let mut rng = JitterRng::new_with_timer(bad_timer);
+ assert!(rng.test_timer().is_err());
+ }
+}
diff --git a/rand/src/rngs/mock.rs b/rand/src/rngs/mock.rs
new file mode 100644
index 0000000..3c9a994
--- /dev/null
+++ b/rand/src/rngs/mock.rs
@@ -0,0 +1,59 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Mock random number generator
+
+use rand_core::{RngCore, Error, impls};
+
+/// A simple implementation of `RngCore` for testing purposes.
+///
+/// This generates an arithmetic sequence (i.e. adds a constant each step)
+/// over a `u64` number, using wrapping arithmetic. If the increment is 0
+/// the generator yields a constant.
+///
+/// ```
+/// use rand::Rng;
+/// use rand::rngs::mock::StepRng;
+///
+/// let mut my_rng = StepRng::new(2, 1);
+/// let sample: [u64; 3] = my_rng.gen();
+/// assert_eq!(sample, [2, 3, 4]);
+/// ```
+#[derive(Debug, Clone)]
+pub struct StepRng {
+ v: u64,
+ a: u64,
+}
+
+impl StepRng {
+ /// Create a `StepRng`, yielding an arithmetic sequence starting with
+ /// `initial` and incremented by `increment` each time.
+ pub fn new(initial: u64, increment: u64) -> Self {
+ StepRng { v: initial, a: increment }
+ }
+}
+
+impl RngCore for StepRng {
+ fn next_u32(&mut self) -> u32 {
+ self.next_u64() as u32
+ }
+
+ fn next_u64(&mut self) -> u64 {
+ let result = self.v;
+ self.v = self.v.wrapping_add(self.a);
+ result
+ }
+
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
+ impls::fill_bytes_via_next(self, dest);
+ }
+
+ fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ Ok(self.fill_bytes(dest))
+ }
+}
diff --git a/rand/src/rngs/mod.rs b/rand/src/rngs/mod.rs
new file mode 100644
index 0000000..70c4506
--- /dev/null
+++ b/rand/src/rngs/mod.rs
@@ -0,0 +1,217 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Random number generators and adapters for common usage:
+//!
+//! - [`ThreadRng`], a fast, secure, auto-seeded thread-local generator
+//! - [`StdRng`] and [`SmallRng`], algorithms to cover typical usage
+//! - [`EntropyRng`], [`OsRng`] and [`JitterRng`] as entropy sources
+//! - [`mock::StepRng`] as a simple counter for tests
+//! - [`adapter::ReadRng`] to read from a file/stream
+//! - [`adapter::ReseedingRng`] to reseed a PRNG on clone / process fork etc.
+//!
+//! # Background — Random number generators (RNGs)
+//!
+//! Computers are inherently deterministic, so to get *random* numbers one
+//! either has to use a hardware generator or collect bits of *entropy* from
+//! various sources (e.g. event timestamps, or jitter). This is a relatively
+//! slow and complicated operation.
+//!
+//! Generally the operating system will collect some entropy, remove bias, and
+//! use that to seed its own PRNG; [`OsRng`] provides an interface to this.
+//! [`JitterRng`] is an entropy collector included with Rand that measures
+//! jitter in the CPU execution time, and jitter in memory access time.
+//! [`EntropyRng`] is a wrapper that uses the best entropy source that is
+//! available.
+//!
+//! ## Pseudo-random number generators
+//!
+//! What is commonly used instead of "true" random number renerators, are
+//! *pseudo-random number generators* (PRNGs), deterministic algorithms that
+//! produce an infinite stream of pseudo-random numbers from a small random
+//! seed. PRNGs are faster, and have better provable properties. The numbers
+//! produced can be statistically of very high quality and can be impossible to
+//! predict. (They can also have obvious correlations and be trivial to predict;
+//! quality varies.)
+//!
+//! There are two different types of PRNGs: those developed for simulations
+//! and statistics, and those developed for use in cryptography; the latter are
+//! called Cryptographically Secure PRNGs (CSPRNG or CPRNG). Both types can
+//! have good statistical quality but the latter also have to be impossible to
+//! predict, even after seeing many previous output values. Rand provides a good
+//! default algorithm from each class:
+//!
+//! - [`SmallRng`] is a PRNG chosen for low memory usage, high performance and
+//! good statistical quality.
+//! - [`StdRng`] is a CSPRNG chosen for good performance and trust of security
+//! (based on reviews, maturity and usage). The current algorithm is HC-128,
+//! which is one of the recommendations by ECRYPT's eSTREAM project.
+//!
+//! The above PRNGs do not cover all use-cases; more algorithms can be found in
+//! the [`prng` module], as well as in several other crates. For example, you
+//! may wish a CSPRNG with significantly lower memory usage than [`StdRng`]
+//! while being less concerned about performance, in which case [`ChaChaRng`]
+//! is a good choice.
+//!
+//! One complexity is that the internal state of a PRNG must change with every
+//! generated number. For APIs this generally means a mutable reference to the
+//! state of the PRNG has to be passed around.
+//!
+//! A solution is [`ThreadRng`]. This is a thread-local implementation of
+//! [`StdRng`] with automatic seeding on first use. It is the best choice if you
+//! "just" want a convenient, secure, fast random number source. Use via the
+//! [`thread_rng`] function, which gets a reference to the current thread's
+//! local instance.
+//!
+//! ## Seeding
+//!
+//! As mentioned above, PRNGs require a random seed in order to produce random
+//! output. This is especially important for CSPRNGs, which are still
+//! deterministic algorithms, thus can only be secure if their seed value is
+//! also secure. To seed a PRNG, use one of:
+//!
+//! - [`FromEntropy::from_entropy`]; this is the most convenient way to seed
+//! with fresh, secure random data.
+//! - [`SeedableRng::from_rng`]; this allows seeding from another PRNG or
+//! from an entropy source such as [`EntropyRng`].
+//! - [`SeedableRng::from_seed`]; this is mostly useful if you wish to be able
+//! to reproduce the output sequence by using a fixed seed. (Don't use
+//! [`StdRng`] or [`SmallRng`] in this case since different algorithms may be
+//! used by future versions of Rand; use an algorithm from the
+//! [`prng` module].)
+//!
+//! ## Conclusion
+//!
+//! - [`thread_rng`] is what you often want to use.
+//! - If you want more control, flexibility, or better performance, use
+//! [`StdRng`], [`SmallRng`] or an algorithm from the [`prng` module].
+//! - Use [`FromEntropy::from_entropy`] to seed new PRNGs.
+//! - If you need reproducibility, use [`SeedableRng::from_seed`] combined with
+//! a named PRNG.
+//!
+//! More information and notes on cryptographic security can be found
+//! in the [`prng` module].
+//!
+//! ## Examples
+//!
+//! Examples of seeding PRNGs:
+//!
+//! ```
+//! use rand::prelude::*;
+//! # use rand::Error;
+//!
+//! // StdRng seeded securely by the OS or local entropy collector:
+//! let mut rng = StdRng::from_entropy();
+//! # let v: u32 = rng.gen();
+//!
+//! // SmallRng seeded from thread_rng:
+//! # fn try_inner() -> Result<(), Error> {
+//! let mut rng = SmallRng::from_rng(thread_rng())?;
+//! # let v: u32 = rng.gen();
+//! # Ok(())
+//! # }
+//! # try_inner().unwrap();
+//!
+//! // SmallRng seeded by a constant, for deterministic results:
+//! let seed = [1,2,3,4, 5,6,7,8, 9,10,11,12, 13,14,15,16]; // byte array
+//! let mut rng = SmallRng::from_seed(seed);
+//! # let v: u32 = rng.gen();
+//! ```
+//!
+//!
+//! # Implementing custom RNGs
+//!
+//! If you want to implement custom RNG, see the [`rand_core`] crate. The RNG
+//! will have to implement the [`RngCore`] trait, where the [`Rng`] trait is
+//! build on top of.
+//!
+//! If the RNG needs seeding, also implement the [`SeedableRng`] trait.
+//!
+//! [`CryptoRng`] is a marker trait cryptographically secure PRNGs can
+//! implement.
+//!
+//!
+// This module:
+//! [`ThreadRng`]: struct.ThreadRng.html
+//! [`StdRng`]: struct.StdRng.html
+//! [`SmallRng`]: struct.SmallRng.html
+//! [`EntropyRng`]: struct.EntropyRng.html
+//! [`OsRng`]: struct.OsRng.html
+//! [`JitterRng`]: struct.JitterRng.html
+// Other traits and functions:
+//! [`rand_core`]: https://crates.io/crates/rand_core
+//! [`prng` module]: ../prng/index.html
+//! [`CryptoRng`]: ../trait.CryptoRng.html
+//! [`FromEntropy`]: ../trait.FromEntropy.html
+//! [`FromEntropy::from_entropy`]: ../trait.FromEntropy.html#tymethod.from_entropy
+//! [`RngCore`]: ../trait.RngCore.html
+//! [`Rng`]: ../trait.Rng.html
+//! [`SeedableRng`]: ../trait.SeedableRng.html
+//! [`SeedableRng::from_rng`]: ../trait.SeedableRng.html#tymethod.from_rng
+//! [`SeedableRng::from_seed`]: ../trait.SeedableRng.html#tymethod.from_seed
+//! [`thread_rng`]: ../fn.thread_rng.html
+//! [`mock::StepRng`]: mock/struct.StepRng.html
+//! [`adapter::ReadRng`]: adapter/struct.ReadRng.html
+//! [`adapter::ReseedingRng`]: adapter/struct.ReseedingRng.html
+//! [`ChaChaRng`]: ../../rand_chacha/struct.ChaChaRng.html
+
+pub mod adapter;
+
+#[cfg(feature="std")] mod entropy;
+mod jitter;
+pub mod mock; // Public so we don't export `StepRng` directly, making it a bit
+ // more clear it is intended for testing.
+mod small;
+mod std;
+#[cfg(feature="std")] pub(crate) mod thread;
+
+
+pub use self::jitter::{JitterRng, TimerError};
+#[cfg(feature="std")] pub use self::entropy::EntropyRng;
+
+pub use self::small::SmallRng;
+pub use self::std::StdRng;
+#[cfg(feature="std")] pub use self::thread::ThreadRng;
+
+#[cfg(all(feature="std",
+ any(target_os = "linux", target_os = "android",
+ target_os = "netbsd",
+ target_os = "dragonfly",
+ target_os = "haiku",
+ target_os = "emscripten",
+ target_os = "solaris",
+ target_os = "cloudabi",
+ target_os = "macos", target_os = "ios",
+ target_os = "freebsd",
+ target_os = "openbsd", target_os = "bitrig",
+ target_os = "redox",
+ target_os = "fuchsia",
+ windows,
+ all(target_arch = "wasm32", feature = "stdweb"),
+ all(target_arch = "wasm32", feature = "wasm-bindgen"),
+)))]
+mod os;
+
+#[cfg(all(feature="std",
+ any(target_os = "linux", target_os = "android",
+ target_os = "netbsd",
+ target_os = "dragonfly",
+ target_os = "haiku",
+ target_os = "emscripten",
+ target_os = "solaris",
+ target_os = "cloudabi",
+ target_os = "macos", target_os = "ios",
+ target_os = "freebsd",
+ target_os = "openbsd", target_os = "bitrig",
+ target_os = "redox",
+ target_os = "fuchsia",
+ windows,
+ all(target_arch = "wasm32", feature = "stdweb"),
+ all(target_arch = "wasm32", feature = "wasm-bindgen"),
+)))]
+pub use self::os::OsRng;
diff --git a/rand/src/rngs/os.rs b/rand/src/rngs/os.rs
new file mode 100644
index 0000000..e609c50
--- /dev/null
+++ b/rand/src/rngs/os.rs
@@ -0,0 +1,1275 @@
+// Copyright 2018 Developers of the Rand project.
+// Copyright 2013-2015 The Rust Project Developers.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Interface to the random number generator of the operating system.
+
+use std::fmt;
+use rand_core::{CryptoRng, RngCore, Error, impls};
+
+/// A random number generator that retrieves randomness straight from the
+/// operating system.
+///
+/// This is the preferred external source of entropy for most applications.
+/// Commonly it is used to initialize a user-space RNG, which can then be used
+/// to generate random values with much less overhead than `OsRng`.
+///
+/// You may prefer to use [`EntropyRng`] instead of `OsRng`. It is unlikely, but
+/// not entirely theoretical, for `OsRng` to fail. In such cases [`EntropyRng`]
+/// falls back on a good alternative entropy source.
+///
+/// `OsRng::new()` is guaranteed to be very cheap (after the first successful
+/// call), and will never consume more than one file handle per process.
+///
+/// # Platform sources
+///
+/// | OS | interface
+/// |------------------|---------------------------------------------------------
+/// | Linux, Android | [`getrandom`][1] system call if available, otherwise [`/dev/urandom`][2] after reading from `/dev/random` once
+/// | Windows | [`RtlGenRandom`][3]
+/// | macOS, iOS | [`SecRandomCopyBytes`][4]
+/// | FreeBSD | [`kern.arandom`][5]
+/// | OpenBSD, Bitrig | [`getentropy`][6]
+/// | NetBSD | [`/dev/urandom`][7] after reading from `/dev/random` once
+/// | Dragonfly BSD | [`/dev/random`][8]
+/// | Solaris, illumos | [`getrandom`][9] system call if available, otherwise [`/dev/random`][10]
+/// | Fuchsia OS | [`cprng_draw`][11]
+/// | Redox | [`rand:`][12]
+/// | CloudABI | [`random_get`][13]
+/// | Haiku | `/dev/random` (identical to `/dev/urandom`)
+/// | Web browsers | [`Crypto.getRandomValues`][14] (see [Support for WebAssembly and ams.js][14])
+/// | Node.js | [`crypto.randomBytes`][15] (see [Support for WebAssembly and ams.js][16])
+///
+/// Rand doesn't have a blanket implementation for all Unix-like operating
+/// systems that reads from `/dev/urandom`. This ensures all supported operating
+/// systems are using the recommended interface and respect maximum buffer
+/// sizes.
+///
+/// ## Support for WebAssembly and ams.js
+///
+/// The three Emscripten targets `asmjs-unknown-emscripten`,
+/// `wasm32-unknown-emscripten` and `wasm32-experimental-emscripten` use
+/// Emscripten's emulation of `/dev/random` on web browsers and Node.js.
+///
+/// The bare Wasm target `wasm32-unknown-unknown` tries to call the javascript
+/// methods directly, using either `stdweb` in combination with `cargo-web` or
+/// `wasm-bindgen` depending on what features are activated for this crate.
+///
+/// ## Early boot
+///
+/// It is possible that early in the boot process the OS hasn't had enough time
+/// yet to collect entropy to securely seed its RNG, especially on virtual
+/// machines.
+///
+/// Some operating systems always block the thread until the RNG is securely
+/// seeded. This can take anywhere from a few seconds to more than a minute.
+/// Others make a best effort to use a seed from before the shutdown and don't
+/// document much.
+///
+/// A few, Linux, NetBSD and Solaris, offer a choice between blocking, and
+/// getting an error. With `try_fill_bytes` we choose to get the error
+/// ([`ErrorKind::NotReady`]), while the other methods use a blocking interface.
+///
+/// On Linux (when the `genrandom` system call is not available) and on NetBSD
+/// reading from `/dev/urandom` never blocks, even when the OS hasn't collected
+/// enough entropy yet. As a countermeasure we try to do a single read from
+/// `/dev/random` until we know the OS RNG is initialized (and store this in a
+/// global static).
+///
+/// # Panics
+///
+/// `OsRng` is extremely unlikely to fail if `OsRng::new()`, and one read from
+/// it, where succesfull. But in case it does fail, only [`try_fill_bytes`] is
+/// able to report the cause. Depending on the error the other [`RngCore`]
+/// methods will retry several times, and panic in case the error remains.
+///
+/// [`EntropyRng`]: struct.EntropyRng.html
+/// [`RngCore`]: ../trait.RngCore.html
+/// [`try_fill_bytes`]: ../trait.RngCore.html#method.tymethod.try_fill_bytes
+/// [`ErrorKind::NotReady`]: ../enum.ErrorKind.html#variant.NotReady
+///
+/// [1]: http://man7.org/linux/man-pages/man2/getrandom.2.html
+/// [2]: http://man7.org/linux/man-pages/man4/urandom.4.html
+/// [3]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa387694.aspx
+/// [4]: https://developer.apple.com/documentation/security/1399291-secrandomcopybytes?language=objc
+/// [5]: https://www.freebsd.org/cgi/man.cgi?query=random&sektion=4
+/// [6]: https://man.openbsd.org/getentropy.2
+/// [7]: http://netbsd.gw.com/cgi-bin/man-cgi?random+4+NetBSD-current
+/// [8]: https://leaf.dragonflybsd.org/cgi/web-man?command=random&section=4
+/// [9]: https://docs.oracle.com/cd/E88353_01/html/E37841/getrandom-2.html
+/// [10]: https://docs.oracle.com/cd/E86824_01/html/E54777/random-7d.html
+/// [11]: https://fuchsia.googlesource.com/zircon/+/HEAD/docs/syscalls/cprng_draw.md
+/// [12]: https://github.com/redox-os/randd/blob/master/src/main.rs
+/// [13]: https://github.com/NuxiNL/cloudabi/blob/v0.20/cloudabi.txt#L1826
+/// [14]: https://www.w3.org/TR/WebCryptoAPI/#Crypto-method-getRandomValues
+/// [15]: https://nodejs.org/api/crypto.html#crypto_crypto_randombytes_size_callback
+/// [16]: #support-for-webassembly-and-amsjs
+
+
+#[derive(Clone)]
+pub struct OsRng(imp::OsRng);
+
+impl fmt::Debug for OsRng {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ self.0.fmt(f)
+ }
+}
+
+impl OsRng {
+ /// Create a new `OsRng`.
+ pub fn new() -> Result<OsRng, Error> {
+ imp::OsRng::new().map(OsRng)
+ }
+}
+
+impl CryptoRng for OsRng {}
+
+impl RngCore for OsRng {
+ fn next_u32(&mut self) -> u32 {
+ impls::next_u32_via_fill(self)
+ }
+
+ fn next_u64(&mut self) -> u64 {
+ impls::next_u64_via_fill(self)
+ }
+
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
+ use std::{time, thread};
+
+ // We cannot return Err(..), so we try to handle before panicking.
+ const MAX_RETRY_PERIOD: u32 = 10; // max 10s
+ const WAIT_DUR_MS: u32 = 100; // retry every 100ms
+ let wait_dur = time::Duration::from_millis(WAIT_DUR_MS as u64);
+ const RETRY_LIMIT: u32 = (MAX_RETRY_PERIOD * 1000) / WAIT_DUR_MS;
+ const TRANSIENT_RETRIES: u32 = 8;
+ let mut err_count = 0;
+ let mut error_logged = false;
+
+ // Maybe block until the OS RNG is initialized
+ let mut read = 0;
+ if let Ok(n) = self.0.test_initialized(dest, true) { read = n };
+ let dest = &mut dest[read..];
+
+ loop {
+ if let Err(e) = self.try_fill_bytes(dest) {
+ if err_count >= RETRY_LIMIT {
+ error!("OsRng failed too many times; last error: {}", e);
+ panic!("OsRng failed too many times; last error: {}", e);
+ }
+
+ if e.kind.should_wait() {
+ if !error_logged {
+ warn!("OsRng failed; waiting up to {}s and retrying. Error: {}",
+ MAX_RETRY_PERIOD, e);
+ error_logged = true;
+ }
+ err_count += 1;
+ thread::sleep(wait_dur);
+ continue;
+ } else if e.kind.should_retry() {
+ if !error_logged {
+ warn!("OsRng failed; retrying up to {} times. Error: {}",
+ TRANSIENT_RETRIES, e);
+ error_logged = true;
+ }
+ err_count += (RETRY_LIMIT + TRANSIENT_RETRIES - 1)
+ / TRANSIENT_RETRIES; // round up
+ continue;
+ } else {
+ error!("OsRng failed: {}", e);
+ panic!("OsRng fatal error: {}", e);
+ }
+ }
+
+ break;
+ }
+ }
+
+ fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ // Some systems do not support reading 0 random bytes.
+ // (And why waste a system call?)
+ if dest.len() == 0 { return Ok(()); }
+
+ let read = self.0.test_initialized(dest, false)?;
+ let dest = &mut dest[read..];
+
+ let max = self.0.max_chunk_size();
+ if dest.len() <= max {
+ trace!("OsRng: reading {} bytes via {}",
+ dest.len(), self.0.method_str());
+ } else {
+ trace!("OsRng: reading {} bytes via {} in {} chunks of {} bytes",
+ dest.len(), self.0.method_str(), (dest.len() + max) / max, max);
+ }
+ for slice in dest.chunks_mut(max) {
+ self.0.fill_chunk(slice)?;
+ }
+ Ok(())
+ }
+}
+
+trait OsRngImpl where Self: Sized {
+ // Create a new `OsRng` platform interface.
+ fn new() -> Result<Self, Error>;
+
+ // Fill a chunk with random bytes.
+ fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error>;
+
+ // Test whether the OS RNG is initialized. This method may not be possible
+ // to support cheaply (or at all) on all operating systems.
+ //
+ // If `blocking` is set, this will cause the OS the block execution until
+ // its RNG is initialized.
+ //
+ // Random values that are read while this are stored in `dest`, the amount
+ // of read bytes is returned.
+ fn test_initialized(&mut self, _dest: &mut [u8], _blocking: bool)
+ -> Result<usize, Error> { Ok(0) }
+
+ // Maximum chunk size supported.
+ fn max_chunk_size(&self) -> usize { ::core::usize::MAX }
+
+ // Name of the OS interface (used for logging).
+ fn method_str(&self) -> &'static str;
+}
+
+
+
+
+// Helper functions to read from a random device such as `/dev/urandom`.
+//
+// All instances use a single internal file handle, to prevent possible
+// exhaustion of file descriptors.
+#[cfg(any(target_os = "linux", target_os = "android",
+ target_os = "netbsd", target_os = "dragonfly",
+ target_os = "solaris", target_os = "redox",
+ target_os = "haiku", target_os = "emscripten"))]
+mod random_device {
+ use {Error, ErrorKind};
+ use std::fs::File;
+ use std::io;
+ use std::io::Read;
+ use std::sync::{Once, Mutex, ONCE_INIT};
+
+ // TODO: remove outer Option when `Mutex::new(None)` is a constant expression
+ static mut READ_RNG_FILE: Option<Mutex<Option<File>>> = None;
+ static READ_RNG_ONCE: Once = ONCE_INIT;
+
+ #[allow(unused)]
+ pub fn open<F>(path: &'static str, open_fn: F) -> Result<(), Error>
+ where F: Fn(&'static str) -> Result<File, io::Error>
+ {
+ READ_RNG_ONCE.call_once(|| {
+ unsafe { READ_RNG_FILE = Some(Mutex::new(None)) }
+ });
+
+ // We try opening the file outside the `call_once` fn because we cannot
+ // clone the error, thus we must retry on failure.
+
+ let mutex = unsafe { READ_RNG_FILE.as_ref().unwrap() };
+ let mut guard = mutex.lock().unwrap();
+ if (*guard).is_none() {
+ info!("OsRng: opening random device {}", path);
+ let file = open_fn(path).map_err(map_err)?;
+ *guard = Some(file);
+ };
+ Ok(())
+ }
+
+ pub fn read(dest: &mut [u8]) -> Result<(), Error> {
+ // We expect this function only to be used after `random_device::open`
+ // was succesful. Therefore we can assume that our memory was set with a
+ // valid object.
+ let mutex = unsafe { READ_RNG_FILE.as_ref().unwrap() };
+ let mut guard = mutex.lock().unwrap();
+ let file = (*guard).as_mut().unwrap();
+
+ // Use `std::io::read_exact`, which retries on `ErrorKind::Interrupted`.
+ file.read_exact(dest).map_err(|err| {
+ Error::with_cause(ErrorKind::Unavailable,
+ "error reading random device", err)
+ })
+
+ }
+
+ pub fn map_err(err: io::Error) -> Error {
+ match err.kind() {
+ io::ErrorKind::Interrupted =>
+ Error::new(ErrorKind::Transient, "interrupted"),
+ io::ErrorKind::WouldBlock =>
+ Error::with_cause(ErrorKind::NotReady,
+ "OS RNG not yet seeded", err),
+ _ => Error::with_cause(ErrorKind::Unavailable,
+ "error while opening random device", err)
+ }
+ }
+}
+
+
+#[cfg(any(target_os = "linux", target_os = "android"))]
+mod imp {
+ extern crate libc;
+
+ use {Error, ErrorKind};
+ use super::random_device;
+ use super::OsRngImpl;
+
+ use std::io;
+ use std::io::Read;
+ use std::fs::{File, OpenOptions};
+ use std::os::unix::fs::OpenOptionsExt;
+ use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};
+ use std::sync::{Once, ONCE_INIT};
+
+ #[derive(Clone, Debug)]
+ pub struct OsRng {
+ method: OsRngMethod,
+ initialized: bool,
+ }
+
+ #[derive(Clone, Debug)]
+ enum OsRngMethod {
+ GetRandom,
+ RandomDevice,
+ }
+
+ impl OsRngImpl for OsRng {
+ fn new() -> Result<OsRng, Error> {
+ if is_getrandom_available() {
+ return Ok(OsRng { method: OsRngMethod::GetRandom,
+ initialized: false });
+ }
+ random_device::open("/dev/urandom", &|p| File::open(p))?;
+ Ok(OsRng { method: OsRngMethod::RandomDevice, initialized: false })
+ }
+
+ fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ match self.method {
+ OsRngMethod::GetRandom => getrandom_try_fill(dest, false),
+ OsRngMethod::RandomDevice => random_device::read(dest),
+ }
+ }
+
+ fn test_initialized(&mut self, dest: &mut [u8], blocking: bool)
+ -> Result<usize, Error>
+ {
+ static OS_RNG_INITIALIZED: AtomicBool = ATOMIC_BOOL_INIT;
+ if !self.initialized {
+ self.initialized = OS_RNG_INITIALIZED.load(Ordering::Relaxed);
+ }
+ if self.initialized { return Ok(0); }
+
+ let result = match self.method {
+ OsRngMethod::GetRandom => {
+ getrandom_try_fill(dest, blocking)?;
+ Ok(dest.len())
+ }
+ OsRngMethod::RandomDevice => {
+ info!("OsRng: testing random device /dev/random");
+ let mut file = OpenOptions::new()
+ .read(true)
+ .custom_flags(if blocking { 0 } else { libc::O_NONBLOCK })
+ .open("/dev/random")
+ .map_err(random_device::map_err)?;
+ file.read(&mut dest[..1]).map_err(random_device::map_err)?;
+ Ok(1)
+ }
+ };
+ OS_RNG_INITIALIZED.store(true, Ordering::Relaxed);
+ self.initialized = true;
+ result
+ }
+
+ fn method_str(&self) -> &'static str {
+ match self.method {
+ OsRngMethod::GetRandom => "getrandom",
+ OsRngMethod::RandomDevice => "/dev/urandom",
+ }
+ }
+ }
+
+ #[cfg(target_arch = "x86_64")]
+ const NR_GETRANDOM: libc::c_long = 318;
+ #[cfg(target_arch = "x86")]
+ const NR_GETRANDOM: libc::c_long = 355;
+ #[cfg(target_arch = "arm")]
+ const NR_GETRANDOM: libc::c_long = 384;
+ #[cfg(target_arch = "aarch64")]
+ const NR_GETRANDOM: libc::c_long = 278;
+ #[cfg(target_arch = "s390x")]
+ const NR_GETRANDOM: libc::c_long = 349;
+ #[cfg(target_arch = "powerpc")]
+ const NR_GETRANDOM: libc::c_long = 359;
+ #[cfg(target_arch = "powerpc64")]
+ const NR_GETRANDOM: libc::c_long = 359;
+ #[cfg(target_arch = "mips")] // old ABI
+ const NR_GETRANDOM: libc::c_long = 4353;
+ #[cfg(target_arch = "mips64")]
+ const NR_GETRANDOM: libc::c_long = 5313;
+ #[cfg(target_arch = "sparc")]
+ const NR_GETRANDOM: libc::c_long = 347;
+ #[cfg(target_arch = "sparc64")]
+ const NR_GETRANDOM: libc::c_long = 347;
+ #[cfg(not(any(target_arch = "x86_64", target_arch = "x86",
+ target_arch = "arm", target_arch = "aarch64",
+ target_arch = "s390x", target_arch = "powerpc",
+ target_arch = "powerpc64", target_arch = "mips",
+ target_arch = "mips64", target_arch = "sparc",
+ target_arch = "sparc64")))]
+ const NR_GETRANDOM: libc::c_long = 0;
+
+ fn getrandom(buf: &mut [u8], blocking: bool) -> libc::c_long {
+ const GRND_NONBLOCK: libc::c_uint = 0x0001;
+
+ if NR_GETRANDOM == 0 { return -1 };
+
+ unsafe {
+ libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(),
+ if blocking { 0 } else { GRND_NONBLOCK })
+ }
+ }
+
+ fn getrandom_try_fill(dest: &mut [u8], blocking: bool) -> Result<(), Error> {
+ let mut read = 0;
+ while read < dest.len() {
+ let result = getrandom(&mut dest[read..], blocking);
+ if result == -1 {
+ let err = io::Error::last_os_error();
+ let kind = err.kind();
+ if kind == io::ErrorKind::Interrupted {
+ continue;
+ } else if kind == io::ErrorKind::WouldBlock {
+ return Err(Error::with_cause(
+ ErrorKind::NotReady,
+ "getrandom not ready",
+ err,
+ ));
+ } else {
+ return Err(Error::with_cause(
+ ErrorKind::Unavailable,
+ "unexpected getrandom error",
+ err,
+ ));
+ }
+ } else {
+ read += result as usize;
+ }
+ }
+ Ok(())
+ }
+
+ fn is_getrandom_available() -> bool {
+ static CHECKER: Once = ONCE_INIT;
+ static AVAILABLE: AtomicBool = ATOMIC_BOOL_INIT;
+
+ if NR_GETRANDOM == 0 { return false };
+
+ CHECKER.call_once(|| {
+ debug!("OsRng: testing getrandom");
+ let mut buf: [u8; 0] = [];
+ let result = getrandom(&mut buf, false);
+ let available = if result == -1 {
+ let err = io::Error::last_os_error().raw_os_error();
+ err != Some(libc::ENOSYS)
+ } else {
+ true
+ };
+ AVAILABLE.store(available, Ordering::Relaxed);
+ info!("OsRng: using {}", if available { "getrandom" } else { "/dev/urandom" });
+ });
+
+ AVAILABLE.load(Ordering::Relaxed)
+ }
+}
+
+
+#[cfg(target_os = "netbsd")]
+mod imp {
+ use Error;
+ use super::random_device;
+ use super::OsRngImpl;
+
+ use std::fs::File;
+ use std::io::Read;
+ use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};
+
+ #[derive(Clone, Debug)]
+ pub struct OsRng { initialized: bool }
+
+ impl OsRngImpl for OsRng {
+ fn new() -> Result<OsRng, Error> {
+ random_device::open("/dev/urandom", &|p| File::open(p))?;
+ Ok(OsRng { initialized: false })
+ }
+
+ fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ random_device::read(dest)
+ }
+
+ // Read a single byte from `/dev/random` to determine if the OS RNG is
+ // already seeded. NetBSD always blocks if not yet ready.
+ fn test_initialized(&mut self, dest: &mut [u8], _blocking: bool)
+ -> Result<usize, Error>
+ {
+ static OS_RNG_INITIALIZED: AtomicBool = ATOMIC_BOOL_INIT;
+ if !self.initialized {
+ self.initialized = OS_RNG_INITIALIZED.load(Ordering::Relaxed);
+ }
+ if self.initialized { return Ok(0); }
+
+ info!("OsRng: testing random device /dev/random");
+ let mut file =
+ File::open("/dev/random").map_err(random_device::map_err)?;
+ file.read(&mut dest[..1]).map_err(random_device::map_err)?;
+
+ OS_RNG_INITIALIZED.store(true, Ordering::Relaxed);
+ self.initialized = true;
+ Ok(1)
+ }
+
+ fn method_str(&self) -> &'static str { "/dev/urandom" }
+ }
+}
+
+
+#[cfg(any(target_os = "dragonfly",
+ target_os = "haiku",
+ target_os = "emscripten"))]
+mod imp {
+ use Error;
+ use super::random_device;
+ use super::OsRngImpl;
+ use std::fs::File;
+
+ #[derive(Clone, Debug)]
+ pub struct OsRng();
+
+ impl OsRngImpl for OsRng {
+ fn new() -> Result<OsRng, Error> {
+ random_device::open("/dev/random", &|p| File::open(p))?;
+ Ok(OsRng())
+ }
+
+ fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ random_device::read(dest)
+ }
+
+ #[cfg(target_os = "emscripten")]
+ fn max_chunk_size(&self) -> usize {
+ // `Crypto.getRandomValues` documents `dest` should be at most 65536
+ // bytes. `crypto.randomBytes` documents: "To minimize threadpool
+ // task length variation, partition large randomBytes requests when
+ // doing so as part of fulfilling a client request.
+ 65536
+ }
+
+ fn method_str(&self) -> &'static str { "/dev/random" }
+ }
+}
+
+
+// Read from `/dev/random`, with chunks of limited size (1040 bytes).
+// `/dev/random` uses the Hash_DRBG with SHA512 algorithm from NIST SP 800-90A.
+// `/dev/urandom` uses the FIPS 186-2 algorithm, which is considered less
+// secure. We choose to read from `/dev/random`.
+//
+// Since Solaris 11.3 the `getrandom` syscall is available. To make sure we can
+// compile on both Solaris and on OpenSolaris derivatives, that do not have the
+// function, we do a direct syscall instead of calling a library function.
+//
+// We have no way to differentiate between Solaris, illumos, SmartOS, etc.
+#[cfg(target_os = "solaris")]
+mod imp {
+ extern crate libc;
+
+ use {Error, ErrorKind};
+ use super::random_device;
+ use super::OsRngImpl;
+
+ use std::io;
+ use std::io::Read;
+ use std::fs::{File, OpenOptions};
+ use std::os::unix::fs::OpenOptionsExt;
+ use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};
+
+ #[derive(Clone, Debug)]
+ pub struct OsRng {
+ method: OsRngMethod,
+ initialized: bool,
+ }
+
+ #[derive(Clone, Debug)]
+ enum OsRngMethod {
+ GetRandom,
+ RandomDevice,
+ }
+
+ impl OsRngImpl for OsRng {
+ fn new() -> Result<OsRng, Error> {
+ if is_getrandom_available() {
+ return Ok(OsRng { method: OsRngMethod::GetRandom,
+ initialized: false });
+ }
+ let open = |p| OpenOptions::new()
+ .read(true)
+ .custom_flags(libc::O_NONBLOCK)
+ .open(p);
+ random_device::open("/dev/random", &open)?;
+ Ok(OsRng { method: OsRngMethod::RandomDevice, initialized: false })
+ }
+
+ fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ match self.method {
+ OsRngMethod::GetRandom => getrandom_try_fill(dest, false),
+ OsRngMethod::RandomDevice => random_device::read(dest),
+ }
+ }
+
+ fn test_initialized(&mut self, dest: &mut [u8], blocking: bool)
+ -> Result<usize, Error>
+ {
+ static OS_RNG_INITIALIZED: AtomicBool = ATOMIC_BOOL_INIT;
+ if !self.initialized {
+ self.initialized = OS_RNG_INITIALIZED.load(Ordering::Relaxed);
+ }
+ if self.initialized { return Ok(0); }
+
+ let chunk_len = ::core::cmp::min(1024, dest.len());
+ let dest = &mut dest[..chunk_len];
+
+ match self.method {
+ OsRngMethod::GetRandom => getrandom_try_fill(dest, blocking)?,
+ OsRngMethod::RandomDevice => {
+ if blocking {
+ info!("OsRng: testing random device /dev/random");
+ // We already have a non-blocking handle, but now need a
+ // blocking one. Not much choice except opening it twice
+ let mut file = File::open("/dev/random")
+ .map_err(random_device::map_err)?;
+ file.read(dest).map_err(random_device::map_err)?;
+ } else {
+ self.fill_chunk(dest)?;
+ }
+ }
+ };
+ OS_RNG_INITIALIZED.store(true, Ordering::Relaxed);
+ self.initialized = true;
+ Ok(chunk_len)
+ }
+
+ fn max_chunk_size(&self) -> usize {
+ // The documentation says 1024 is the maximum for getrandom, but
+ // 1040 for /dev/random.
+ 1024
+ }
+
+ fn method_str(&self) -> &'static str {
+ match self.method {
+ OsRngMethod::GetRandom => "getrandom",
+ OsRngMethod::RandomDevice => "/dev/random",
+ }
+ }
+ }
+
+ fn getrandom(buf: &mut [u8], blocking: bool) -> libc::c_long {
+ extern "C" {
+ fn syscall(number: libc::c_long, ...) -> libc::c_long;
+ }
+
+ const SYS_GETRANDOM: libc::c_long = 143;
+ const GRND_NONBLOCK: libc::c_uint = 0x0001;
+ const GRND_RANDOM: libc::c_uint = 0x0002;
+
+ unsafe {
+ syscall(SYS_GETRANDOM, buf.as_mut_ptr(), buf.len(),
+ if blocking { 0 } else { GRND_NONBLOCK } | GRND_RANDOM)
+ }
+ }
+
+ fn getrandom_try_fill(dest: &mut [u8], blocking: bool) -> Result<(), Error> {
+ let result = getrandom(dest, blocking);
+ if result == -1 || result == 0 {
+ let err = io::Error::last_os_error();
+ let kind = err.kind();
+ if kind == io::ErrorKind::WouldBlock {
+ return Err(Error::with_cause(
+ ErrorKind::NotReady,
+ "getrandom not ready",
+ err,
+ ));
+ } else {
+ return Err(Error::with_cause(
+ ErrorKind::Unavailable,
+ "unexpected getrandom error",
+ err,
+ ));
+ }
+ } else if result != dest.len() as i64 {
+ return Err(Error::new(ErrorKind::Unavailable,
+ "unexpected getrandom error"));
+ }
+ Ok(())
+ }
+
+ fn is_getrandom_available() -> bool {
+ use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};
+ use std::sync::{Once, ONCE_INIT};
+
+ static CHECKER: Once = ONCE_INIT;
+ static AVAILABLE: AtomicBool = ATOMIC_BOOL_INIT;
+
+ CHECKER.call_once(|| {
+ debug!("OsRng: testing getrandom");
+ let mut buf: [u8; 0] = [];
+ let result = getrandom(&mut buf, false);
+ let available = if result == -1 {
+ let err = io::Error::last_os_error().raw_os_error();
+ err != Some(libc::ENOSYS)
+ } else {
+ true
+ };
+ AVAILABLE.store(available, Ordering::Relaxed);
+ info!("OsRng: using {}", if available { "getrandom" } else { "/dev/random" });
+ });
+
+ AVAILABLE.load(Ordering::Relaxed)
+ }
+}
+
+
+#[cfg(target_os = "cloudabi")]
+mod imp {
+ extern crate cloudabi;
+
+ use std::io;
+ use {Error, ErrorKind};
+ use super::OsRngImpl;
+
+ #[derive(Clone, Debug)]
+ pub struct OsRng;
+
+ impl OsRngImpl for OsRng {
+ fn new() -> Result<OsRng, Error> { Ok(OsRng) }
+
+ fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ let errno = unsafe { cloudabi::random_get(dest) };
+ if errno == cloudabi::errno::SUCCESS {
+ Ok(())
+ } else {
+ // Cloudlibc provides its own `strerror` implementation so we
+ // can use `from_raw_os_error` here.
+ Err(Error::with_cause(
+ ErrorKind::Unavailable,
+ "random_get() system call failed",
+ io::Error::from_raw_os_error(errno as i32),
+ ))
+ }
+ }
+
+ fn method_str(&self) -> &'static str { "cloudabi::random_get" }
+ }
+}
+
+
+#[cfg(any(target_os = "macos", target_os = "ios"))]
+mod imp {
+ extern crate libc;
+
+ use {Error, ErrorKind};
+ use super::OsRngImpl;
+
+ use std::io;
+ use self::libc::{c_int, size_t};
+
+ #[derive(Clone, Debug)]
+ pub struct OsRng;
+
+ enum SecRandom {}
+
+ #[allow(non_upper_case_globals)]
+ const kSecRandomDefault: *const SecRandom = 0 as *const SecRandom;
+
+ #[link(name = "Security", kind = "framework")]
+ extern {
+ fn SecRandomCopyBytes(rnd: *const SecRandom,
+ count: size_t, bytes: *mut u8) -> c_int;
+ }
+
+ impl OsRngImpl for OsRng {
+ fn new() -> Result<OsRng, Error> { Ok(OsRng) }
+
+ fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ let ret = unsafe {
+ SecRandomCopyBytes(kSecRandomDefault,
+ dest.len() as size_t,
+ dest.as_mut_ptr())
+ };
+ if ret == -1 {
+ Err(Error::with_cause(
+ ErrorKind::Unavailable,
+ "couldn't generate random bytes",
+ io::Error::last_os_error()))
+ } else {
+ Ok(())
+ }
+ }
+
+ fn method_str(&self) -> &'static str { "SecRandomCopyBytes" }
+ }
+}
+
+
+#[cfg(target_os = "freebsd")]
+mod imp {
+ extern crate libc;
+
+ use {Error, ErrorKind};
+ use super::OsRngImpl;
+
+ use std::ptr;
+ use std::io;
+
+ #[derive(Clone, Debug)]
+ pub struct OsRng;
+
+ impl OsRngImpl for OsRng {
+ fn new() -> Result<OsRng, Error> { Ok(OsRng) }
+
+ fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ let mib = [libc::CTL_KERN, libc::KERN_ARND];
+ let mut len = dest.len();
+ let ret = unsafe {
+ libc::sysctl(mib.as_ptr(), mib.len() as libc::c_uint,
+ dest.as_mut_ptr() as *mut _, &mut len,
+ ptr::null(), 0)
+ };
+ if ret == -1 || len != dest.len() {
+ return Err(Error::with_cause(
+ ErrorKind::Unavailable,
+ "kern.arandom sysctl failed",
+ io::Error::last_os_error()));
+ }
+ Ok(())
+ }
+
+ fn max_chunk_size(&self) -> usize { 256 }
+
+ fn method_str(&self) -> &'static str { "kern.arandom" }
+ }
+}
+
+
+#[cfg(any(target_os = "openbsd", target_os = "bitrig"))]
+mod imp {
+ extern crate libc;
+
+ use {Error, ErrorKind};
+ use super::OsRngImpl;
+
+ use std::io;
+
+ #[derive(Clone, Debug)]
+ pub struct OsRng;
+
+ impl OsRngImpl for OsRng {
+ fn new() -> Result<OsRng, Error> { Ok(OsRng) }
+
+ fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ let ret = unsafe {
+ libc::getentropy(dest.as_mut_ptr() as *mut libc::c_void, dest.len())
+ };
+ if ret == -1 {
+ return Err(Error::with_cause(
+ ErrorKind::Unavailable,
+ "getentropy failed",
+ io::Error::last_os_error()));
+ }
+ Ok(())
+ }
+
+ fn max_chunk_size(&self) -> usize { 256 }
+
+ fn method_str(&self) -> &'static str { "getentropy" }
+ }
+}
+
+
+#[cfg(target_os = "redox")]
+mod imp {
+ use Error;
+ use super::random_device;
+ use super::OsRngImpl;
+ use std::fs::File;
+
+ #[derive(Clone, Debug)]
+ pub struct OsRng();
+
+ impl OsRngImpl for OsRng {
+ fn new() -> Result<OsRng, Error> {
+ random_device::open("rand:", &|p| File::open(p))?;
+ Ok(OsRng())
+ }
+
+ fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ random_device::read(dest)
+ }
+
+ fn method_str(&self) -> &'static str { "'rand:'" }
+ }
+}
+
+
+#[cfg(target_os = "fuchsia")]
+mod imp {
+ extern crate fuchsia_zircon;
+
+ use {Error, ErrorKind};
+ use super::OsRngImpl;
+
+ #[derive(Clone, Debug)]
+ pub struct OsRng;
+
+ impl OsRngImpl for OsRng {
+ fn new() -> Result<OsRng, Error> { Ok(OsRng) }
+
+ fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ let mut read = 0;
+ while read < dest.len() {
+ match fuchsia_zircon::cprng_draw(&mut dest[read..]) {
+ Ok(actual) => read += actual,
+ Err(e) => {
+ return Err(Error::with_cause(
+ ErrorKind::Unavailable,
+ "cprng_draw failed",
+ e.into_io_error()));
+ }
+ };
+ }
+ Ok(())
+ }
+
+ fn max_chunk_size(&self) -> usize {
+ fuchsia_zircon::sys::ZX_CPRNG_DRAW_MAX_LEN
+ }
+
+ fn method_str(&self) -> &'static str { "cprng_draw" }
+ }
+}
+
+
+#[cfg(windows)]
+mod imp {
+ extern crate winapi;
+
+ use {Error, ErrorKind};
+ use super::OsRngImpl;
+
+ use std::io;
+
+ use self::winapi::shared::minwindef::ULONG;
+ use self::winapi::um::ntsecapi::RtlGenRandom;
+ use self::winapi::um::winnt::PVOID;
+
+ #[derive(Clone, Debug)]
+ pub struct OsRng;
+
+ impl OsRngImpl for OsRng {
+ fn new() -> Result<OsRng, Error> { Ok(OsRng) }
+
+ fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ let ret = unsafe {
+ RtlGenRandom(dest.as_mut_ptr() as PVOID, dest.len() as ULONG)
+ };
+ if ret == 0 {
+ return Err(Error::with_cause(
+ ErrorKind::Unavailable,
+ "couldn't generate random bytes",
+ io::Error::last_os_error()));
+ }
+ Ok(())
+ }
+
+ fn max_chunk_size(&self) -> usize { <ULONG>::max_value() as usize }
+
+ fn method_str(&self) -> &'static str { "RtlGenRandom" }
+ }
+}
+
+
+#[cfg(all(target_arch = "wasm32",
+ not(target_os = "emscripten"),
+ feature = "stdweb"))]
+mod imp {
+ use std::mem;
+ use stdweb::unstable::TryInto;
+ use stdweb::web::error::Error as WebError;
+ use {Error, ErrorKind};
+ use super::OsRngImpl;
+
+ #[derive(Clone, Debug)]
+ enum OsRngMethod {
+ Browser,
+ Node
+ }
+
+ #[derive(Clone, Debug)]
+ pub struct OsRng(OsRngMethod);
+
+ impl OsRngImpl for OsRng {
+ fn new() -> Result<OsRng, Error> {
+ let result = js! {
+ try {
+ if (
+ typeof self === "object" &&
+ typeof self.crypto === "object" &&
+ typeof self.crypto.getRandomValues === "function"
+ ) {
+ return { success: true, ty: 1 };
+ }
+
+ if (typeof require("crypto").randomBytes === "function") {
+ return { success: true, ty: 2 };
+ }
+
+ return { success: false, error: new Error("not supported") };
+ } catch(err) {
+ return { success: false, error: err };
+ }
+ };
+
+ if js!{ return @{ result.as_ref() }.success } == true {
+ let ty = js!{ return @{ result }.ty };
+
+ if ty == 1 { Ok(OsRng(OsRngMethod::Browser)) }
+ else if ty == 2 { Ok(OsRng(OsRngMethod::Node)) }
+ else { unreachable!() }
+ } else {
+ let err: WebError = js!{ return @{ result }.error }.try_into().unwrap();
+ Err(Error::with_cause(ErrorKind::Unavailable, "WASM Error", err))
+ }
+ }
+
+
+ fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ assert_eq!(mem::size_of::<usize>(), 4);
+
+ let len = dest.len() as u32;
+ let ptr = dest.as_mut_ptr() as i32;
+
+ let result = match self.0 {
+ OsRngMethod::Browser => js! {
+ try {
+ let array = new Uint8Array(@{ len });
+ self.crypto.getRandomValues(array);
+ HEAPU8.set(array, @{ ptr });
+
+ return { success: true };
+ } catch(err) {
+ return { success: false, error: err };
+ }
+ },
+ OsRngMethod::Node => js! {
+ try {
+ let bytes = require("crypto").randomBytes(@{ len });
+ HEAPU8.set(new Uint8Array(bytes), @{ ptr });
+
+ return { success: true };
+ } catch(err) {
+ return { success: false, error: err };
+ }
+ }
+ };
+
+ if js!{ return @{ result.as_ref() }.success } == true {
+ Ok(())
+ } else {
+ let err: WebError = js!{ return @{ result }.error }.try_into().unwrap();
+ Err(Error::with_cause(ErrorKind::Unexpected, "WASM Error", err))
+ }
+ }
+
+ fn max_chunk_size(&self) -> usize { 65536 }
+
+ fn method_str(&self) -> &'static str {
+ match self.0 {
+ OsRngMethod::Browser => "Crypto.getRandomValues",
+ OsRngMethod::Node => "crypto.randomBytes",
+ }
+ }
+ }
+}
+
+#[cfg(all(target_arch = "wasm32",
+ not(target_os = "emscripten"),
+ not(feature = "stdweb"),
+ feature = "wasm-bindgen"))]
+mod imp {
+ use __wbg_shims::*;
+
+ use {Error, ErrorKind};
+ use super::OsRngImpl;
+
+ #[derive(Clone, Debug)]
+ pub enum OsRng {
+ Node(NodeCrypto),
+ Browser(BrowserCrypto),
+ }
+
+ impl OsRngImpl for OsRng {
+ fn new() -> Result<OsRng, Error> {
+ // First up we need to detect if we're running in node.js or a
+ // browser. To do this we get ahold of the `this` object (in a bit
+ // of a roundabout fashion).
+ //
+ // Once we have `this` we look at its `self` property, which is
+ // only defined on the web (either a main window or web worker).
+ let this = Function::new("return this").call(&JsValue::undefined());
+ assert!(this != JsValue::undefined());
+ let this = This::from(this);
+ let is_browser = this.self_() != JsValue::undefined();
+
+ if !is_browser {
+ return Ok(OsRng::Node(node_require("crypto")))
+ }
+
+ // If `self` is defined then we're in a browser somehow (main window
+ // or web worker). Here we want to try to use
+ // `crypto.getRandomValues`, but if `crypto` isn't defined we assume
+ // we're in an older web browser and the OS RNG isn't available.
+ let crypto = this.crypto();
+ if crypto.is_undefined() {
+ let msg = "self.crypto is undefined";
+ return Err(Error::new(ErrorKind::Unavailable, msg))
+ }
+
+ // Test if `crypto.getRandomValues` is undefined as well
+ let crypto: BrowserCrypto = crypto.into();
+ if crypto.get_random_values_fn().is_undefined() {
+ let msg = "crypto.getRandomValues is undefined";
+ return Err(Error::new(ErrorKind::Unavailable, msg))
+ }
+
+ // Ok! `self.crypto.getRandomValues` is a defined value, so let's
+ // assume we can do browser crypto.
+ Ok(OsRng::Browser(crypto))
+ }
+
+ fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ match *self {
+ OsRng::Node(ref n) => n.random_fill_sync(dest),
+ OsRng::Browser(ref n) => n.get_random_values(dest),
+ }
+ Ok(())
+ }
+
+ fn max_chunk_size(&self) -> usize {
+ match *self {
+ OsRng::Node(_) => usize::max_value(),
+ OsRng::Browser(_) => {
+ // see https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues
+ //
+ // where it says:
+ //
+ // > A QuotaExceededError DOMException is thrown if the
+ // > requested length is greater than 65536 bytes.
+ 65536
+ }
+ }
+ }
+
+ fn method_str(&self) -> &'static str {
+ match *self {
+ OsRng::Node(_) => "crypto.randomFillSync",
+ OsRng::Browser(_) => "crypto.getRandomValues",
+ }
+ }
+ }
+}
+
+
+#[cfg(test)]
+mod test {
+ use RngCore;
+ use super::OsRng;
+
+ #[test]
+ fn test_os_rng() {
+ let mut r = OsRng::new().unwrap();
+
+ r.next_u32();
+ r.next_u64();
+
+ let mut v1 = [0u8; 1000];
+ r.fill_bytes(&mut v1);
+
+ let mut v2 = [0u8; 1000];
+ r.fill_bytes(&mut v2);
+
+ let mut n_diff_bits = 0;
+ for i in 0..v1.len() {
+ n_diff_bits += (v1[i] ^ v2[i]).count_ones();
+ }
+
+ // Check at least 1 bit per byte differs. p(failure) < 1e-1000 with random input.
+ assert!(n_diff_bits >= v1.len() as u32);
+ }
+
+ #[test]
+ fn test_os_rng_empty() {
+ let mut r = OsRng::new().unwrap();
+
+ let mut empty = [0u8; 0];
+ r.fill_bytes(&mut empty);
+ }
+
+ #[test]
+ fn test_os_rng_huge() {
+ let mut r = OsRng::new().unwrap();
+
+ let mut huge = [0u8; 100_000];
+ r.fill_bytes(&mut huge);
+ }
+
+ #[cfg(not(any(target_arch = "wasm32", target_arch = "asmjs")))]
+ #[test]
+ fn test_os_rng_tasks() {
+ use std::sync::mpsc::channel;
+ use std::thread;
+
+ let mut txs = vec!();
+ for _ in 0..20 {
+ let (tx, rx) = channel();
+ txs.push(tx);
+
+ thread::spawn(move|| {
+ // wait until all the tasks are ready to go.
+ rx.recv().unwrap();
+
+ // deschedule to attempt to interleave things as much
+ // as possible (XXX: is this a good test?)
+ let mut r = OsRng::new().unwrap();
+ thread::yield_now();
+ let mut v = [0u8; 1000];
+
+ for _ in 0..100 {
+ r.next_u32();
+ thread::yield_now();
+ r.next_u64();
+ thread::yield_now();
+ r.fill_bytes(&mut v);
+ thread::yield_now();
+ }
+ });
+ }
+
+ // start all the tasks
+ for tx in txs.iter() {
+ tx.send(()).unwrap();
+ }
+ }
+}
diff --git a/rand/src/rngs/small.rs b/rand/src/rngs/small.rs
new file mode 100644
index 0000000..e74a83e
--- /dev/null
+++ b/rand/src/rngs/small.rs
@@ -0,0 +1,105 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! A small fast RNG
+
+use {RngCore, SeedableRng, Error};
+
+#[cfg(all(rust_1_26, target_pointer_width = "64"))]
+type Rng = ::rand_pcg::Pcg64Mcg;
+#[cfg(not(all(rust_1_26, target_pointer_width = "64")))]
+type Rng = ::rand_pcg::Pcg32;
+
+/// An RNG recommended when small state, cheap initialization and good
+/// performance are required. The PRNG algorithm in `SmallRng` is chosen to be
+/// efficient on the current platform, **without consideration for cryptography
+/// or security**. The size of its state is much smaller than for [`StdRng`].
+///
+/// Reproducibility of output from this generator is however not required, thus
+/// future library versions may use a different internal generator with
+/// different output. Further, this generator may not be portable and can
+/// produce different output depending on the architecture. If you require
+/// reproducible output, use a named RNG. Refer to the documentation on the
+/// [`prng` module](../prng/index.html).
+///
+/// The current algorithm is [`Pcg64Mcg`] on 64-bit platforms with Rust version
+/// 1.26 and later, or [`Pcg32`] otherwise.
+///
+/// # Examples
+///
+/// Initializing `SmallRng` with a random seed can be done using [`FromEntropy`]:
+///
+/// ```
+/// # use rand::Rng;
+/// use rand::FromEntropy;
+/// use rand::rngs::SmallRng;
+///
+/// // Create small, cheap to initialize and fast RNG with a random seed.
+/// // The randomness is supplied by the operating system.
+/// let mut small_rng = SmallRng::from_entropy();
+/// # let v: u32 = small_rng.gen();
+/// ```
+///
+/// When initializing a lot of `SmallRng`'s, using [`thread_rng`] can be more
+/// efficient:
+///
+/// ```
+/// use std::iter;
+/// use rand::{SeedableRng, thread_rng};
+/// use rand::rngs::SmallRng;
+///
+/// // Create a big, expensive to initialize and slower, but unpredictable RNG.
+/// // This is cached and done only once per thread.
+/// let mut thread_rng = thread_rng();
+/// // Create small, cheap to initialize and fast RNGs with random seeds.
+/// // One can generally assume this won't fail.
+/// let rngs: Vec<SmallRng> = iter::repeat(())
+/// .map(|()| SmallRng::from_rng(&mut thread_rng).unwrap())
+/// .take(10)
+/// .collect();
+/// ```
+///
+/// [`FromEntropy`]: ../trait.FromEntropy.html
+/// [`StdRng`]: struct.StdRng.html
+/// [`thread_rng`]: ../fn.thread_rng.html
+/// [`Pcg64Mcg`]: ../../rand_pcg/type.Pcg64Mcg.html
+/// [`Pcg32`]: ../../rand_pcg/type.Pcg32.html
+#[derive(Clone, Debug)]
+pub struct SmallRng(Rng);
+
+impl RngCore for SmallRng {
+ #[inline(always)]
+ fn next_u32(&mut self) -> u32 {
+ self.0.next_u32()
+ }
+
+ #[inline(always)]
+ fn next_u64(&mut self) -> u64 {
+ self.0.next_u64()
+ }
+
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
+ self.0.fill_bytes(dest);
+ }
+
+ fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ self.0.try_fill_bytes(dest)
+ }
+}
+
+impl SeedableRng for SmallRng {
+ type Seed = <Rng as SeedableRng>::Seed;
+
+ fn from_seed(seed: Self::Seed) -> Self {
+ SmallRng(Rng::from_seed(seed))
+ }
+
+ fn from_rng<R: RngCore>(rng: R) -> Result<Self, Error> {
+ Rng::from_rng(rng).map(SmallRng)
+ }
+}
diff --git a/rand/src/rngs/std.rs b/rand/src/rngs/std.rs
new file mode 100644
index 0000000..ce1658b
--- /dev/null
+++ b/rand/src/rngs/std.rs
@@ -0,0 +1,81 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! The standard RNG
+
+use {RngCore, CryptoRng, Error, SeedableRng};
+use rand_hc::Hc128Rng;
+
+/// The standard RNG. The PRNG algorithm in `StdRng` is chosen to be efficient
+/// on the current platform, to be statistically strong and unpredictable
+/// (meaning a cryptographically secure PRNG).
+///
+/// The current algorithm used on all platforms is [HC-128].
+///
+/// Reproducibility of output from this generator is however not required, thus
+/// future library versions may use a different internal generator with
+/// different output. Further, this generator may not be portable and can
+/// produce different output depending on the architecture. If you require
+/// reproducible output, use a named RNG, for example [`ChaChaRng`].
+///
+/// [HC-128]: ../../rand_hc/struct.Hc128Rng.html
+/// [`ChaChaRng`]: ../../rand_chacha/struct.ChaChaRng.html
+#[derive(Clone, Debug)]
+pub struct StdRng(Hc128Rng);
+
+impl RngCore for StdRng {
+ #[inline(always)]
+ fn next_u32(&mut self) -> u32 {
+ self.0.next_u32()
+ }
+
+ #[inline(always)]
+ fn next_u64(&mut self) -> u64 {
+ self.0.next_u64()
+ }
+
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
+ self.0.fill_bytes(dest);
+ }
+
+ fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ self.0.try_fill_bytes(dest)
+ }
+}
+
+impl SeedableRng for StdRng {
+ type Seed = <Hc128Rng as SeedableRng>::Seed;
+
+ fn from_seed(seed: Self::Seed) -> Self {
+ StdRng(Hc128Rng::from_seed(seed))
+ }
+
+ fn from_rng<R: RngCore>(rng: R) -> Result<Self, Error> {
+ Hc128Rng::from_rng(rng).map(StdRng)
+ }
+}
+
+impl CryptoRng for StdRng {}
+
+
+#[cfg(test)]
+mod test {
+ use {RngCore, SeedableRng};
+ use rngs::StdRng;
+
+ #[test]
+ fn test_stdrng_construction() {
+ let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0,
+ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0];
+ let mut rng1 = StdRng::from_seed(seed);
+ assert_eq!(rng1.next_u64(), 15759097995037006553);
+
+ let mut rng2 = StdRng::from_rng(rng1).unwrap();
+ assert_eq!(rng2.next_u64(), 6766915756997287454);
+ }
+}
diff --git a/rand/src/rngs/thread.rs b/rand/src/rngs/thread.rs
new file mode 100644
index 0000000..ff772e3
--- /dev/null
+++ b/rand/src/rngs/thread.rs
@@ -0,0 +1,135 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Thread-local random number generator
+
+use std::cell::UnsafeCell;
+
+use {RngCore, CryptoRng, SeedableRng, Error};
+use rngs::adapter::ReseedingRng;
+use rngs::EntropyRng;
+use rand_hc::Hc128Core;
+
+// Rationale for using `UnsafeCell` in `ThreadRng`:
+//
+// Previously we used a `RefCell`, with an overhead of ~15%. There will only
+// ever be one mutable reference to the interior of the `UnsafeCell`, because
+// we only have such a reference inside `next_u32`, `next_u64`, etc. Within a
+// single thread (which is the definition of `ThreadRng`), there will only ever
+// be one of these methods active at a time.
+//
+// A possible scenario where there could be multiple mutable references is if
+// `ThreadRng` is used inside `next_u32` and co. But the implementation is
+// completely under our control. We just have to ensure none of them use
+// `ThreadRng` internally, which is nonsensical anyway. We should also never run
+// `ThreadRng` in destructors of its implementation, which is also nonsensical.
+//
+// The additional `Rc` is not strictly neccesary, and could be removed. For now
+// it ensures `ThreadRng` stays `!Send` and `!Sync`, and implements `Clone`.
+
+
+// Number of generated bytes after which to reseed `TreadRng`.
+//
+// The time it takes to reseed HC-128 is roughly equivalent to generating 7 KiB.
+// We pick a treshold here that is large enough to not reduce the average
+// performance too much, but also small enough to not make reseeding something
+// that basically never happens.
+const THREAD_RNG_RESEED_THRESHOLD: u64 = 32*1024*1024; // 32 MiB
+
+/// The type returned by [`thread_rng`], essentially just a reference to the
+/// PRNG in thread-local memory.
+///
+/// `ThreadRng` uses [`ReseedingRng`] wrapping the same PRNG as [`StdRng`],
+/// which is reseeded after generating 32 MiB of random data. A single instance
+/// is cached per thread and the returned `ThreadRng` is a reference to this
+/// instance — hence `ThreadRng` is neither `Send` nor `Sync` but is safe to use
+/// within a single thread. This RNG is seeded and reseeded via [`EntropyRng`]
+/// as required.
+///
+/// Note that the reseeding is done as an extra precaution against entropy
+/// leaks and is in theory unnecessary — to predict `ThreadRng`'s output, an
+/// attacker would have to either determine most of the RNG's seed or internal
+/// state, or crack the algorithm used.
+///
+/// Like [`StdRng`], `ThreadRng` is a cryptographically secure PRNG. The current
+/// algorithm used is [HC-128], which is an array-based PRNG that trades memory
+/// usage for better performance. This makes it similar to ISAAC, the algorithm
+/// used in `ThreadRng` before rand 0.5.
+///
+/// Cloning this handle just produces a new reference to the same thread-local
+/// generator.
+///
+/// [`thread_rng`]: ../fn.thread_rng.html
+/// [`ReseedingRng`]: adapter/struct.ReseedingRng.html
+/// [`StdRng`]: struct.StdRng.html
+/// [`EntropyRng`]: struct.EntropyRng.html
+/// [HC-128]: ../../rand_hc/struct.Hc128Rng.html
+#[derive(Clone, Debug)]
+pub struct ThreadRng {
+ // use of raw pointer implies type is neither Send nor Sync
+ rng: *mut ReseedingRng<Hc128Core, EntropyRng>,
+}
+
+thread_local!(
+ static THREAD_RNG_KEY: UnsafeCell<ReseedingRng<Hc128Core, EntropyRng>> = {
+ let mut entropy_source = EntropyRng::new();
+ let r = Hc128Core::from_rng(&mut entropy_source).unwrap_or_else(|err|
+ panic!("could not initialize thread_rng: {}", err));
+ let rng = ReseedingRng::new(r,
+ THREAD_RNG_RESEED_THRESHOLD,
+ entropy_source);
+ UnsafeCell::new(rng)
+ }
+);
+
+/// Retrieve the lazily-initialized thread-local random number
+/// generator, seeded by the system. Intended to be used in method
+/// chaining style, e.g. `thread_rng().gen::<i32>()`, or cached locally, e.g.
+/// `let mut rng = thread_rng();`.
+///
+/// For more information see [`ThreadRng`].
+///
+/// [`ThreadRng`]: rngs/struct.ThreadRng.html
+pub fn thread_rng() -> ThreadRng {
+ ThreadRng { rng: THREAD_RNG_KEY.with(|t| t.get()) }
+}
+
+impl RngCore for ThreadRng {
+ #[inline(always)]
+ fn next_u32(&mut self) -> u32 {
+ unsafe { (*self.rng).next_u32() }
+ }
+
+ #[inline(always)]
+ fn next_u64(&mut self) -> u64 {
+ unsafe { (*self.rng).next_u64() }
+ }
+
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
+ unsafe { (*self.rng).fill_bytes(dest) }
+ }
+
+ fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ unsafe { (*self.rng).try_fill_bytes(dest) }
+ }
+}
+
+impl CryptoRng for ThreadRng {}
+
+
+#[cfg(test)]
+mod test {
+ #[test]
+ #[cfg(not(feature="stdweb"))]
+ fn test_thread_rng() {
+ use Rng;
+ let mut r = ::thread_rng();
+ r.gen::<i32>();
+ assert_eq!(r.gen_range(0, 1), 0);
+ }
+}
diff --git a/rand/src/seq.rs b/rand/src/seq.rs
deleted file mode 100644
index a7889fe..0000000
--- a/rand/src/seq.rs
+++ /dev/null
@@ -1,337 +0,0 @@
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Functions for randomly accessing and sampling sequences.
-
-use super::Rng;
-
-// This crate is only enabled when either std or alloc is available.
-// BTreeMap is not as fast in tests, but better than nothing.
-#[cfg(feature="std")] use std::collections::HashMap;
-#[cfg(not(feature="std"))] use alloc::btree_map::BTreeMap;
-
-#[cfg(not(feature="std"))] use alloc::Vec;
-
-/// Randomly sample `amount` elements from a finite iterator.
-///
-/// The following can be returned:
-/// - `Ok`: `Vec` of `amount` non-repeating randomly sampled elements. The order is not random.
-/// - `Err`: `Vec` of all the elements from `iterable` in sequential order. This happens when the
-/// length of `iterable` was less than `amount`. This is considered an error since exactly
-/// `amount` elements is typically expected.
-///
-/// This implementation uses `O(len(iterable))` time and `O(amount)` memory.
-///
-/// # Example
-///
-/// ```rust
-/// use rand::{thread_rng, seq};
-///
-/// let mut rng = thread_rng();
-/// let sample = seq::sample_iter(&mut rng, 1..100, 5).unwrap();
-/// println!("{:?}", sample);
-/// ```
-pub fn sample_iter<T, I, R>(rng: &mut R, iterable: I, amount: usize) -> Result<Vec<T>, Vec<T>>
- where I: IntoIterator<Item=T>,
- R: Rng,
-{
- let mut iter = iterable.into_iter();
- let mut reservoir = Vec::with_capacity(amount);
- reservoir.extend(iter.by_ref().take(amount));
-
- // Continue unless the iterator was exhausted
- //
- // note: this prevents iterators that "restart" from causing problems.
- // If the iterator stops once, then so do we.
- if reservoir.len() == amount {
- for (i, elem) in iter.enumerate() {
- let k = rng.gen_range(0, i + 1 + amount);
- if let Some(spot) = reservoir.get_mut(k) {
- *spot = elem;
- }
- }
- Ok(reservoir)
- } else {
- // Don't hang onto extra memory. There is a corner case where
- // `amount` was much less than `len(iterable)`.
- reservoir.shrink_to_fit();
- Err(reservoir)
- }
-}
-
-/// Randomly sample exactly `amount` values from `slice`.
-///
-/// The values are non-repeating and in random order.
-///
-/// This implementation uses `O(amount)` time and memory.
-///
-/// Panics if `amount > slice.len()`
-///
-/// # Example
-///
-/// ```rust
-/// use rand::{thread_rng, seq};
-///
-/// let mut rng = thread_rng();
-/// let values = vec![5, 6, 1, 3, 4, 6, 7];
-/// println!("{:?}", seq::sample_slice(&mut rng, &values, 3));
-/// ```
-pub fn sample_slice<R, T>(rng: &mut R, slice: &[T], amount: usize) -> Vec<T>
- where R: Rng,
- T: Clone
-{
- let indices = sample_indices(rng, slice.len(), amount);
-
- let mut out = Vec::with_capacity(amount);
- out.extend(indices.iter().map(|i| slice[*i].clone()));
- out
-}
-
-/// Randomly sample exactly `amount` references from `slice`.
-///
-/// The references are non-repeating and in random order.
-///
-/// This implementation uses `O(amount)` time and memory.
-///
-/// Panics if `amount > slice.len()`
-///
-/// # Example
-///
-/// ```rust
-/// use rand::{thread_rng, seq};
-///
-/// let mut rng = thread_rng();
-/// let values = vec![5, 6, 1, 3, 4, 6, 7];
-/// println!("{:?}", seq::sample_slice_ref(&mut rng, &values, 3));
-/// ```
-pub fn sample_slice_ref<'a, R, T>(rng: &mut R, slice: &'a [T], amount: usize) -> Vec<&'a T>
- where R: Rng
-{
- let indices = sample_indices(rng, slice.len(), amount);
-
- let mut out = Vec::with_capacity(amount);
- out.extend(indices.iter().map(|i| &slice[*i]));
- out
-}
-
-/// Randomly sample exactly `amount` indices from `0..length`.
-///
-/// The values are non-repeating and in random order.
-///
-/// This implementation uses `O(amount)` time and memory.
-///
-/// This method is used internally by the slice sampling methods, but it can sometimes be useful to
-/// have the indices themselves so this is provided as an alternative.
-///
-/// Panics if `amount > length`
-pub fn sample_indices<R>(rng: &mut R, length: usize, amount: usize) -> Vec<usize>
- where R: Rng,
-{
- if amount > length {
- panic!("`amount` must be less than or equal to `slice.len()`");
- }
-
- // We are going to have to allocate at least `amount` for the output no matter what. However,
- // if we use the `cached` version we will have to allocate `amount` as a HashMap as well since
- // it inserts an element for every loop.
- //
- // Therefore, if `amount >= length / 2` then inplace will be both faster and use less memory.
- // In fact, benchmarks show the inplace version is faster for length up to about 20 times
- // faster than amount.
- //
- // TODO: there is probably even more fine-tuning that can be done here since
- // `HashMap::with_capacity(amount)` probably allocates more than `amount` in practice,
- // and a trade off could probably be made between memory/cpu, since hashmap operations
- // are slower than array index swapping.
- if amount >= length / 20 {
- sample_indices_inplace(rng, length, amount)
- } else {
- sample_indices_cache(rng, length, amount)
- }
-}
-
-/// Sample an amount of indices using an inplace partial fisher yates method.
-///
-/// This allocates the entire `length` of indices and randomizes only the first `amount`.
-/// It then truncates to `amount` and returns.
-///
-/// This is better than using a HashMap "cache" when `amount >= length / 2` since it does not
-/// require allocating an extra cache and is much faster.
-fn sample_indices_inplace<R>(rng: &mut R, length: usize, amount: usize) -> Vec<usize>
- where R: Rng,
-{
- debug_assert!(amount <= length);
- let mut indices: Vec<usize> = Vec::with_capacity(length);
- indices.extend(0..length);
- for i in 0..amount {
- let j: usize = rng.gen_range(i, length);
- let tmp = indices[i];
- indices[i] = indices[j];
- indices[j] = tmp;
- }
- indices.truncate(amount);
- debug_assert_eq!(indices.len(), amount);
- indices
-}
-
-
-/// This method performs a partial fisher-yates on a range of indices using a HashMap
-/// as a cache to record potential collisions.
-///
-/// The cache avoids allocating the entire `length` of values. This is especially useful when
-/// `amount <<< length`, i.e. select 3 non-repeating from 1_000_000
-fn sample_indices_cache<R>(
- rng: &mut R,
- length: usize,
- amount: usize,
-) -> Vec<usize>
- where R: Rng,
-{
- debug_assert!(amount <= length);
- #[cfg(feature="std")] let mut cache = HashMap::with_capacity(amount);
- #[cfg(not(feature="std"))] let mut cache = BTreeMap::new();
- let mut out = Vec::with_capacity(amount);
- for i in 0..amount {
- let j: usize = rng.gen_range(i, length);
-
- // equiv: let tmp = slice[i];
- let tmp = match cache.get(&i) {
- Some(e) => *e,
- None => i,
- };
-
- // equiv: slice[i] = slice[j];
- let x = match cache.get(&j) {
- Some(x) => *x,
- None => j,
- };
-
- // equiv: slice[j] = tmp;
- cache.insert(j, tmp);
-
- // note that in the inplace version, slice[i] is automatically "returned" value
- out.push(x);
- }
- debug_assert_eq!(out.len(), amount);
- out
-}
-
-#[cfg(test)]
-mod test {
- use super::*;
- use {thread_rng, XorShiftRng, SeedableRng};
-
- #[test]
- fn test_sample_iter() {
- let min_val = 1;
- let max_val = 100;
-
- let mut r = thread_rng();
- let vals = (min_val..max_val).collect::<Vec<i32>>();
- let small_sample = sample_iter(&mut r, vals.iter(), 5).unwrap();
- let large_sample = sample_iter(&mut r, vals.iter(), vals.len() + 5).unwrap_err();
-
- assert_eq!(small_sample.len(), 5);
- assert_eq!(large_sample.len(), vals.len());
- // no randomization happens when amount >= len
- assert_eq!(large_sample, vals.iter().collect::<Vec<_>>());
-
- assert!(small_sample.iter().all(|e| {
- **e >= min_val && **e <= max_val
- }));
- }
- #[test]
- fn test_sample_slice_boundaries() {
- let empty: &[u8] = &[];
-
- let mut r = thread_rng();
-
- // sample 0 items
- assert_eq!(sample_slice(&mut r, empty, 0), vec![]);
- assert_eq!(sample_slice(&mut r, &[42, 2, 42], 0), vec![]);
-
- // sample 1 item
- assert_eq!(sample_slice(&mut r, &[42], 1), vec![42]);
- let v = sample_slice(&mut r, &[1, 42], 1)[0];
- assert!(v == 1 || v == 42);
-
- // sample "all" the items
- let v = sample_slice(&mut r, &[42, 133], 2);
- assert!(v == vec![42, 133] || v == vec![133, 42]);
-
- assert_eq!(sample_indices_inplace(&mut r, 0, 0), vec![]);
- assert_eq!(sample_indices_inplace(&mut r, 1, 0), vec![]);
- assert_eq!(sample_indices_inplace(&mut r, 1, 1), vec![0]);
-
- assert_eq!(sample_indices_cache(&mut r, 0, 0), vec![]);
- assert_eq!(sample_indices_cache(&mut r, 1, 0), vec![]);
- assert_eq!(sample_indices_cache(&mut r, 1, 1), vec![0]);
-
- // Make sure lucky 777's aren't lucky
- let slice = &[42, 777];
- let mut num_42 = 0;
- let total = 1000;
- for _ in 0..total {
- let v = sample_slice(&mut r, slice, 1);
- assert_eq!(v.len(), 1);
- let v = v[0];
- assert!(v == 42 || v == 777);
- if v == 42 {
- num_42 += 1;
- }
- }
- let ratio_42 = num_42 as f64 / 1000 as f64;
- assert!(0.4 <= ratio_42 || ratio_42 <= 0.6, "{}", ratio_42);
- }
-
- #[test]
- fn test_sample_slice() {
- let xor_rng = XorShiftRng::from_seed;
-
- let max_range = 100;
- let mut r = thread_rng();
-
- for length in 1usize..max_range {
- let amount = r.gen_range(0, length);
- let seed: [u32; 4] = [
- r.next_u32(), r.next_u32(), r.next_u32(), r.next_u32()
- ];
-
- println!("Selecting indices: len={}, amount={}, seed={:?}", length, amount, seed);
-
- // assert that the two index methods give exactly the same result
- let inplace = sample_indices_inplace(
- &mut xor_rng(seed), length, amount);
- let cache = sample_indices_cache(
- &mut xor_rng(seed), length, amount);
- assert_eq!(inplace, cache);
-
- // assert the basics work
- let regular = sample_indices(
- &mut xor_rng(seed), length, amount);
- assert_eq!(regular.len(), amount);
- assert!(regular.iter().all(|e| *e < length));
- assert_eq!(regular, inplace);
-
- // also test that sampling the slice works
- let vec: Vec<usize> = (0..length).collect();
- {
- let result = sample_slice(&mut xor_rng(seed), &vec, amount);
- assert_eq!(result, regular);
- }
-
- {
- let result = sample_slice_ref(&mut xor_rng(seed), &vec, amount);
- let expected = regular.iter().map(|v| v).collect::<Vec<_>>();
- assert_eq!(result, expected);
- }
- }
- }
-}
diff --git a/rand/src/seq/index.rs b/rand/src/seq/index.rs
new file mode 100644
index 0000000..3d4df3a
--- /dev/null
+++ b/rand/src/seq/index.rs
@@ -0,0 +1,378 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Index sampling
+
+#[cfg(feature="alloc")] use core::slice;
+
+#[cfg(feature="std")] use std::vec;
+#[cfg(all(feature="alloc", not(feature="std")))] use alloc::vec::{self, Vec};
+// BTreeMap is not as fast in tests, but better than nothing.
+#[cfg(feature="std")] use std::collections::{HashSet};
+#[cfg(all(feature="alloc", not(feature="std")))] use alloc::collections::BTreeSet;
+
+#[cfg(feature="alloc")] use distributions::{Distribution, Uniform};
+use Rng;
+
+/// A vector of indices.
+///
+/// Multiple internal representations are possible.
+#[derive(Clone, Debug)]
+pub enum IndexVec {
+ #[doc(hidden)] U32(Vec<u32>),
+ #[doc(hidden)] USize(Vec<usize>),
+}
+
+impl IndexVec {
+ /// Returns the number of indices
+ pub fn len(&self) -> usize {
+ match self {
+ &IndexVec::U32(ref v) => v.len(),
+ &IndexVec::USize(ref v) => v.len(),
+ }
+ }
+
+ /// Return the value at the given `index`.
+ ///
+ /// (Note: we cannot implement `std::ops::Index` because of lifetime
+ /// restrictions.)
+ pub fn index(&self, index: usize) -> usize {
+ match self {
+ &IndexVec::U32(ref v) => v[index] as usize,
+ &IndexVec::USize(ref v) => v[index],
+ }
+ }
+
+ /// Return result as a `Vec<usize>`. Conversion may or may not be trivial.
+ pub fn into_vec(self) -> Vec<usize> {
+ match self {
+ IndexVec::U32(v) => v.into_iter().map(|i| i as usize).collect(),
+ IndexVec::USize(v) => v,
+ }
+ }
+
+ /// Iterate over the indices as a sequence of `usize` values
+ pub fn iter<'a>(&'a self) -> IndexVecIter<'a> {
+ match self {
+ &IndexVec::U32(ref v) => IndexVecIter::U32(v.iter()),
+ &IndexVec::USize(ref v) => IndexVecIter::USize(v.iter()),
+ }
+ }
+
+ /// Convert into an iterator over the indices as a sequence of `usize` values
+ pub fn into_iter(self) -> IndexVecIntoIter {
+ match self {
+ IndexVec::U32(v) => IndexVecIntoIter::U32(v.into_iter()),
+ IndexVec::USize(v) => IndexVecIntoIter::USize(v.into_iter()),
+ }
+ }
+}
+
+impl PartialEq for IndexVec {
+ fn eq(&self, other: &IndexVec) -> bool {
+ use self::IndexVec::*;
+ match (self, other) {
+ (&U32(ref v1), &U32(ref v2)) => v1 == v2,
+ (&USize(ref v1), &USize(ref v2)) => v1 == v2,
+ (&U32(ref v1), &USize(ref v2)) => (v1.len() == v2.len())
+ && (v1.iter().zip(v2.iter()).all(|(x, y)| *x as usize == *y)),
+ (&USize(ref v1), &U32(ref v2)) => (v1.len() == v2.len())
+ && (v1.iter().zip(v2.iter()).all(|(x, y)| *x == *y as usize)),
+ }
+ }
+}
+
+impl From<Vec<u32>> for IndexVec {
+ fn from(v: Vec<u32>) -> Self {
+ IndexVec::U32(v)
+ }
+}
+
+impl From<Vec<usize>> for IndexVec {
+ fn from(v: Vec<usize>) -> Self {
+ IndexVec::USize(v)
+ }
+}
+
+/// Return type of `IndexVec::iter`.
+#[derive(Debug)]
+pub enum IndexVecIter<'a> {
+ #[doc(hidden)] U32(slice::Iter<'a, u32>),
+ #[doc(hidden)] USize(slice::Iter<'a, usize>),
+}
+
+impl<'a> Iterator for IndexVecIter<'a> {
+ type Item = usize;
+ fn next(&mut self) -> Option<usize> {
+ use self::IndexVecIter::*;
+ match self {
+ &mut U32(ref mut iter) => iter.next().map(|i| *i as usize),
+ &mut USize(ref mut iter) => iter.next().cloned(),
+ }
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ match self {
+ &IndexVecIter::U32(ref v) => v.size_hint(),
+ &IndexVecIter::USize(ref v) => v.size_hint(),
+ }
+ }
+}
+
+impl<'a> ExactSizeIterator for IndexVecIter<'a> {}
+
+/// Return type of `IndexVec::into_iter`.
+#[derive(Clone, Debug)]
+pub enum IndexVecIntoIter {
+ #[doc(hidden)] U32(vec::IntoIter<u32>),
+ #[doc(hidden)] USize(vec::IntoIter<usize>),
+}
+
+impl Iterator for IndexVecIntoIter {
+ type Item = usize;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ use self::IndexVecIntoIter::*;
+ match self {
+ &mut U32(ref mut v) => v.next().map(|i| i as usize),
+ &mut USize(ref mut v) => v.next(),
+ }
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ use self::IndexVecIntoIter::*;
+ match self {
+ &U32(ref v) => v.size_hint(),
+ &USize(ref v) => v.size_hint(),
+ }
+ }
+}
+
+impl ExactSizeIterator for IndexVecIntoIter {}
+
+
+/// Randomly sample exactly `amount` distinct indices from `0..length`, and
+/// return them in random order (fully shuffled).
+///
+/// This method is used internally by the slice sampling methods, but it can
+/// sometimes be useful to have the indices themselves so this is provided as
+/// an alternative.
+///
+/// The implementation used is not specified; we automatically select the
+/// fastest available algorithm for the `length` and `amount` parameters
+/// (based on detailed profiling on an Intel Haswell CPU). Roughly speaking,
+/// complexity is `O(amount)`, except that when `amount` is small, performance
+/// is closer to `O(amount^2)`, and when `length` is close to `amount` then
+/// `O(length)`.
+///
+/// Note that performance is significantly better over `u32` indices than over
+/// `u64` indices. Because of this we hide the underlying type behind an
+/// abstraction, `IndexVec`.
+///
+/// If an allocation-free `no_std` function is required, it is suggested
+/// to adapt the internal `sample_floyd` implementation.
+///
+/// Panics if `amount > length`.
+pub fn sample<R>(rng: &mut R, length: usize, amount: usize) -> IndexVec
+ where R: Rng + ?Sized,
+{
+ if amount > length {
+ panic!("`amount` of samples must be less than or equal to `length`");
+ }
+ if length > (::core::u32::MAX as usize) {
+ // We never want to use inplace here, but could use floyd's alg
+ // Lazy version: always use the cache alg.
+ return sample_rejection(rng, length, amount);
+ }
+ let amount = amount as u32;
+ let length = length as u32;
+
+ // Choice of algorithm here depends on both length and amount. See:
+ // https://github.com/rust-random/rand/pull/479
+ // We do some calculations with f32. Accuracy is not very important.
+
+ if amount < 163 {
+ const C: [[f32; 2]; 2] = [[1.6, 8.0/45.0], [10.0, 70.0/9.0]];
+ let j = if length < 500_000 { 0 } else { 1 };
+ let amount_fp = amount as f32;
+ let m4 = C[0][j] * amount_fp;
+ // Short-cut: when amount < 12, floyd's is always faster
+ if amount > 11 && (length as f32) < (C[1][j] + m4) * amount_fp {
+ sample_inplace(rng, length, amount)
+ } else {
+ sample_floyd(rng, length, amount)
+ }
+ } else {
+ const C: [f32; 2] = [270.0, 330.0/9.0];
+ let j = if length < 500_000 { 0 } else { 1 };
+ if (length as f32) < C[j] * (amount as f32) {
+ sample_inplace(rng, length, amount)
+ } else {
+ // note: could have a specific u32 impl, but I'm lazy and
+ // generics don't have usable conversions
+ sample_rejection(rng, length as usize, amount as usize)
+ }
+ }
+}
+
+/// Randomly sample exactly `amount` indices from `0..length`, using Floyd's
+/// combination algorithm.
+///
+/// The output values are fully shuffled. (Overhead is under 50%.)
+///
+/// This implementation uses `O(amount)` memory and `O(amount^2)` time.
+fn sample_floyd<R>(rng: &mut R, length: u32, amount: u32) -> IndexVec
+ where R: Rng + ?Sized,
+{
+ // For small amount we use Floyd's fully-shuffled variant. For larger
+ // amounts this is slow due to Vec::insert performance, so we shuffle
+ // afterwards. Benchmarks show little overhead from extra logic.
+ let floyd_shuffle = amount < 50;
+
+ debug_assert!(amount <= length);
+ let mut indices = Vec::with_capacity(amount as usize);
+ for j in length - amount .. length {
+ let t = rng.gen_range(0, j + 1);
+ if floyd_shuffle {
+ if let Some(pos) = indices.iter().position(|&x| x == t) {
+ indices.insert(pos, j);
+ continue;
+ }
+ } else {
+ if indices.contains(&t) {
+ indices.push(j);
+ continue;
+ }
+ }
+ indices.push(t);
+ }
+ if !floyd_shuffle {
+ // Reimplement SliceRandom::shuffle with smaller indices
+ for i in (1..amount).rev() {
+ // invariant: elements with index > i have been locked in place.
+ indices.swap(i as usize, rng.gen_range(0, i + 1) as usize);
+ }
+ }
+ IndexVec::from(indices)
+}
+
+/// Randomly sample exactly `amount` indices from `0..length`, using an inplace
+/// partial Fisher-Yates method.
+/// Sample an amount of indices using an inplace partial fisher yates method.
+///
+/// This allocates the entire `length` of indices and randomizes only the first `amount`.
+/// It then truncates to `amount` and returns.
+///
+/// This method is not appropriate for large `length` and potentially uses a lot
+/// of memory; because of this we only implement for `u32` index (which improves
+/// performance in all cases).
+///
+/// Set-up is `O(length)` time and memory and shuffling is `O(amount)` time.
+fn sample_inplace<R>(rng: &mut R, length: u32, amount: u32) -> IndexVec
+ where R: Rng + ?Sized,
+{
+ debug_assert!(amount <= length);
+ let mut indices: Vec<u32> = Vec::with_capacity(length as usize);
+ indices.extend(0..length);
+ for i in 0..amount {
+ let j: u32 = rng.gen_range(i, length);
+ indices.swap(i as usize, j as usize);
+ }
+ indices.truncate(amount as usize);
+ debug_assert_eq!(indices.len(), amount as usize);
+ IndexVec::from(indices)
+}
+
+/// Randomly sample exactly `amount` indices from `0..length`, using rejection
+/// sampling.
+///
+/// Since `amount <<< length` there is a low chance of a random sample in
+/// `0..length` being a duplicate. We test for duplicates and resample where
+/// necessary. The algorithm is `O(amount)` time and memory.
+fn sample_rejection<R>(rng: &mut R, length: usize, amount: usize) -> IndexVec
+ where R: Rng + ?Sized,
+{
+ debug_assert!(amount < length);
+ #[cfg(feature="std")] let mut cache = HashSet::with_capacity(amount);
+ #[cfg(not(feature="std"))] let mut cache = BTreeSet::new();
+ let distr = Uniform::new(0, length);
+ let mut indices = Vec::with_capacity(amount);
+ for _ in 0..amount {
+ let mut pos = distr.sample(rng);
+ while !cache.insert(pos) {
+ pos = distr.sample(rng);
+ }
+ indices.push(pos);
+ }
+
+ debug_assert_eq!(indices.len(), amount);
+ IndexVec::from(indices)
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+
+ #[test]
+ fn test_sample_boundaries() {
+ let mut r = ::test::rng(404);
+
+ assert_eq!(sample_inplace(&mut r, 0, 0).len(), 0);
+ assert_eq!(sample_inplace(&mut r, 1, 0).len(), 0);
+ assert_eq!(sample_inplace(&mut r, 1, 1).into_vec(), vec![0]);
+
+ assert_eq!(sample_rejection(&mut r, 1, 0).len(), 0);
+
+ assert_eq!(sample_floyd(&mut r, 0, 0).len(), 0);
+ assert_eq!(sample_floyd(&mut r, 1, 0).len(), 0);
+ assert_eq!(sample_floyd(&mut r, 1, 1).into_vec(), vec![0]);
+
+ // These algorithms should be fast with big numbers. Test average.
+ let sum: usize = sample_rejection(&mut r, 1 << 25, 10)
+ .into_iter().sum();
+ assert!(1 << 25 < sum && sum < (1 << 25) * 25);
+
+ let sum: usize = sample_floyd(&mut r, 1 << 25, 10)
+ .into_iter().sum();
+ assert!(1 << 25 < sum && sum < (1 << 25) * 25);
+ }
+
+ #[test]
+ fn test_sample_alg() {
+ let seed_rng = ::test::rng;
+
+ // We can't test which algorithm is used directly, but Floyd's alg
+ // should produce different results from the others. (Also, `inplace`
+ // and `cached` currently use different sizes thus produce different results.)
+
+ // A small length and relatively large amount should use inplace
+ let (length, amount): (usize, usize) = (100, 50);
+ let v1 = sample(&mut seed_rng(420), length, amount);
+ let v2 = sample_inplace(&mut seed_rng(420), length as u32, amount as u32);
+ assert!(v1.iter().all(|e| e < length));
+ assert_eq!(v1, v2);
+
+ // Test Floyd's alg does produce different results
+ let v3 = sample_floyd(&mut seed_rng(420), length as u32, amount as u32);
+ assert!(v1 != v3);
+
+ // A large length and small amount should use Floyd
+ let (length, amount): (usize, usize) = (1<<20, 50);
+ let v1 = sample(&mut seed_rng(421), length, amount);
+ let v2 = sample_floyd(&mut seed_rng(421), length as u32, amount as u32);
+ assert!(v1.iter().all(|e| e < length));
+ assert_eq!(v1, v2);
+
+ // A large length and larger amount should use cache
+ let (length, amount): (usize, usize) = (1<<20, 600);
+ let v1 = sample(&mut seed_rng(422), length, amount);
+ let v2 = sample_rejection(&mut seed_rng(422), length, amount);
+ assert!(v1.iter().all(|e| e < length));
+ assert_eq!(v1, v2);
+ }
+}
diff --git a/rand/src/seq/mod.rs b/rand/src/seq/mod.rs
new file mode 100644
index 0000000..9959602
--- /dev/null
+++ b/rand/src/seq/mod.rs
@@ -0,0 +1,836 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Functions for randomly accessing and sampling sequences.
+//!
+//! TODO: module doc
+
+
+#[cfg(feature="alloc")] pub mod index;
+
+#[cfg(feature="alloc")] use core::ops::Index;
+
+#[cfg(all(feature="alloc", not(feature="std")))] use alloc::vec::Vec;
+
+use Rng;
+#[cfg(feature="alloc")] use distributions::WeightedError;
+#[cfg(feature="alloc")] use distributions::uniform::{SampleUniform, SampleBorrow};
+
+/// Extension trait on slices, providing random mutation and sampling methods.
+///
+/// An implementation is provided for slices. This may also be implementable for
+/// other types.
+pub trait SliceRandom {
+ /// The element type.
+ type Item;
+
+ /// Returns a reference to one random element of the slice, or `None` if the
+ /// slice is empty.
+ ///
+ /// Depending on the implementation, complexity is expected to be `O(1)`.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use rand::thread_rng;
+ /// use rand::seq::SliceRandom;
+ ///
+ /// let choices = [1, 2, 4, 8, 16, 32];
+ /// let mut rng = thread_rng();
+ /// println!("{:?}", choices.choose(&mut rng));
+ /// assert_eq!(choices[..0].choose(&mut rng), None);
+ /// ```
+ fn choose<R>(&self, rng: &mut R) -> Option<&Self::Item>
+ where R: Rng + ?Sized;
+
+ /// Returns a mutable reference to one random element of the slice, or
+ /// `None` if the slice is empty.
+ ///
+ /// Depending on the implementation, complexity is expected to be `O(1)`.
+ fn choose_mut<R>(&mut self, rng: &mut R) -> Option<&mut Self::Item>
+ where R: Rng + ?Sized;
+
+ /// Produces an iterator that chooses `amount` elements from the slice at
+ /// random without repeating any, and returns them in random order.
+ ///
+ /// In case this API is not sufficiently flexible, use `index::sample` then
+ /// apply the indices to the slice.
+ ///
+ /// Complexity is expected to be the same as `index::sample`.
+ ///
+ /// # Example
+ /// ```
+ /// use rand::seq::SliceRandom;
+ ///
+ /// let mut rng = &mut rand::thread_rng();
+ /// let sample = "Hello, audience!".as_bytes();
+ ///
+ /// // collect the results into a vector:
+ /// let v: Vec<u8> = sample.choose_multiple(&mut rng, 3).cloned().collect();
+ ///
+ /// // store in a buffer:
+ /// let mut buf = [0u8; 5];
+ /// for (b, slot) in sample.choose_multiple(&mut rng, buf.len()).zip(buf.iter_mut()) {
+ /// *slot = *b;
+ /// }
+ /// ```
+ #[cfg(feature = "alloc")]
+ fn choose_multiple<R>(&self, rng: &mut R, amount: usize) -> SliceChooseIter<Self, Self::Item>
+ where R: Rng + ?Sized;
+
+ /// Similar to [`choose`], where the likelihood of each outcome may be
+ /// specified. The specified function `weight` maps items `x` to a relative
+ /// likelihood `weight(x)`. The probability of each item being selected is
+ /// therefore `weight(x) / s`, where `s` is the sum of all `weight(x)`.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use rand::prelude::*;
+ ///
+ /// let choices = [('a', 2), ('b', 1), ('c', 1)];
+ /// let mut rng = thread_rng();
+ /// // 50% chance to print 'a', 25% chance to print 'b', 25% chance to print 'c'
+ /// println!("{:?}", choices.choose_weighted(&mut rng, |item| item.1).unwrap().0);
+ /// ```
+ /// [`choose`]: trait.SliceRandom.html#method.choose
+ #[cfg(feature = "alloc")]
+ fn choose_weighted<R, F, B, X>(&self, rng: &mut R, weight: F) -> Result<&Self::Item, WeightedError>
+ where R: Rng + ?Sized,
+ F: Fn(&Self::Item) -> B,
+ B: SampleBorrow<X>,
+ X: SampleUniform +
+ for<'a> ::core::ops::AddAssign<&'a X> +
+ ::core::cmp::PartialOrd<X> +
+ Clone +
+ Default;
+
+ /// Similar to [`choose_mut`], where the likelihood of each outcome may be
+ /// specified. The specified function `weight` maps items `x` to a relative
+ /// likelihood `weight(x)`. The probability of each item being selected is
+ /// therefore `weight(x) / s`, where `s` is the sum of all `weight(x)`.
+ ///
+ /// See also [`choose_weighted`].
+ ///
+ /// [`choose_mut`]: trait.SliceRandom.html#method.choose_mut
+ /// [`choose_weighted`]: trait.SliceRandom.html#method.choose_weighted
+ #[cfg(feature = "alloc")]
+ fn choose_weighted_mut<R, F, B, X>(&mut self, rng: &mut R, weight: F) -> Result<&mut Self::Item, WeightedError>
+ where R: Rng + ?Sized,
+ F: Fn(&Self::Item) -> B,
+ B: SampleBorrow<X>,
+ X: SampleUniform +
+ for<'a> ::core::ops::AddAssign<&'a X> +
+ ::core::cmp::PartialOrd<X> +
+ Clone +
+ Default;
+
+ /// Shuffle a mutable slice in place.
+ ///
+ /// Depending on the implementation, complexity is expected to be `O(1)`.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use rand::thread_rng;
+ /// use rand::seq::SliceRandom;
+ ///
+ /// let mut rng = thread_rng();
+ /// let mut y = [1, 2, 3, 4, 5];
+ /// println!("Unshuffled: {:?}", y);
+ /// y.shuffle(&mut rng);
+ /// println!("Shuffled: {:?}", y);
+ /// ```
+ fn shuffle<R>(&mut self, rng: &mut R) where R: Rng + ?Sized;
+
+ /// Shuffle a slice in place, but exit early.
+ ///
+ /// Returns two mutable slices from the source slice. The first contains
+ /// `amount` elements randomly permuted. The second has the remaining
+ /// elements that are not fully shuffled.
+ ///
+ /// This is an efficient method to select `amount` elements at random from
+ /// the slice, provided the slice may be mutated.
+ ///
+ /// If you only need to choose elements randomly and `amount > self.len()/2`
+ /// then you may improve performance by taking
+ /// `amount = values.len() - amount` and using only the second slice.
+ ///
+ /// If `amount` is greater than the number of elements in the slice, this
+ /// will perform a full shuffle.
+ ///
+ /// Complexity is expected to be `O(m)` where `m = amount`.
+ fn partial_shuffle<R>(&mut self, rng: &mut R, amount: usize)
+ -> (&mut [Self::Item], &mut [Self::Item]) where R: Rng + ?Sized;
+}
+
+/// Extension trait on iterators, providing random sampling methods.
+pub trait IteratorRandom: Iterator + Sized {
+ /// Choose one element at random from the iterator. If you have a slice,
+ /// it's significantly faster to call the [`choose`] or [`choose_mut`]
+ /// functions using the slice instead.
+ ///
+ /// Returns `None` if and only if the iterator is empty.
+ ///
+ /// Complexity is `O(n)`, where `n` is the length of the iterator.
+ /// This likely consumes multiple random numbers, but the exact number
+ /// is unspecified.
+ ///
+ /// [`choose`]: trait.SliceRandom.html#method.choose
+ /// [`choose_mut`]: trait.SliceRandom.html#method.choose_mut
+ fn choose<R>(mut self, rng: &mut R) -> Option<Self::Item>
+ where R: Rng + ?Sized
+ {
+ let (mut lower, mut upper) = self.size_hint();
+ let mut consumed = 0;
+ let mut result = None;
+
+ if upper == Some(lower) {
+ return if lower == 0 { None } else { self.nth(rng.gen_range(0, lower)) };
+ }
+
+ // Continue until the iterator is exhausted
+ loop {
+ if lower > 1 {
+ let ix = rng.gen_range(0, lower + consumed);
+ let skip;
+ if ix < lower {
+ result = self.nth(ix);
+ skip = lower - (ix + 1);
+ } else {
+ skip = lower;
+ }
+ if upper == Some(lower) {
+ return result;
+ }
+ consumed += lower;
+ if skip > 0 {
+ self.nth(skip - 1);
+ }
+ } else {
+ let elem = self.next();
+ if elem.is_none() {
+ return result;
+ }
+ consumed += 1;
+ let denom = consumed as f64; // accurate to 2^53 elements
+ if rng.gen_bool(1.0 / denom) {
+ result = elem;
+ }
+ }
+
+ let hint = self.size_hint();
+ lower = hint.0;
+ upper = hint.1;
+ }
+ }
+
+ /// Collects `amount` values at random from the iterator into a supplied
+ /// buffer.
+ ///
+ /// Although the elements are selected randomly, the order of elements in
+ /// the buffer is neither stable nor fully random. If random ordering is
+ /// desired, shuffle the result.
+ ///
+ /// Returns the number of elements added to the buffer. This equals `amount`
+ /// unless the iterator contains insufficient elements, in which case this
+ /// equals the number of elements available.
+ ///
+ /// Complexity is `O(n)` where `n` is the length of the iterator.
+ fn choose_multiple_fill<R>(mut self, rng: &mut R, buf: &mut [Self::Item])
+ -> usize where R: Rng + ?Sized
+ {
+ let amount = buf.len();
+ let mut len = 0;
+ while len < amount {
+ if let Some(elem) = self.next() {
+ buf[len] = elem;
+ len += 1;
+ } else {
+ // Iterator exhausted; stop early
+ return len;
+ }
+ }
+
+ // Continue, since the iterator was not exhausted
+ for (i, elem) in self.enumerate() {
+ let k = rng.gen_range(0, i + 1 + amount);
+ if let Some(slot) = buf.get_mut(k) {
+ *slot = elem;
+ }
+ }
+ len
+ }
+
+ /// Collects `amount` values at random from the iterator into a vector.
+ ///
+ /// This is equivalent to `choose_multiple_fill` except for the result type.
+ ///
+ /// Although the elements are selected randomly, the order of elements in
+ /// the buffer is neither stable nor fully random. If random ordering is
+ /// desired, shuffle the result.
+ ///
+ /// The length of the returned vector equals `amount` unless the iterator
+ /// contains insufficient elements, in which case it equals the number of
+ /// elements available.
+ ///
+ /// Complexity is `O(n)` where `n` is the length of the iterator.
+ #[cfg(feature = "alloc")]
+ fn choose_multiple<R>(mut self, rng: &mut R, amount: usize) -> Vec<Self::Item>
+ where R: Rng + ?Sized
+ {
+ let mut reservoir = Vec::with_capacity(amount);
+ reservoir.extend(self.by_ref().take(amount));
+
+ // Continue unless the iterator was exhausted
+ //
+ // note: this prevents iterators that "restart" from causing problems.
+ // If the iterator stops once, then so do we.
+ if reservoir.len() == amount {
+ for (i, elem) in self.enumerate() {
+ let k = rng.gen_range(0, i + 1 + amount);
+ if let Some(slot) = reservoir.get_mut(k) {
+ *slot = elem;
+ }
+ }
+ } else {
+ // Don't hang onto extra memory. There is a corner case where
+ // `amount` was much less than `self.len()`.
+ reservoir.shrink_to_fit();
+ }
+ reservoir
+ }
+}
+
+
+impl<T> SliceRandom for [T] {
+ type Item = T;
+
+ fn choose<R>(&self, rng: &mut R) -> Option<&Self::Item>
+ where R: Rng + ?Sized
+ {
+ if self.is_empty() {
+ None
+ } else {
+ Some(&self[rng.gen_range(0, self.len())])
+ }
+ }
+
+ fn choose_mut<R>(&mut self, rng: &mut R) -> Option<&mut Self::Item>
+ where R: Rng + ?Sized
+ {
+ if self.is_empty() {
+ None
+ } else {
+ let len = self.len();
+ Some(&mut self[rng.gen_range(0, len)])
+ }
+ }
+
+ #[cfg(feature = "alloc")]
+ fn choose_multiple<R>(&self, rng: &mut R, amount: usize)
+ -> SliceChooseIter<Self, Self::Item>
+ where R: Rng + ?Sized
+ {
+ let amount = ::core::cmp::min(amount, self.len());
+ SliceChooseIter {
+ slice: self,
+ _phantom: Default::default(),
+ indices: index::sample(rng, self.len(), amount).into_iter(),
+ }
+ }
+
+ #[cfg(feature = "alloc")]
+ fn choose_weighted<R, F, B, X>(&self, rng: &mut R, weight: F) -> Result<&Self::Item, WeightedError>
+ where R: Rng + ?Sized,
+ F: Fn(&Self::Item) -> B,
+ B: SampleBorrow<X>,
+ X: SampleUniform +
+ for<'a> ::core::ops::AddAssign<&'a X> +
+ ::core::cmp::PartialOrd<X> +
+ Clone +
+ Default {
+ use distributions::{Distribution, WeightedIndex};
+ let distr = WeightedIndex::new(self.iter().map(weight))?;
+ Ok(&self[distr.sample(rng)])
+ }
+
+ #[cfg(feature = "alloc")]
+ fn choose_weighted_mut<R, F, B, X>(&mut self, rng: &mut R, weight: F) -> Result<&mut Self::Item, WeightedError>
+ where R: Rng + ?Sized,
+ F: Fn(&Self::Item) -> B,
+ B: SampleBorrow<X>,
+ X: SampleUniform +
+ for<'a> ::core::ops::AddAssign<&'a X> +
+ ::core::cmp::PartialOrd<X> +
+ Clone +
+ Default {
+ use distributions::{Distribution, WeightedIndex};
+ let distr = WeightedIndex::new(self.iter().map(weight))?;
+ Ok(&mut self[distr.sample(rng)])
+ }
+
+ fn shuffle<R>(&mut self, rng: &mut R) where R: Rng + ?Sized
+ {
+ for i in (1..self.len()).rev() {
+ // invariant: elements with index > i have been locked in place.
+ self.swap(i, rng.gen_range(0, i + 1));
+ }
+ }
+
+ fn partial_shuffle<R>(&mut self, rng: &mut R, amount: usize)
+ -> (&mut [Self::Item], &mut [Self::Item]) where R: Rng + ?Sized
+ {
+ // This applies Durstenfeld's algorithm for the
+ // [Fisher–Yates shuffle](https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#The_modern_algorithm)
+ // for an unbiased permutation, but exits early after choosing `amount`
+ // elements.
+
+ let len = self.len();
+ let end = if amount >= len { 0 } else { len - amount };
+
+ for i in (end..len).rev() {
+ // invariant: elements with index > i have been locked in place.
+ self.swap(i, rng.gen_range(0, i + 1));
+ }
+ let r = self.split_at_mut(end);
+ (r.1, r.0)
+ }
+}
+
+impl<I> IteratorRandom for I where I: Iterator + Sized {}
+
+
+/// Iterator over multiple choices, as returned by [`SliceRandom::choose_multiple](
+/// trait.SliceRandom.html#method.choose_multiple).
+#[cfg(feature = "alloc")]
+#[derive(Debug)]
+pub struct SliceChooseIter<'a, S: ?Sized + 'a, T: 'a> {
+ slice: &'a S,
+ _phantom: ::core::marker::PhantomData<T>,
+ indices: index::IndexVecIntoIter,
+}
+
+#[cfg(feature = "alloc")]
+impl<'a, S: Index<usize, Output = T> + ?Sized + 'a, T: 'a> Iterator for SliceChooseIter<'a, S, T> {
+ type Item = &'a T;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ // TODO: investigate using SliceIndex::get_unchecked when stable
+ self.indices.next().map(|i| &self.slice[i as usize])
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (self.indices.len(), Some(self.indices.len()))
+ }
+}
+
+#[cfg(feature = "alloc")]
+impl<'a, S: Index<usize, Output = T> + ?Sized + 'a, T: 'a> ExactSizeIterator
+ for SliceChooseIter<'a, S, T>
+{
+ fn len(&self) -> usize {
+ self.indices.len()
+ }
+}
+
+
+/// Randomly sample `amount` elements from a finite iterator.
+///
+/// Deprecated: use [`IteratorRandom::choose_multiple`] instead.
+///
+/// [`IteratorRandom::choose_multiple`]: trait.IteratorRandom.html#method.choose_multiple
+#[cfg(feature = "alloc")]
+#[deprecated(since="0.6.0", note="use IteratorRandom::choose_multiple instead")]
+pub fn sample_iter<T, I, R>(rng: &mut R, iterable: I, amount: usize) -> Result<Vec<T>, Vec<T>>
+ where I: IntoIterator<Item=T>,
+ R: Rng + ?Sized,
+{
+ use seq::IteratorRandom;
+ let iter = iterable.into_iter();
+ let result = iter.choose_multiple(rng, amount);
+ if result.len() == amount {
+ Ok(result)
+ } else {
+ Err(result)
+ }
+}
+
+/// Randomly sample exactly `amount` values from `slice`.
+///
+/// The values are non-repeating and in random order.
+///
+/// This implementation uses `O(amount)` time and memory.
+///
+/// Panics if `amount > slice.len()`
+///
+/// Deprecated: use [`SliceRandom::choose_multiple`] instead.
+///
+/// [`SliceRandom::choose_multiple`]: trait.SliceRandom.html#method.choose_multiple
+#[cfg(feature = "alloc")]
+#[deprecated(since="0.6.0", note="use SliceRandom::choose_multiple instead")]
+pub fn sample_slice<R, T>(rng: &mut R, slice: &[T], amount: usize) -> Vec<T>
+ where R: Rng + ?Sized,
+ T: Clone
+{
+ let indices = index::sample(rng, slice.len(), amount).into_iter();
+
+ let mut out = Vec::with_capacity(amount);
+ out.extend(indices.map(|i| slice[i].clone()));
+ out
+}
+
+/// Randomly sample exactly `amount` references from `slice`.
+///
+/// The references are non-repeating and in random order.
+///
+/// This implementation uses `O(amount)` time and memory.
+///
+/// Panics if `amount > slice.len()`
+///
+/// Deprecated: use [`SliceRandom::choose_multiple`] instead.
+///
+/// [`SliceRandom::choose_multiple`]: trait.SliceRandom.html#method.choose_multiple
+#[cfg(feature = "alloc")]
+#[deprecated(since="0.6.0", note="use SliceRandom::choose_multiple instead")]
+pub fn sample_slice_ref<'a, R, T>(rng: &mut R, slice: &'a [T], amount: usize) -> Vec<&'a T>
+ where R: Rng + ?Sized
+{
+ let indices = index::sample(rng, slice.len(), amount).into_iter();
+
+ let mut out = Vec::with_capacity(amount);
+ out.extend(indices.map(|i| &slice[i]));
+ out
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+ #[cfg(feature = "alloc")] use {Rng, SeedableRng};
+ #[cfg(feature = "alloc")] use rngs::SmallRng;
+ #[cfg(all(feature="alloc", not(feature="std")))]
+ use alloc::vec::Vec;
+
+ #[test]
+ fn test_slice_choose() {
+ let mut r = ::test::rng(107);
+ let chars = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n'];
+ let mut chosen = [0i32; 14];
+ for _ in 0..1000 {
+ let picked = *chars.choose(&mut r).unwrap();
+ chosen[(picked as usize) - ('a' as usize)] += 1;
+ }
+ for count in chosen.iter() {
+ let err = *count - (1000 / (chars.len() as i32));
+ assert!(-20 <= err && err <= 20);
+ }
+
+ chosen.iter_mut().for_each(|x| *x = 0);
+ for _ in 0..1000 {
+ *chosen.choose_mut(&mut r).unwrap() += 1;
+ }
+ for count in chosen.iter() {
+ let err = *count - (1000 / (chosen.len() as i32));
+ assert!(-20 <= err && err <= 20);
+ }
+
+ let mut v: [isize; 0] = [];
+ assert_eq!(v.choose(&mut r), None);
+ assert_eq!(v.choose_mut(&mut r), None);
+ }
+
+ #[derive(Clone)]
+ struct UnhintedIterator<I: Iterator + Clone> {
+ iter: I,
+ }
+ impl<I: Iterator + Clone> Iterator for UnhintedIterator<I> {
+ type Item = I::Item;
+ fn next(&mut self) -> Option<Self::Item> {
+ self.iter.next()
+ }
+ }
+
+ #[derive(Clone)]
+ struct ChunkHintedIterator<I: ExactSizeIterator + Iterator + Clone> {
+ iter: I,
+ chunk_remaining: usize,
+ chunk_size: usize,
+ hint_total_size: bool,
+ }
+ impl<I: ExactSizeIterator + Iterator + Clone> Iterator for ChunkHintedIterator<I> {
+ type Item = I::Item;
+ fn next(&mut self) -> Option<Self::Item> {
+ if self.chunk_remaining == 0 {
+ self.chunk_remaining = ::core::cmp::min(self.chunk_size,
+ self.iter.len());
+ }
+ self.chunk_remaining = self.chunk_remaining.saturating_sub(1);
+
+ self.iter.next()
+ }
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (self.chunk_remaining,
+ if self.hint_total_size { Some(self.iter.len()) } else { None })
+ }
+ }
+
+ #[derive(Clone)]
+ struct WindowHintedIterator<I: ExactSizeIterator + Iterator + Clone> {
+ iter: I,
+ window_size: usize,
+ hint_total_size: bool,
+ }
+ impl<I: ExactSizeIterator + Iterator + Clone> Iterator for WindowHintedIterator<I> {
+ type Item = I::Item;
+ fn next(&mut self) -> Option<Self::Item> {
+ self.iter.next()
+ }
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (::core::cmp::min(self.iter.len(), self.window_size),
+ if self.hint_total_size { Some(self.iter.len()) } else { None })
+ }
+ }
+
+ #[test]
+ fn test_iterator_choose() {
+ let r = &mut ::test::rng(109);
+ fn test_iter<R: Rng + ?Sized, Iter: Iterator<Item=usize> + Clone>(r: &mut R, iter: Iter) {
+ let mut chosen = [0i32; 9];
+ for _ in 0..1000 {
+ let picked = iter.clone().choose(r).unwrap();
+ chosen[picked] += 1;
+ }
+ for count in chosen.iter() {
+ // Samples should follow Binomial(1000, 1/9)
+ // Octave: binopdf(x, 1000, 1/9) gives the prob of *count == x
+ // Note: have seen 153, which is unlikely but not impossible.
+ assert!(72 < *count && *count < 154, "count not close to 1000/9: {}", count);
+ }
+ }
+
+ test_iter(r, 0..9);
+ test_iter(r, [0, 1, 2, 3, 4, 5, 6, 7, 8].iter().cloned());
+ #[cfg(feature = "alloc")]
+ test_iter(r, (0..9).collect::<Vec<_>>().into_iter());
+ test_iter(r, UnhintedIterator { iter: 0..9 });
+ test_iter(r, ChunkHintedIterator { iter: 0..9, chunk_size: 4, chunk_remaining: 4, hint_total_size: false });
+ test_iter(r, ChunkHintedIterator { iter: 0..9, chunk_size: 4, chunk_remaining: 4, hint_total_size: true });
+ test_iter(r, WindowHintedIterator { iter: 0..9, window_size: 2, hint_total_size: false });
+ test_iter(r, WindowHintedIterator { iter: 0..9, window_size: 2, hint_total_size: true });
+
+ assert_eq!((0..0).choose(r), None);
+ assert_eq!(UnhintedIterator{ iter: 0..0 }.choose(r), None);
+ }
+
+ #[test]
+ fn test_shuffle() {
+ let mut r = ::test::rng(108);
+ let empty: &mut [isize] = &mut [];
+ empty.shuffle(&mut r);
+ let mut one = [1];
+ one.shuffle(&mut r);
+ let b: &[_] = &[1];
+ assert_eq!(one, b);
+
+ let mut two = [1, 2];
+ two.shuffle(&mut r);
+ assert!(two == [1, 2] || two == [2, 1]);
+
+ fn move_last(slice: &mut [usize], pos: usize) {
+ // use slice[pos..].rotate_left(1); once we can use that
+ let last_val = slice[pos];
+ for i in pos..slice.len() - 1 {
+ slice[i] = slice[i + 1];
+ }
+ *slice.last_mut().unwrap() = last_val;
+ }
+ let mut counts = [0i32; 24];
+ for _ in 0..10000 {
+ let mut arr: [usize; 4] = [0, 1, 2, 3];
+ arr.shuffle(&mut r);
+ let mut permutation = 0usize;
+ let mut pos_value = counts.len();
+ for i in 0..4 {
+ pos_value /= 4 - i;
+ let pos = arr.iter().position(|&x| x == i).unwrap();
+ assert!(pos < (4 - i));
+ permutation += pos * pos_value;
+ move_last(&mut arr, pos);
+ assert_eq!(arr[3], i);
+ }
+ for i in 0..4 {
+ assert_eq!(arr[i], i);
+ }
+ counts[permutation] += 1;
+ }
+ for count in counts.iter() {
+ let err = *count - 10000i32 / 24;
+ assert!(-50 <= err && err <= 50);
+ }
+ }
+
+ #[test]
+ fn test_partial_shuffle() {
+ let mut r = ::test::rng(118);
+
+ let mut empty: [u32; 0] = [];
+ let res = empty.partial_shuffle(&mut r, 10);
+ assert_eq!((res.0.len(), res.1.len()), (0, 0));
+
+ let mut v = [1, 2, 3, 4, 5];
+ let res = v.partial_shuffle(&mut r, 2);
+ assert_eq!((res.0.len(), res.1.len()), (2, 3));
+ assert!(res.0[0] != res.0[1]);
+ // First elements are only modified if selected, so at least one isn't modified:
+ assert!(res.1[0] == 1 || res.1[1] == 2 || res.1[2] == 3);
+ }
+
+ #[test]
+ #[cfg(feature = "alloc")]
+ fn test_sample_iter() {
+ let min_val = 1;
+ let max_val = 100;
+
+ let mut r = ::test::rng(401);
+ let vals = (min_val..max_val).collect::<Vec<i32>>();
+ let small_sample = vals.iter().choose_multiple(&mut r, 5);
+ let large_sample = vals.iter().choose_multiple(&mut r, vals.len() + 5);
+
+ assert_eq!(small_sample.len(), 5);
+ assert_eq!(large_sample.len(), vals.len());
+ // no randomization happens when amount >= len
+ assert_eq!(large_sample, vals.iter().collect::<Vec<_>>());
+
+ assert!(small_sample.iter().all(|e| {
+ **e >= min_val && **e <= max_val
+ }));
+ }
+
+ #[test]
+ #[cfg(feature = "alloc")]
+ #[allow(deprecated)]
+ fn test_sample_slice_boundaries() {
+ let empty: &[u8] = &[];
+
+ let mut r = ::test::rng(402);
+
+ // sample 0 items
+ assert_eq!(&sample_slice(&mut r, empty, 0)[..], [0u8; 0]);
+ assert_eq!(&sample_slice(&mut r, &[42, 2, 42], 0)[..], [0u8; 0]);
+
+ // sample 1 item
+ assert_eq!(&sample_slice(&mut r, &[42], 1)[..], [42]);
+ let v = sample_slice(&mut r, &[1, 42], 1)[0];
+ assert!(v == 1 || v == 42);
+
+ // sample "all" the items
+ let v = sample_slice(&mut r, &[42, 133], 2);
+ assert!(&v[..] == [42, 133] || v[..] == [133, 42]);
+
+ // Make sure lucky 777's aren't lucky
+ let slice = &[42, 777];
+ let mut num_42 = 0;
+ let total = 1000;
+ for _ in 0..total {
+ let v = sample_slice(&mut r, slice, 1);
+ assert_eq!(v.len(), 1);
+ let v = v[0];
+ assert!(v == 42 || v == 777);
+ if v == 42 {
+ num_42 += 1;
+ }
+ }
+ let ratio_42 = num_42 as f64 / 1000 as f64;
+ assert!(0.4 <= ratio_42 || ratio_42 <= 0.6, "{}", ratio_42);
+ }
+
+ #[test]
+ #[cfg(feature = "alloc")]
+ #[allow(deprecated)]
+ fn test_sample_slice() {
+ let seeded_rng = SmallRng::from_seed;
+
+ let mut r = ::test::rng(403);
+
+ for n in 1..20 {
+ let length = 5*n - 4; // 1, 6, ...
+ let amount = r.gen_range(0, length);
+ let mut seed = [0u8; 16];
+ r.fill(&mut seed);
+
+ // assert the basics work
+ let regular = index::sample(&mut seeded_rng(seed), length, amount);
+ assert_eq!(regular.len(), amount);
+ assert!(regular.iter().all(|e| e < length));
+
+ // also test that sampling the slice works
+ let vec: Vec<u32> = (0..(length as u32)).collect();
+ let result = sample_slice(&mut seeded_rng(seed), &vec, amount);
+ assert_eq!(result, regular.iter().map(|i| i as u32).collect::<Vec<_>>());
+
+ let result = sample_slice_ref(&mut seeded_rng(seed), &vec, amount);
+ assert!(result.iter().zip(regular.iter()).all(|(i,j)| **i == j as u32));
+ }
+ }
+
+ #[test]
+ #[cfg(feature = "alloc")]
+ fn test_weighted() {
+ let mut r = ::test::rng(406);
+ const N_REPS: u32 = 3000;
+ let weights = [1u32, 2, 3, 0, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7];
+ let total_weight = weights.iter().sum::<u32>() as f32;
+
+ let verify = |result: [i32; 14]| {
+ for (i, count) in result.iter().enumerate() {
+ let exp = (weights[i] * N_REPS) as f32 / total_weight;
+ let mut err = (*count as f32 - exp).abs();
+ if err != 0.0 {
+ err /= exp;
+ }
+ assert!(err <= 0.25);
+ }
+ };
+
+ // choose_weighted
+ fn get_weight<T>(item: &(u32, T)) -> u32 {
+ item.0
+ }
+ let mut chosen = [0i32; 14];
+ let mut items = [(0u32, 0usize); 14]; // (weight, index)
+ for (i, item) in items.iter_mut().enumerate() {
+ *item = (weights[i], i);
+ }
+ for _ in 0..N_REPS {
+ let item = items.choose_weighted(&mut r, get_weight).unwrap();
+ chosen[item.1] += 1;
+ }
+ verify(chosen);
+
+ // choose_weighted_mut
+ let mut items = [(0u32, 0i32); 14]; // (weight, count)
+ for (i, item) in items.iter_mut().enumerate() {
+ *item = (weights[i], 0);
+ }
+ for _ in 0..N_REPS {
+ items.choose_weighted_mut(&mut r, get_weight).unwrap().1 += 1;
+ }
+ for (ch, item) in chosen.iter_mut().zip(items.iter()) {
+ *ch = item.1;
+ }
+ verify(chosen);
+
+ // Check error cases
+ let empty_slice = &mut [10][0..0];
+ assert_eq!(empty_slice.choose_weighted(&mut r, |_| 1), Err(WeightedError::NoItem));
+ assert_eq!(empty_slice.choose_weighted_mut(&mut r, |_| 1), Err(WeightedError::NoItem));
+ assert_eq!(['x'].choose_weighted_mut(&mut r, |_| 0), Err(WeightedError::AllWeightsZero));
+ assert_eq!([0, -1].choose_weighted_mut(&mut r, |x| *x), Err(WeightedError::NegativeWeight));
+ assert_eq!([-1, 0].choose_weighted_mut(&mut r, |x| *x), Err(WeightedError::NegativeWeight));
+ }
+}
diff --git a/rand/tests/uniformity.rs b/rand/tests/uniformity.rs
new file mode 100644
index 0000000..b8f74a6
--- /dev/null
+++ b/rand/tests/uniformity.rs
@@ -0,0 +1,67 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![cfg(feature = "std")]
+
+#[macro_use]
+extern crate average;
+extern crate rand;
+
+use std as core;
+use rand::FromEntropy;
+use rand::distributions::Distribution;
+use average::Histogram;
+
+const N_BINS: usize = 100;
+const N_SAMPLES: u32 = 1_000_000;
+const TOL: f64 = 1e-3;
+define_histogram!(hist, 100);
+use hist::Histogram as Histogram100;
+
+#[test]
+fn unit_sphere() {
+ const N_DIM: usize = 3;
+ let h = Histogram100::with_const_width(-1., 1.);
+ let mut histograms = [h.clone(), h.clone(), h];
+ let dist = rand::distributions::UnitSphereSurface::new();
+ let mut rng = rand::rngs::SmallRng::from_entropy();
+ for _ in 0..N_SAMPLES {
+ let v = dist.sample(&mut rng);
+ for i in 0..N_DIM {
+ histograms[i].add(v[i]).map_err(
+ |e| { println!("v: {}", v[i]); e }
+ ).unwrap();
+ }
+ }
+ for h in &histograms {
+ let sum: u64 = h.bins().iter().sum();
+ println!("{:?}", h);
+ for &b in h.bins() {
+ let p = (b as f64) / (sum as f64);
+ assert!((p - 1.0 / (N_BINS as f64)).abs() < TOL, "{}", p);
+ }
+ }
+}
+
+#[test]
+fn unit_circle() {
+ use ::std::f64::consts::PI;
+ let mut h = Histogram100::with_const_width(-PI, PI);
+ let dist = rand::distributions::UnitCircle::new();
+ let mut rng = rand::rngs::SmallRng::from_entropy();
+ for _ in 0..N_SAMPLES {
+ let v = dist.sample(&mut rng);
+ h.add(v[0].atan2(v[1])).unwrap();
+ }
+ let sum: u64 = h.bins().iter().sum();
+ println!("{:?}", h);
+ for &b in h.bins() {
+ let p = (b as f64) / (sum as f64);
+ assert!((p - 1.0 / (N_BINS as f64)).abs() < TOL, "{}", p);
+ }
+}
diff --git a/rand/utils/ci/install.sh b/rand/utils/ci/install.sh
new file mode 100644
index 0000000..8e636e1
--- /dev/null
+++ b/rand/utils/ci/install.sh
@@ -0,0 +1,49 @@
+# From https://github.com/japaric/trust
+
+set -ex
+
+main() {
+ local target=
+ if [ $TRAVIS_OS_NAME = linux ]; then
+ target=x86_64-unknown-linux-musl
+ sort=sort
+ else
+ target=x86_64-apple-darwin
+ sort=gsort # for `sort --sort-version`, from brew's coreutils.
+ fi
+
+ # Builds for iOS are done on OSX, but require the specific target to be
+ # installed.
+ case $TARGET in
+ aarch64-apple-ios)
+ rustup target install aarch64-apple-ios
+ ;;
+ armv7-apple-ios)
+ rustup target install armv7-apple-ios
+ ;;
+ armv7s-apple-ios)
+ rustup target install armv7s-apple-ios
+ ;;
+ i386-apple-ios)
+ rustup target install i386-apple-ios
+ ;;
+ x86_64-apple-ios)
+ rustup target install x86_64-apple-ios
+ ;;
+ esac
+
+ # This fetches latest stable release
+ local tag=$(git ls-remote --tags --refs --exit-code https://github.com/japaric/cross \
+ | cut -d/ -f3 \
+ | grep -E '^v[0.1.0-9.]+$' \
+ | $sort --version-sort \
+ | tail -n1)
+ curl -LSfs https://japaric.github.io/trust/install.sh | \
+ sh -s -- \
+ --force \
+ --git japaric/cross \
+ --tag $tag \
+ --target $target
+}
+
+main
diff --git a/rand/utils/ci/script.sh b/rand/utils/ci/script.sh
new file mode 100644
index 0000000..33786f6
--- /dev/null
+++ b/rand/utils/ci/script.sh
@@ -0,0 +1,22 @@
+# Derived from https://github.com/japaric/trust
+
+set -ex
+
+main() {
+ cross test --target $TARGET --lib --no-default-features
+ # TODO: add simd_support feature:
+ cross test --target $TARGET --features=serde1,log
+ cross test --target $TARGET --examples
+ cross test --target $TARGET --manifest-path rand_core/Cargo.toml
+ cross test --target $TARGET --manifest-path rand_core/Cargo.toml --no-default-features
+ cross test --target $TARGET --manifest-path rand_isaac/Cargo.toml --features=serde1
+ cross test --target $TARGET --manifest-path rand_pcg/Cargo.toml --features=serde1
+ cross test --target $TARGET --manifest-path rand_xorshift/Cargo.toml --features=serde1
+ cross test --target $TARGET --manifest-path rand_chacha/Cargo.toml
+ cross test --target $TARGET --manifest-path rand_hc/Cargo.toml
+}
+
+# we don't run the "test phase" when doing deploys
+if [ -z $TRAVIS_TAG ]; then
+ main
+fi
diff --git a/rand/utils/ziggurat_tables.py b/rand/utils/ziggurat_tables.py
index 762f956..88cfdab 100755
--- a/rand/utils/ziggurat_tables.py
+++ b/rand/utils/ziggurat_tables.py
@@ -1,12 +1,11 @@
#!/usr/bin/env python
#
-# Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-# file at the top-level directory of this distribution and at
-# http://rust-lang.org/COPYRIGHT.
+# Copyright 2018 Developers of the Rand project.
+# Copyright 2013 The Rust Project Developers.
#
# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+# https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
# option. This file may not be copied, modified, or distributed
# except according to those terms.
@@ -105,13 +104,12 @@ def render_table(name, values):
with open('ziggurat_tables.rs', 'w') as f:
- f.write('''// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
+ f.write('''// Copyright 2018 Developers of the Rand project.
+// Copyright 2013 The Rust Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
diff --git a/rustc_version/.gitignore b/rustc_version/.gitignore
new file mode 100644
index 0000000..a9d37c5
--- /dev/null
+++ b/rustc_version/.gitignore
@@ -0,0 +1,2 @@
+target
+Cargo.lock
diff --git a/rustc_version/.travis.yml b/rustc_version/.travis.yml
new file mode 100644
index 0000000..ccb8411
--- /dev/null
+++ b/rustc_version/.travis.yml
@@ -0,0 +1,21 @@
+language: rust
+rust:
+- nightly
+- beta
+- stable
+before_script:
+- |
+ pip install 'travis-cargo<0.2' --user &&
+ export PATH=$HOME/.local/bin:$PATH
+script:
+- |
+ travis-cargo build &&
+ travis-cargo test &&
+ travis-cargo bench &&
+ travis-cargo --only stable doc
+after_success:
+- travis-cargo --only stable doc-upload
+env:
+ global:
+ - TRAVIS_CARGO_NIGHTLY_FEATURE=""
+ - secure: mxQyrd6tyvcC10H7crLgKSSRHwquSnLb5mjzaj8iXf4mkooKpoRaffIiwmGf0IACQUN3nKlA6D6irfD2CqaFiUiUav8RqeAd8FjHFTlYu0nKZkqB1iGZBA7/JrW7mlGJIdmNIbzVRoPRQI/lY/730M/eqxIAb+9/xaSktkD2cJYGUikdiyeTm8idezkB+BOOWIN20yopLWzmBIVs7doQJOA0ewqMlEduwn6axvEk17r9qlSgucywDsTvDWkXSAuYldyJU4PdFez4t10sGsXx+TKfbwcaRmwaOj/MImZUVCtQvutEW9Hb/2hJXjCN2uefZ64BfodKn3wyB7ie7PgOixsLkqoR01d/qbfDsWGg/4iLi3DCq5bVtWJoCCT4lS8kfwi8D8HmvcoCQnT+CdU4LhlV9aHTSEMx0SEJW0DHYE/RnoqJjCj+QsK4ji7HAnyYWVwSGYJfnrL0EAwKararAzKY/vABStJKu1IlBzKCsjIQ+0hMpqnFiWldhfRHt/rYhBtK+HYXElamc8xpF/taK8E40NSHDgC+4TciTAZtyAXOWiMhXS0653U3hvJqYY/LtHmobpIqc1XkHe53gQ0QrBd6UsyUN9FjWOLxvPUx4zcyNFJHXcFiwevfK6gYF+OXepVu8TznAQLSP7ToA7KXbhSSVQDM+7UFVcT41VgDbGY=
diff --git a/rustc_version/Cargo.toml b/rustc_version/Cargo.toml
new file mode 100644
index 0000000..422a881
--- /dev/null
+++ b/rustc_version/Cargo.toml
@@ -0,0 +1,18 @@
+[package]
+name = "rustc_version"
+version = "0.2.3"
+authors = ["Marvin Löbel <loebel.marvin@gmail.com>"]
+license = "MIT/Apache-2.0"
+
+description = "A library for querying the version of a installed rustc compiler"
+readme = "README.md"
+documentation = "https://docs.rs/rustc_version/"
+
+repository = "https://github.com/Kimundi/rustc-version-rs"
+keywords = ["version", "rustc"]
+
+[badges]
+travis-ci = { repository = "Kimundi/rustc-version-rs" }
+
+[dependencies]
+semver = "0.9"
diff --git a/rustc_version/LICENSE-APACHE b/rustc_version/LICENSE-APACHE
new file mode 100644
index 0000000..16fe87b
--- /dev/null
+++ b/rustc_version/LICENSE-APACHE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/rustc_version/LICENSE-MIT b/rustc_version/LICENSE-MIT
new file mode 100644
index 0000000..40b8817
--- /dev/null
+++ b/rustc_version/LICENSE-MIT
@@ -0,0 +1,25 @@
+Copyright (c) 2016 The Rust Project Developers
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/rustc_version/README.md b/rustc_version/README.md
new file mode 100644
index 0000000..f491ca9
--- /dev/null
+++ b/rustc_version/README.md
@@ -0,0 +1,75 @@
+rustc-version-rs
+==============
+
+A library for querying the version of a `rustc` compiler.
+
+This can be used by build scripts or other tools dealing with Rust sources
+to make decisions based on the version of the compiler.
+
+[![Travis-CI Status](https://travis-ci.org/Kimundi/rustc-version-rs.png?branch=master)](https://travis-ci.org/Kimundi/rustc-version-rs)
+
+# Getting Started
+
+[rustc-version-rs is available on crates.io](https://crates.io/crates/rustc_version).
+It is recommended to look there for the newest released version, as well as links to the newest builds of the docs.
+
+At the point of the last update of this README, the latest published version could be used like this:
+
+Add the following dependency to your Cargo manifest...
+
+```toml
+[build-dependencies]
+rustc_version = "0.2"
+```
+
+...and see the [docs](http://kimundi.github.io/rustc-version-rs/rustc_version/index.html) for how to use it.
+
+# Example
+
+```rust
+// This could be a cargo build script
+
+extern crate rustc_version;
+use rustc_version::{version, version_meta, Channel, Version};
+
+fn main() {
+ // Assert we haven't travelled back in time
+ assert!(version().unwrap().major >= 1);
+
+ // Set cfg flags depending on release channel
+ match version_meta().unwrap().channel {
+ Channel::Stable => {
+ println!("cargo:rustc-cfg=RUSTC_IS_STABLE");
+ }
+ Channel::Beta => {
+ println!("cargo:rustc-cfg=RUSTC_IS_BETA");
+ }
+ Channel::Nightly => {
+ println!("cargo:rustc-cfg=RUSTC_IS_NIGHTLY");
+ }
+ Channel::Dev => {
+ println!("cargo:rustc-cfg=RUSTC_IS_DEV");
+ }
+ }
+
+ // Check for a minimum version
+ if version().unwrap() >= Version::parse("1.4.0").unwrap() {
+ println!("cargo:rustc-cfg=compiler_has_important_bugfix");
+ }
+}
+```
+
+## License
+
+Licensed under either of
+
+ * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
+ * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
+
+at your option.
+
+### Contribution
+
+Unless you explicitly state otherwise, any contribution intentionally submitted
+for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any
+additional terms or conditions.
diff --git a/rustc_version/src/errors.rs b/rustc_version/src/errors.rs
new file mode 100644
index 0000000..54557b6
--- /dev/null
+++ b/rustc_version/src/errors.rs
@@ -0,0 +1,79 @@
+use std::{self, error, fmt, io, str};
+use semver::{self, Identifier};
+
+/// The error type for this crate.
+#[derive(Debug)]
+pub enum Error {
+ /// An error ocurrend when executing the `rustc` command.
+ CouldNotExecuteCommand(io::Error),
+ /// The output of `rustc -vV` was not valid utf-8.
+ Utf8Error(str::Utf8Error),
+ /// The output of `rustc -vV` was not in the expected format.
+ UnexpectedVersionFormat,
+ /// An error ocurred in parsing a `VersionReq`.
+ ReqParseError(semver::ReqParseError),
+ /// An error ocurred in parsing the semver.
+ SemVerError(semver::SemVerError),
+ /// The pre-release tag is unknown.
+ UnknownPreReleaseTag(Identifier),
+}
+use Error::*;
+
+impl fmt::Display for Error {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ use std::error::Error;
+ match *self {
+ CouldNotExecuteCommand(ref e) => write!(f, "{}: {}", self.description(), e),
+ Utf8Error(_) => write!(f, "{}", self.description()),
+ UnexpectedVersionFormat => write!(f, "{}", self.description()),
+ ReqParseError(ref e) => write!(f, "{}: {}", self.description(), e),
+ SemVerError(ref e) => write!(f, "{}: {}", self.description(), e),
+ UnknownPreReleaseTag(ref i) => write!(f, "{}: {}", self.description(), i),
+ }
+ }
+}
+
+impl error::Error for Error {
+ fn cause(&self) -> Option<&error::Error> {
+ match *self {
+ CouldNotExecuteCommand(ref e) => Some(e),
+ Utf8Error(ref e) => Some(e),
+ UnexpectedVersionFormat => None,
+ ReqParseError(ref e) => Some(e),
+ SemVerError(ref e) => Some(e),
+ UnknownPreReleaseTag(_) => None,
+ }
+ }
+
+ fn description(&self) -> &str {
+ match *self {
+ CouldNotExecuteCommand(_) => "could not execute command",
+ Utf8Error(_) => "invalid UTF-8 output from `rustc -vV`",
+ UnexpectedVersionFormat => "unexpected `rustc -vV` format",
+ ReqParseError(_) => "error parsing version requirement",
+ SemVerError(_) => "error parsing version",
+ UnknownPreReleaseTag(_) => "unknown pre-release tag",
+ }
+ }
+}
+
+macro_rules! impl_from {
+ ($($err_ty:ty => $variant:ident),* $(,)*) => {
+ $(
+ impl From<$err_ty> for Error {
+ fn from(e: $err_ty) -> Error {
+ Error::$variant(e)
+ }
+ }
+ )*
+ }
+}
+
+impl_from! {
+ str::Utf8Error => Utf8Error,
+ semver::SemVerError => SemVerError,
+ semver::ReqParseError => ReqParseError,
+}
+
+/// The result type for this crate.
+pub type Result<T> = std::result::Result<T, Error>;
diff --git a/rustc_version/src/lib.rs b/rustc_version/src/lib.rs
new file mode 100644
index 0000000..c038288
--- /dev/null
+++ b/rustc_version/src/lib.rs
@@ -0,0 +1,347 @@
+// Copyright 2016 rustc-version-rs developers
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![warn(missing_docs)]
+
+//! Simple library for getting the version information of a `rustc`
+//! compiler.
+//!
+//! This can be used by build scripts or other tools dealing with Rust sources
+//! to make decisions based on the version of the compiler.
+//!
+//! It calls `$RUSTC --version -v` and parses the output, falling
+//! back to `rustc` if `$RUSTC` is not set.
+//!
+//! # Example
+//!
+//! ```rust
+//! // This could be a cargo build script
+//!
+//! extern crate rustc_version;
+//! use rustc_version::{version, version_meta, Channel, Version};
+//!
+//! fn main() {
+//! // Assert we haven't travelled back in time
+//! assert!(version().unwrap().major >= 1);
+//!
+//! // Set cfg flags depending on release channel
+//! match version_meta().unwrap().channel {
+//! Channel::Stable => {
+//! println!("cargo:rustc-cfg=RUSTC_IS_STABLE");
+//! }
+//! Channel::Beta => {
+//! println!("cargo:rustc-cfg=RUSTC_IS_BETA");
+//! }
+//! Channel::Nightly => {
+//! println!("cargo:rustc-cfg=RUSTC_IS_NIGHTLY");
+//! }
+//! Channel::Dev => {
+//! println!("cargo:rustc-cfg=RUSTC_IS_DEV");
+//! }
+//! }
+//!
+//! // Check for a minimum version
+//! if version().unwrap() >= Version::parse("1.4.0").unwrap() {
+//! println!("cargo:rustc-cfg=compiler_has_important_bugfix");
+//! }
+//! }
+//! ```
+
+extern crate semver;
+use semver::Identifier;
+use std::process::Command;
+use std::{env, str};
+use std::ffi::OsString;
+
+// Convenience re-export to allow version comparison without needing to add
+// semver crate.
+pub use semver::Version;
+
+mod errors;
+pub use errors::{Error, Result};
+
+/// Release channel of the compiler.
+#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
+pub enum Channel {
+ /// Development release channel
+ Dev,
+ /// Nightly release channel
+ Nightly,
+ /// Beta release channel
+ Beta,
+ /// Stable release channel
+ Stable,
+}
+
+/// Rustc version plus metada like git short hash and build date.
+#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
+pub struct VersionMeta {
+ /// Version of the compiler
+ pub semver: Version,
+
+ /// Git short hash of the build of the compiler
+ pub commit_hash: Option<String>,
+
+ /// Commit date of the compiler
+ pub commit_date: Option<String>,
+
+ /// Build date of the compiler; this was removed between Rust 1.0.0 and 1.1.0.
+ pub build_date: Option<String>,
+
+ /// Release channel of the compiler
+ pub channel: Channel,
+
+ /// Host target triple of the compiler
+ pub host: String,
+
+ /// Short version string of the compiler
+ pub short_version_string: String,
+}
+
+impl VersionMeta {
+ /// Returns the version metadata for `cmd`, which should be a `rustc` command.
+ pub fn for_command(cmd: Command) -> Result<VersionMeta> {
+ let mut cmd = cmd;
+
+ let out = cmd.arg("-vV").output().map_err(Error::CouldNotExecuteCommand)?;
+ let out = str::from_utf8(&out.stdout)?;
+
+ version_meta_for(out)
+ }
+}
+
+/// Returns the `rustc` SemVer version.
+pub fn version() -> Result<Version> {
+ Ok(version_meta()?.semver)
+}
+
+/// Returns the `rustc` SemVer version and additional metadata
+/// like the git short hash and build date.
+pub fn version_meta() -> Result<VersionMeta> {
+ let cmd = env::var_os("RUSTC").unwrap_or_else(|| OsString::from("rustc"));
+
+ VersionMeta::for_command(Command::new(cmd))
+}
+
+/// Parses a "rustc -vV" output string and returns
+/// the SemVer version and additional metadata
+/// like the git short hash and build date.
+pub fn version_meta_for(verbose_version_string: &str) -> Result<VersionMeta> {
+ let out: Vec<_> = verbose_version_string.lines().collect();
+
+ if !(out.len() >= 6 && out.len() <= 8) {
+ return Err(Error::UnexpectedVersionFormat);
+ }
+
+ let short_version_string = out[0];
+
+ fn expect_prefix<'a>(line: &'a str, prefix: &str) -> Result<&'a str> {
+ if line.starts_with(prefix) {
+ Ok(&line[prefix.len()..])
+ } else {
+ Err(Error::UnexpectedVersionFormat)
+ }
+ }
+
+ let commit_hash = match expect_prefix(out[2], "commit-hash: ")? {
+ "unknown" => None,
+ hash => Some(hash.to_owned()),
+ };
+
+ let commit_date = match expect_prefix(out[3], "commit-date: ")? {
+ "unknown" => None,
+ hash => Some(hash.to_owned()),
+ };
+
+ // Handle that the build date may or may not be present.
+ let mut idx = 4;
+ let mut build_date = None;
+ if out[idx].starts_with("build-date") {
+ build_date = match expect_prefix(out[idx], "build-date: ")? {
+ "unknown" => None,
+ s => Some(s.to_owned()),
+ };
+ idx += 1;
+ }
+
+ let host = expect_prefix(out[idx], "host: ")?;
+ idx += 1;
+ let release = expect_prefix(out[idx], "release: ")?;
+
+ let semver: Version = release.parse()?;
+
+ let channel = if semver.pre.is_empty() {
+ Channel::Stable
+ } else {
+ match semver.pre[0] {
+ Identifier::AlphaNumeric(ref s) if s == "dev" => Channel::Dev,
+ Identifier::AlphaNumeric(ref s) if s == "beta" => Channel::Beta,
+ Identifier::AlphaNumeric(ref s) if s == "nightly" => Channel::Nightly,
+ ref x => return Err(Error::UnknownPreReleaseTag(x.clone())),
+ }
+ };
+
+ Ok(VersionMeta {
+ semver: semver,
+ commit_hash: commit_hash,
+ commit_date: commit_date,
+ build_date: build_date,
+ channel: channel,
+ host: host.into(),
+ short_version_string: short_version_string.into(),
+ })
+}
+
+#[test]
+fn smoketest() {
+ let v = version().unwrap();
+ assert!(v.major >= 1);
+
+ let v = version_meta().unwrap();
+ assert!(v.semver.major >= 1);
+
+ assert!(version().unwrap() >= Version::parse("1.0.0").unwrap());
+}
+
+#[test]
+fn parse_unexpected() {
+ let res = version_meta_for(
+"rustc 1.0.0 (a59de37e9 2015-05-13) (built 2015-05-14)
+binary: rustc
+commit-hash: a59de37e99060162a2674e3ff45409ac73595c0e
+commit-date: 2015-05-13
+rust-birthday: 2015-05-14
+host: x86_64-unknown-linux-gnu
+release: 1.0.0");
+
+ assert!(match res {
+ Err(Error::UnexpectedVersionFormat) => true,
+ _ => false,
+ });
+
+}
+
+#[test]
+fn parse_1_0_0() {
+ let version = version_meta_for(
+"rustc 1.0.0 (a59de37e9 2015-05-13) (built 2015-05-14)
+binary: rustc
+commit-hash: a59de37e99060162a2674e3ff45409ac73595c0e
+commit-date: 2015-05-13
+build-date: 2015-05-14
+host: x86_64-unknown-linux-gnu
+release: 1.0.0").unwrap();
+
+ assert_eq!(version.semver, Version::parse("1.0.0").unwrap());
+ assert_eq!(version.commit_hash, Some("a59de37e99060162a2674e3ff45409ac73595c0e".into()));
+ assert_eq!(version.commit_date, Some("2015-05-13".into()));
+ assert_eq!(version.build_date, Some("2015-05-14".into()));
+ assert_eq!(version.channel, Channel::Stable);
+ assert_eq!(version.host, "x86_64-unknown-linux-gnu");
+ assert_eq!(version.short_version_string, "rustc 1.0.0 (a59de37e9 2015-05-13) (built 2015-05-14)");
+}
+
+
+#[test]
+fn parse_unknown() {
+ let version = version_meta_for(
+"rustc 1.3.0
+binary: rustc
+commit-hash: unknown
+commit-date: unknown
+host: x86_64-unknown-linux-gnu
+release: 1.3.0").unwrap();
+
+ assert_eq!(version.semver, Version::parse("1.3.0").unwrap());
+ assert_eq!(version.commit_hash, None);
+ assert_eq!(version.commit_date, None);
+ assert_eq!(version.channel, Channel::Stable);
+ assert_eq!(version.host, "x86_64-unknown-linux-gnu");
+ assert_eq!(version.short_version_string, "rustc 1.3.0");
+}
+
+#[test]
+fn parse_nightly() {
+ let version = version_meta_for(
+"rustc 1.5.0-nightly (65d5c0833 2015-09-29)
+binary: rustc
+commit-hash: 65d5c083377645a115c4ac23a620d3581b9562b6
+commit-date: 2015-09-29
+host: x86_64-unknown-linux-gnu
+release: 1.5.0-nightly").unwrap();
+
+ assert_eq!(version.semver, Version::parse("1.5.0-nightly").unwrap());
+ assert_eq!(version.commit_hash, Some("65d5c083377645a115c4ac23a620d3581b9562b6".into()));
+ assert_eq!(version.commit_date, Some("2015-09-29".into()));
+ assert_eq!(version.channel, Channel::Nightly);
+ assert_eq!(version.host, "x86_64-unknown-linux-gnu");
+ assert_eq!(version.short_version_string, "rustc 1.5.0-nightly (65d5c0833 2015-09-29)");
+}
+
+#[test]
+fn parse_stable() {
+ let version = version_meta_for(
+"rustc 1.3.0 (9a92aaf19 2015-09-15)
+binary: rustc
+commit-hash: 9a92aaf19a64603b02b4130fe52958cc12488900
+commit-date: 2015-09-15
+host: x86_64-unknown-linux-gnu
+release: 1.3.0").unwrap();
+
+ assert_eq!(version.semver, Version::parse("1.3.0").unwrap());
+ assert_eq!(version.commit_hash, Some("9a92aaf19a64603b02b4130fe52958cc12488900".into()));
+ assert_eq!(version.commit_date, Some("2015-09-15".into()));
+ assert_eq!(version.channel, Channel::Stable);
+ assert_eq!(version.host, "x86_64-unknown-linux-gnu");
+ assert_eq!(version.short_version_string, "rustc 1.3.0 (9a92aaf19 2015-09-15)");
+}
+
+#[test]
+fn parse_1_16_0_nightly() {
+ let version = version_meta_for(
+"rustc 1.16.0-nightly (5d994d8b7 2017-01-05)
+binary: rustc
+commit-hash: 5d994d8b7e482e87467d4a521911477bd8284ce3
+commit-date: 2017-01-05
+host: x86_64-unknown-linux-gnu
+release: 1.16.0-nightly
+LLVM version: 3.9").unwrap();
+
+ assert_eq!(version.semver, Version::parse("1.16.0-nightly").unwrap());
+ assert_eq!(version.commit_hash, Some("5d994d8b7e482e87467d4a521911477bd8284ce3".into()));
+ assert_eq!(version.commit_date, Some("2017-01-05".into()));
+ assert_eq!(version.channel, Channel::Nightly);
+ assert_eq!(version.host, "x86_64-unknown-linux-gnu");
+ assert_eq!(version.short_version_string, "rustc 1.16.0-nightly (5d994d8b7 2017-01-05)");
+}
+
+/*
+#[test]
+fn version_matches_replacement() {
+ let f = |s1: &str, s2: &str| {
+ let a = Version::parse(s1).unwrap();
+ let b = Version::parse(s2).unwrap();
+ println!("{} <= {} : {}", s1, s2, a <= b);
+ };
+
+ println!();
+
+ f("1.5.0", "1.5.0");
+ f("1.5.0-nightly", "1.5.0");
+ f("1.5.0", "1.5.0-nightly");
+ f("1.5.0-nightly", "1.5.0-nightly");
+
+ f("1.5.0", "1.6.0");
+ f("1.5.0-nightly", "1.6.0");
+ f("1.5.0", "1.6.0-nightly");
+ f("1.5.0-nightly", "1.6.0-nightly");
+
+ panic!();
+
+}
+*/
diff --git a/semver-parser/.gitignore b/semver-parser/.gitignore
new file mode 100644
index 0000000..a9d37c5
--- /dev/null
+++ b/semver-parser/.gitignore
@@ -0,0 +1,2 @@
+target
+Cargo.lock
diff --git a/semver-parser/Cargo.toml b/semver-parser/Cargo.toml
new file mode 100644
index 0000000..c2be878
--- /dev/null
+++ b/semver-parser/Cargo.toml
@@ -0,0 +1,11 @@
+[package]
+name = "semver-parser"
+version = "0.7.0"
+authors = ["Steve Klabnik <steve@steveklabnik.com>"]
+license = "MIT/Apache-2.0"
+repository = "https://github.com/steveklabnik/semver-parser"
+homepage = "https://github.com/steveklabnik/semver-parser"
+documentation = "https://docs.rs/semver-parser"
+description = """
+Parsing of the semver spec.
+"""
diff --git a/semver-parser/LICENSE-APACHE b/semver-parser/LICENSE-APACHE
new file mode 100644
index 0000000..16fe87b
--- /dev/null
+++ b/semver-parser/LICENSE-APACHE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/semver-parser/LICENSE-MIT b/semver-parser/LICENSE-MIT
new file mode 100644
index 0000000..fb7494a
--- /dev/null
+++ b/semver-parser/LICENSE-MIT
@@ -0,0 +1,25 @@
+Copyright (c) 2016 Steve Klabnik
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/semver-parser/src/common.rs b/semver-parser/src/common.rs
new file mode 100644
index 0000000..267b4d9
--- /dev/null
+++ b/semver-parser/src/common.rs
@@ -0,0 +1,66 @@
+use version::Identifier;
+use recognize::{Recognize, Alt, OneOrMore, Inclusive, OneByte};
+use std::str::from_utf8;
+
+// by the time we get here, we know that it's all valid characters, so this doesn't need to return
+// a result or anything
+fn parse_meta(s: &str) -> Vec<Identifier> {
+ // Originally, I wanted to implement this method via calling parse, but parse is tolerant of
+ // leading zeroes, and we want anything with leading zeroes to be considered alphanumeric, not
+ // numeric. So the strategy is to check with a recognizer first, and then call parse once
+ // we've determined that it's a number without a leading zero.
+ s.split(".")
+ .map(|part| {
+ // another wrinkle: we made sure that any number starts with a
+ // non-zero. But there's a problem: an actual zero is a number, yet
+ // gets left out by this heuristic. So let's also check for the
+ // single, lone zero.
+ if is_alpha_numeric(part) {
+ Identifier::AlphaNumeric(part.to_string())
+ } else {
+ // we can unwrap here because we know it is only digits due to the regex
+ Identifier::Numeric(part.parse().unwrap())
+ }
+ }).collect()
+}
+
+// parse optional metadata (preceded by the prefix character)
+pub fn parse_optional_meta(s: &[u8], prefix_char: u8)-> Result<(Vec<Identifier>, usize), String> {
+ if let Some(len) = prefix_char.p(s) {
+ let start = len;
+ if let Some(len) = letters_numbers_dash_dot(&s[start..]) {
+ let end = start + len;
+ Ok((parse_meta(from_utf8(&s[start..end]).unwrap()), end))
+ } else {
+ Err("Error parsing prerelease".to_string())
+ }
+ } else {
+ Ok((Vec::new(), 0))
+ }
+}
+
+pub fn is_alpha_numeric(s: &str) -> bool {
+ if let Some((_val, len)) = numeric_identifier(s.as_bytes()) {
+ // Return true for number with leading zero
+ // Note: doing it this way also handily makes overflow fail over.
+ len != s.len()
+ } else {
+ true
+ }
+}
+
+// Note: could plumb overflow error up to return value as Result
+pub fn numeric_identifier(s: &[u8]) -> Option<(u64, usize)> {
+ if let Some(len) = Alt(b'0', OneOrMore(Inclusive(b'0'..b'9'))).p(s) {
+ from_utf8(&s[0..len]).unwrap().parse().ok().map(|val| (val, len))
+ } else {
+ None
+ }
+}
+
+pub fn letters_numbers_dash_dot(s: &[u8]) -> Option<usize> {
+ OneOrMore(OneByte(|c| c == b'-' || c == b'.' ||
+ (b'0' <= c && c <= b'9') ||
+ (b'a' <= c && c <= b'z') ||
+ (b'A' <= c && c <= b'Z'))).p(s)
+}
diff --git a/semver-parser/src/lib.rs b/semver-parser/src/lib.rs
new file mode 100644
index 0000000..3b0d8f0
--- /dev/null
+++ b/semver-parser/src/lib.rs
@@ -0,0 +1,8 @@
+pub mod version;
+pub mod range;
+
+// for private stuff the two share
+mod common;
+
+// for recognizer combinators
+mod recognize;
diff --git a/semver-parser/src/range.rs b/semver-parser/src/range.rs
new file mode 100644
index 0000000..858be9f
--- /dev/null
+++ b/semver-parser/src/range.rs
@@ -0,0 +1,696 @@
+use common::{self, numeric_identifier, letters_numbers_dash_dot};
+use version::Identifier;
+use std::str::{FromStr, from_utf8};
+use recognize::*;
+
+#[derive(Debug)]
+pub struct VersionReq {
+ pub predicates: Vec<Predicate>,
+}
+
+#[derive(PartialEq,Debug)]
+pub enum WildcardVersion {
+ Major,
+ Minor,
+ Patch,
+}
+
+#[derive(PartialEq,Debug)]
+pub enum Op {
+ Ex, // Exact
+ Gt, // Greater than
+ GtEq, // Greater than or equal to
+ Lt, // Less than
+ LtEq, // Less than or equal to
+ Tilde, // e.g. ~1.0.0
+ Compatible, // compatible by definition of semver, indicated by ^
+ Wildcard(WildcardVersion), // x.y.*, x.*, *
+}
+
+impl FromStr for Op {
+ type Err = String;
+
+ fn from_str(s: &str) -> Result<Op, String> {
+ match s {
+ "=" => Ok(Op::Ex),
+ ">" => Ok(Op::Gt),
+ ">=" => Ok(Op::GtEq),
+ "<" => Ok(Op::Lt),
+ "<=" => Ok(Op::LtEq),
+ "~" => Ok(Op::Tilde),
+ "^" => Ok(Op::Compatible),
+ _ => Err(String::from("Could not parse Op")),
+ }
+ }
+}
+
+#[derive(PartialEq,Debug)]
+pub struct Predicate {
+ pub op: Op,
+ pub major: u64,
+ pub minor: Option<u64>,
+ pub patch: Option<u64>,
+ pub pre: Vec<Identifier>,
+}
+
+fn numeric_or_wild(s: &[u8]) -> Option<(Option<u64>, usize)> {
+ if let Some((val, len)) = numeric_identifier(s) {
+ Some((Some(val), len))
+ } else if let Some(len) = OneOf(b"*xX").p(s) {
+ Some((None, len))
+ } else {
+ None
+ }
+}
+
+fn dot_numeric_or_wild(s: &[u8]) -> Option<(Option<u64>, usize)> {
+ b'.'.p(s).and_then(|len|
+ numeric_or_wild(&s[len..]).map(|(val, len2)| (val, len + len2))
+ )
+}
+
+fn operation(s: &[u8]) -> Option<(Op, usize)> {
+ if let Some(len) = "=".p(s) {
+ Some((Op::Ex, len))
+ } else if let Some(len) = ">=".p(s) {
+ Some((Op::GtEq, len))
+ } else if let Some(len) = ">".p(s) {
+ Some((Op::Gt, len))
+ } else if let Some(len) = "<=".p(s) {
+ Some((Op::LtEq, len))
+ } else if let Some(len) = "<".p(s) {
+ Some((Op::Lt, len))
+ } else if let Some(len) = "~".p(s) {
+ Some((Op::Tilde, len))
+ } else if let Some(len) = "^".p(s) {
+ Some((Op::Compatible, len))
+ } else {
+ None
+ }
+}
+
+fn whitespace(s: &[u8]) -> Option<usize> {
+ ZeroOrMore(OneOf(b"\t\r\n ")).p(s)
+}
+
+pub fn parse_predicate(range: &str) -> Result<Predicate, String> {
+ let s = range.trim().as_bytes();
+ let mut i = 0;
+ let mut operation = if let Some((op, len)) = operation(&s[i..]) {
+ i += len;
+ op
+ } else {
+ // operations default to Compatible
+ Op::Compatible
+ };
+ if let Some(len) = whitespace.p(&s[i..]) {
+ i += len;
+ }
+ let major = if let Some((major, len)) = numeric_identifier(&s[i..]) {
+ i += len;
+ major
+ } else {
+ return Err("Error parsing major version number: ".to_string());
+ };
+ let minor = if let Some((minor, len)) = dot_numeric_or_wild(&s[i..]) {
+ i += len;
+ if minor.is_none() {
+ operation = Op::Wildcard(WildcardVersion::Minor);
+ }
+ minor
+ } else {
+ None
+ };
+ let patch = if let Some((patch, len)) = dot_numeric_or_wild(&s[i..]) {
+ i += len;
+ if patch.is_none() {
+ operation = Op::Wildcard(WildcardVersion::Patch);
+ }
+ patch
+ } else {
+ None
+ };
+ let (pre, pre_len) = common::parse_optional_meta(&s[i..], b'-')?;
+ i += pre_len;
+ if let Some(len) = (b'+', letters_numbers_dash_dot).p(&s[i..]) {
+ i += len;
+ }
+ if i != s.len() {
+ return Err("Extra junk after valid predicate: ".to_string() +
+ from_utf8(&s[i..]).unwrap());
+ }
+ Ok(Predicate {
+ op: operation,
+ major: major,
+ minor: minor,
+ patch: patch,
+ pre: pre,
+ })
+}
+
+pub fn parse(ranges: &str) -> Result<VersionReq, String> {
+ // null is an error
+ if ranges == "\0" {
+ return Err(String::from("Null is not a valid VersionReq"));
+ }
+
+ // an empty range is a major version wildcard
+ // so is a lone * or x of either capitalization
+ if (ranges == "")
+ || (ranges == "*")
+ || (ranges == "x")
+ || (ranges == "X") {
+ return Ok(VersionReq {
+ predicates: vec![Predicate {
+ op: Op::Wildcard(WildcardVersion::Major),
+ major: 0,
+ minor: None,
+ patch: None,
+ pre: Vec::new(),
+ }],
+ });
+ }
+
+
+ let ranges = ranges.trim();
+
+ let predicates: Result<Vec<_>, String> = ranges
+ .split(",")
+ .map(|range| {
+ parse_predicate(range)
+ })
+ .collect();
+
+ let predicates = try!(predicates);
+
+ if predicates.len() == 0 {
+ return Err(String::from("VersionReq did not parse properly"));
+ }
+
+ Ok(VersionReq {
+ predicates: predicates,
+ })
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use range;
+ use version::Identifier;
+
+ #[test]
+ fn test_parsing_default() {
+ let r = range::parse("1.0.0").unwrap();
+
+ assert_eq!(Predicate {
+ op: Op::Compatible,
+ major: 1,
+ minor: Some(0),
+ patch: Some(0),
+ pre: Vec::new(),
+ },
+ r.predicates[0]
+ );
+ }
+
+ #[test]
+ fn test_parsing_exact_01() {
+ let r = range::parse("=1.0.0").unwrap();
+
+ assert_eq!(Predicate {
+ op: Op::Ex,
+ major: 1,
+ minor: Some(0),
+ patch: Some(0),
+ pre: Vec::new(),
+ },
+ r.predicates[0]
+ );
+ }
+
+ #[test]
+ fn test_parsing_exact_02() {
+ let r = range::parse("=0.9.0").unwrap();
+
+ assert_eq!(Predicate {
+ op: Op::Ex,
+ major: 0,
+ minor: Some(9),
+ patch: Some(0),
+ pre: Vec::new(),
+ },
+ r.predicates[0]
+ );
+ }
+
+ #[test]
+ fn test_parsing_exact_03() {
+ let r = range::parse("=0.1.0-beta2.a").unwrap();
+
+ assert_eq!(Predicate {
+ op: Op::Ex,
+ major: 0,
+ minor: Some(1),
+ patch: Some(0),
+ pre: vec![Identifier::AlphaNumeric(String::from("beta2")),
+ Identifier::AlphaNumeric(String::from("a"))],
+ },
+ r.predicates[0]
+ );
+ }
+
+ #[test]
+ pub fn test_parsing_greater_than() {
+ let r = range::parse("> 1.0.0").unwrap();
+
+ assert_eq!(Predicate {
+ op: Op::Gt,
+ major: 1,
+ minor: Some(0),
+ patch: Some(0),
+ pre: Vec::new(),
+ },
+ r.predicates[0]
+ );
+ }
+
+ #[test]
+ pub fn test_parsing_greater_than_01() {
+ let r = range::parse(">= 1.0.0").unwrap();
+
+ assert_eq!(Predicate {
+ op: Op::GtEq,
+ major: 1,
+ minor: Some(0),
+ patch: Some(0),
+ pre: Vec::new(),
+ },
+ r.predicates[0]
+ );
+ }
+
+ #[test]
+ pub fn test_parsing_greater_than_02() {
+ let r = range::parse(">= 2.1.0-alpha2").unwrap();
+
+ assert_eq!(Predicate {
+ op: Op::GtEq,
+ major: 2,
+ minor: Some(1),
+ patch: Some(0),
+ pre: vec![Identifier::AlphaNumeric(String::from("alpha2"))],
+ },
+ r.predicates[0]
+ );
+ }
+
+ #[test]
+ pub fn test_parsing_less_than() {
+ let r = range::parse("< 1.0.0").unwrap();
+
+ assert_eq!(Predicate {
+ op: Op::Lt,
+ major: 1,
+ minor: Some(0),
+ patch: Some(0),
+ pre: Vec::new(),
+ },
+ r.predicates[0]
+ );
+ }
+
+ #[test]
+ pub fn test_parsing_less_than_eq() {
+ let r = range::parse("<= 2.1.0-alpha2").unwrap();
+
+ assert_eq!(Predicate {
+ op: Op::LtEq,
+ major: 2,
+ minor: Some(1),
+ patch: Some(0),
+ pre: vec![Identifier::AlphaNumeric(String::from("alpha2"))],
+ },
+ r.predicates[0]
+ );
+ }
+
+ #[test]
+ pub fn test_parsing_tilde() {
+ let r = range::parse("~1").unwrap();
+
+ assert_eq!(Predicate {
+ op: Op::Tilde,
+ major: 1,
+ minor: None,
+ patch: None,
+ pre: Vec::new(),
+ },
+ r.predicates[0]
+ );
+ }
+
+ #[test]
+ pub fn test_parsing_compatible() {
+ let r = range::parse("^0").unwrap();
+
+ assert_eq!(Predicate {
+ op: Op::Compatible,
+ major: 0,
+ minor: None,
+ patch: None,
+ pre: Vec::new(),
+ },
+ r.predicates[0]
+ );
+ }
+
+ #[test]
+ fn test_parsing_blank() {
+ let r = range::parse("").unwrap();
+
+ assert_eq!(Predicate {
+ op: Op::Wildcard(WildcardVersion::Major),
+ major: 0,
+ minor: None,
+ patch: None,
+ pre: Vec::new(),
+ },
+ r.predicates[0]
+ );
+ }
+
+ #[test]
+ fn test_parsing_wildcard() {
+ let r = range::parse("*").unwrap();
+
+ assert_eq!(Predicate {
+ op: Op::Wildcard(WildcardVersion::Major),
+ major: 0,
+ minor: None,
+ patch: None,
+ pre: Vec::new(),
+ },
+ r.predicates[0]
+ );
+ }
+
+ #[test]
+ fn test_parsing_x() {
+ let r = range::parse("x").unwrap();
+
+ assert_eq!(Predicate {
+ op: Op::Wildcard(WildcardVersion::Major),
+ major: 0,
+ minor: None,
+ patch: None,
+ pre: Vec::new(),
+ },
+ r.predicates[0]
+ );
+ }
+
+ #[test]
+ fn test_parsing_capital_x() {
+ let r = range::parse("X").unwrap();
+
+ assert_eq!(Predicate {
+ op: Op::Wildcard(WildcardVersion::Major),
+ major: 0,
+ minor: None,
+ patch: None,
+ pre: Vec::new(),
+ },
+ r.predicates[0]
+ );
+ }
+
+ #[test]
+ fn test_parsing_minor_wildcard_star() {
+ let r = range::parse("1.*").unwrap();
+
+ assert_eq!(Predicate {
+ op: Op::Wildcard(WildcardVersion::Minor),
+ major: 1,
+ minor: None,
+ patch: None,
+ pre: Vec::new(),
+ },
+ r.predicates[0]
+ );
+ }
+
+ #[test]
+ fn test_parsing_minor_wildcard_x() {
+ let r = range::parse("1.x").unwrap();
+
+ assert_eq!(Predicate {
+ op: Op::Wildcard(WildcardVersion::Minor),
+ major: 1,
+ minor: None,
+ patch: None,
+ pre: Vec::new(),
+ },
+ r.predicates[0]
+ );
+ }
+
+ #[test]
+ fn test_parsing_minor_wildcard_capital_x() {
+ let r = range::parse("1.X").unwrap();
+
+ assert_eq!(Predicate {
+ op: Op::Wildcard(WildcardVersion::Minor),
+ major: 1,
+ minor: None,
+ patch: None,
+ pre: Vec::new(),
+ },
+ r.predicates[0]
+ );
+ }
+
+ #[test]
+ fn test_parsing_patch_wildcard_star() {
+ let r = range::parse("1.2.*").unwrap();
+
+ assert_eq!(Predicate {
+ op: Op::Wildcard(WildcardVersion::Patch),
+ major: 1,
+ minor: Some(2),
+ patch: None,
+ pre: Vec::new(),
+ },
+ r.predicates[0]
+ );
+ }
+
+ #[test]
+ fn test_parsing_patch_wildcard_x() {
+ let r = range::parse("1.2.x").unwrap();
+
+ assert_eq!(Predicate {
+ op: Op::Wildcard(WildcardVersion::Patch),
+ major: 1,
+ minor: Some(2),
+ patch: None,
+ pre: Vec::new(),
+ },
+ r.predicates[0]
+ );
+ }
+
+ #[test]
+ fn test_parsing_patch_wildcard_capital_x() {
+ let r = range::parse("1.2.X").unwrap();
+
+ assert_eq!(Predicate {
+ op: Op::Wildcard(WildcardVersion::Patch),
+ major: 1,
+ minor: Some(2),
+ patch: None,
+ pre: Vec::new(),
+ },
+ r.predicates[0]
+ );
+ }
+
+ #[test]
+ pub fn test_multiple_01() {
+ let r = range::parse("> 0.0.9, <= 2.5.3").unwrap();
+
+ assert_eq!(Predicate {
+ op: Op::Gt,
+ major: 0,
+ minor: Some(0),
+ patch: Some(9),
+ pre: Vec::new(),
+ },
+ r.predicates[0]
+ );
+
+ assert_eq!(Predicate {
+ op: Op::LtEq,
+ major: 2,
+ minor: Some(5),
+ patch: Some(3),
+ pre: Vec::new(),
+ },
+ r.predicates[1]
+ );
+ }
+
+ #[test]
+ pub fn test_multiple_02() {
+ let r = range::parse("0.3.0, 0.4.0").unwrap();
+
+ assert_eq!(Predicate {
+ op: Op::Compatible,
+ major: 0,
+ minor: Some(3),
+ patch: Some(0),
+ pre: Vec::new(),
+ },
+ r.predicates[0]
+ );
+
+ assert_eq!(Predicate {
+ op: Op::Compatible,
+ major: 0,
+ minor: Some(4),
+ patch: Some(0),
+ pre: Vec::new(),
+ },
+ r.predicates[1]
+ );
+ }
+
+ #[test]
+ pub fn test_multiple_03() {
+ let r = range::parse("<= 0.2.0, >= 0.5.0").unwrap();
+
+ assert_eq!(Predicate {
+ op: Op::LtEq,
+ major: 0,
+ minor: Some(2),
+ patch: Some(0),
+ pre: Vec::new(),
+ },
+ r.predicates[0]
+ );
+
+ assert_eq!(Predicate {
+ op: Op::GtEq,
+ major: 0,
+ minor: Some(5),
+ patch: Some(0),
+ pre: Vec::new(),
+ },
+ r.predicates[1]
+ );
+ }
+
+ #[test]
+ pub fn test_multiple_04() {
+ let r = range::parse("0.1.0, 0.1.4, 0.1.6").unwrap();
+
+ assert_eq!(Predicate {
+ op: Op::Compatible,
+ major: 0,
+ minor: Some(1),
+ patch: Some(0),
+ pre: Vec::new(),
+ },
+ r.predicates[0]
+ );
+
+ assert_eq!(Predicate {
+ op: Op::Compatible,
+ major: 0,
+ minor: Some(1),
+ patch: Some(4),
+ pre: Vec::new(),
+ },
+ r.predicates[1]
+ );
+
+ assert_eq!(Predicate {
+ op: Op::Compatible,
+ major: 0,
+ minor: Some(1),
+ patch: Some(6),
+ pre: Vec::new(),
+ },
+ r.predicates[2]
+ );
+ }
+
+ #[test]
+ pub fn test_multiple_05() {
+ let r = range::parse(">=0.5.1-alpha3, <0.6").unwrap();
+
+ assert_eq!(Predicate {
+ op: Op::GtEq,
+ major: 0,
+ minor: Some(5),
+ patch: Some(1),
+ pre: vec![Identifier::AlphaNumeric(String::from("alpha3"))],
+ },
+ r.predicates[0]
+ );
+
+ assert_eq!(Predicate {
+ op: Op::Lt,
+ major: 0,
+ minor: Some(6),
+ patch: None,
+ pre: Vec::new(),
+ },
+ r.predicates[1]
+ );
+ }
+
+ #[test]
+ fn test_parse_build_metadata_with_predicate() {
+ assert_eq!(range::parse("^1.2.3+meta").unwrap().predicates[0].op,
+ Op::Compatible);
+ assert_eq!(range::parse("~1.2.3+meta").unwrap().predicates[0].op,
+ Op::Tilde);
+ assert_eq!(range::parse("=1.2.3+meta").unwrap().predicates[0].op,
+ Op::Ex);
+ assert_eq!(range::parse("<=1.2.3+meta").unwrap().predicates[0].op,
+ Op::LtEq);
+ assert_eq!(range::parse(">=1.2.3+meta").unwrap().predicates[0].op,
+ Op::GtEq);
+ assert_eq!(range::parse("<1.2.3+meta").unwrap().predicates[0].op,
+ Op::Lt);
+ assert_eq!(range::parse(">1.2.3+meta").unwrap().predicates[0].op,
+ Op::Gt);
+ }
+
+ #[test]
+ pub fn test_parse_errors() {
+ assert!(range::parse("\0").is_err());
+ assert!(range::parse(">= >= 0.0.2").is_err());
+ assert!(range::parse(">== 0.0.2").is_err());
+ assert!(range::parse("a.0.0").is_err());
+ assert!(range::parse("1.0.0-").is_err());
+ assert!(range::parse(">=").is_err());
+ assert!(range::parse("> 0.1.0,").is_err());
+ assert!(range::parse("> 0.3.0, ,").is_err());
+ }
+
+ #[test]
+ pub fn test_large_major_version() {
+ assert!(range::parse("18446744073709551617.0.0").is_err());
+ }
+
+ #[test]
+ pub fn test_large_minor_version() {
+ assert!(range::parse("0.18446744073709551617.0").is_err());
+ }
+
+ #[test]
+ pub fn test_large_patch_version() {
+ assert!(range::parse("0.0.18446744073709551617").is_err());
+ }
+}
diff --git a/semver-parser/src/recognize.rs b/semver-parser/src/recognize.rs
new file mode 100644
index 0000000..c0dd771
--- /dev/null
+++ b/semver-parser/src/recognize.rs
@@ -0,0 +1,154 @@
+// Copyright 2017 Google Inc. All rights reserved.
+//
+// Licensed under either of MIT or Apache License, Version 2.0,
+// at your option.
+//
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file or at
+// https://opensource.org/licenses/MIT.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Simple recognizer combinators.
+
+// This version is similar to a similar one in the "lang" module of
+// xi-editor, but is stripped down to only the needed combinators.
+
+use std::ops;
+
+pub trait Recognize {
+ fn p(&self, s: &[u8]) -> Option<usize>;
+}
+
+impl<F: Fn(&[u8]) -> Option<usize>> Recognize for F {
+ #[inline(always)]
+ fn p(&self, s: &[u8]) -> Option<usize> {
+ self(s)
+ }
+}
+
+pub struct OneByte<F>(pub F);
+
+impl<F: Fn(u8) -> bool> Recognize for OneByte<F> {
+ #[inline(always)]
+ fn p(&self, s: &[u8]) -> Option<usize> {
+ if s.is_empty() || !self.0(s[0]) {
+ None
+ } else {
+ Some(1)
+ }
+ }
+}
+
+impl Recognize for u8 {
+ #[inline(always)]
+ fn p(&self, s: &[u8]) -> Option<usize> {
+ OneByte(|b| b == *self).p(s)
+ }
+}
+
+/// Use Inclusive(a..b) to indicate an inclusive range. When a...b syntax becomes
+/// stable, we can get rid of this and switch to that.
+pub struct Inclusive<T>(pub T);
+
+impl Recognize for Inclusive<ops::Range<u8>> {
+ #[inline(always)]
+ fn p(&self, s: &[u8]) -> Option<usize> {
+ OneByte(|x| x >= self.0.start && x <= self.0.end).p(s)
+ }
+}
+
+impl<'a> Recognize for &'a [u8] {
+ #[inline(always)]
+ fn p(&self, s: &[u8]) -> Option<usize> {
+ let len = self.len();
+ if s.len() >= len && &s[..len] == *self {
+ Some(len)
+ } else {
+ None
+ }
+ }
+}
+
+impl<'a> Recognize for &'a str {
+ #[inline(always)]
+ fn p(&self, s: &[u8]) -> Option<usize> {
+ self.as_bytes().p(s)
+ }
+}
+
+impl<P1: Recognize, P2: Recognize> Recognize for (P1, P2) {
+ #[inline(always)]
+ fn p(&self, s: &[u8]) -> Option<usize> {
+ self.0.p(s).and_then(|len1|
+ self.1.p(&s[len1..]).map(|len2|
+ len1 + len2))
+ }
+}
+
+/// Choice from two heterogeneous alternatives.
+pub struct Alt<P1, P2>(pub P1, pub P2);
+
+impl<P1: Recognize, P2: Recognize> Recognize for Alt<P1, P2> {
+ #[inline(always)]
+ fn p(&self, s: &[u8]) -> Option<usize> {
+ self.0.p(s).or_else(|| self.1.p(s))
+ }
+}
+
+/// Choice from a homogenous slice of parsers.
+pub struct OneOf<'a, P: 'a>(pub &'a [P]);
+
+impl<'a, P: Recognize> Recognize for OneOf<'a, P> {
+ #[inline]
+ fn p(&self, s: &[u8]) -> Option<usize> {
+ for ref p in self.0 {
+ if let Some(len) = p.p(s) {
+ return Some(len);
+ }
+ }
+ None
+ }
+}
+
+pub struct OneOrMore<P>(pub P);
+
+impl<P: Recognize> Recognize for OneOrMore<P> {
+ #[inline]
+ fn p(&self, s: &[u8]) -> Option<usize> {
+ let mut i = 0;
+ let mut count = 0;
+ while let Some(len) = self.0.p(&s[i..]) {
+ i += len;
+ count += 1;
+ }
+ if count >= 1 {
+ Some(i)
+ } else {
+ None
+ }
+ }
+}
+
+pub struct ZeroOrMore<P>(pub P);
+
+impl<P: Recognize> Recognize for ZeroOrMore<P> {
+ #[inline]
+ fn p(&self, s: &[u8]) -> Option<usize> {
+ let mut i = 0;
+ while let Some(len) = self.0.p(&s[i..]) {
+ i += len;
+ }
+ Some(i)
+ }
+}
diff --git a/semver-parser/src/version.rs b/semver-parser/src/version.rs
new file mode 100644
index 0000000..570f947
--- /dev/null
+++ b/semver-parser/src/version.rs
@@ -0,0 +1,365 @@
+use std::fmt;
+use std::str::from_utf8;
+
+use recognize::*;
+
+use common::{self, numeric_identifier};
+
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct Version {
+ pub major: u64,
+ pub minor: u64,
+ pub patch: u64,
+ pub pre: Vec<Identifier>,
+ pub build: Vec<Identifier>,
+}
+
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub enum Identifier {
+ /// An identifier that's solely numbers.
+ Numeric(u64),
+ /// An identifier with letters and numbers.
+ AlphaNumeric(String),
+}
+
+pub fn parse(version: &str) -> Result<Version, String> {
+ let s = version.trim().as_bytes();
+ let mut i = 0;
+ let major = if let Some((major, len)) = numeric_identifier(&s[i..]) {
+ i += len;
+ major
+ } else {
+ return Err("Error parsing major identifier".to_string());
+ };
+ if let Some(len) = b'.'.p(&s[i..]) {
+ i += len;
+ } else {
+ return Err("Expected dot".to_string());
+ }
+ let minor = if let Some((minor, len)) = numeric_identifier(&s[i..]) {
+ i += len;
+ minor
+ } else {
+ return Err("Error parsing minor identifier".to_string());
+ };
+ if let Some(len) = b'.'.p(&s[i..]) {
+ i += len;
+ } else {
+ return Err("Expected dot".to_string());
+ }
+ let patch = if let Some((patch, len)) = numeric_identifier(&s[i..]) {
+ i += len;
+ patch
+ } else {
+ return Err("Error parsing patch identifier".to_string());
+ };
+ let (pre, pre_len) = common::parse_optional_meta(&s[i..], b'-')?;
+ i += pre_len;
+ let (build, build_len) = common::parse_optional_meta(&s[i..], b'+')?;
+ i += build_len;
+ if i != s.len() {
+ return Err("Extra junk after valid version: ".to_string() +
+ from_utf8(&s[i..]).unwrap());
+ }
+ Ok(Version {
+ major: major,
+ minor: minor,
+ patch: patch,
+ pre: pre,
+ build: build,
+ })
+}
+
+impl fmt::Display for Version {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ try!(write!(f, "{}.{}.{}", self.major, self.minor, self.patch));
+ if !self.pre.is_empty() {
+ let strs: Vec<_> =
+ self.pre.iter().map(ToString::to_string).collect();
+ try!(write!(f, "-{}", strs.join(".")));
+ }
+ if !self.build.is_empty() {
+ let strs: Vec<_> =
+ self.build.iter().map(ToString::to_string).collect();
+ try!(write!(f, "+{}", strs.join(".")));
+ }
+ Ok(())
+ }
+}
+
+impl fmt::Display for Identifier {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ Identifier::Numeric(ref id) => id.fmt(f),
+ Identifier::AlphaNumeric(ref id) => id.fmt(f),
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use version;
+ use super::*;
+
+ #[test]
+ fn parse_empty() {
+ let version = "";
+
+ let parsed = version::parse(version);
+
+ assert!(parsed.is_err(), "empty string incorrectly considered a valid parse");
+ }
+
+ #[test]
+ fn parse_blank() {
+ let version = " ";
+
+ let parsed = version::parse(version);
+
+ assert!(parsed.is_err(), "blank string incorrectly considered a valid parse");
+ }
+
+ #[test]
+ fn parse_no_minor_patch() {
+ let version = "1";
+
+ let parsed = version::parse(version);
+
+ assert!(parsed.is_err(), format!("'{}' incorrectly considered a valid parse", version));
+ }
+
+ #[test]
+ fn parse_no_patch() {
+ let version = "1.2";
+
+ let parsed = version::parse(version);
+
+ assert!(parsed.is_err(), format!("'{}' incorrectly considered a valid parse", version));
+ }
+
+ #[test]
+ fn parse_empty_pre() {
+ let version = "1.2.3-";
+
+ let parsed = version::parse(version);
+
+ assert!(parsed.is_err(), format!("'{}' incorrectly considered a valid parse", version));
+ }
+
+ #[test]
+ fn parse_letters() {
+ let version = "a.b.c";
+
+ let parsed = version::parse(version);
+
+ assert!(parsed.is_err(), format!("'{}' incorrectly considered a valid parse", version));
+ }
+
+ #[test]
+ fn parse_with_letters() {
+ let version = "1.2.3 a.b.c";
+
+ let parsed = version::parse(version);
+
+ assert!(parsed.is_err(), format!("'{}' incorrectly considered a valid parse", version));
+ }
+
+ #[test]
+ fn parse_basic_version() {
+ let version = "1.2.3";
+
+ let parsed = version::parse(version).unwrap();
+
+ assert_eq!(1, parsed.major);
+ assert_eq!(2, parsed.minor);
+ assert_eq!(3, parsed.patch);
+ }
+
+ #[test]
+ fn parse_trims_input() {
+ let version = " 1.2.3 ";
+
+ let parsed = version::parse(version).unwrap();
+
+ assert_eq!(1, parsed.major);
+ assert_eq!(2, parsed.minor);
+ assert_eq!(3, parsed.patch);
+ }
+
+ #[test]
+ fn parse_no_major_leading_zeroes() {
+ let version = "01.0.0";
+
+ let parsed = version::parse(version);
+
+ assert!(parsed.is_err(), "01 incorrectly considered a valid major version");
+ }
+
+ #[test]
+ fn parse_no_minor_leading_zeroes() {
+ let version = "0.01.0";
+
+ let parsed = version::parse(version);
+
+ assert!(parsed.is_err(), "01 incorrectly considered a valid minor version");
+ }
+
+ #[test]
+ fn parse_no_patch_leading_zeroes() {
+ let version = "0.0.01";
+
+ let parsed = version::parse(version);
+
+ assert!(parsed.is_err(), "01 incorrectly considered a valid patch version");
+ }
+
+ #[test]
+ fn parse_no_major_overflow() {
+ let version = "98765432109876543210.0.0";
+
+ let parsed = version::parse(version);
+
+ assert!(parsed.is_err(), "98765432109876543210 incorrectly considered a valid major version");
+ }
+
+ #[test]
+ fn parse_no_minor_overflow() {
+ let version = "0.98765432109876543210.0";
+
+ let parsed = version::parse(version);
+
+ assert!(parsed.is_err(), "98765432109876543210 incorrectly considered a valid minor version");
+ }
+
+ #[test]
+ fn parse_no_patch_overflow() {
+ let version = "0.0.98765432109876543210";
+
+ let parsed = version::parse(version);
+
+ assert!(parsed.is_err(), "98765432109876543210 incorrectly considered a valid patch version");
+ }
+
+ #[test]
+ fn parse_basic_prerelease() {
+ let version = "1.2.3-pre";
+
+ let parsed = version::parse(version).unwrap();
+
+ let expected_pre = vec![Identifier::AlphaNumeric(String::from("pre"))];
+ assert_eq!(expected_pre, parsed.pre);
+ }
+
+ #[test]
+ fn parse_prerelease_alphanumeric() {
+ let version = "1.2.3-alpha1";
+
+ let parsed = version::parse(version).unwrap();
+
+ let expected_pre = vec![Identifier::AlphaNumeric(String::from("alpha1"))];
+ assert_eq!(expected_pre, parsed.pre);
+ }
+
+ #[test]
+ fn parse_prerelease_zero() {
+ let version = "1.2.3-pre.0";
+
+ let parsed = version::parse(version).unwrap();
+
+ let expected_pre = vec![Identifier::AlphaNumeric(String::from("pre")),
+ Identifier::Numeric(0)];
+ assert_eq!(expected_pre, parsed.pre);
+ }
+
+ #[test]
+ fn parse_basic_build() {
+ let version = "1.2.3+build";
+
+ let parsed = version::parse(version).unwrap();
+
+ let expected_build = vec![Identifier::AlphaNumeric(String::from("build"))];
+ assert_eq!(expected_build, parsed.build);
+ }
+
+ #[test]
+ fn parse_build_alphanumeric() {
+ let version = "1.2.3+build5";
+
+ let parsed = version::parse(version).unwrap();
+
+ let expected_build = vec![Identifier::AlphaNumeric(String::from("build5"))];
+ assert_eq!(expected_build, parsed.build);
+ }
+
+ #[test]
+ fn parse_pre_and_build() {
+ let version = "1.2.3-alpha1+build5";
+
+ let parsed = version::parse(version).unwrap();
+
+ let expected_pre = vec![Identifier::AlphaNumeric(String::from("alpha1"))];
+ assert_eq!(expected_pre, parsed.pre);
+
+ let expected_build = vec![Identifier::AlphaNumeric(String::from("build5"))];
+ assert_eq!(expected_build, parsed.build);
+ }
+
+ #[test]
+ fn parse_complex_metadata_01() {
+ let version = "1.2.3-1.alpha1.9+build5.7.3aedf ";
+
+ let parsed = version::parse(version).unwrap();
+
+ let expected_pre = vec![Identifier::Numeric(1),
+ Identifier::AlphaNumeric(String::from("alpha1")),
+ Identifier::Numeric(9)];
+ assert_eq!(expected_pre, parsed.pre);
+
+ let expected_build = vec![Identifier::AlphaNumeric(String::from("build5")),
+ Identifier::Numeric(7),
+ Identifier::AlphaNumeric(String::from("3aedf"))];
+ assert_eq!(expected_build, parsed.build);
+ }
+
+ #[test]
+ fn parse_complex_metadata_02() {
+ let version = "0.4.0-beta.1+0851523";
+
+ let parsed = version::parse(version).unwrap();
+
+ let expected_pre = vec![Identifier::AlphaNumeric(String::from("beta")),
+ Identifier::Numeric(1)];
+ assert_eq!(expected_pre, parsed.pre);
+
+ let expected_build = vec![Identifier::AlphaNumeric(String::from("0851523"))];
+ assert_eq!(expected_build, parsed.build);
+ }
+
+ #[test]
+ fn parse_metadata_overflow() {
+ let version = "0.4.0-beta.1+98765432109876543210";
+
+ let parsed = version::parse(version).unwrap();
+
+ let expected_pre = vec![Identifier::AlphaNumeric(String::from("beta")),
+ Identifier::Numeric(1)];
+ assert_eq!(expected_pre, parsed.pre);
+
+ let expected_build = vec![Identifier::AlphaNumeric(String::from("98765432109876543210"))];
+ assert_eq!(expected_build, parsed.build);
+ }
+
+ #[test]
+ fn parse_regression_01() {
+ let version = "0.0.0-WIP";
+
+ let parsed = version::parse(version).unwrap();
+
+ assert_eq!(0, parsed.major);
+ assert_eq!(0, parsed.minor);
+ assert_eq!(0, parsed.patch);
+
+ let expected_pre = vec![Identifier::AlphaNumeric(String::from("WIP"))];
+ assert_eq!(expected_pre, parsed.pre);
+ }
+}
diff --git a/semver/.gitignore b/semver/.gitignore
new file mode 100644
index 0000000..cc3b589
--- /dev/null
+++ b/semver/.gitignore
@@ -0,0 +1,3 @@
+target/
+*.sw?
+Cargo.lock
diff --git a/semver/.travis.yml b/semver/.travis.yml
new file mode 100644
index 0000000..bb4ba27
--- /dev/null
+++ b/semver/.travis.yml
@@ -0,0 +1,18 @@
+language: rust
+rust:
+ - nightly
+ - beta
+ - stable
+sudo: false
+script:
+ - cargo build --verbose
+ - cargo test --verbose --features ci
+addons:
+ apt:
+ sources:
+ - kalakris-cmake
+ packages:
+ - cmake
+notifications:
+ email:
+ on_success: never
diff --git a/semver/Cargo.toml b/semver/Cargo.toml
new file mode 100644
index 0000000..1a31f59
--- /dev/null
+++ b/semver/Cargo.toml
@@ -0,0 +1,32 @@
+[package]
+
+name = "semver"
+version = "0.9.0"
+authors = ["Steve Klabnik <steve@steveklabnik.com>", "The Rust Project Developers"]
+license = "MIT/Apache-2.0"
+repository = "https://github.com/steveklabnik/semver"
+homepage = "https://docs.rs/crate/semver/"
+documentation = "https://docs.rs/crate/semver/"
+description = """
+Semantic version parsing and comparison.
+"""
+readme = "README.md"
+
+[badges]
+travis-ci = { repository = "steveklabnik/semver" }
+
+[dependencies]
+semver-parser = "0.7.0"
+serde = { version = "1.0", optional = true }
+
+[features]
+default = []
+
+# are we testing on CI?
+ci = ["serde"]
+
+[dev-dependencies]
+crates-index = "0.5.0"
+tempdir = "0.3.4"
+serde_json = "1.0"
+serde_derive = "1.0"
diff --git a/semver/LICENSE-APACHE b/semver/LICENSE-APACHE
new file mode 100644
index 0000000..16fe87b
--- /dev/null
+++ b/semver/LICENSE-APACHE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/semver/LICENSE-MIT b/semver/LICENSE-MIT
new file mode 100644
index 0000000..39d4bdb
--- /dev/null
+++ b/semver/LICENSE-MIT
@@ -0,0 +1,25 @@
+Copyright (c) 2014 The Rust Project Developers
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/semver/README.md b/semver/README.md
new file mode 100644
index 0000000..2a5306d
--- /dev/null
+++ b/semver/README.md
@@ -0,0 +1,103 @@
+semver
+======
+
+Semantic version parsing and comparison.
+
+[![Build Status](https://api.travis-ci.org/steveklabnik/semver.svg?branch=master)](https://travis-ci.org/steveklabnik/semver)
+
+[Documentation](https://steveklabnik.github.io/semver)
+
+Semantic versioning (see http://semver.org/) is a set of rules for
+assigning version numbers.
+
+## SemVer and the Rust ecosystem
+
+Rust itself follows the SemVer specification, as does its standard libraries. The two are
+not tied together.
+
+[Cargo](https://crates.io), Rust's package manager, uses SemVer to determine which versions of
+packages you need installed.
+
+## Installation
+
+To use `semver`, add this to your `[dependencies]` section:
+
+```toml
+semver = "0.7.0"
+```
+
+And this to your crate root:
+
+```rust
+extern crate semver;
+```
+
+## Versions
+
+At its simplest, the `semver` crate allows you to construct `Version` objects using the `parse`
+method:
+
+```rust
+use semver::Version;
+
+assert!(Version::parse("1.2.3") == Ok(Version {
+ major: 1,
+ minor: 2,
+ patch: 3,
+ pre: vec!(),
+ build: vec!(),
+}));
+```
+
+If you have multiple `Version`s, you can use the usual comparison operators to compare them:
+
+```rust
+use semver::Version;
+
+assert!(Version::parse("1.2.3-alpha") != Version::parse("1.2.3-beta"));
+assert!(Version::parse("1.2.3-alpha2") > Version::parse("1.2.0"));
+```
+
+## Requirements
+
+The `semver` crate also provides the ability to compare requirements, which are more complex
+comparisons.
+
+For example, creating a requirement that only matches versions greater than or
+equal to 1.0.0:
+
+```rust
+use semver::Version;
+use semver::VersionReq;
+
+let r = VersionReq::parse(">= 1.0.0").unwrap();
+let v = Version::parse("1.0.0").unwrap();
+
+assert!(r.to_string() == ">= 1.0.0".to_string());
+assert!(r.matches(&v))
+```
+
+It also allows parsing of `~x.y.z` and `^x.y.z` requirements as defined at
+https://www.npmjs.org/doc/misc/semver.html
+
+**Tilde requirements** specify a minimal version with some updates:
+
+```notrust
+~1.2.3 := >=1.2.3 <1.3.0
+~1.2 := >=1.2.0 <1.3.0
+~1 := >=1.0.0 <2.0.0
+```
+
+**Caret requirements** allow SemVer compatible updates to a specified version,
+`0.x` and `0.x+1` are not considered compatible, but `1.x` and `1.x+1` are.
+
+`0.0.x` is not considered compatible with any other version.
+Missing minor and patch versions are desugared to `0` but allow flexibility for that value.
+
+```notrust
+^1.2.3 := >=1.2.3 <2.0.0
+^0.2.3 := >=0.2.3 <0.3.0
+^0.0.3 := >=0.0.3 <0.0.4
+^0.0 := >=0.0.0 <0.1.0
+^0 := >=0.0.0 <1.0.0
+```
diff --git a/semver/src/lib.rs b/semver/src/lib.rs
new file mode 100644
index 0000000..a38aae0
--- /dev/null
+++ b/semver/src/lib.rs
@@ -0,0 +1,182 @@
+// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Semantic version parsing and comparison.
+//!
+//! Semantic versioning (see http://semver.org/) is a set of rules for
+//! assigning version numbers.
+//!
+//! ## SemVer overview
+//!
+//! Given a version number MAJOR.MINOR.PATCH, increment the:
+//!
+//! 1. MAJOR version when you make incompatible API changes,
+//! 2. MINOR version when you add functionality in a backwards-compatible
+//! manner, and
+//! 3. PATCH version when you make backwards-compatible bug fixes.
+//!
+//! Additional labels for pre-release and build metadata are available as
+//! extensions to the MAJOR.MINOR.PATCH format.
+//!
+//! Any references to 'the spec' in this documentation refer to [version 2.0 of
+//! the SemVer spec](http://semver.org/spec/v2.0.0.html).
+//!
+//! ## SemVer and the Rust ecosystem
+//!
+//! Rust itself follows the SemVer specification, as does its standard
+//! libraries. The two are not tied together.
+//!
+//! [Cargo](http://crates.io), Rust's package manager, uses SemVer to determine
+//! which versions of packages you need installed.
+//!
+//! ## Versions
+//!
+//! At its simplest, the `semver` crate allows you to construct `Version`
+//! objects using the `parse` method:
+//!
+//! ```{rust}
+//! use semver::Version;
+//!
+//! assert!(Version::parse("1.2.3") == Ok(Version {
+//! major: 1,
+//! minor: 2,
+//! patch: 3,
+//! pre: vec!(),
+//! build: vec!(),
+//! }));
+//! ```
+//!
+//! If you have multiple `Version`s, you can use the usual comparison operators
+//! to compare them:
+//!
+//! ```{rust}
+//! use semver::Version;
+//!
+//! assert!(Version::parse("1.2.3-alpha") != Version::parse("1.2.3-beta"));
+//! assert!(Version::parse("1.2.3-alpha2") > Version::parse("1.2.0"));
+//! ```
+//!
+//! If you explicitly need to modify a Version, SemVer also allows you to
+//! increment the major, minor, and patch numbers in accordance with the spec.
+//!
+//! Please note that in order to do this, you must use a mutable Version:
+//!
+//! ```{rust}
+//! use semver::Version;
+//!
+//! let mut bugfix_release = Version::parse("1.0.0").unwrap();
+//! bugfix_release.increment_patch();
+//!
+//! assert_eq!(Ok(bugfix_release), Version::parse("1.0.1"));
+//! ```
+//!
+//! When incrementing the minor version number, the patch number resets to zero
+//! (in accordance with section 7 of the spec)
+//!
+//! ```{rust}
+//! use semver::Version;
+//!
+//! let mut feature_release = Version::parse("1.4.6").unwrap();
+//! feature_release.increment_minor();
+//!
+//! assert_eq!(Ok(feature_release), Version::parse("1.5.0"));
+//! ```
+//!
+//! Similarly, when incrementing the major version number, the patch and minor
+//! numbers reset to zero (in accordance with section 8 of the spec)
+//!
+//! ```{rust}
+//! use semver::Version;
+//!
+//! let mut chrome_release = Version::parse("41.5.5377").unwrap();
+//! chrome_release.increment_major();
+//!
+//! assert_eq!(Ok(chrome_release), Version::parse("42.0.0"));
+//! ```
+//!
+//! ## Requirements
+//!
+//! The `semver` crate also provides the ability to compare requirements, which
+//! are more complex comparisons.
+//!
+//! For example, creating a requirement that only matches versions greater than
+//! or equal to 1.0.0:
+//!
+//! ```{rust}
+//! # #![allow(unstable)]
+//! use semver::Version;
+//! use semver::VersionReq;
+//!
+//! let r = VersionReq::parse(">= 1.0.0").unwrap();
+//! let v = Version::parse("1.0.0").unwrap();
+//!
+//! assert!(r.to_string() == ">= 1.0.0".to_string());
+//! assert!(r.matches(&v))
+//! ```
+//!
+//! It also allows parsing of `~x.y.z` and `^x.y.z` requirements as defined at
+//! https://www.npmjs.org/doc/misc/semver.html
+//!
+//! **Tilde requirements** specify a minimal version with some updates:
+//!
+//! ```notrust
+//! ~1.2.3 := >=1.2.3 <1.3.0
+//! ~1.2 := >=1.2.0 <1.3.0
+//! ~1 := >=1.0.0 <2.0.0
+//! ```
+//!
+//! **Caret requirements** allow SemVer compatible updates to a specified
+//! verion, `0.x` and `0.x+1` are not considered compatible, but `1.x` and
+//! `1.x+1` are.
+//!
+//! `0.0.x` is not considered compatible with any other version.
+//! Missing minor and patch versions are desugared to `0` but allow flexibility
+//! for that value.
+//!
+//! ```notrust
+//! ^1.2.3 := >=1.2.3 <2.0.0
+//! ^0.2.3 := >=0.2.3 <0.3.0
+//! ^0.0.3 := >=0.0.3 <0.0.4
+//! ^0.0 := >=0.0.0 <0.1.0
+//! ^0 := >=0.0.0 <1.0.0
+//! ```
+//!
+//! **Wildcard requirements** allows parsing of version requirements of the
+//! formats `*`, `x.*` and `x.y.*`.
+//!
+//! ```notrust
+//! * := >=0.0.0
+//! 1.* := >=1.0.0 <2.0.0
+//! 1.2.* := >=1.2.0 <1.3.0
+//! ```
+
+#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
+ html_favicon_url = "https://www.rust-lang.org/favicon.ico")]
+#![deny(missing_docs)]
+#![cfg_attr(test, deny(warnings))]
+
+extern crate semver_parser;
+
+// Serialization and deserialization support for version numbers
+#[cfg(feature = "serde")]
+extern crate serde;
+
+// We take the common approach of keeping our own module system private, and
+// just re-exporting the interface that we want.
+
+pub use version::{Version, Identifier, SemVerError};
+pub use version::Identifier::{Numeric, AlphaNumeric};
+pub use version_req::{VersionReq, ReqParseError};
+
+// SemVer-compliant versions.
+mod version;
+
+// advanced version comparisons
+mod version_req;
diff --git a/semver/src/version.rs b/semver/src/version.rs
new file mode 100644
index 0000000..38de133
--- /dev/null
+++ b/semver/src/version.rs
@@ -0,0 +1,759 @@
+// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! The `version` module gives you tools to create and compare SemVer-compliant
+//! versions.
+
+use std::cmp::{self, Ordering};
+use std::fmt;
+use std::hash;
+use std::error::Error;
+
+use std::result;
+use std::str;
+
+use semver_parser;
+
+#[cfg(feature = "serde")]
+use serde::ser::{Serialize, Serializer};
+#[cfg(feature = "serde")]
+use serde::de::{self, Deserialize, Deserializer, Visitor};
+
+/// An identifier in the pre-release or build metadata.
+///
+/// See sections 9 and 10 of the spec for more about pre-release identifers and
+/// build metadata.
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+pub enum Identifier {
+ /// An identifier that's solely numbers.
+ Numeric(u64),
+ /// An identifier with letters and numbers.
+ AlphaNumeric(String),
+}
+
+impl From<semver_parser::version::Identifier> for Identifier {
+ fn from(other: semver_parser::version::Identifier) -> Identifier {
+ match other {
+ semver_parser::version::Identifier::Numeric(n) => Identifier::Numeric(n),
+ semver_parser::version::Identifier::AlphaNumeric(s) => Identifier::AlphaNumeric(s),
+ }
+ }
+}
+
+impl fmt::Display for Identifier {
+ #[inline]
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ Identifier::Numeric(ref n) => fmt::Display::fmt(n, f),
+ Identifier::AlphaNumeric(ref s) => fmt::Display::fmt(s, f),
+ }
+ }
+}
+
+#[cfg(feature = "serde")]
+impl Serialize for Identifier {
+ fn serialize<S>(&self, serializer: S) -> result::Result<S::Ok, S::Error>
+ where S: Serializer
+ {
+ // Serialize Identifier as a number or string.
+ match *self {
+ Identifier::Numeric(n) => serializer.serialize_u64(n),
+ Identifier::AlphaNumeric(ref s) => serializer.serialize_str(s),
+ }
+ }
+}
+
+#[cfg(feature = "serde")]
+impl<'de> Deserialize<'de> for Identifier {
+ fn deserialize<D>(deserializer: D) -> result::Result<Self, D::Error>
+ where D: Deserializer<'de>
+ {
+ struct IdentifierVisitor;
+
+ // Deserialize Identifier from a number or string.
+ impl<'de> Visitor<'de> for IdentifierVisitor {
+ type Value = Identifier;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("a SemVer pre-release or build identifier")
+ }
+
+ fn visit_u64<E>(self, numeric: u64) -> result::Result<Self::Value, E>
+ where E: de::Error
+ {
+ Ok(Identifier::Numeric(numeric))
+ }
+
+ fn visit_str<E>(self, alphanumeric: &str) -> result::Result<Self::Value, E>
+ where E: de::Error
+ {
+ Ok(Identifier::AlphaNumeric(alphanumeric.to_owned()))
+ }
+ }
+
+ deserializer.deserialize_any(IdentifierVisitor)
+ }
+}
+
+/// Represents a version number conforming to the semantic versioning scheme.
+#[derive(Clone, Eq, Debug)]
+pub struct Version {
+ /// The major version, to be incremented on incompatible changes.
+ pub major: u64,
+ /// The minor version, to be incremented when functionality is added in a
+ /// backwards-compatible manner.
+ pub minor: u64,
+ /// The patch version, to be incremented when backwards-compatible bug
+ /// fixes are made.
+ pub patch: u64,
+ /// The pre-release version identifier, if one exists.
+ pub pre: Vec<Identifier>,
+ /// The build metadata, ignored when determining version precedence.
+ pub build: Vec<Identifier>,
+}
+
+impl From<semver_parser::version::Version> for Version {
+ fn from(other: semver_parser::version::Version) -> Version {
+ Version {
+ major: other.major,
+ minor: other.minor,
+ patch: other.patch,
+ pre: other.pre.into_iter().map(From::from).collect(),
+ build: other.build.into_iter().map(From::from).collect(),
+ }
+ }
+}
+
+#[cfg(feature = "serde")]
+impl Serialize for Version {
+ fn serialize<S>(&self, serializer: S) -> result::Result<S::Ok, S::Error>
+ where S: Serializer
+ {
+ // Serialize Version as a string.
+ serializer.collect_str(self)
+ }
+}
+
+#[cfg(feature = "serde")]
+impl<'de> Deserialize<'de> for Version {
+ fn deserialize<D>(deserializer: D) -> result::Result<Self, D::Error>
+ where D: Deserializer<'de>
+ {
+ struct VersionVisitor;
+
+ // Deserialize Version from a string.
+ impl<'de> Visitor<'de> for VersionVisitor {
+ type Value = Version;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("a SemVer version as a string")
+ }
+
+ fn visit_str<E>(self, v: &str) -> result::Result<Self::Value, E>
+ where E: de::Error
+ {
+ Version::parse(v).map_err(de::Error::custom)
+ }
+ }
+
+ deserializer.deserialize_str(VersionVisitor)
+ }
+}
+
+/// An error type for this crate
+///
+/// Currently, just a generic error. Will make this nicer later.
+#[derive(Clone,PartialEq,Debug,PartialOrd)]
+pub enum SemVerError {
+ /// An error ocurred while parsing.
+ ParseError(String),
+}
+
+impl fmt::Display for SemVerError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ &SemVerError::ParseError(ref m) => write!(f, "{}", m),
+ }
+ }
+}
+
+impl Error for SemVerError {
+ fn description(&self) -> &str {
+ match self {
+ &SemVerError::ParseError(ref m) => m,
+ }
+ }
+}
+
+/// A Result type for errors
+pub type Result<T> = result::Result<T, SemVerError>;
+
+impl Version {
+
+ /// Contructs the simple case without pre or build.
+ pub fn new(major: u64, minor: u64, patch: u64) -> Version {
+ Version {
+ major: major,
+ minor: minor,
+ patch: patch,
+ pre: Vec::new(),
+ build: Vec::new()
+ }
+ }
+
+ /// Parse a string into a semver object.
+ pub fn parse(version: &str) -> Result<Version> {
+ let res = semver_parser::version::parse(version);
+
+ match res {
+ // Convert plain String error into proper ParseError
+ Err(e) => Err(SemVerError::ParseError(e)),
+ Ok(v) => Ok(From::from(v)),
+ }
+ }
+
+ /// Clears the build metadata
+ fn clear_metadata(&mut self) {
+ self.build = Vec::new();
+ self.pre = Vec::new();
+ }
+
+ /// Increments the patch number for this Version (Must be mutable)
+ pub fn increment_patch(&mut self) {
+ self.patch += 1;
+ self.clear_metadata();
+ }
+
+ /// Increments the minor version number for this Version (Must be mutable)
+ ///
+ /// As instructed by section 7 of the spec, the patch number is reset to 0.
+ pub fn increment_minor(&mut self) {
+ self.minor += 1;
+ self.patch = 0;
+ self.clear_metadata();
+ }
+
+ /// Increments the major version number for this Version (Must be mutable)
+ ///
+ /// As instructed by section 8 of the spec, the minor and patch numbers are
+ /// reset to 0
+ pub fn increment_major(&mut self) {
+ self.major += 1;
+ self.minor = 0;
+ self.patch = 0;
+ self.clear_metadata();
+ }
+
+ /// Checks to see if the current Version is in pre-release status
+ pub fn is_prerelease(&self) -> bool {
+ !self.pre.is_empty()
+ }
+}
+
+impl str::FromStr for Version {
+ type Err = SemVerError;
+
+ fn from_str(s: &str) -> Result<Version> {
+ Version::parse(s)
+ }
+}
+
+impl fmt::Display for Version {
+ #[inline]
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ try!(write!(f, "{}.{}.{}", self.major, self.minor, self.patch));
+ if !self.pre.is_empty() {
+ try!(write!(f, "-"));
+ for (i, x) in self.pre.iter().enumerate() {
+ if i != 0 {
+ try!(write!(f, "."))
+ }
+ try!(write!(f, "{}", x));
+ }
+ }
+ if !self.build.is_empty() {
+ try!(write!(f, "+"));
+ for (i, x) in self.build.iter().enumerate() {
+ if i != 0 {
+ try!(write!(f, "."))
+ }
+ try!(write!(f, "{}", x));
+ }
+ }
+ Ok(())
+ }
+}
+
+impl cmp::PartialEq for Version {
+ #[inline]
+ fn eq(&self, other: &Version) -> bool {
+ // We should ignore build metadata here, otherwise versions v1 and v2
+ // can exist such that !(v1 < v2) && !(v1 > v2) && v1 != v2, which
+ // violate strict total ordering rules.
+ self.major == other.major && self.minor == other.minor && self.patch == other.patch &&
+ self.pre == other.pre
+ }
+}
+
+impl cmp::PartialOrd for Version {
+ fn partial_cmp(&self, other: &Version) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+impl cmp::Ord for Version {
+ fn cmp(&self, other: &Version) -> Ordering {
+ match self.major.cmp(&other.major) {
+ Ordering::Equal => {}
+ r => return r,
+ }
+
+ match self.minor.cmp(&other.minor) {
+ Ordering::Equal => {}
+ r => return r,
+ }
+
+ match self.patch.cmp(&other.patch) {
+ Ordering::Equal => {}
+ r => return r,
+ }
+
+ // NB: semver spec says 0.0.0-pre < 0.0.0
+ // but the version of ord defined for vec
+ // says that [] < [pre] so we alter it here
+ match (self.pre.len(), other.pre.len()) {
+ (0, 0) => Ordering::Equal,
+ (0, _) => Ordering::Greater,
+ (_, 0) => Ordering::Less,
+ (_, _) => self.pre.cmp(&other.pre),
+ }
+ }
+}
+
+impl hash::Hash for Version {
+ fn hash<H: hash::Hasher>(&self, into: &mut H) {
+ self.major.hash(into);
+ self.minor.hash(into);
+ self.patch.hash(into);
+ self.pre.hash(into);
+ }
+}
+
+impl From<(u64,u64,u64)> for Version {
+ fn from(tuple: (u64,u64,u64)) -> Version {
+ let (major, minor, patch) = tuple;
+ Version::new(major, minor, patch)
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use std::result;
+ use super::Version;
+ use super::Identifier;
+ use super::SemVerError;
+
+ #[test]
+ fn test_parse() {
+ fn parse_error(e: &str) -> result::Result<Version, SemVerError> {
+ return Err(SemVerError::ParseError(e.to_string()));
+ }
+
+ assert_eq!(Version::parse(""),
+ parse_error("Error parsing major identifier"));
+ assert_eq!(Version::parse(" "),
+ parse_error("Error parsing major identifier"));
+ assert_eq!(Version::parse("1"),
+ parse_error("Expected dot"));
+ assert_eq!(Version::parse("1.2"),
+ parse_error("Expected dot"));
+ assert_eq!(Version::parse("1.2.3-"),
+ parse_error("Error parsing prerelease"));
+ assert_eq!(Version::parse("a.b.c"),
+ parse_error("Error parsing major identifier"));
+ assert_eq!(Version::parse("1.2.3 abc"),
+ parse_error("Extra junk after valid version: abc"));
+
+ assert_eq!(Version::parse("1.2.3"),
+ Ok(Version {
+ major: 1,
+ minor: 2,
+ patch: 3,
+ pre: Vec::new(),
+ build: Vec::new(),
+ }));
+
+ assert_eq!(Version::parse("1.2.3"),
+ Ok(Version::new(1,2,3)));
+
+ assert_eq!(Version::parse(" 1.2.3 "),
+ Ok(Version {
+ major: 1,
+ minor: 2,
+ patch: 3,
+ pre: Vec::new(),
+ build: Vec::new(),
+ }));
+ assert_eq!(Version::parse("1.2.3-alpha1"),
+ Ok(Version {
+ major: 1,
+ minor: 2,
+ patch: 3,
+ pre: vec![Identifier::AlphaNumeric(String::from("alpha1"))],
+ build: Vec::new(),
+ }));
+ assert_eq!(Version::parse(" 1.2.3-alpha1 "),
+ Ok(Version {
+ major: 1,
+ minor: 2,
+ patch: 3,
+ pre: vec![Identifier::AlphaNumeric(String::from("alpha1"))],
+ build: Vec::new(),
+ }));
+ assert_eq!(Version::parse("1.2.3+build5"),
+ Ok(Version {
+ major: 1,
+ minor: 2,
+ patch: 3,
+ pre: Vec::new(),
+ build: vec![Identifier::AlphaNumeric(String::from("build5"))],
+ }));
+ assert_eq!(Version::parse(" 1.2.3+build5 "),
+ Ok(Version {
+ major: 1,
+ minor: 2,
+ patch: 3,
+ pre: Vec::new(),
+ build: vec![Identifier::AlphaNumeric(String::from("build5"))],
+ }));
+ assert_eq!(Version::parse("1.2.3-alpha1+build5"),
+ Ok(Version {
+ major: 1,
+ minor: 2,
+ patch: 3,
+ pre: vec![Identifier::AlphaNumeric(String::from("alpha1"))],
+ build: vec![Identifier::AlphaNumeric(String::from("build5"))],
+ }));
+ assert_eq!(Version::parse(" 1.2.3-alpha1+build5 "),
+ Ok(Version {
+ major: 1,
+ minor: 2,
+ patch: 3,
+ pre: vec![Identifier::AlphaNumeric(String::from("alpha1"))],
+ build: vec![Identifier::AlphaNumeric(String::from("build5"))],
+ }));
+ assert_eq!(Version::parse("1.2.3-1.alpha1.9+build5.7.3aedf "),
+ Ok(Version {
+ major: 1,
+ minor: 2,
+ patch: 3,
+ pre: vec![Identifier::Numeric(1),
+ Identifier::AlphaNumeric(String::from("alpha1")),
+ Identifier::Numeric(9),
+ ],
+ build: vec![Identifier::AlphaNumeric(String::from("build5")),
+ Identifier::Numeric(7),
+ Identifier::AlphaNumeric(String::from("3aedf")),
+ ],
+ }));
+ assert_eq!(Version::parse("0.4.0-beta.1+0851523"),
+ Ok(Version {
+ major: 0,
+ minor: 4,
+ patch: 0,
+ pre: vec![Identifier::AlphaNumeric(String::from("beta")),
+ Identifier::Numeric(1),
+ ],
+ build: vec![Identifier::AlphaNumeric(String::from("0851523"))],
+ }));
+
+ }
+
+ #[test]
+ fn test_increment_patch() {
+ let mut buggy_release = Version::parse("0.1.0").unwrap();
+ buggy_release.increment_patch();
+ assert_eq!(buggy_release, Version::parse("0.1.1").unwrap());
+ }
+
+ #[test]
+ fn test_increment_minor() {
+ let mut feature_release = Version::parse("1.4.6").unwrap();
+ feature_release.increment_minor();
+ assert_eq!(feature_release, Version::parse("1.5.0").unwrap());
+ }
+
+ #[test]
+ fn test_increment_major() {
+ let mut chrome_release = Version::parse("46.1.246773").unwrap();
+ chrome_release.increment_major();
+ assert_eq!(chrome_release, Version::parse("47.0.0").unwrap());
+ }
+
+ #[test]
+ fn test_increment_keep_prerelease() {
+ let mut release = Version::parse("1.0.0-alpha").unwrap();
+ release.increment_patch();
+
+ assert_eq!(release, Version::parse("1.0.1").unwrap());
+
+ release.increment_minor();
+
+ assert_eq!(release, Version::parse("1.1.0").unwrap());
+
+ release.increment_major();
+
+ assert_eq!(release, Version::parse("2.0.0").unwrap());
+ }
+
+
+ #[test]
+ fn test_increment_clear_metadata() {
+ let mut release = Version::parse("1.0.0+4442").unwrap();
+ release.increment_patch();
+
+ assert_eq!(release, Version::parse("1.0.1").unwrap());
+ release = Version::parse("1.0.1+hello").unwrap();
+
+ release.increment_minor();
+
+ assert_eq!(release, Version::parse("1.1.0").unwrap());
+ release = Version::parse("1.1.3747+hello").unwrap();
+
+ release.increment_major();
+
+ assert_eq!(release, Version::parse("2.0.0").unwrap());
+ }
+
+ #[test]
+ fn test_eq() {
+ assert_eq!(Version::parse("1.2.3"), Version::parse("1.2.3"));
+ assert_eq!(Version::parse("1.2.3-alpha1"),
+ Version::parse("1.2.3-alpha1"));
+ assert_eq!(Version::parse("1.2.3+build.42"),
+ Version::parse("1.2.3+build.42"));
+ assert_eq!(Version::parse("1.2.3-alpha1+42"),
+ Version::parse("1.2.3-alpha1+42"));
+ assert_eq!(Version::parse("1.2.3+23"), Version::parse("1.2.3+42"));
+ }
+
+ #[test]
+ fn test_ne() {
+ assert!(Version::parse("0.0.0") != Version::parse("0.0.1"));
+ assert!(Version::parse("0.0.0") != Version::parse("0.1.0"));
+ assert!(Version::parse("0.0.0") != Version::parse("1.0.0"));
+ assert!(Version::parse("1.2.3-alpha") != Version::parse("1.2.3-beta"));
+ }
+
+ #[test]
+ fn test_show() {
+ assert_eq!(format!("{}", Version::parse("1.2.3").unwrap()),
+ "1.2.3".to_string());
+ assert_eq!(format!("{}", Version::parse("1.2.3-alpha1").unwrap()),
+ "1.2.3-alpha1".to_string());
+ assert_eq!(format!("{}", Version::parse("1.2.3+build.42").unwrap()),
+ "1.2.3+build.42".to_string());
+ assert_eq!(format!("{}", Version::parse("1.2.3-alpha1+42").unwrap()),
+ "1.2.3-alpha1+42".to_string());
+ }
+
+ #[test]
+ fn test_to_string() {
+ assert_eq!(Version::parse("1.2.3").unwrap().to_string(),
+ "1.2.3".to_string());
+ assert_eq!(Version::parse("1.2.3-alpha1").unwrap().to_string(),
+ "1.2.3-alpha1".to_string());
+ assert_eq!(Version::parse("1.2.3+build.42").unwrap().to_string(),
+ "1.2.3+build.42".to_string());
+ assert_eq!(Version::parse("1.2.3-alpha1+42").unwrap().to_string(),
+ "1.2.3-alpha1+42".to_string());
+ }
+
+ #[test]
+ fn test_lt() {
+ assert!(Version::parse("0.0.0") < Version::parse("1.2.3-alpha2"));
+ assert!(Version::parse("1.0.0") < Version::parse("1.2.3-alpha2"));
+ assert!(Version::parse("1.2.0") < Version::parse("1.2.3-alpha2"));
+ assert!(Version::parse("1.2.3-alpha1") < Version::parse("1.2.3"));
+ assert!(Version::parse("1.2.3-alpha1") < Version::parse("1.2.3-alpha2"));
+ assert!(!(Version::parse("1.2.3-alpha2") < Version::parse("1.2.3-alpha2")));
+ assert!(!(Version::parse("1.2.3+23") < Version::parse("1.2.3+42")));
+ }
+
+ #[test]
+ fn test_le() {
+ assert!(Version::parse("0.0.0") <= Version::parse("1.2.3-alpha2"));
+ assert!(Version::parse("1.0.0") <= Version::parse("1.2.3-alpha2"));
+ assert!(Version::parse("1.2.0") <= Version::parse("1.2.3-alpha2"));
+ assert!(Version::parse("1.2.3-alpha1") <= Version::parse("1.2.3-alpha2"));
+ assert!(Version::parse("1.2.3-alpha2") <= Version::parse("1.2.3-alpha2"));
+ assert!(Version::parse("1.2.3+23") <= Version::parse("1.2.3+42"));
+ }
+
+ #[test]
+ fn test_gt() {
+ assert!(Version::parse("1.2.3-alpha2") > Version::parse("0.0.0"));
+ assert!(Version::parse("1.2.3-alpha2") > Version::parse("1.0.0"));
+ assert!(Version::parse("1.2.3-alpha2") > Version::parse("1.2.0"));
+ assert!(Version::parse("1.2.3-alpha2") > Version::parse("1.2.3-alpha1"));
+ assert!(Version::parse("1.2.3") > Version::parse("1.2.3-alpha2"));
+ assert!(!(Version::parse("1.2.3-alpha2") > Version::parse("1.2.3-alpha2")));
+ assert!(!(Version::parse("1.2.3+23") > Version::parse("1.2.3+42")));
+ }
+
+ #[test]
+ fn test_ge() {
+ assert!(Version::parse("1.2.3-alpha2") >= Version::parse("0.0.0"));
+ assert!(Version::parse("1.2.3-alpha2") >= Version::parse("1.0.0"));
+ assert!(Version::parse("1.2.3-alpha2") >= Version::parse("1.2.0"));
+ assert!(Version::parse("1.2.3-alpha2") >= Version::parse("1.2.3-alpha1"));
+ assert!(Version::parse("1.2.3-alpha2") >= Version::parse("1.2.3-alpha2"));
+ assert!(Version::parse("1.2.3+23") >= Version::parse("1.2.3+42"));
+ }
+
+ #[test]
+ fn test_prerelease_check() {
+ assert!(Version::parse("1.0.0").unwrap().is_prerelease() == false);
+ assert!(Version::parse("0.0.1").unwrap().is_prerelease() == false);
+ assert!(Version::parse("4.1.4-alpha").unwrap().is_prerelease());
+ assert!(Version::parse("1.0.0-beta294296").unwrap().is_prerelease());
+ }
+
+ #[test]
+ fn test_spec_order() {
+ let vs = ["1.0.0-alpha",
+ "1.0.0-alpha.1",
+ "1.0.0-alpha.beta",
+ "1.0.0-beta",
+ "1.0.0-beta.2",
+ "1.0.0-beta.11",
+ "1.0.0-rc.1",
+ "1.0.0"];
+ let mut i = 1;
+ while i < vs.len() {
+ let a = Version::parse(vs[i - 1]);
+ let b = Version::parse(vs[i]);
+ assert!(a < b, "nope {:?} < {:?}", a, b);
+ i += 1;
+ }
+ }
+
+ #[test]
+ fn test_from_str() {
+ assert_eq!("1.2.3".parse(),
+ Ok(Version {
+ major: 1,
+ minor: 2,
+ patch: 3,
+ pre: Vec::new(),
+ build: Vec::new(),
+ }));
+ assert_eq!(" 1.2.3 ".parse(),
+ Ok(Version {
+ major: 1,
+ minor: 2,
+ patch: 3,
+ pre: Vec::new(),
+ build: Vec::new(),
+ }));
+ assert_eq!("1.2.3-alpha1".parse(),
+ Ok(Version {
+ major: 1,
+ minor: 2,
+ patch: 3,
+ pre: vec![Identifier::AlphaNumeric(String::from("alpha1"))],
+ build: Vec::new(),
+ }));
+ assert_eq!(" 1.2.3-alpha1 ".parse(),
+ Ok(Version {
+ major: 1,
+ minor: 2,
+ patch: 3,
+ pre: vec![Identifier::AlphaNumeric(String::from("alpha1"))],
+ build: Vec::new(),
+ }));
+ assert_eq!("1.2.3+build5".parse(),
+ Ok(Version {
+ major: 1,
+ minor: 2,
+ patch: 3,
+ pre: Vec::new(),
+ build: vec![Identifier::AlphaNumeric(String::from("build5"))],
+ }));
+ assert_eq!(" 1.2.3+build5 ".parse(),
+ Ok(Version {
+ major: 1,
+ minor: 2,
+ patch: 3,
+ pre: Vec::new(),
+ build: vec![Identifier::AlphaNumeric(String::from("build5"))],
+ }));
+ assert_eq!("1.2.3-alpha1+build5".parse(),
+ Ok(Version {
+ major: 1,
+ minor: 2,
+ patch: 3,
+ pre: vec![Identifier::AlphaNumeric(String::from("alpha1"))],
+ build: vec![Identifier::AlphaNumeric(String::from("build5"))],
+ }));
+ assert_eq!(" 1.2.3-alpha1+build5 ".parse(),
+ Ok(Version {
+ major: 1,
+ minor: 2,
+ patch: 3,
+ pre: vec![Identifier::AlphaNumeric(String::from("alpha1"))],
+ build: vec![Identifier::AlphaNumeric(String::from("build5"))],
+ }));
+ assert_eq!("1.2.3-1.alpha1.9+build5.7.3aedf ".parse(),
+ Ok(Version {
+ major: 1,
+ minor: 2,
+ patch: 3,
+ pre: vec![Identifier::Numeric(1),
+ Identifier::AlphaNumeric(String::from("alpha1")),
+ Identifier::Numeric(9),
+ ],
+ build: vec![Identifier::AlphaNumeric(String::from("build5")),
+ Identifier::Numeric(7),
+ Identifier::AlphaNumeric(String::from("3aedf")),
+ ],
+ }));
+ assert_eq!("0.4.0-beta.1+0851523".parse(),
+ Ok(Version {
+ major: 0,
+ minor: 4,
+ patch: 0,
+ pre: vec![Identifier::AlphaNumeric(String::from("beta")),
+ Identifier::Numeric(1),
+ ],
+ build: vec![Identifier::AlphaNumeric(String::from("0851523"))],
+ }));
+
+ }
+
+ #[test]
+ fn test_from_str_errors() {
+ fn parse_error(e: &str) -> result::Result<Version, SemVerError> {
+ return Err(SemVerError::ParseError(e.to_string()));
+ }
+
+ assert_eq!("".parse(), parse_error("Error parsing major identifier"));
+ assert_eq!(" ".parse(), parse_error("Error parsing major identifier"));
+ assert_eq!("1".parse(), parse_error("Expected dot"));
+ assert_eq!("1.2".parse(),
+ parse_error("Expected dot"));
+ assert_eq!("1.2.3-".parse(),
+ parse_error("Error parsing prerelease"));
+ assert_eq!("a.b.c".parse(),
+ parse_error("Error parsing major identifier"));
+ assert_eq!("1.2.3 abc".parse(),
+ parse_error("Extra junk after valid version: abc"));
+ }
+}
diff --git a/semver/src/version_req.rs b/semver/src/version_req.rs
new file mode 100644
index 0000000..6e6a542
--- /dev/null
+++ b/semver/src/version_req.rs
@@ -0,0 +1,895 @@
+// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::error::Error;
+use std::fmt;
+use std::result;
+use std::str;
+
+use Version;
+use version::Identifier;
+use semver_parser;
+
+#[cfg(feature = "serde")]
+use serde::ser::{Serialize, Serializer};
+#[cfg(feature = "serde")]
+use serde::de::{self, Deserialize, Deserializer, Visitor};
+
+use self::Op::{Ex, Gt, GtEq, Lt, LtEq, Tilde, Compatible, Wildcard};
+use self::WildcardVersion::{Major, Minor, Patch};
+use self::ReqParseError::*;
+
+/// A `VersionReq` is a struct containing a list of predicates that can apply to ranges of version
+/// numbers. Matching operations can then be done with the `VersionReq` against a particular
+/// version to see if it satisfies some or all of the constraints.
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+pub struct VersionReq {
+ predicates: Vec<Predicate>,
+}
+
+impl From<semver_parser::range::VersionReq> for VersionReq {
+ fn from(other: semver_parser::range::VersionReq) -> VersionReq {
+ VersionReq { predicates: other.predicates.into_iter().map(From::from).collect() }
+ }
+}
+
+#[cfg(feature = "serde")]
+impl Serialize for VersionReq {
+ fn serialize<S>(&self, serializer: S) -> result::Result<S::Ok, S::Error>
+ where S: Serializer
+ {
+ // Serialize VersionReq as a string.
+ serializer.collect_str(self)
+ }
+}
+
+#[cfg(feature = "serde")]
+impl<'de> Deserialize<'de> for VersionReq {
+ fn deserialize<D>(deserializer: D) -> result::Result<Self, D::Error>
+ where D: Deserializer<'de>
+ {
+ struct VersionReqVisitor;
+
+ /// Deserialize `VersionReq` from a string.
+ impl<'de> Visitor<'de> for VersionReqVisitor {
+ type Value = VersionReq;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("a SemVer version requirement as a string")
+ }
+
+ fn visit_str<E>(self, v: &str) -> result::Result<Self::Value, E>
+ where E: de::Error
+ {
+ VersionReq::parse(v).map_err(de::Error::custom)
+ }
+ }
+
+ deserializer.deserialize_str(VersionReqVisitor)
+ }
+}
+
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+enum WildcardVersion {
+ Major,
+ Minor,
+ Patch,
+}
+
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+enum Op {
+ Ex, // Exact
+ Gt, // Greater than
+ GtEq, // Greater than or equal to
+ Lt, // Less than
+ LtEq, // Less than or equal to
+ Tilde, // e.g. ~1.0.0
+ Compatible, // compatible by definition of semver, indicated by ^
+ Wildcard(WildcardVersion), // x.y.*, x.*, *
+}
+
+impl From<semver_parser::range::Op> for Op {
+ fn from(other: semver_parser::range::Op) -> Op {
+ use semver_parser::range;
+ match other {
+ range::Op::Ex => Op::Ex,
+ range::Op::Gt => Op::Gt,
+ range::Op::GtEq => Op::GtEq,
+ range::Op::Lt => Op::Lt,
+ range::Op::LtEq => Op::LtEq,
+ range::Op::Tilde => Op::Tilde,
+ range::Op::Compatible => Op::Compatible,
+ range::Op::Wildcard(version) => {
+ match version {
+ range::WildcardVersion::Major => Op::Wildcard(WildcardVersion::Major),
+ range::WildcardVersion::Minor => Op::Wildcard(WildcardVersion::Minor),
+ range::WildcardVersion::Patch => Op::Wildcard(WildcardVersion::Patch),
+ }
+ }
+ }
+ }
+}
+
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+struct Predicate {
+ op: Op,
+ major: u64,
+ minor: Option<u64>,
+ patch: Option<u64>,
+ pre: Vec<Identifier>,
+}
+
+impl From<semver_parser::range::Predicate> for Predicate {
+ fn from(other: semver_parser::range::Predicate) -> Predicate {
+ Predicate {
+ op: From::from(other.op),
+ major: other.major,
+ minor: other.minor,
+ patch: other.patch,
+ pre: other.pre.into_iter().map(From::from).collect(),
+ }
+ }
+}
+
+/// A `ReqParseError` is returned from methods which parse a string into a `VersionReq`. Each
+/// enumeration is one of the possible errors that can occur.
+#[derive(Clone, Debug, PartialEq)]
+pub enum ReqParseError {
+ /// The given version requirement is invalid.
+ InvalidVersionRequirement,
+ /// You have already provided an operation, such as `=`, `~`, or `^`. Only use one.
+ OpAlreadySet,
+ /// The sigil you have written is not correct.
+ InvalidSigil,
+ /// All components of a version must be numeric.
+ VersionComponentsMustBeNumeric,
+ /// There was an error parsing an identifier.
+ InvalidIdentifier,
+ /// At least a major version is required.
+ MajorVersionRequired,
+ /// An unimplemented version requirement.
+ UnimplementedVersionRequirement,
+ /// This form of requirement is deprecated.
+ DeprecatedVersionRequirement(VersionReq),
+}
+
+impl fmt::Display for ReqParseError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ self.description().fmt(f)
+ }
+}
+
+impl Error for ReqParseError {
+ fn description(&self) -> &str {
+ match self {
+ &InvalidVersionRequirement => "the given version requirement is invalid",
+ &OpAlreadySet => {
+ "you have already provided an operation, such as =, ~, or ^; only use one"
+ },
+ &InvalidSigil => "the sigil you have written is not correct",
+ &VersionComponentsMustBeNumeric => "version components must be numeric",
+ &InvalidIdentifier => "invalid identifier",
+ &MajorVersionRequired => "at least a major version number is required",
+ &UnimplementedVersionRequirement => {
+ "the given version requirement is not implemented, yet"
+ },
+ &DeprecatedVersionRequirement(_) => "This requirement is deprecated",
+ }
+ }
+}
+
+impl From<String> for ReqParseError {
+ fn from(other: String) -> ReqParseError {
+ match &*other {
+ "Null is not a valid VersionReq" => ReqParseError::InvalidVersionRequirement,
+ "VersionReq did not parse properly." => ReqParseError::OpAlreadySet,
+ _ => ReqParseError::InvalidVersionRequirement,
+ }
+ }
+}
+
+impl VersionReq {
+ /// `any()` is a factory method which creates a `VersionReq` with no constraints. In other
+ /// words, any version will match against it.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use semver::VersionReq;
+ ///
+ /// let anything = VersionReq::any();
+ /// ```
+ pub fn any() -> VersionReq {
+ VersionReq { predicates: vec![] }
+ }
+
+ /// `parse()` is the main constructor of a `VersionReq`. It takes a string like `"^1.2.3"`
+ /// and turns it into a `VersionReq` that matches that particular constraint.
+ ///
+ /// A `Result` is returned which contains a `ReqParseError` if there was a problem parsing the
+ /// `VersionReq`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use semver::VersionReq;
+ ///
+ /// let version = VersionReq::parse("=1.2.3");
+ /// let version = VersionReq::parse(">1.2.3");
+ /// let version = VersionReq::parse("<1.2.3");
+ /// let version = VersionReq::parse("~1.2.3");
+ /// let version = VersionReq::parse("^1.2.3");
+ /// let version = VersionReq::parse("1.2.3"); // synonym for ^1.2.3
+ /// let version = VersionReq::parse("<=1.2.3");
+ /// let version = VersionReq::parse(">=1.2.3");
+ /// ```
+ ///
+ /// This example demonstrates error handling, and will panic.
+ ///
+ /// ```should-panic
+ /// use semver::VersionReq;
+ ///
+ /// let version = match VersionReq::parse("not a version") {
+ /// Ok(version) => version,
+ /// Err(e) => panic!("There was a problem parsing: {}", e),
+ /// }
+ /// ```
+ pub fn parse(input: &str) -> Result<VersionReq, ReqParseError> {
+ let res = semver_parser::range::parse(input);
+
+ if let Ok(v) = res {
+ return Ok(From::from(v));
+ }
+
+ return match VersionReq::parse_deprecated(input) {
+ Some(v) => {
+ Err(ReqParseError::DeprecatedVersionRequirement(v))
+ }
+ None => Err(From::from(res.err().unwrap())),
+ }
+ }
+
+ fn parse_deprecated(version: &str) -> Option<VersionReq> {
+ return match version {
+ ".*" => Some(VersionReq::any()),
+ "0.1.0." => Some(VersionReq::parse("0.1.0").unwrap()),
+ "0.3.1.3" => Some(VersionReq::parse("0.3.13").unwrap()),
+ "0.2*" => Some(VersionReq::parse("0.2.*").unwrap()),
+ "*.0" => Some(VersionReq::any()),
+ _ => None,
+ }
+ }
+
+ /// `exact()` is a factory method which creates a `VersionReq` with one exact constraint.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use semver::VersionReq;
+ /// use semver::Version;
+ ///
+ /// let version = Version { major: 1, minor: 1, patch: 1, pre: vec![], build: vec![] };
+ /// let exact = VersionReq::exact(&version);
+ /// ```
+ pub fn exact(version: &Version) -> VersionReq {
+ VersionReq { predicates: vec![Predicate::exact(version)] }
+ }
+
+ /// `matches()` matches a given `Version` against this `VersionReq`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use semver::VersionReq;
+ /// use semver::Version;
+ ///
+ /// let version = Version { major: 1, minor: 1, patch: 1, pre: vec![], build: vec![] };
+ /// let exact = VersionReq::exact(&version);
+ ///
+ /// assert!(exact.matches(&version));
+ /// ```
+ pub fn matches(&self, version: &Version) -> bool {
+ // no predicates means anything matches
+ if self.predicates.is_empty() {
+ return true;
+ }
+
+ self.predicates.iter().all(|p| p.matches(version)) &&
+ self.predicates.iter().any(|p| p.pre_tag_is_compatible(version))
+ }
+}
+
+impl str::FromStr for VersionReq {
+ type Err = ReqParseError;
+
+ fn from_str(s: &str) -> Result<VersionReq, ReqParseError> {
+ VersionReq::parse(s)
+ }
+}
+
+impl Predicate {
+ fn exact(version: &Version) -> Predicate {
+ Predicate {
+ op: Ex,
+ major: version.major,
+ minor: Some(version.minor),
+ patch: Some(version.patch),
+ pre: version.pre.clone(),
+ }
+ }
+
+ /// `matches()` takes a `Version` and determines if it matches this particular `Predicate`.
+ pub fn matches(&self, ver: &Version) -> bool {
+ match self.op {
+ Ex => self.is_exact(ver),
+ Gt => self.is_greater(ver),
+ GtEq => self.is_exact(ver) || self.is_greater(ver),
+ Lt => !self.is_exact(ver) && !self.is_greater(ver),
+ LtEq => !self.is_greater(ver),
+ Tilde => self.matches_tilde(ver),
+ Compatible => self.is_compatible(ver),
+ Wildcard(_) => self.matches_wildcard(ver),
+ }
+ }
+
+ fn is_exact(&self, ver: &Version) -> bool {
+ if self.major != ver.major {
+ return false;
+ }
+
+ match self.minor {
+ Some(minor) => {
+ if minor != ver.minor {
+ return false;
+ }
+ }
+ None => return true,
+ }
+
+ match self.patch {
+ Some(patch) => {
+ if patch != ver.patch {
+ return false;
+ }
+ }
+ None => return true,
+ }
+
+ if self.pre != ver.pre {
+ return false;
+ }
+
+ true
+ }
+
+ // https://docs.npmjs.com/misc/semver#prerelease-tags
+ fn pre_tag_is_compatible(&self, ver: &Version) -> bool {
+ // If a version has a prerelease tag (for example, 1.2.3-alpha.3) then it will
+ // only be
+ // allowed to satisfy comparator sets if at least one comparator with the same
+ // [major,
+ // minor, patch] tuple also has a prerelease tag.
+ !ver.is_prerelease() ||
+ (self.major == ver.major && self.minor == Some(ver.minor) &&
+ self.patch == Some(ver.patch) && !self.pre.is_empty())
+ }
+
+ fn is_greater(&self, ver: &Version) -> bool {
+ if self.major != ver.major {
+ return ver.major > self.major;
+ }
+
+ match self.minor {
+ Some(minor) => {
+ if minor != ver.minor {
+ return ver.minor > minor;
+ }
+ }
+ None => return false,
+ }
+
+ match self.patch {
+ Some(patch) => {
+ if patch != ver.patch {
+ return ver.patch > patch;
+ }
+ }
+ None => return false,
+ }
+
+ if !self.pre.is_empty() {
+ return ver.pre.is_empty() || ver.pre > self.pre;
+ }
+
+ false
+ }
+
+ // see https://www.npmjs.org/doc/misc/semver.html for behavior
+ fn matches_tilde(&self, ver: &Version) -> bool {
+ let minor = match self.minor {
+ Some(n) => n,
+ None => return self.major == ver.major,
+ };
+
+ match self.patch {
+ Some(patch) => {
+ self.major == ver.major && minor == ver.minor &&
+ (ver.patch > patch || (ver.patch == patch && self.pre_is_compatible(ver)))
+ }
+ None => self.major == ver.major && minor == ver.minor,
+ }
+ }
+
+ // see https://www.npmjs.org/doc/misc/semver.html for behavior
+ fn is_compatible(&self, ver: &Version) -> bool {
+ if self.major != ver.major {
+ return false;
+ }
+
+ let minor = match self.minor {
+ Some(n) => n,
+ None => return self.major == ver.major,
+ };
+
+ match self.patch {
+ Some(patch) => {
+ if self.major == 0 {
+ if minor == 0 {
+ ver.minor == minor && ver.patch == patch && self.pre_is_compatible(ver)
+ } else {
+ ver.minor == minor &&
+ (ver.patch > patch || (ver.patch == patch && self.pre_is_compatible(ver)))
+ }
+ } else {
+ ver.minor > minor ||
+ (ver.minor == minor &&
+ (ver.patch > patch || (ver.patch == patch && self.pre_is_compatible(ver))))
+ }
+ }
+ None => {
+ if self.major == 0 {
+ ver.minor == minor
+ } else {
+ ver.minor >= minor
+ }
+ }
+ }
+ }
+
+ fn pre_is_compatible(&self, ver: &Version) -> bool {
+ ver.pre.is_empty() || ver.pre >= self.pre
+ }
+
+ // see https://www.npmjs.org/doc/misc/semver.html for behavior
+ fn matches_wildcard(&self, ver: &Version) -> bool {
+ match self.op {
+ Wildcard(Major) => true,
+ Wildcard(Minor) => self.major == ver.major,
+ Wildcard(Patch) => {
+ match self.minor {
+ Some(minor) => self.major == ver.major && minor == ver.minor,
+ None => {
+ // minor and patch version astericks mean match on major
+ self.major == ver.major
+ }
+ }
+ }
+ _ => false, // unreachable
+ }
+ }
+}
+
+impl fmt::Display for VersionReq {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ if self.predicates.is_empty() {
+ try!(write!(fmt, "*"));
+ } else {
+ for (i, ref pred) in self.predicates.iter().enumerate() {
+ if i == 0 {
+ try!(write!(fmt, "{}", pred));
+ } else {
+ try!(write!(fmt, ", {}", pred));
+ }
+ }
+ }
+
+ Ok(())
+ }
+}
+
+impl fmt::Display for Predicate {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ match self.op {
+ Wildcard(Major) => try!(write!(fmt, "*")),
+ Wildcard(Minor) => try!(write!(fmt, "{}.*", self.major)),
+ Wildcard(Patch) => {
+ if let Some(minor) = self.minor {
+ try!(write!(fmt, "{}.{}.*", self.major, minor))
+ } else {
+ try!(write!(fmt, "{}.*.*", self.major))
+ }
+ }
+ _ => {
+ try!(write!(fmt, "{}{}", self.op, self.major));
+
+ match self.minor {
+ Some(v) => try!(write!(fmt, ".{}", v)),
+ None => (),
+ }
+
+ match self.patch {
+ Some(v) => try!(write!(fmt, ".{}", v)),
+ None => (),
+ }
+
+ if !self.pre.is_empty() {
+ try!(write!(fmt, "-"));
+ for (i, x) in self.pre.iter().enumerate() {
+ if i != 0 {
+ try!(write!(fmt, "."))
+ }
+ try!(write!(fmt, "{}", x));
+ }
+ }
+ }
+ }
+
+ Ok(())
+ }
+}
+
+impl fmt::Display for Op {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ Ex => try!(write!(fmt, "= ")),
+ Gt => try!(write!(fmt, "> ")),
+ GtEq => try!(write!(fmt, ">= ")),
+ Lt => try!(write!(fmt, "< ")),
+ LtEq => try!(write!(fmt, "<= ")),
+ Tilde => try!(write!(fmt, "~")),
+ Compatible => try!(write!(fmt, "^")),
+ // gets handled specially in Predicate::fmt
+ Wildcard(_) => try!(write!(fmt, "")),
+ }
+ Ok(())
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::{VersionReq, Op};
+ use super::super::version::Version;
+ use std::hash::{Hash, Hasher};
+
+ fn req(s: &str) -> VersionReq {
+ VersionReq::parse(s).unwrap()
+ }
+
+ fn version(s: &str) -> Version {
+ match Version::parse(s) {
+ Ok(v) => v,
+ Err(e) => panic!("`{}` is not a valid version. Reason: {:?}", s, e),
+ }
+ }
+
+ fn assert_match(req: &VersionReq, vers: &[&str]) {
+ for ver in vers.iter() {
+ assert!(req.matches(&version(*ver)), "did not match {}", ver);
+ }
+ }
+
+ fn assert_not_match(req: &VersionReq, vers: &[&str]) {
+ for ver in vers.iter() {
+ assert!(!req.matches(&version(*ver)), "matched {}", ver);
+ }
+ }
+
+ fn calculate_hash<T: Hash>(t: T) -> u64 {
+ use std::collections::hash_map::DefaultHasher;
+
+ let mut s = DefaultHasher::new();
+ t.hash(&mut s);
+ s.finish()
+ }
+
+ #[test]
+ fn test_parsing_default() {
+ let r = req("1.0.0");
+
+ assert_eq!(r.to_string(), "^1.0.0".to_string());
+
+ assert_match(&r, &["1.0.0", "1.0.1"]);
+ assert_not_match(&r, &["0.9.9", "0.10.0", "0.1.0"]);
+ }
+
+ #[test]
+ fn test_parsing_exact() {
+ let r = req("=1.0.0");
+
+ assert!(r.to_string() == "= 1.0.0".to_string());
+ assert_eq!(r.to_string(), "= 1.0.0".to_string());
+
+ assert_match(&r, &["1.0.0"]);
+ assert_not_match(&r, &["1.0.1", "0.9.9", "0.10.0", "0.1.0", "1.0.0-pre"]);
+
+ let r = req("=0.9.0");
+
+ assert_eq!(r.to_string(), "= 0.9.0".to_string());
+
+ assert_match(&r, &["0.9.0"]);
+ assert_not_match(&r, &["0.9.1", "1.9.0", "0.0.9"]);
+
+ let r = req("=0.1.0-beta2.a");
+
+ assert_eq!(r.to_string(), "= 0.1.0-beta2.a".to_string());
+
+ assert_match(&r, &["0.1.0-beta2.a"]);
+ assert_not_match(&r, &["0.9.1", "0.1.0", "0.1.1-beta2.a", "0.1.0-beta2"]);
+ }
+
+ #[test]
+ fn test_parse_metadata_see_issue_88_see_issue_88() {
+ for op in &[Op::Compatible, Op::Ex, Op::Gt, Op::GtEq, Op::Lt, Op::LtEq, Op::Tilde] {
+ req(&format!("{} 1.2.3+meta", op));
+ }
+ }
+
+ #[test]
+ pub fn test_parsing_greater_than() {
+ let r = req(">= 1.0.0");
+
+ assert_eq!(r.to_string(), ">= 1.0.0".to_string());
+
+ assert_match(&r, &["1.0.0", "2.0.0"]);
+ assert_not_match(&r, &["0.1.0", "0.0.1", "1.0.0-pre", "2.0.0-pre"]);
+
+ let r = req(">= 2.1.0-alpha2");
+
+ assert_match(&r, &["2.1.0-alpha2", "2.1.0-alpha3", "2.1.0", "3.0.0"]);
+ assert_not_match(&r,
+ &["2.0.0", "2.1.0-alpha1", "2.0.0-alpha2", "3.0.0-alpha2"]);
+ }
+
+ #[test]
+ pub fn test_parsing_less_than() {
+ let r = req("< 1.0.0");
+
+ assert_eq!(r.to_string(), "< 1.0.0".to_string());
+
+ assert_match(&r, &["0.1.0", "0.0.1"]);
+ assert_not_match(&r, &["1.0.0", "1.0.0-beta", "1.0.1", "0.9.9-alpha"]);
+
+ let r = req("<= 2.1.0-alpha2");
+
+ assert_match(&r, &["2.1.0-alpha2", "2.1.0-alpha1", "2.0.0", "1.0.0"]);
+ assert_not_match(&r,
+ &["2.1.0", "2.2.0-alpha1", "2.0.0-alpha2", "1.0.0-alpha2"]);
+ }
+
+ #[test]
+ pub fn test_multiple() {
+ let r = req("> 0.0.9, <= 2.5.3");
+ assert_eq!(r.to_string(), "> 0.0.9, <= 2.5.3".to_string());
+ assert_match(&r, &["0.0.10", "1.0.0", "2.5.3"]);
+ assert_not_match(&r, &["0.0.8", "2.5.4"]);
+
+ let r = req("0.3.0, 0.4.0");
+ assert_eq!(r.to_string(), "^0.3.0, ^0.4.0".to_string());
+ assert_not_match(&r, &["0.0.8", "0.3.0", "0.4.0"]);
+
+ let r = req("<= 0.2.0, >= 0.5.0");
+ assert_eq!(r.to_string(), "<= 0.2.0, >= 0.5.0".to_string());
+ assert_not_match(&r, &["0.0.8", "0.3.0", "0.5.1"]);
+
+ let r = req("0.1.0, 0.1.4, 0.1.6");
+ assert_eq!(r.to_string(), "^0.1.0, ^0.1.4, ^0.1.6".to_string());
+ assert_match(&r, &["0.1.6", "0.1.9"]);
+ assert_not_match(&r, &["0.1.0", "0.1.4", "0.2.0"]);
+
+ assert!(VersionReq::parse("> 0.1.0,").is_err());
+ assert!(VersionReq::parse("> 0.3.0, ,").is_err());
+
+ let r = req(">=0.5.1-alpha3, <0.6");
+ assert_eq!(r.to_string(), ">= 0.5.1-alpha3, < 0.6".to_string());
+ assert_match(&r,
+ &["0.5.1-alpha3", "0.5.1-alpha4", "0.5.1-beta", "0.5.1", "0.5.5"]);
+ assert_not_match(&r,
+ &["0.5.1-alpha1", "0.5.2-alpha3", "0.5.5-pre", "0.5.0-pre"]);
+ assert_not_match(&r, &["0.6.0", "0.6.0-pre"]);
+ }
+
+ #[test]
+ pub fn test_parsing_tilde() {
+ let r = req("~1");
+ assert_match(&r, &["1.0.0", "1.0.1", "1.1.1"]);
+ assert_not_match(&r, &["0.9.1", "2.9.0", "0.0.9"]);
+
+ let r = req("~1.2");
+ assert_match(&r, &["1.2.0", "1.2.1"]);
+ assert_not_match(&r, &["1.1.1", "1.3.0", "0.0.9"]);
+
+ let r = req("~1.2.2");
+ assert_match(&r, &["1.2.2", "1.2.4"]);
+ assert_not_match(&r, &["1.2.1", "1.9.0", "1.0.9", "2.0.1", "0.1.3"]);
+
+ let r = req("~1.2.3-beta.2");
+ assert_match(&r, &["1.2.3", "1.2.4", "1.2.3-beta.2", "1.2.3-beta.4"]);
+ assert_not_match(&r, &["1.3.3", "1.1.4", "1.2.3-beta.1", "1.2.4-beta.2"]);
+ }
+
+ #[test]
+ pub fn test_parsing_compatible() {
+ let r = req("^1");
+ assert_match(&r, &["1.1.2", "1.1.0", "1.2.1", "1.0.1"]);
+ assert_not_match(&r, &["0.9.1", "2.9.0", "0.1.4"]);
+ assert_not_match(&r, &["1.0.0-beta1", "0.1.0-alpha", "1.0.1-pre"]);
+
+ let r = req("^1.1");
+ assert_match(&r, &["1.1.2", "1.1.0", "1.2.1"]);
+ assert_not_match(&r, &["0.9.1", "2.9.0", "1.0.1", "0.1.4"]);
+
+ let r = req("^1.1.2");
+ assert_match(&r, &["1.1.2", "1.1.4", "1.2.1"]);
+ assert_not_match(&r, &["0.9.1", "2.9.0", "1.1.1", "0.0.1"]);
+ assert_not_match(&r, &["1.1.2-alpha1", "1.1.3-alpha1", "2.9.0-alpha1"]);
+
+ let r = req("^0.1.2");
+ assert_match(&r, &["0.1.2", "0.1.4"]);
+ assert_not_match(&r, &["0.9.1", "2.9.0", "1.1.1", "0.0.1"]);
+ assert_not_match(&r, &["0.1.2-beta", "0.1.3-alpha", "0.2.0-pre"]);
+
+ let r = req("^0.5.1-alpha3");
+ assert_match(&r,
+ &["0.5.1-alpha3", "0.5.1-alpha4", "0.5.1-beta", "0.5.1", "0.5.5"]);
+ assert_not_match(&r,
+ &["0.5.1-alpha1", "0.5.2-alpha3", "0.5.5-pre", "0.5.0-pre", "0.6.0"]);
+
+ let r = req("^0.0.2");
+ assert_match(&r, &["0.0.2"]);
+ assert_not_match(&r, &["0.9.1", "2.9.0", "1.1.1", "0.0.1", "0.1.4"]);
+
+ let r = req("^0.0");
+ assert_match(&r, &["0.0.2", "0.0.0"]);
+ assert_not_match(&r, &["0.9.1", "2.9.0", "1.1.1", "0.1.4"]);
+
+ let r = req("^0");
+ assert_match(&r, &["0.9.1", "0.0.2", "0.0.0"]);
+ assert_not_match(&r, &["2.9.0", "1.1.1"]);
+
+ let r = req("^1.4.2-beta.5");
+ assert_match(&r,
+ &["1.4.2", "1.4.3", "1.4.2-beta.5", "1.4.2-beta.6", "1.4.2-c"]);
+ assert_not_match(&r,
+ &["0.9.9", "2.0.0", "1.4.2-alpha", "1.4.2-beta.4", "1.4.3-beta.5"]);
+ }
+
+ #[test]
+ pub fn test_parsing_wildcard() {
+ let r = req("");
+ assert_match(&r, &["0.9.1", "2.9.0", "0.0.9", "1.0.1", "1.1.1"]);
+ assert_not_match(&r, &[]);
+ let r = req("*");
+ assert_match(&r, &["0.9.1", "2.9.0", "0.0.9", "1.0.1", "1.1.1"]);
+ assert_not_match(&r, &[]);
+ let r = req("x");
+ assert_match(&r, &["0.9.1", "2.9.0", "0.0.9", "1.0.1", "1.1.1"]);
+ assert_not_match(&r, &[]);
+ let r = req("X");
+ assert_match(&r, &["0.9.1", "2.9.0", "0.0.9", "1.0.1", "1.1.1"]);
+ assert_not_match(&r, &[]);
+
+ let r = req("1.*");
+ assert_match(&r, &["1.2.0", "1.2.1", "1.1.1", "1.3.0"]);
+ assert_not_match(&r, &["0.0.9"]);
+ let r = req("1.x");
+ assert_match(&r, &["1.2.0", "1.2.1", "1.1.1", "1.3.0"]);
+ assert_not_match(&r, &["0.0.9"]);
+ let r = req("1.X");
+ assert_match(&r, &["1.2.0", "1.2.1", "1.1.1", "1.3.0"]);
+ assert_not_match(&r, &["0.0.9"]);
+
+ let r = req("1.2.*");
+ assert_match(&r, &["1.2.0", "1.2.2", "1.2.4"]);
+ assert_not_match(&r, &["1.9.0", "1.0.9", "2.0.1", "0.1.3"]);
+ let r = req("1.2.x");
+ assert_match(&r, &["1.2.0", "1.2.2", "1.2.4"]);
+ assert_not_match(&r, &["1.9.0", "1.0.9", "2.0.1", "0.1.3"]);
+ let r = req("1.2.X");
+ assert_match(&r, &["1.2.0", "1.2.2", "1.2.4"]);
+ assert_not_match(&r, &["1.9.0", "1.0.9", "2.0.1", "0.1.3"]);
+ }
+
+ #[test]
+ pub fn test_any() {
+ let r = VersionReq::any();
+ assert_match(&r, &["0.0.1", "0.1.0", "1.0.0"]);
+ }
+
+ #[test]
+ pub fn test_pre() {
+ let r = req("=2.1.1-really.0");
+ assert_match(&r, &["2.1.1-really.0"]);
+ }
+
+ // #[test]
+ // pub fn test_parse_errors() {
+ // assert_eq!(Err(InvalidVersionRequirement), VersionReq::parse("\0"));
+ // assert_eq!(Err(OpAlreadySet), VersionReq::parse(">= >= 0.0.2"));
+ // assert_eq!(Err(InvalidSigil), VersionReq::parse(">== 0.0.2"));
+ // assert_eq!(Err(VersionComponentsMustBeNumeric),
+ // VersionReq::parse("a.0.0"));
+ // assert_eq!(Err(InvalidIdentifier), VersionReq::parse("1.0.0-"));
+ // assert_eq!(Err(MajorVersionRequired), VersionReq::parse(">="));
+ // }
+
+ #[test]
+ pub fn test_from_str() {
+ assert_eq!("1.0.0".parse::<VersionReq>().unwrap().to_string(),
+ "^1.0.0".to_string());
+ assert_eq!("=1.0.0".parse::<VersionReq>().unwrap().to_string(),
+ "= 1.0.0".to_string());
+ assert_eq!("~1".parse::<VersionReq>().unwrap().to_string(),
+ "~1".to_string());
+ assert_eq!("~1.2".parse::<VersionReq>().unwrap().to_string(),
+ "~1.2".to_string());
+ assert_eq!("^1".parse::<VersionReq>().unwrap().to_string(),
+ "^1".to_string());
+ assert_eq!("^1.1".parse::<VersionReq>().unwrap().to_string(),
+ "^1.1".to_string());
+ assert_eq!("*".parse::<VersionReq>().unwrap().to_string(),
+ "*".to_string());
+ assert_eq!("1.*".parse::<VersionReq>().unwrap().to_string(),
+ "1.*".to_string());
+ assert_eq!("< 1.0.0".parse::<VersionReq>().unwrap().to_string(),
+ "< 1.0.0".to_string());
+ }
+
+ // #[test]
+ // pub fn test_from_str_errors() {
+ // assert_eq!(Err(InvalidVersionRequirement), "\0".parse::<VersionReq>());
+ // assert_eq!(Err(OpAlreadySet), ">= >= 0.0.2".parse::<VersionReq>());
+ // assert_eq!(Err(InvalidSigil), ">== 0.0.2".parse::<VersionReq>());
+ // assert_eq!(Err(VersionComponentsMustBeNumeric),
+ // "a.0.0".parse::<VersionReq>());
+ // assert_eq!(Err(InvalidIdentifier), "1.0.0-".parse::<VersionReq>());
+ // assert_eq!(Err(MajorVersionRequired), ">=".parse::<VersionReq>());
+ // }
+
+ #[test]
+ fn test_cargo3202() {
+ let v = "0.*.*".parse::<VersionReq>().unwrap();
+ assert_eq!("0.*.*", format!("{}", v.predicates[0]));
+
+ let v = "0.0.*".parse::<VersionReq>().unwrap();
+ assert_eq!("0.0.*", format!("{}", v.predicates[0]));
+
+ let r = req("0.*.*");
+ assert_match(&r, &["0.5.0"]);
+ }
+
+ #[test]
+ fn test_eq_hash() {
+ assert!(req("^1") == req("^1"));
+ assert!(calculate_hash(req("^1")) == calculate_hash(req("^1")));
+ assert!(req("^1") != req("^2"));
+ }
+
+ #[test]
+ fn test_ordering() {
+ assert!(req("=1") < req("*"));
+ assert!(req(">1") < req("*"));
+ assert!(req(">=1") < req("*"));
+ assert!(req("<1") < req("*"));
+ assert!(req("<=1") < req("*"));
+ assert!(req("~1") < req("*"));
+ assert!(req("^1") < req("*"));
+ assert!(req("*") == req("*"));
+ }
+}
diff --git a/semver/tests/deprecation.rs b/semver/tests/deprecation.rs
new file mode 100644
index 0000000..a5f533a
--- /dev/null
+++ b/semver/tests/deprecation.rs
@@ -0,0 +1,22 @@
+extern crate semver;
+
+#[test]
+fn test_regressions() {
+ use semver::VersionReq;
+ use semver::ReqParseError;
+
+ let versions = vec![
+ (".*", VersionReq::any()),
+ ("0.1.0.", VersionReq::parse("0.1.0").unwrap()),
+ ("0.3.1.3", VersionReq::parse("0.3.13").unwrap()),
+ ("0.2*", VersionReq::parse("0.2.*").unwrap()),
+ ("*.0", VersionReq::any()),
+ ];
+
+ for (version, requirement) in versions.into_iter() {
+ let parsed = VersionReq::parse(version);
+ let error = parsed.err().unwrap();
+
+ assert_eq!(ReqParseError::DeprecatedVersionRequirement(requirement), error);
+ }
+}
diff --git a/semver/tests/regression.rs b/semver/tests/regression.rs
new file mode 100644
index 0000000..ef568a7
--- /dev/null
+++ b/semver/tests/regression.rs
@@ -0,0 +1,25 @@
+extern crate semver;
+extern crate crates_index;
+extern crate tempdir;
+
+// This test checks to see if every existing crate parses successfully. Important to not break the
+// Rust universe!
+
+#[cfg(feature = "ci")]
+#[test]
+fn test_regressions() {
+ use tempdir::TempDir;
+ use crates_index::Index;
+ use semver::Version;
+
+ let dir = TempDir::new("semver").unwrap();
+ let index = Index::new(dir.into_path());
+ index.clone().unwrap();
+
+ for krate in index.crates() {
+ for version in krate.versions() {
+ let v = version.version();
+ assert!(Version::parse(v).is_ok(), "failed: {} ({})", version.name(), v);
+ }
+ }
+}
diff --git a/semver/tests/serde.rs b/semver/tests/serde.rs
new file mode 100644
index 0000000..bcb9264
--- /dev/null
+++ b/semver/tests/serde.rs
@@ -0,0 +1,90 @@
+#![cfg(feature = "serde")]
+
+#[macro_use]
+extern crate serde_derive;
+
+extern crate semver;
+extern crate serde_json;
+
+use semver::{Identifier, Version, VersionReq};
+
+#[derive(Serialize, Deserialize, PartialEq, Debug)]
+struct Identified {
+ name: String,
+ identifier: Identifier,
+}
+
+#[derive(Serialize, Deserialize, PartialEq, Debug)]
+struct Versioned {
+ name: String,
+ vers: Version,
+}
+
+#[test]
+fn serialize_identifier() {
+ let id = Identified {
+ name: "serde".to_owned(),
+ identifier: Identifier::Numeric(100),
+ };
+ let j = serde_json::to_string(&id).unwrap();
+ assert_eq!(j, r#"{"name":"serde","identifier":100}"#);
+
+ let id = Identified {
+ name: "serde".to_owned(),
+ identifier: Identifier::AlphaNumeric("b100".to_owned()),
+ };
+ let j = serde_json::to_string(&id).unwrap();
+ assert_eq!(j, r#"{"name":"serde","identifier":"b100"}"#);
+}
+
+#[test]
+fn deserialize_identifier() {
+ let j = r#"{"name":"serde","identifier":100}"#;
+ let id = serde_json::from_str::<Identified>(j).unwrap();
+ let expected = Identified {
+ name: "serde".to_owned(),
+ identifier: Identifier::Numeric(100),
+ };
+ assert_eq!(id, expected);
+
+ let j = r#"{"name":"serde","identifier":"b100"}"#;
+ let id = serde_json::from_str::<Identified>(j).unwrap();
+ let expected = Identified {
+ name: "serde".to_owned(),
+ identifier: Identifier::AlphaNumeric("b100".to_owned()),
+ };
+ assert_eq!(id, expected);
+}
+
+#[test]
+fn serialize_version() {
+ let v = Versioned {
+ name: "serde".to_owned(),
+ vers: Version::parse("1.0.0").unwrap(),
+ };
+ let j = serde_json::to_string(&v).unwrap();
+ assert_eq!(j, r#"{"name":"serde","vers":"1.0.0"}"#);
+}
+
+#[test]
+fn deserialize_version() {
+ let j = r#"{"name":"serde","vers":"1.0.0"}"#;
+ let v = serde_json::from_str::<Versioned>(j).unwrap();
+ let expected = Versioned {
+ name: "serde".to_owned(),
+ vers: Version::parse("1.0.0").unwrap(),
+ };
+ assert_eq!(v, expected);
+}
+
+#[test]
+fn serialize_versionreq() {
+ let v = VersionReq::exact(&Version::parse("1.0.0").unwrap());
+
+ assert_eq!(serde_json::to_string(&v).unwrap(), r#""= 1.0.0""#);
+}
+
+#[test]
+fn deserialize_versionreq() {
+ assert_eq!("1.0.0".parse::<VersionReq>().unwrap(), serde_json::from_str(r#""1.0.0""#).unwrap());
+}