Bug 1770894 - Force update rand to 0.8. r=emilio

Differential Revision: https://phabricator.services.mozilla.com/D147377
This commit is contained in:
Mike Hommey 2022-05-31 22:05:01 +00:00
parent f05ced899f
commit 1cda4fe2c7
140 changed files with 4841 additions and 8599 deletions

64
Cargo.lock generated
View file

@ -325,7 +325,7 @@ dependencies = [
"libc",
"libudev",
"log",
"rand",
"rand 0.7.999",
"runloop",
"winapi",
]
@ -468,7 +468,7 @@ dependencies = [
"comedy",
"guid_win",
"lazy_static",
"rand",
"rand 0.7.999",
"regex",
"tempfile",
"thiserror",
@ -1974,9 +1974,9 @@ dependencies = [
[[package]]
name = "getrandom"
version = "0.1.16"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad"
dependencies = [
"cfg-if 1.0.0",
"libc",
@ -3893,7 +3893,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526"
dependencies = [
"phf_shared",
"rand",
"rand 0.7.999",
]
[[package]]
@ -4154,23 +4154,27 @@ dependencies = [
[[package]]
name = "rand"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
version = "0.7.999"
dependencies = [
"rand 0.8.5",
]
[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"getrandom",
"libc",
"rand_chacha",
"rand_core",
"rand_hc",
"rand_pcg",
]
[[package]]
name = "rand_chacha"
version = "0.2.2"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core",
@ -4178,31 +4182,13 @@ dependencies = [
[[package]]
name = "rand_core"
version = "0.5.1"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
dependencies = [
"getrandom",
]
[[package]]
name = "rand_hc"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
dependencies = [
"rand_core",
]
[[package]]
name = "rand_pcg"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429"
dependencies = [
"rand_core",
]
[[package]]
name = "range-alloc"
version = "0.1.2"
@ -4406,7 +4392,7 @@ checksum = "ef248456c30c6607f1eb1e5d11025367b3340e235314dd33d2b31b41b35ac335"
dependencies = [
"byteorder",
"murmurhash3",
"rand",
"rand 0.7.999",
"sha2",
]
@ -4961,7 +4947,7 @@ version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=c51b63595a27a6ef45161012323e0261475c10c9#c51b63595a27a6ef45161012323e0261475c10c9"
dependencies = [
"base64 0.12.3",
"rand",
"rand 0.7.999",
"rusqlite",
"serde",
]
@ -5006,7 +4992,7 @@ checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
dependencies = [
"cfg-if 0.1.999",
"libc",
"rand",
"rand 0.7.999",
"redox_syscall",
"remove_dir_all",
"winapi",
@ -5529,7 +5515,7 @@ version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fde2f6a4bea1d6e007c4ad38c6839fa71cbb63b6dbf5b595aa38dc9b1093c11"
dependencies = [
"rand",
"rand 0.7.999",
"serde",
]
@ -5612,9 +5598,9 @@ dependencies = [
[[package]]
name = "wasi"
version = "0.9.0+wasi-snapshot-preview1"
version = "0.10.2+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
[[package]]
name = "wasm-bindgen"

View file

@ -111,6 +111,9 @@ redox_users = { path = "build/rust/redox_users" }
# Patch memmap2 0.2 to 0.3
memmap2 = { path = "build/rust/memmap2" }
# Patch getrandom 0.7 to 0.8
rand = { path = "build/rust/rand" }
# Patch autocfg to hide rustc output. Workaround for https://github.com/cuviper/autocfg/issues/30
autocfg = { path = "third_party/rust/autocfg" }

View file

@ -0,0 +1,21 @@
[package]
name = "rand"
version = "0.7.999"
edition = "2018"
license = "MPL-2.0"
[lib]
path = "lib.rs"
[dependencies]
rand = "0.8"
[features]
alloc = ["rand/alloc"]
default = ["rand/default"]
getrandom = ["rand/getrandom"]
nightly = ["rand/nightly"]
serde1 = ["rand/serde1"]
simd_support = ["rand/simd_support"]
small_rng = ["rand/small_rng"]
std = ["rand/std"]

5
build/rust/rand/lib.rs Normal file
View file

@ -0,0 +1,5 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
pub use rand::*;

View file

@ -1 +1 @@
{"files":{"CHANGELOG.md":"242905000c20a456bf6affca0c637c985d24c355c696c6941ed5a7158e5f9c94","Cargo.toml":"f7684384d43eb72a83aec42080a3ce30cdf17518752f81aa783fbf8de4497ce9","LICENSE-APACHE":"aaff376532ea30a0cd5330b9502ad4a4c8bf769c539c87ffe78819d188a18ebf","LICENSE-MIT":"209fbbe0ad52d9235e37badf9cadfe4dbdc87203179c0899e738b39ade42177b","README.md":"434a2c0978ade0a0c1d24b72a23952243358982b34ebb3a52f9ae41dac18a6ae","benches/mod.rs":"eae05a2128105062d27090af25e5c35ac2cf422115e335582f13c5127c3507b4","build.rs":"9000429ff834eb551f6e3800414cd8d339a6e45ea96c751aa465e204c673357d","src/bsd_arandom.rs":"4f90c31eb72046ad8181c5cee217d38a3c964e601fcf02e57bb97453f4d4023b","src/cloudabi.rs":"cd493b696ab968113d46b3b38cff52ecd89e79228640802ba523452932183d2b","src/dummy.rs":"184e81035f38a5edd3e7f3ed9ea0d3e4dc462ca5d224fad11cb660412dcd9198","src/error.rs":"1673d24e1fae25553c4317a3a093c1f76bee494644b4c8f5b96e56dfbd2dd56e","src/error_impls.rs":"e8a33ce04a71c588d88776dcd895446da9526f3843ae72ed438c65ac386e87da","src/fuchsia.rs":"470d8509deb5b06fa6417f294c0a49e0e35a580249a5d8944c3be5aa746f64ea","src/ios.rs":"e88214b6077eb75e471b388d57f952a9af8f6f0e514df5c6e655d6c22384313d","src/lib.rs":"af9222fce17ec218bea74dbb74abfdb11cbba78a393226829bdf4428b8440e2e","src/linux_android.rs":"b7975157fa1b28f4eb3dabf3ca28e055f974fcc391163cf4c9e5c8123fabc1e1","src/macos.rs":"757ddafd8645ad382fb041f2db3735f4da4ea174f87892411de63a208b3db619","src/openbsd.rs":"c77acddffa3287dc7f82d13a4650a8ac8ef991ee882f71650ebbc76f9df431f6","src/rdrand.rs":"c3435e63b9d54d3423b2d31f7cb605901b795a4e982cd50b2428b1dc6de580b4","src/solaris_illumos.rs":"e3323277622d35d8a544879cabc539f9a684e799007861b824a1cba09285be13","src/use_file.rs":"7aa9391f35fb04a5af4d74aa0a810a6a5962b382e342fc9fa9b922560bddd5f6","src/util.rs":"da6964dc1523f1cb8d26365fa6a8ece46360587e6974931624b271f0c72cda8b","src/util_libc.rs":"d5901c8cc5189437ed250ca500f7ad6a7db3774080cbc50422db9a23178a6039","src/vxworks.rs":"e5159caf5ae2521c977f5e824e3a580e2440f182deae2433f74e37a8ac01bc8d","src/wasi.rs":"3413e5a391b156f5d05600f4651f7f8eb4df2c8984fca7766ca50c0cfe0b2e9c","src/wasm32_bindgen.rs":"cb24a13459983208adc7662800bdcbda01a903640f871f135ee2936ab5b783be","src/wasm32_stdweb.rs":"274e1a6b12b4812008e1bac36b2468e8b6e02a9d7e95954b860a1a3c64f6f7a8","src/windows.rs":"f568b343e6bfbdc158ebc4728baa1c1c08d55417657b940540d9df279f9536d9","src/windows_uwp.rs":"9d8d98fd55f8b1e0ca5b80da318d1238cd376b552731c8605dc4a30ea2f34874","tests/common.rs":"2be3a0abf4ecd74b1bafee22e032a14582c1cd3da041fa1ed37bbc393dac312e"},"package":"8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"}
{"files":{"CHANGELOG.md":"e972a70c9a4729acbd6bd81ca0c3e03944cab242743b308d124d64b3552f8e63","Cargo.toml":"66283df4cc6406f65b46dded3469d23f9d1c6372a0385af8cdcde9da1b6cf5d9","LICENSE-APACHE":"aaff376532ea30a0cd5330b9502ad4a4c8bf769c539c87ffe78819d188a18ebf","LICENSE-MIT":"209fbbe0ad52d9235e37badf9cadfe4dbdc87203179c0899e738b39ade42177b","README.md":"7ae74633326a22fd6298d7f209fb14884277bd98049795f444945acbb2b0dfbd","benches/mod.rs":"5495735ff210a50cab23c2cc84191ed910af7c30395a3d9d6095b722765b3864","src/3ds.rs":"0f48fc15f89b518fb92e06aaa4838b62dc073598e8f288df56ad1e5a9251af1e","src/bsd_arandom.rs":"d2ee195acd80c7d1364a369ad0d2dad46f5f9f973f9d3960367413fd87acfcd6","src/custom.rs":"b363ee77664203d141985402433afd6808b72cc50bff586b3034d303eccfc281","src/dragonfly.rs":"28f3f7ac4f093dfb6cd2c8e7e0714f16d0f03f8c658e56caa8fe9bd03b1ff39b","src/error.rs":"110ffe8a2c6b0fa46a4e317e837efe617b343f250fedac61bcabc3c5250e7432","src/error_impls.rs":"9c34832ebb99cd5e31bc5c8ffc5beb5b3fa6f7ff0226aaa1cdf8e10e6d64b324","src/espidf.rs":"19f101486584fde6dad962f4d9792de168658047312106641a5caf6866a5bbcf","src/fuchsia.rs":"470d8509deb5b06fa6417f294c0a49e0e35a580249a5d8944c3be5aa746f64ea","src/ios.rs":"4bad4f5c096a50338b86aeac91a937c18bc55b9555e6f34806ad13732e64523d","src/js.rs":"04c750491ba3bcdad3609265938410ee09928c5d6dfd0d33d826a9884d13ac4c","src/lib.rs":"674af2d277b66ecf2e49e1059638abd58db089df095b8b65d9e347782e4bb1e0","src/linux_android.rs":"39cb80999c8534145240a350976d261b8924436bf9a4563960c7bd8c2c83c773","src/macos.rs":"b692f2fcc2319a5195f47751d5bd7dd87c7c24a61d14fa4e3dbc992ae66212b7","src/openbsd.rs":"066b2dd395c190444a658bb0b52a052eabbd68ea5a534fb729c7e5373abc0a6a","src/rdrand.rs":"79d23183b1905d61bd9df9729dc798505a2ed750d3339e342ab144e1709827e4","src/solaris_illumos.rs":"9c7004446fabe5a7a21c73d5a65d7e2115b5bd1d1dbb735c984cab3dba239785","src/solid.rs":"997035d54c9762d22a5a14f54e7fbed4dd266cdeacbdf6aab7d8aee05537e8ba","src/use_file.rs":"16e42eb0a56e375c330c1ca8eb58c444e82ef3ad35230b961fdba96a02a68804","src/util.rs":"da6964dc1523f1cb8d26365fa6a8ece46360587e6974931624b271f0c72cda8b","src/util_libc.rs":"9fd636b23121a86630f0c7891a310444f5b1bb29b0013290e130b79ed1e1f79e","src/vxworks.rs":"a5aa0e40f890e0f35626458bb656a3340b8af3111e4bacd2e12505a8d50a3505","src/wasi.rs":"02b3a75613dc80444847675ecfea59f390c2597ce1d3334612a8dba71f6082de","src/windows.rs":"e3c8f033d5d2a6b8abc5c92b005232f5aca8ce941bd94964a0f58f2436af9990","tests/common/mod.rs":"b6beee8f535d2d094a65711fe0af91a6fc220aa09729ed7269fe33cafdc9177f","tests/custom.rs":"9f2c0193193f6bcf641116ca0b3653b33d2015e0e98ce107ee1d1f60c5eeae3a","tests/normal.rs":"9e1c4b1e468a09ed0225370dfb6608f8b8135e0fabb09bbc1a718105164aade6","tests/rdrand.rs":"4474ccebf9d33c89288862a7e367018405968dddc55c7c6f97e21b5fe2264601"},"package":"9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad"}

View file

@ -4,6 +4,110 @@ 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.2.6] - 2022-03-28
### Added
- Nintendo 3DS (`armv6k-nintendo-3ds`) support [#248]
### Changed
- Retry `open` when interrupted [#252]
[#248]: https://github.com/rust-random/getrandom/pull/248
[#252]: https://github.com/rust-random/getrandom/pull/252
## [0.2.5] - 2022-02-22
### Added
- ESP-IDF targets (`*espidf`) support [#245]
### Fixed
- Webpack warning caused by dynamic require [#234]
- Error checking on iOS for `SecRandomCopyBytes` [#244]
[#234]: https://github.com/rust-random/getrandom/pull/234
[#244]: https://github.com/rust-random/getrandom/pull/244
[#245]: https://github.com/rust-random/getrandom/pull/245
## [0.2.4] - 2021-12-13
### Changed
- Use explicit imports in the `js` backend [#220]
- Use `/dev/urandom` on Redox instead of `rand:` [#222]
- Use `NonZeroU32::new_unchecked` to convert wasi error [#233]
### Added
- SOLID targets (`*-kmc-solid_*`) support [#235]
- Limited Hermit (`x86_64-unknown-hermit`) support [#236]
[#220]: https://github.com/rust-random/getrandom/pull/220
[#222]: https://github.com/rust-random/getrandom/pull/222
[#233]: https://github.com/rust-random/getrandom/pull/233
[#235]: https://github.com/rust-random/getrandom/pull/235
[#236]: https://github.com/rust-random/getrandom/pull/236
## [0.2.3] - 2021-04-10
### Changed
- Replace build.rs with link attributes. [#205]
- Add support for getrandom syscall on DragonFly BSD. [#210]
- Improve Node.js detection. [#215]
[#205]: https://github.com/rust-random/getrandom/pull/205
[#210]: https://github.com/rust-random/getrandom/pull/210
[#215]: https://github.com/rust-random/getrandom/pull/215
## [0.2.2] - 2021-01-19
### Changed
- Forward `rustc-dep-of-std` to dependencies. [#198]
- Highlight feature-dependend functionality in documentation using the `doc_cfg` feature. [#200]
[#198]: https://github.com/rust-random/getrandom/pull/198
[#200]: https://github.com/rust-random/getrandom/pull/200
## [0.2.1] - 2021-01-03
### Changed
- Update `cfg-if` to v1.0. [#166]
- Update `wasi` to v0.10. [#167]
### Fixed
- Multithreaded WASM support. [#165]
### Removed
- Windows XP support. [#177]
- Direct `stdweb` support. [#178]
- CloudABI support. [#184]
[#165]: https://github.com/rust-random/getrandom/pull/165
[#166]: https://github.com/rust-random/getrandom/pull/166
[#167]: https://github.com/rust-random/getrandom/pull/167
[#177]: https://github.com/rust-random/getrandom/pull/177
[#178]: https://github.com/rust-random/getrandom/pull/178
[#184]: https://github.com/rust-random/getrandom/pull/184
## [0.2.0] - 2020-09-10
### Features for using getrandom on unsupported targets
The following (off by default) Cargo features have been added:
- `"rdrand"` - use the RDRAND instruction on `no_std` `x86`/`x86_64` targets [#133]
- `"js"` - use JavaScript calls on `wasm32-unknown-unknown` [#149]
- Replaces the `stdweb` and `wasm-bindgen` features (which are removed)
- `"custom"` - allows a user to specify a custom implementation [#109]
### Breaking Changes
- Unsupported targets no longer compile [#107]
- Change/Add `Error` constants [#120]
- Only impl `std` traits when the `"std"` Cargo feature is specified [#106]
- Remove official support for Hermit, L4Re, and UEFI [#133]
- Remove optional `"log"` dependency [#131]
- Update minimum supported Linux kernel to 2.6.32 [#153]
- Update MSRV to 1.34 [#159]
[#106]: https://github.com/rust-random/getrandom/pull/106
[#107]: https://github.com/rust-random/getrandom/pull/107
[#109]: https://github.com/rust-random/getrandom/pull/109
[#120]: https://github.com/rust-random/getrandom/pull/120
[#131]: https://github.com/rust-random/getrandom/pull/131
[#133]: https://github.com/rust-random/getrandom/pull/133
[#149]: https://github.com/rust-random/getrandom/pull/149
[#153]: https://github.com/rust-random/getrandom/pull/153
[#159]: https://github.com/rust-random/getrandom/pull/159
## [0.1.16] - 2020-12-31
### Changed
- Update `cfg-if` to v1.0. [#173]
@ -186,3 +290,29 @@ Publish initial implementation.
## [0.0.0] - 2019-01-19
Publish an empty template library.
[0.2.5]: https://github.com/rust-random/getrandom/compare/v0.2.5...v0.2.6
[0.2.5]: https://github.com/rust-random/getrandom/compare/v0.2.4...v0.2.5
[0.2.4]: https://github.com/rust-random/getrandom/compare/v0.2.3...v0.2.4
[0.2.3]: https://github.com/rust-random/getrandom/compare/v0.2.2...v0.2.3
[0.2.2]: https://github.com/rust-random/getrandom/compare/v0.2.1...v0.2.2
[0.2.1]: https://github.com/rust-random/getrandom/compare/v0.2.0...v0.2.1
[0.2.0]: https://github.com/rust-random/getrandom/compare/v0.1.15...v0.2.0
[0.1.16]: https://github.com/rust-random/getrandom/compare/v0.1.15...v0.1.16
[0.1.15]: https://github.com/rust-random/getrandom/compare/v0.1.14...v0.1.15
[0.1.14]: https://github.com/rust-random/getrandom/compare/v0.1.13...v0.1.14
[0.1.13]: https://github.com/rust-random/getrandom/compare/v0.1.12...v0.1.13
[0.1.12]: https://github.com/rust-random/getrandom/compare/v0.1.11...v0.1.12
[0.1.11]: https://github.com/rust-random/getrandom/compare/v0.1.10...v0.1.11
[0.1.10]: https://github.com/rust-random/getrandom/compare/v0.1.9...v0.1.10
[0.1.9]: https://github.com/rust-random/getrandom/compare/v0.1.8...v0.1.9
[0.1.8]: https://github.com/rust-random/getrandom/compare/v0.1.7...v0.1.8
[0.1.7]: https://github.com/rust-random/getrandom/compare/v0.1.6...v0.1.7
[0.1.6]: https://github.com/rust-random/getrandom/compare/v0.1.5...v0.1.6
[0.1.5]: https://github.com/rust-random/getrandom/compare/v0.1.4...v0.1.5
[0.1.4]: https://github.com/rust-random/getrandom/compare/v0.1.3...v0.1.4
[0.1.3]: https://github.com/rust-random/getrandom/compare/v0.1.2...v0.1.3
[0.1.2]: https://github.com/rust-random/getrandom/compare/v0.1.1...v0.1.2
[0.1.1]: https://github.com/rust-random/getrandom/compare/v0.1.0...v0.1.1
[0.1.0]: https://github.com/rust-random/getrandom/compare/v0.0.0...v0.1.0
[0.0.0]: https://github.com/rust-random/getrandom/releases/tag/v0.0.0

View file

@ -3,24 +3,26 @@
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g., crates.io) dependencies
# to registry (e.g., crates.io) dependencies.
#
# If you believe there's an error in this file please file an
# issue against the rust-lang/cargo repository. If you're
# editing this file be aware that the upstream Cargo.toml
# will likely look very different (and much more reasonable)
# If you are reading this file be aware that the original Cargo.toml
# will likely look very different (and much more reasonable).
# See Cargo.toml.orig for the original contents.
[package]
edition = "2018"
name = "getrandom"
version = "0.1.16"
version = "0.2.6"
authors = ["The Rand Project Developers"]
exclude = ["utils/*", ".*", "appveyor.yml"]
exclude = [".*"]
description = "A small cross-platform library for retrieving random data from system source"
documentation = "https://docs.rs/getrandom"
categories = ["os", "no-std"]
license = "MIT OR Apache-2.0"
repository = "https://github.com/rust-random/getrandom"
[package.metadata.docs.rs]
features = ["std", "custom"]
rustdoc-args = ["--cfg", "docsrs"]
[dependencies.cfg-if]
version = "1"
@ -33,37 +35,25 @@ version = "1.0"
optional = true
package = "rustc-std-workspace-core"
[dependencies.log]
version = "0.4"
optional = true
[features]
dummy = []
rustc-dep-of-std = ["compiler_builtins", "core"]
custom = []
js = ["wasm-bindgen", "js-sys"]
rdrand = []
rustc-dep-of-std = ["compiler_builtins", "core", "libc/rustc-dep-of-std", "wasi/rustc-dep-of-std"]
std = []
test-in-browser = ["wasm-bindgen"]
wasm-bindgen = ["bindgen", "js-sys"]
[target."cfg(target_os = \"wasi\")".dependencies.wasi]
version = "0.9"
[target."cfg(unix)".dependencies.libc]
version = "0.2.64"
default-features = false
[target.wasm32-unknown-unknown.dependencies.bindgen]
version = "0.2.29"
optional = true
package = "wasm-bindgen"
[target.wasm32-unknown-unknown.dependencies.js-sys]
test-in-browser = []
[target."cfg(all(target_arch = \"wasm32\", target_os = \"unknown\"))".dependencies.js-sys]
version = "0.3"
optional = true
[target.wasm32-unknown-unknown.dependencies.stdweb]
version = "0.4.18"
[target."cfg(all(target_arch = \"wasm32\", target_os = \"unknown\"))".dependencies.wasm-bindgen]
version = "0.2.62"
optional = true
[target.wasm32-unknown-unknown.dev-dependencies.wasm-bindgen-test]
version = "0.2"
[badges.appveyor]
repository = "rust-random/getrandom"
[badges.travis-ci]
repository = "rust-random/getrandom"
default-features = false
[target."cfg(all(target_arch = \"wasm32\", target_os = \"unknown\"))".dev-dependencies.wasm-bindgen-test]
version = "0.3.18"
[target."cfg(target_os = \"wasi\")".dependencies.wasi]
version = "0.10"
[target."cfg(unix)".dependencies.libc]
version = "0.2.120"
default-features = false

View file

@ -1,10 +1,18 @@
# getrandom
[![Build Status](https://travis-ci.org/rust-random/getrandom.svg?branch=master)](https://travis-ci.org/rust-random/getrandom)
[![Build Status](https://ci.appveyor.com/api/projects/status/github/rust-random/getrandom?svg=true)](https://ci.appveyor.com/project/rust-random/getrandom)
[![Crate](https://img.shields.io/crates/v/getrandom.svg)](https://crates.io/crates/getrandom)
[![Documentation](https://docs.rs/getrandom/badge.svg)](https://docs.rs/getrandom)
[![Dependency status](https://deps.rs/repo/github/rust-random/getrandom/status.svg)](https://deps.rs/repo/github/rust-random/getrandom)
[![Build Status]][GitHub Actions] [![Crate]][crates.io] [![Documentation]][docs.rs] [![Dependency Status]][deps.rs] [![Downloads]][crates.io] [![License]][LICENSE-MIT]
[GitHub Actions]: https://github.com/rust-random/getrandom/actions?query=workflow:Tests+branch:master
[Build Status]: https://github.com/rust-random/getrandom/workflows/Tests/badge.svg?branch=master
[crates.io]: https://crates.io/crates/getrandom
[Crate]: https://img.shields.io/crates/v/getrandom
[docs.rs]: https://docs.rs/getrandom
[Documentation]: https://docs.rs/getrandom/badge.svg
[deps.rs]: https://deps.rs/repo/github/rust-random/getrandom
[Dependency Status]: https://deps.rs/repo/github/rust-random/getrandom/status.svg
[Downloads]: https://img.shields.io/crates/d/getrandom
[LICENSE-MIT]: https://raw.githubusercontent.com/rust-random/getrandom/master/LICENSE-MIT
[License]: https://img.shields.io/crates/l/getrandom
A Rust library for retrieving random data from (operating) system source. It is
@ -24,7 +32,7 @@ Add this to your `Cargo.toml`:
```toml
[dependencies]
getrandom = "0.1"
getrandom = "0.2"
```
Then invoke the `getrandom` function:
@ -37,36 +45,14 @@ fn get_random_buf() -> Result<[u8; 32], getrandom::Error> {
}
```
## Features
This library is `no_std` for every supported target. However, getting randomness
usually requires calling some external system API. This means most platforms
will require linking against system libraries (i.e. `libc` for Unix,
`Advapi32.dll` for Windows, Security framework on iOS, etc...).
The `log` library is supported as an optional dependency. If enabled, error
reporting will be improved on some platforms.
For the `wasm32-unknown-unknown` target, one of the following features should be
enabled:
- [`wasm-bindgen`](https://crates.io/crates/wasm_bindgen)
- [`stdweb`](https://crates.io/crates/stdweb)
By default, compiling `getrandom` for an unsupported target will result in
a compilation error. If you want to build an application which uses `getrandom`
for such target, you can either:
- Use [`[replace]`][replace] or [`[patch]`][patch] section in your `Cargo.toml`
to switch to a custom implementation with a support of your target.
- Enable the `dummy` feature to have getrandom use an implementation that always
fails at run-time on unsupported targets.
[replace]: https://doc.rust-lang.org/cargo/reference/manifest.html#the-replace-section
[patch]: https://doc.rust-lang.org/cargo/reference/manifest.html#the-patch-section
For more information about supported targets, entropy sources, `no_std` targets,
crate features, WASM support and Custom RNGs see the
[`getrandom` documentation](https://docs.rs/getrandom/latest) and
[`getrandom::Error` documentation](https://docs.rs/getrandom/latest/getrandom/struct.Error.html).
## Minimum Supported Rust Version
This crate requires Rust 1.32.0 or later.
This crate requires Rust 1.34.0 or later.
# License

View file

@ -1,5 +1,4 @@
#![feature(test)]
extern crate getrandom;
extern crate test;
#[bench]

View file

@ -1,19 +0,0 @@
#![deny(warnings)]
use std::env;
fn main() {
let target = env::var("TARGET").expect("TARGET was not set");
if target.contains("-uwp-windows-") {
// for BCryptGenRandom
println!("cargo:rustc-link-lib=bcrypt");
// to work around unavailability of `target_vendor` on Rust 1.33
println!("cargo:rustc-cfg=getrandom_uwp");
} else if target.contains("windows") {
// for RtlGenRandom (aka SystemFunction036)
println!("cargo:rustc-link-lib=advapi32");
} else if target.contains("apple-ios") {
// for SecRandomCopyBytes and kSecRandomDefault
println!("cargo:rustc-link-lib=framework=Security");
}
}

17
third_party/rust/getrandom/src/3ds.rs vendored Normal file
View file

@ -0,0 +1,17 @@
// Copyright 2021 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.
//! Implementation for Nintendo 3DS
use crate::util_libc::sys_fill_exact;
use crate::Error;
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
sys_fill_exact(dest, |buf| unsafe {
libc::getrandom(buf.as_mut_ptr() as *mut libc::c_void, buf.len(), 0)
})
}

View file

@ -7,8 +7,7 @@
// except according to those terms.
//! Implementation for FreeBSD and NetBSD
use crate::util_libc::sys_fill_exact;
use crate::Error;
use crate::{util_libc::sys_fill_exact, Error};
use core::ptr;
fn kern_arnd(buf: &mut [u8]) -> libc::ssize_t {
@ -25,7 +24,6 @@ fn kern_arnd(buf: &mut [u8]) -> libc::ssize_t {
)
};
if ret == -1 {
error!("sysctl kern.arandom: syscall failed");
-1
} else {
len as libc::ssize_t
@ -45,5 +43,10 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
return sys_fill_exact(dest, |buf| unsafe { func(buf.as_mut_ptr(), buf.len(), 0) });
}
}
sys_fill_exact(dest, kern_arnd)
// Both FreeBSD and NetBSD will only return up to 256 bytes at a time, and
// older NetBSD kernels will fail on longer buffers.
for chunk in dest.chunks_mut(256) {
sys_fill_exact(chunk, kern_arnd)?
}
Ok(())
}

View file

@ -1,25 +0,0 @@
// 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.
//! Implementation for CloudABI
use crate::Error;
use core::num::NonZeroU32;
extern "C" {
fn cloudabi_sys_random_get(buf: *mut u8, buf_len: usize) -> u16;
}
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
let errno = unsafe { cloudabi_sys_random_get(dest.as_mut_ptr(), dest.len()) };
if let Some(code) = NonZeroU32::new(errno as u32) {
error!("cloudabi_sys_random_get: failed with {}", errno);
Err(Error::from(code))
} else {
Ok(()) // Zero means success for CloudABI
}
}

102
third_party/rust/getrandom/src/custom.rs vendored Normal file
View file

@ -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.
//! An implementation which calls out to an externally defined function.
use crate::Error;
use core::num::NonZeroU32;
/// Register a function to be invoked by `getrandom` on unsupported targets.
///
/// ## Writing a custom `getrandom` implementation
///
/// The function to register must have the same signature as
/// [`getrandom::getrandom`](crate::getrandom). The function can be defined
/// wherever you want, either in root crate or a dependent crate.
///
/// For example, if we wanted a `failure-getrandom` crate containing an
/// implementation that always fails, we would first depend on `getrandom`
/// (for the [`Error`] type) in `failure-getrandom/Cargo.toml`:
/// ```toml
/// [dependencies]
/// getrandom = "0.2"
/// ```
/// Note that the crate containing this function does **not** need to enable the
/// `"custom"` Cargo feature.
///
/// Next, in `failure-getrandom/src/lib.rs`, we define our function:
/// ```rust
/// use core::num::NonZeroU32;
/// use getrandom::Error;
///
/// // Some application-specific error code
/// const MY_CUSTOM_ERROR_CODE: u32 = Error::CUSTOM_START + 42;
/// pub fn always_fail(buf: &mut [u8]) -> Result<(), Error> {
/// let code = NonZeroU32::new(MY_CUSTOM_ERROR_CODE).unwrap();
/// Err(Error::from(code))
/// }
/// ```
///
/// ## Registering a custom `getrandom` implementation
///
/// Functions can only be registered in the root binary crate. Attempting to
/// register a function in a non-root crate will result in a linker error.
/// This is similar to
/// [`#[panic_handler]`](https://doc.rust-lang.org/nomicon/panic-handler.html) or
/// [`#[global_allocator]`](https://doc.rust-lang.org/edition-guide/rust-2018/platform-and-target-support/global-allocators.html),
/// where helper crates define handlers/allocators but only the binary crate
/// actually _uses_ the functionality.
///
/// To register the function, we first depend on `failure-getrandom` _and_
/// `getrandom` in `Cargo.toml`:
/// ```toml
/// [dependencies]
/// failure-getrandom = "0.1"
/// getrandom = { version = "0.2", features = ["custom"] }
/// ```
///
/// Then, we register the function in `src/main.rs`:
/// ```rust
/// # mod failure_getrandom { pub fn always_fail(_: &mut [u8]) -> Result<(), getrandom::Error> { unimplemented!() } }
/// use failure_getrandom::always_fail;
/// use getrandom::register_custom_getrandom;
///
/// register_custom_getrandom!(always_fail);
/// ```
///
/// Now any user of `getrandom` (direct or indirect) on this target will use the
/// registered function. As noted in the
/// [top-level documentation](index.html#custom-implementations) this
/// registration only has an effect on unsupported targets.
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "custom")))]
macro_rules! register_custom_getrandom {
($path:path) => {
// We use an extern "C" function to get the guarantees of a stable ABI.
#[no_mangle]
extern "C" fn __getrandom_custom(dest: *mut u8, len: usize) -> u32 {
let f: fn(&mut [u8]) -> Result<(), ::getrandom::Error> = $path;
let slice = unsafe { ::core::slice::from_raw_parts_mut(dest, len) };
match f(slice) {
Ok(()) => 0,
Err(e) => e.code().get(),
}
}
};
}
#[allow(dead_code)]
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
extern "C" {
fn __getrandom_custom(dest: *mut u8, len: usize) -> u32;
}
let ret = unsafe { __getrandom_custom(dest.as_mut_ptr(), dest.len()) };
match NonZeroU32::new(ret) {
None => Ok(()),
Some(code) => Err(Error::from(code)),
}
}

View file

@ -0,0 +1,26 @@
// Copyright 2021 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.
//! Implementation for DragonFly BSD
use crate::{
use_file,
util_libc::{sys_fill_exact, Weak},
Error,
};
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
static GETRANDOM: Weak = unsafe { Weak::new("getrandom\0") };
type GetRandomFn = unsafe extern "C" fn(*mut u8, libc::size_t, libc::c_uint) -> libc::ssize_t;
if let Some(fptr) = GETRANDOM.ptr() {
let func: GetRandomFn = unsafe { core::mem::transmute(fptr) };
return sys_fill_exact(dest, |buf| unsafe { func(buf.as_mut_ptr(), buf.len(), 0) });
} else {
use_file::getrandom_inner(dest)
}
}

View file

@ -1,14 +0,0 @@
// 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 dummy implementation for unsupported targets which always fails
use crate::{error::UNSUPPORTED, Error};
pub fn getrandom_inner(_: &mut [u8]) -> Result<(), Error> {
Err(UNSUPPORTED)
}

View file

@ -5,10 +5,9 @@
// <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 core::fmt;
use core::num::NonZeroU32;
use core::{fmt, num::NonZeroU32};
/// A small and `no_std` compatible error type.
/// A small and `no_std` compatible error type
///
/// The [`Error::raw_os_error()`] will indicate if the error is from the OS, and
/// if so, which error code the OS gave the application. If such an error is
@ -16,16 +15,44 @@ use core::num::NonZeroU32;
///
/// Internally this type is a NonZeroU32, with certain values reserved for
/// certain purposes, see [`Error::INTERNAL_START`] and [`Error::CUSTOM_START`].
///
/// *If this crate's `"std"` Cargo feature is enabled*, then:
/// - [`getrandom::Error`][Error] implements
/// [`std::error::Error`](https://doc.rust-lang.org/std/error/trait.Error.html)
/// - [`std::io::Error`](https://doc.rust-lang.org/std/io/struct.Error.html) implements
/// [`From<getrandom::Error>`](https://doc.rust-lang.org/std/convert/trait.From.html).
#[derive(Copy, Clone, Eq, PartialEq)]
pub struct Error(NonZeroU32);
const fn internal_error(n: u16) -> Error {
// SAFETY: code > 0 as INTERNAL_START > 0 and adding n won't overflow a u32.
let code = Error::INTERNAL_START + (n as u32);
Error(unsafe { NonZeroU32::new_unchecked(code) })
}
impl Error {
#[deprecated(since = "0.1.7")]
/// Unknown error.
pub const UNKNOWN: Error = UNSUPPORTED;
#[deprecated(since = "0.1.7")]
/// System entropy source is unavailable.
pub const UNAVAILABLE: Error = UNSUPPORTED;
/// This target/platform is not supported by `getrandom`.
pub const UNSUPPORTED: Error = internal_error(0);
/// The platform-specific `errno` returned a non-positive value.
pub const ERRNO_NOT_POSITIVE: Error = internal_error(1);
/// Call to iOS [`SecRandomCopyBytes`](https://developer.apple.com/documentation/security/1399291-secrandomcopybytes) failed.
pub const IOS_SEC_RANDOM: Error = internal_error(3);
/// Call to Windows [`RtlGenRandom`](https://docs.microsoft.com/en-us/windows/win32/api/ntsecapi/nf-ntsecapi-rtlgenrandom) failed.
pub const WINDOWS_RTL_GEN_RANDOM: Error = internal_error(4);
/// RDRAND instruction failed due to a hardware issue.
pub const FAILED_RDRAND: Error = internal_error(5);
/// RDRAND instruction unsupported on this target.
pub const NO_RDRAND: Error = internal_error(6);
/// The browser does not have support for `self.crypto`.
pub const WEB_CRYPTO: Error = internal_error(7);
/// The browser does not have support for `crypto.getRandomValues`.
pub const WEB_GET_RANDOM_VALUES: Error = internal_error(8);
/// On VxWorks, call to `randSecure` failed (random number generator is not yet initialized).
pub const VXWORKS_RAND_SECURE: Error = internal_error(11);
/// NodeJS does not have support for the `crypto` module.
pub const NODE_CRYPTO: Error = internal_error(12);
/// NodeJS does not have support for `crypto.randomFillSync`.
pub const NODE_RANDOM_FILL_SYNC: Error = internal_error(13);
/// Codes below this point represent OS Errors (i.e. positive i32 values).
/// Codes at or above this point, but below [`Error::CUSTOM_START`] are
@ -38,13 +65,22 @@ impl Error {
/// Extract the raw OS error code (if this error came from the OS)
///
/// This method is identical to `std::io::Error::raw_os_error()`, except
/// This method is identical to [`std::io::Error::raw_os_error()`][1], except
/// that it works in `no_std` contexts. If this method returns `None`, the
/// error value can still be formatted via the `Display` implementation.
///
/// [1]: https://doc.rust-lang.org/std/io/struct.Error.html#method.raw_os_error
#[inline]
pub fn raw_os_error(self) -> Option<i32> {
if self.0.get() < Self::INTERNAL_START {
Some(self.0.get() as i32)
match () {
#[cfg(target_os = "solid_asp3")]
// On SOLID, negate the error code again to obtain the original
// error code.
() => Some(-(self.0.get() as i32)),
#[cfg(not(target_os = "solid_asp3"))]
() => Some(self.0.get() as i32),
}
} else {
None
}
@ -55,7 +91,7 @@ impl Error {
/// This code can either come from the underlying OS, or be a custom error.
/// Use [`Error::raw_os_error()`] to disambiguate.
#[inline]
pub fn code(self) -> NonZeroU32 {
pub const fn code(self) -> NonZeroU32 {
self.0
}
}
@ -125,41 +161,19 @@ impl From<NonZeroU32> for Error {
}
}
// TODO: Convert to a function when min_version >= 1.33
macro_rules! internal_error {
($n:expr) => {
Error(unsafe { NonZeroU32::new_unchecked(Error::INTERNAL_START + $n as u16 as u32) })
};
}
/// Internal Error constants
pub(crate) const UNSUPPORTED: Error = internal_error!(0);
pub(crate) const ERRNO_NOT_POSITIVE: Error = internal_error!(1);
pub(crate) const UNKNOWN_IO_ERROR: Error = internal_error!(2);
pub(crate) const SEC_RANDOM_FAILED: Error = internal_error!(3);
pub(crate) const RTL_GEN_RANDOM_FAILED: Error = internal_error!(4);
pub(crate) const FAILED_RDRAND: Error = internal_error!(5);
pub(crate) const NO_RDRAND: Error = internal_error!(6);
pub(crate) const BINDGEN_CRYPTO_UNDEF: Error = internal_error!(7);
pub(crate) const BINDGEN_GRV_UNDEF: Error = internal_error!(8);
pub(crate) const STDWEB_NO_RNG: Error = internal_error!(9);
pub(crate) const STDWEB_RNG_FAILED: Error = internal_error!(10);
pub(crate) const RAND_SECURE_FATAL: Error = internal_error!(11);
fn internal_desc(error: Error) -> Option<&'static str> {
match error {
UNSUPPORTED => Some("getrandom: this target is not supported"),
ERRNO_NOT_POSITIVE => Some("errno: did not return a positive value"),
UNKNOWN_IO_ERROR => Some("Unknown std::io::Error"),
SEC_RANDOM_FAILED => Some("SecRandomCopyBytes: call failed"),
RTL_GEN_RANDOM_FAILED => Some("RtlGenRandom: call failed"),
FAILED_RDRAND => Some("RDRAND: failed multiple times: CPU issue likely"),
NO_RDRAND => Some("RDRAND: instruction not supported"),
BINDGEN_CRYPTO_UNDEF => Some("wasm-bindgen: self.crypto is undefined"),
BINDGEN_GRV_UNDEF => Some("wasm-bindgen: crypto.getRandomValues is undefined"),
STDWEB_NO_RNG => Some("stdweb: no randomness source available"),
STDWEB_RNG_FAILED => Some("stdweb: failed to get randomness"),
RAND_SECURE_FATAL => Some("randSecure: random number generator module is not initialized"),
Error::UNSUPPORTED => Some("getrandom: this target is not supported"),
Error::ERRNO_NOT_POSITIVE => Some("errno: did not return a positive value"),
Error::IOS_SEC_RANDOM => Some("SecRandomCopyBytes: iOS Security framework failure"),
Error::WINDOWS_RTL_GEN_RANDOM => Some("RtlGenRandom: Windows system function failure"),
Error::FAILED_RDRAND => Some("RDRAND: failed multiple times: CPU issue likely"),
Error::NO_RDRAND => Some("RDRAND: instruction not supported"),
Error::WEB_CRYPTO => Some("Web Crypto API is unavailable"),
Error::WEB_GET_RANDOM_VALUES => Some("Web API crypto.getRandomValues is unavailable"),
Error::VXWORKS_RAND_SECURE => Some("randSecure: VxWorks RNG module is not initialized"),
Error::NODE_CRYPTO => Some("Node.js crypto module is unavailable"),
Error::NODE_RANDOM_FILL_SYNC => Some("Node.js API crypto.randomFillSync is unavailable"),
_ => None,
}
}

View file

@ -5,24 +5,13 @@
// <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_attr(docsrs, doc(cfg(feature = "std")))]
extern crate std;
use crate::{error::UNKNOWN_IO_ERROR, Error};
use crate::Error;
use core::convert::From;
use core::num::NonZeroU32;
use std::io;
impl From<io::Error> for Error {
fn from(err: io::Error) -> Self {
if let Some(errno) = err.raw_os_error() {
if let Some(code) = NonZeroU32::new(errno as u32) {
return Error::from(code);
}
}
UNKNOWN_IO_ERROR
}
}
impl From<Error> for io::Error {
fn from(err: Error) -> Self {
match err.raw_os_error() {

View file

@ -0,0 +1,26 @@
// Copyright 2021 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.
//! Implementation for ESP-IDF
use crate::Error;
use core::ffi::c_void;
extern "C" {
fn esp_fill_random(buf: *mut c_void, len: usize) -> u32;
}
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
// Not that NOT enabling WiFi, BT, or the voltage noise entropy source (via `bootloader_random_enable`)
// will cause ESP-IDF to return pseudo-random numbers based on the voltage noise entropy, after the initial boot process:
// https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/random.html
//
// However tracking if some of these entropy sources is enabled is way too difficult to implement here
unsafe { esp_fill_random(dest.as_mut_ptr().cast(), dest.len()) };
Ok(())
}

View file

@ -7,24 +7,20 @@
// except according to those terms.
//! Implementation for iOS
use crate::{error::SEC_RANDOM_FAILED, Error};
// TODO: Make extern once extern_types feature is stabilized. See:
// https://github.com/rust-lang/rust/issues/43467
#[repr(C)]
struct SecRandom([u8; 0]);
use crate::Error;
use core::{ffi::c_void, ptr::null};
#[link(name = "Security", kind = "framework")]
extern "C" {
static kSecRandomDefault: *const SecRandom;
fn SecRandomCopyBytes(rnd: *const SecRandom, count: usize, bytes: *mut u8) -> i32;
fn SecRandomCopyBytes(rnd: *const c_void, count: usize, bytes: *mut u8) -> i32;
}
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
let ret = unsafe { SecRandomCopyBytes(kSecRandomDefault, dest.len(), dest.as_mut_ptr()) };
if ret == -1 {
Err(SEC_RANDOM_FAILED)
// Apple's documentation guarantees kSecRandomDefault is a synonym for NULL.
let ret = unsafe { SecRandomCopyBytes(null(), dest.len(), dest.as_mut_ptr()) };
// errSecSuccess (from SecBase.h) is always zero.
if ret != 0 {
Err(Error::IOS_SEC_RANDOM)
} else {
Ok(())
}

129
third_party/rust/getrandom/src/js.rs vendored Normal file
View file

@ -0,0 +1,129 @@
// 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 crate::Error;
extern crate std;
use std::thread_local;
use js_sys::{global, Uint8Array};
use wasm_bindgen::{prelude::wasm_bindgen, JsCast, JsValue};
// Maximum is 65536 bytes see https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues
const BROWSER_CRYPTO_BUFFER_SIZE: usize = 256;
enum RngSource {
Node(NodeCrypto),
Browser(BrowserCrypto, Uint8Array),
}
// JsValues are always per-thread, so we initialize RngSource for each thread.
// See: https://github.com/rustwasm/wasm-bindgen/pull/955
thread_local!(
static RNG_SOURCE: Result<RngSource, Error> = getrandom_init();
);
pub(crate) fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
RNG_SOURCE.with(|result| {
let source = result.as_ref().map_err(|&e| e)?;
match source {
RngSource::Node(n) => {
if n.random_fill_sync(dest).is_err() {
return Err(Error::NODE_RANDOM_FILL_SYNC);
}
}
RngSource::Browser(crypto, buf) => {
// getRandomValues does not work with all types of WASM memory,
// so we initially write to browser memory to avoid exceptions.
for chunk in dest.chunks_mut(BROWSER_CRYPTO_BUFFER_SIZE) {
// The chunk can be smaller than buf's length, so we call to
// JS to create a smaller view of buf without allocation.
let sub_buf = buf.subarray(0, chunk.len() as u32);
if crypto.get_random_values(&sub_buf).is_err() {
return Err(Error::WEB_GET_RANDOM_VALUES);
}
sub_buf.copy_to(chunk);
}
}
};
Ok(())
})
}
fn getrandom_init() -> Result<RngSource, Error> {
let global: Global = global().unchecked_into();
if is_node(&global) {
let crypto = NODE_MODULE
.require("crypto")
.map_err(|_| Error::NODE_CRYPTO)?;
return Ok(RngSource::Node(crypto));
}
// Assume we are in some Web environment (browser or web worker). We get
// `self.crypto` (called `msCrypto` on IE), so we can call
// `crypto.getRandomValues`. If `crypto` isn't defined, we assume that
// we are in an older web browser and the OS RNG isn't available.
let crypto = match (global.crypto(), global.ms_crypto()) {
(c, _) if c.is_object() => c,
(_, c) if c.is_object() => c,
_ => return Err(Error::WEB_CRYPTO),
};
let buf = Uint8Array::new_with_length(BROWSER_CRYPTO_BUFFER_SIZE as u32);
Ok(RngSource::Browser(crypto, buf))
}
// Taken from https://www.npmjs.com/package/browser-or-node
fn is_node(global: &Global) -> bool {
let process = global.process();
if process.is_object() {
let versions = process.versions();
if versions.is_object() {
return versions.node().is_string();
}
}
false
}
#[wasm_bindgen]
extern "C" {
type Global; // Return type of js_sys::global()
// Web Crypto API (https://www.w3.org/TR/WebCryptoAPI/)
#[wasm_bindgen(method, getter, js_name = "msCrypto")]
fn ms_crypto(this: &Global) -> BrowserCrypto;
#[wasm_bindgen(method, getter)]
fn crypto(this: &Global) -> BrowserCrypto;
type BrowserCrypto;
#[wasm_bindgen(method, js_name = getRandomValues, catch)]
fn get_random_values(this: &BrowserCrypto, buf: &Uint8Array) -> Result<(), JsValue>;
// We use a "module" object here instead of just annotating require() with
// js_name = "module.require", so that Webpack doesn't give a warning. See:
// https://github.com/rust-random/getrandom/issues/224
type NodeModule;
#[wasm_bindgen(js_name = module)]
static NODE_MODULE: NodeModule;
// Node JS crypto module (https://nodejs.org/api/crypto.html)
#[wasm_bindgen(method, catch)]
fn require(this: &NodeModule, s: &str) -> Result<NodeCrypto, JsValue>;
type NodeCrypto;
#[wasm_bindgen(method, js_name = randomFillSync, catch)]
fn random_fill_sync(this: &NodeCrypto, buf: &mut [u8]) -> Result<(), JsValue>;
// Node JS process Object (https://nodejs.org/api/process.html)
#[wasm_bindgen(method, getter)]
fn process(this: &Global) -> Process;
type Process;
#[wasm_bindgen(method, getter)]
fn versions(this: &Process) -> Versions;
type Versions;
#[wasm_bindgen(method, getter)]
fn node(this: &Versions) -> JsValue;
}

View file

@ -6,89 +6,116 @@
// 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.
//! Interface to the operating system's random number generator.
//!
//! # Platform sources
//! # Supported targets
//!
//! | OS | interface
//! |------------------|---------------------------------------------------------
//! | Linux, Android | [`getrandom`][1] system call if available, otherwise [`/dev/urandom`][2] after successfully polling `/dev/random`
//! | Windows | [`RtlGenRandom`][3]
//! | macOS | [`getentropy()`][19] if available, otherwise [`/dev/random`][20] (identical to `/dev/urandom`)
//! | iOS | [`SecRandomCopyBytes`][4]
//! | FreeBSD | [`getrandom()`][21] if available, otherwise [`kern.arandom`][5]
//! | OpenBSD | [`getentropy`][6]
//! | NetBSD | [`kern.arandom`][7]
//! | 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 | [`cloudabi_sys_random_get`][13]
//! | Haiku | `/dev/random` (identical to `/dev/urandom`)
//! | L4RE, SGX, UEFI | [RDRAND][18]
//! | Hermit | [RDRAND][18] as [`sys_rand`][22] is currently broken.
//! | VxWorks | `randABytes` after checking entropy pool initialization with `randSecure`
//! | Web browsers | [`Crypto.getRandomValues`][14] (see [Support for WebAssembly and asm.js][16])
//! | Node.js | [`crypto.randomBytes`][15] (see [Support for WebAssembly and asm.js][16])
//! | WASI | [`__wasi_random_get`][17]
//! | Target | Target Triple | Implementation
//! | ----------------- | ------------------ | --------------
//! | Linux, Android | `*linux*` | [`getrandom`][1] system call if available, otherwise [`/dev/urandom`][2] after successfully polling `/dev/random`
//! | Windows | `*windows*` | [`BCryptGenRandom`]
//! | macOS | `*appledarwin` | [`getentropy`][3] if available, otherwise [`/dev/random`][4] (identical to `/dev/urandom`)
//! | iOS | `*appleios` | [`SecRandomCopyBytes`]
//! | FreeBSD | `*freebsd` | [`getrandom`][5] if available, otherwise [`kern.arandom`][6]
//! | OpenBSD | `*openbsd` | [`getentropy`][7]
//! | NetBSD | `*netbsd` | [`kern.arandom`][8]
//! | Dragonfly BSD | `*dragonfly` | [`getrandom`][9] if available, otherwise [`/dev/random`][10]
//! | Solaris, illumos | `*solaris`, `*illumos` | [`getrandom`][11] if available, otherwise [`/dev/random`][12]
//! | Fuchsia OS | `*fuchsia` | [`cprng_draw`]
//! | Redox | `*redox` | `/dev/urandom`
//! | Haiku | `*haiku` | `/dev/random` (identical to `/dev/urandom`)
//! | Hermit | `x86_64-*-hermit` | [`RDRAND`]
//! | SGX | `x86_64*sgx` | [`RDRAND`]
//! | VxWorks | `*wrsvxworks*` | `randABytes` after checking entropy pool initialization with `randSecure`
//! | ESP-IDF | `*espidf` | [`esp_fill_random`]
//! | Emscripten | `*emscripten` | `/dev/random` (identical to `/dev/urandom`)
//! | WASI | `wasm32wasi` | [`random_get`]
//! | Web Browser | `wasm32*unknown` | [`Crypto.getRandomValues`], see [WebAssembly support]
//! | Node.js | `wasm32*unknown` | [`crypto.randomBytes`], see [WebAssembly support]
//! | SOLID | `*-kmc-solid_*` | `SOLID_RNG_SampleRandomBytes`
//! | Nintendo 3DS | `armv6k-nintendo-3ds` | [`getrandom`][1]
//!
//! Getrandom 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.
//! There is no blanket implementation on `unix` targets that reads from
//! `/dev/urandom`. This ensures all supported targets are using the recommended
//! interface and respect maximum buffer sizes.
//!
//! Pull Requests that add support for new targets to `getrandom` are always welcome.
//!
//! ## Unsupported targets
//!
//! By default, compiling `getrandom` for an unsupported target will result in
//! a compilation error. If you want to build an application which uses `getrandom`
//! for such target, you can either:
//! - Use [`[replace]`][replace] or [`[patch]`][patch] section in your `Cargo.toml`
//! to switch to a custom implementation with a support of your target.
//! - Enable the `dummy` feature to have getrandom use an implementation that always
//! fails at run-time on unsupported targets.
//! By default, `getrandom` will not compile on unsupported targets, but certain
//! features allow a user to select a "fallback" implementation if no supported
//! implementation exists.
//!
//! [replace]: https://doc.rust-lang.org/cargo/reference/manifest.html#the-replace-section
//! [patch]: https://doc.rust-lang.org/cargo/reference/manifest.html#the-patch-section
//! All of the below mechanisms only affect unsupported
//! targets. Supported targets will _always_ use their supported implementations.
//! This prevents a crate from overriding a secure source of randomness
//! (either accidentally or intentionally).
//!
//! ## Support for WebAssembly and asm.js
//! ### RDRAND on x86
//!
//! Getrandom supports all of Rust's current `wasm32` targets, and it works with
//! both Node.js and web browsers. The three Emscripten targets
//! `asmjs-unknown-emscripten`, `wasm32-unknown-emscripten`, and
//! `wasm32-experimental-emscripten` use Emscripten's `/dev/random` emulation.
//! The WASI target `wasm32-wasi` uses the [`__wasi_random_get`][17] function
//! defined by the WASI standard.
//! *If the `rdrand` Cargo feature is enabled*, `getrandom` will fallback to using
//! the [`RDRAND`] instruction to get randomness on `no_std` `x86`/`x86_64`
//! targets. This feature has no effect on other CPU architectures.
//!
//! Getrandom also supports `wasm32-unknown-unknown` by directly calling
//! JavaScript methods. Rust currently has two ways to do this: [bindgen] and
//! [stdweb]. Getrandom supports using either one by enabling the
//! `wasm-bindgen` or `stdweb` crate features. Note that if both features are
//! enabled, `wasm-bindgen` will be used. If neither feature is enabled, calls
//! to `getrandom` will always fail at runtime.
//! ### WebAssembly support
//!
//! [bindgen]: https://github.com/rust-lang/rust-bindgen
//! [stdweb]: https://github.com/koute/stdweb
//! This crate fully supports the
//! [`wasm32-wasi`](https://github.com/CraneStation/wasi) and
//! [`wasm32-unknown-emscripten`](https://www.hellorust.com/setup/emscripten/)
//! targets. However, the `wasm32-unknown-unknown` target (i.e. the target used
//! by `wasm-pack`) is not automatically
//! supported since, from the target name alone, we cannot deduce which
//! JavaScript interface is in use (or if JavaScript is available at all).
//!
//! Instead, *if the `js` Cargo feature is enabled*, this crate will assume
//! that you are building for an environment containing JavaScript, and will
//! call the appropriate methods. Both web browser (main window and Web Workers)
//! and Node.js environments are supported, invoking the methods
//! [described above](#supported-targets) using the
//! [wasm-bindgen](https://github.com/rust-lang/rust-bindgen) toolchain.
//!
//! This feature has no effect on targets other than `wasm32-unknown-unknown`.
//!
//! ### Custom implementations
//!
//! The [`register_custom_getrandom!`] macro allows a user to mark their own
//! function as the backing implementation for [`getrandom`]. See the macro's
//! documentation for more information about writing and registering your own
//! custom implementations.
//!
//! Note that registering a custom implementation only has an effect on targets
//! that would otherwise not compile. Any supported targets (including those
//! using `rdrand` and `js` Cargo features) continue using their normal
//! implementations even if a function is registered.
//!
//! ### Indirect Dependencies
//!
//! If `getrandom` is not a direct dependency of your crate, you can still
//! enable any of the above fallback behaviors by enabling the relevant
//! feature in your root crate's `Cargo.toml`:
//! ```toml
//! [dependencies]
//! getrandom = { version = "0.2", features = ["js"] }
//! ```
//!
//! ## 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.
//! Sometimes, early in the boot process, the OS has not collected enough
//! entropy to securely seed its RNG. This is especially common on virtual
//! machines, where standard "random" events are hard to come by.
//!
//! Some operating systems always block the thread until the RNG is securely
//! Some operating system interfaces always block 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; in these cases, we always choose to block.
//!
//! A few, Linux, NetBSD and Solaris, offer a choice between blocking and
//! getting an error; in these cases we always choose to block.
//!
//! On Linux (when the `getrandom` system call is not available) and on NetBSD
//! reading from `/dev/urandom` never blocks, even when the OS hasn't collected
//! enough entropy yet. To avoid returning low-entropy bytes, we first read from
//! On Linux (when the `getrandom` system call is not available), reading from
//! `/dev/urandom` never blocks, even when the OS hasn't collected enough
//! entropy yet. To avoid returning low-entropy bytes, we first poll
//! `/dev/random` and only switch to `/dev/urandom` once this has succeeded.
//!
//! # Error handling
//! ## Error handling
//!
//! We always choose failure over returning insecure "random" bytes. In general,
//! on supported platforms, failure is highly unlikely, though not impossible.
@ -96,178 +123,122 @@
//! `getrandom`, hence after the first successful call one can be reasonably
//! confident that no errors will occur.
//!
//! On unsupported platforms, `getrandom` always fails. See the [`Error`] type
//! for more information on what data is returned on failure.
//!
//! [1]: http://man7.org/linux/man-pages/man2/getrandom.2.html
//! [2]: http://man7.org/linux/man-pages/man4/urandom.4.html
//! [3]: https://docs.microsoft.com/en-us/windows/desktop/api/ntsecapi/nf-ntsecapi-rtlgenrandom
//! [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]: https://netbsd.gw.com/cgi-bin/man-cgi?sysctl+7+NetBSD-8.0
//! [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.dev/fuchsia-src/zircon/syscalls/cprng_draw
//! [12]: https://github.com/redox-os/randd/blob/master/src/main.rs
//! [13]: https://github.com/nuxinl/cloudabi#random_get
//! [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-asmjs
//! [17]: https://github.com/WebAssembly/WASI/blob/master/design/WASI-core.md#__wasi_random_get
//! [18]: https://software.intel.com/en-us/articles/intel-digital-random-number-generator-drng-software-implementation-guide
//! [19]: https://www.unix.com/man-page/mojave/2/getentropy/
//! [20]: https://www.unix.com/man-page/mojave/4/random/
//! [21]: https://www.freebsd.org/cgi/man.cgi?query=getrandom&manpath=FreeBSD+12.0-stable
//! [22]: https://github.com/hermitcore/libhermit-rs/blob/09c38b0371cee6f56a541400ba453e319e43db53/src/syscalls/random.rs#L21
//! [3]: https://www.unix.com/man-page/mojave/2/getentropy/
//! [4]: https://www.unix.com/man-page/mojave/4/random/
//! [5]: https://www.freebsd.org/cgi/man.cgi?query=getrandom&manpath=FreeBSD+12.0-stable
//! [6]: https://www.freebsd.org/cgi/man.cgi?query=random&sektion=4
//! [7]: https://man.openbsd.org/getentropy.2
//! [8]: https://man.netbsd.org/sysctl.7
//! [9]: https://leaf.dragonflybsd.org/cgi/web-man?command=getrandom
//! [10]: https://leaf.dragonflybsd.org/cgi/web-man?command=random&section=4
//! [11]: https://docs.oracle.com/cd/E88353_01/html/E37841/getrandom-2.html
//! [12]: https://docs.oracle.com/cd/E86824_01/html/E54777/random-7d.html
//!
//! [`BCryptGenRandom`]: https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom
//! [`Crypto.getRandomValues`]: https://www.w3.org/TR/WebCryptoAPI/#Crypto-method-getRandomValues
//! [`RDRAND`]: https://software.intel.com/en-us/articles/intel-digital-random-number-generator-drng-software-implementation-guide
//! [`SecRandomCopyBytes`]: https://developer.apple.com/documentation/security/1399291-secrandomcopybytes?language=objc
//! [`cprng_draw`]: https://fuchsia.dev/fuchsia-src/zircon/syscalls/cprng_draw
//! [`crypto.randomBytes`]: https://nodejs.org/api/crypto.html#crypto_crypto_randombytes_size_callback
//! [`esp_fill_random`]: https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/random.html#_CPPv415esp_fill_randomPv6size_t
//! [`random_get`]: https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/docs.md#-random_getbuf-pointeru8-buf_len-size---errno
//! [WebAssembly support]: #webassembly-support
#![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/"
html_root_url = "https://docs.rs/getrandom/0.2.6"
)]
#![no_std]
#![cfg_attr(feature = "stdweb", recursion_limit = "128")]
#![warn(rust_2018_idioms, unused_lifetimes, missing_docs)]
#![cfg_attr(docsrs, feature(doc_cfg))]
#[macro_use]
extern crate cfg_if;
cfg_if! {
if #[cfg(feature = "log")] {
#[allow(unused)]
#[macro_use]
extern crate log;
} else {
#[allow(unused)]
macro_rules! error {
($($x:tt)*) => {};
}
#[allow(unused)]
macro_rules! warn {
($($x:tt)*) => {};
}
#[allow(unused)]
macro_rules! info {
($($x:tt)*) => {};
}
}
}
mod error;
pub use crate::error::Error;
mod util;
// For backwards compatibility, we provide the std-only trait implementations
// for some platforms, even if they don't enable the "std" feature.
#[cfg(any(
feature = "std",
all(windows, not(getrandom_uwp)),
target_os = "android",
target_os = "dragonfly",
target_os = "emscripten",
target_os = "freebsd",
target_os = "fuchsia",
target_os = "haiku",
target_os = "illumos",
target_os = "ios",
target_os = "linux",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd",
target_os = "redox",
target_os = "solaris",
))]
// To prevent a breaking change when targets are added, we always export the
// register_custom_getrandom macro, so old Custom RNG crates continue to build.
#[cfg(feature = "custom")]
mod custom;
#[cfg(feature = "std")]
mod error_impls;
pub use crate::error::Error;
// System-specific implementations.
//
// These should all provide getrandom_inner with the same signature as getrandom.
cfg_if! {
if #[cfg(target_os = "android")] {
if #[cfg(any(target_os = "emscripten", target_os = "haiku",
target_os = "redox"))] {
mod util_libc;
#[path = "use_file.rs"] mod imp;
} else if #[cfg(any(target_os = "android", target_os = "linux"))] {
mod util_libc;
mod use_file;
#[path = "linux_android.rs"] mod imp;
} else if #[cfg(target_os = "cloudabi")] {
#[path = "cloudabi.rs"] mod imp;
} else if #[cfg(target_os = "dragonfly")] {
mod util_libc;
#[path = "use_file.rs"] mod imp;
} else if #[cfg(target_os = "emscripten")] {
mod util_libc;
#[path = "use_file.rs"] mod imp;
} else if #[cfg(target_os = "freebsd")] {
mod util_libc;
#[path = "bsd_arandom.rs"] mod imp;
} else if #[cfg(target_os = "fuchsia")] {
#[path = "fuchsia.rs"] mod imp;
} else if #[cfg(target_os = "haiku")] {
mod util_libc;
#[path = "use_file.rs"] mod imp;
} else if #[cfg(target_os = "illumos")] {
} else if #[cfg(any(target_os = "illumos", target_os = "solaris"))] {
mod util_libc;
mod use_file;
#[path = "solaris_illumos.rs"] mod imp;
} else if #[cfg(target_os = "ios")] {
#[path = "ios.rs"] mod imp;
} else if #[cfg(target_os = "linux")] {
} else if #[cfg(any(target_os = "freebsd", target_os = "netbsd"))] {
mod util_libc;
#[path = "bsd_arandom.rs"] mod imp;
} else if #[cfg(target_os = "dragonfly")] {
mod util_libc;
mod use_file;
#[path = "linux_android.rs"] mod imp;
#[path = "dragonfly.rs"] mod imp;
} else if #[cfg(target_os = "fuchsia")] {
#[path = "fuchsia.rs"] mod imp;
} else if #[cfg(target_os = "ios")] {
#[path = "ios.rs"] mod imp;
} else if #[cfg(target_os = "macos")] {
mod util_libc;
mod use_file;
#[path = "macos.rs"] mod imp;
} else if #[cfg(target_os = "netbsd")] {
mod util_libc;
#[path = "bsd_arandom.rs"] mod imp;
} else if #[cfg(target_os = "openbsd")] {
mod util_libc;
#[path = "openbsd.rs"] mod imp;
} else if #[cfg(target_os = "redox")] {
mod util_libc;
#[path = "use_file.rs"] mod imp;
} else if #[cfg(target_os = "solaris")] {
mod util_libc;
mod use_file;
#[path = "solaris_illumos.rs"] mod imp;
} else if #[cfg(target_os = "wasi")] {
#[path = "wasi.rs"] mod imp;
} else if #[cfg(all(target_arch = "x86_64", target_os = "hermit"))] {
#[path = "rdrand.rs"] mod imp;
} else if #[cfg(target_os = "vxworks")] {
mod util_libc;
#[path = "vxworks.rs"] mod imp;
} else if #[cfg(all(windows, getrandom_uwp))] {
#[path = "windows_uwp.rs"] mod imp;
} else if #[cfg(target_os = "solid_asp3")] {
#[path = "solid.rs"] mod imp;
} else if #[cfg(target_os = "espidf")] {
#[path = "espidf.rs"] mod imp;
} else if #[cfg(windows)] {
#[path = "windows.rs"] mod imp;
} else if #[cfg(all(target_arch = "x86_64", any(
target_os = "hermit",
target_os = "l4re",
target_os = "uefi",
target_env = "sgx",
)))] {
} else if #[cfg(all(target_arch = "x86_64", target_env = "sgx"))] {
#[path = "rdrand.rs"] mod imp;
} else if #[cfg(all(feature = "rdrand",
any(target_arch = "x86_64", target_arch = "x86")))] {
#[path = "rdrand.rs"] mod imp;
} else if #[cfg(all(feature = "js",
target_arch = "wasm32", target_os = "unknown"))] {
#[path = "js.rs"] mod imp;
} else if #[cfg(all(target_os = "horizon", target_arch = "arm"))] {
// We check for target_arch = "arm" because the Nintendo Switch also
// uses Horizon OS (it is aarch64).
mod util_libc;
#[path = "3ds.rs"] mod imp;
} else if #[cfg(feature = "custom")] {
use custom as imp;
} else if #[cfg(all(target_arch = "wasm32", target_os = "unknown"))] {
cfg_if! {
if #[cfg(feature = "wasm-bindgen")] {
#[path = "wasm32_bindgen.rs"] mod imp;
} else if #[cfg(feature = "stdweb")] {
#[path = "wasm32_stdweb.rs"] mod imp;
compile_error!("the wasm32-unknown-unknown target is not supported by \
default, you may need to enable the \"js\" feature. \
For more information see: \
https://docs.rs/getrandom/#webassembly-support");
} else {
// Always have an implementation for wasm32-unknown-unknown.
// See https://github.com/rust-random/getrandom/issues/87
#[path = "dummy.rs"] mod imp;
}
}
} else if #[cfg(feature = "dummy")] {
#[path = "dummy.rs"] mod imp;
} else {
compile_error!("\
target is not supported, for more information see: \
https://docs.rs/getrandom/#unsupported-targets\
");
compile_error!("target is not supported, for more information see: \
https://docs.rs/getrandom/#unsupported-targets");
}
}
@ -284,7 +255,7 @@ cfg_if! {
/// In general, `getrandom` will be fast enough for interactive usage, though
/// significantly slower than a user-space CSPRNG; for the latter consider
/// [`rand::thread_rng`](https://docs.rs/rand/*/rand/fn.thread_rng.html).
pub fn getrandom(dest: &mut [u8]) -> Result<(), error::Error> {
pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
if dest.is_empty() {
return Ok(());
}

View file

@ -7,9 +7,11 @@
// except according to those terms.
//! Implementation for Linux / Android
use crate::util::LazyBool;
use crate::util_libc::{last_os_error, sys_fill_exact};
use crate::{use_file, Error};
use crate::{
util::LazyBool,
util_libc::{last_os_error, sys_fill_exact},
{use_file, Error},
};
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
static HAS_GETRANDOM: LazyBool = LazyBool::new();

View file

@ -7,8 +7,11 @@
// except according to those terms.
//! Implementation for macOS
use crate::util_libc::{last_os_error, Weak};
use crate::{use_file, Error};
use crate::{
use_file,
util_libc::{last_os_error, Weak},
Error,
};
use core::mem;
type GetEntropyFn = unsafe extern "C" fn(*mut u8, libc::size_t) -> libc::c_int;
@ -20,9 +23,7 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
for chunk in dest.chunks_mut(256) {
let ret = unsafe { func(chunk.as_mut_ptr(), chunk.len()) };
if ret != 0 {
let err = last_os_error();
error!("getentropy syscall failed");
return Err(err);
return Err(last_os_error());
}
}
Ok(())

View file

@ -7,16 +7,13 @@
// except according to those terms.
//! Implementation for OpenBSD
use crate::util_libc::last_os_error;
use crate::Error;
use crate::{util_libc::last_os_error, Error};
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
for chunk in dest.chunks_mut(256) {
let ret = unsafe { libc::getentropy(chunk.as_mut_ptr() as *mut libc::c_void, chunk.len()) };
if ret == -1 {
let err = last_os_error();
error!("libc::getentropy call failed");
return Err(err);
return Err(last_os_error());
}
}
Ok(())

View file

@ -7,24 +7,30 @@
// except according to those terms.
//! Implementation for SGX using RDRAND instruction
use crate::error::{FAILED_RDRAND, NO_RDRAND};
#[cfg(not(target_feature = "rdrand"))]
use crate::util::LazyBool;
use crate::Error;
use core::arch::x86_64::_rdrand64_step;
use core::mem;
cfg_if! {
if #[cfg(target_arch = "x86_64")] {
use core::arch::x86_64 as arch;
use arch::_rdrand64_step as rdrand_step;
} else if #[cfg(target_arch = "x86")] {
use core::arch::x86 as arch;
use arch::_rdrand32_step as rdrand_step;
}
}
// Recommendation from "Intel® Digital Random Number Generator (DRNG) Software
// Implementation Guide" - Section 5.2.1 and "Intel® 64 and IA-32 Architectures
// Software Developers Manual" - Volume 1 - Section 7.3.17.1.
const RETRY_LIMIT: usize = 10;
const WORD_SIZE: usize = mem::size_of::<u64>();
const WORD_SIZE: usize = mem::size_of::<usize>();
#[target_feature(enable = "rdrand")]
unsafe fn rdrand() -> Result<[u8; WORD_SIZE], Error> {
for _ in 0..RETRY_LIMIT {
let mut el = mem::zeroed();
if _rdrand64_step(&mut el) == 1 {
if rdrand_step(&mut el) == 1 {
// AMD CPUs from families 14h to 16h (pre Ryzen) sometimes fail to
// set CF on bogus random data, so we check these values explicitly.
// See https://github.com/systemd/systemd/issues/11810#issuecomment-489727505
@ -33,11 +39,10 @@ unsafe fn rdrand() -> Result<[u8; WORD_SIZE], Error> {
if el != 0 && el != !0 {
return Ok(el.to_ne_bytes());
}
error!("RDRAND returned {:X}, CPU RNG may be broken", el);
// Keep looping in case this was a false positive.
}
}
Err(FAILED_RDRAND)
Err(Error::FAILED_RDRAND)
}
// "rdrand" target feature requires "+rdrnd" flag, see https://github.com/rust-lang/rust/issues/49653.
@ -55,16 +60,18 @@ fn is_rdrand_supported() -> bool {
// https://github.com/rust-lang-nursery/stdsimd/issues/464
#[cfg(not(target_feature = "rdrand"))]
fn is_rdrand_supported() -> bool {
use core::arch::x86_64::__cpuid;
// SAFETY: All x86_64 CPUs support CPUID leaf 1
use crate::util::LazyBool;
// SAFETY: All Rust x86 targets are new enough to have CPUID, and if CPUID
// is supported, CPUID leaf 1 is always supported.
const FLAG: u32 = 1 << 30;
static HAS_RDRAND: LazyBool = LazyBool::new();
HAS_RDRAND.unsync_init(|| unsafe { (__cpuid(1).ecx & FLAG) != 0 })
HAS_RDRAND.unsync_init(|| unsafe { (arch::__cpuid(1).ecx & FLAG) != 0 })
}
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
if !is_rdrand_supported() {
return Err(NO_RDRAND);
return Err(Error::NO_RDRAND);
}
// SAFETY: After this point, rdrand is supported, so calling the rdrand

View file

@ -17,8 +17,11 @@
//! To make sure we can compile on both Solaris and its derivatives, as well as
//! function, we check for the existence of getrandom(2) in libc by calling
//! libc::dlsym.
use crate::util_libc::{sys_fill_exact, Weak};
use crate::{use_file, Error};
use crate::{
use_file,
util_libc::{sys_fill_exact, Weak},
Error,
};
use core::mem;
#[cfg(target_os = "illumos")]

26
third_party/rust/getrandom/src/solid.rs vendored Normal file
View file

@ -0,0 +1,26 @@
// Copyright 2021 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.
//! Implementation for SOLID
use crate::Error;
use core::num::NonZeroU32;
extern "C" {
pub fn SOLID_RNG_SampleRandomBytes(buffer: *mut u8, length: usize) -> i32;
}
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
let ret = unsafe { SOLID_RNG_SampleRandomBytes(dest.as_mut_ptr(), dest.len()) };
if ret >= 0 {
Ok(())
} else {
// ITRON error numbers are always negative, so we negate it so that it
// falls in the dedicated OS error range (1..INTERNAL_START).
Err(NonZeroU32::new((-ret) as u32).unwrap().into())
}
}

View file

@ -7,14 +7,16 @@
// except according to those terms.
//! Implementations that just need to read from a file
use crate::util::LazyUsize;
use crate::util_libc::{open_readonly, sys_fill_exact};
use crate::Error;
use core::cell::UnsafeCell;
use core::sync::atomic::{AtomicUsize, Ordering::Relaxed};
use crate::{
util::LazyUsize,
util_libc::{open_readonly, sys_fill_exact},
Error,
};
use core::{
cell::UnsafeCell,
sync::atomic::{AtomicUsize, Ordering::Relaxed},
};
#[cfg(target_os = "redox")]
const FILE_PATH: &str = "rand:\0";
#[cfg(any(
target_os = "dragonfly",
target_os = "emscripten",
@ -24,7 +26,7 @@ const FILE_PATH: &str = "rand:\0";
target_os = "illumos"
))]
const FILE_PATH: &str = "/dev/random\0";
#[cfg(any(target_os = "android", target_os = "linux"))]
#[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))]
const FILE_PATH: &str = "/dev/urandom\0";
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
@ -43,7 +45,7 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
}
// Returns the file descriptor for the device file used to retrieve random
// bytes. The file will be opened exactly once. All successful calls will
// bytes. The file will be opened exactly once. All subsequent calls will
// return the same file descriptor. This file descriptor is never closed.
fn get_rng_fd() -> Result<libc::c_int, Error> {
static FD: AtomicUsize = AtomicUsize::new(LazyUsize::UNINIT);
@ -99,7 +101,7 @@ fn wait_until_rng_ready() -> Result<(), Error> {
// A negative timeout means an infinite timeout.
let res = unsafe { libc::poll(&mut pfd, 1, -1) };
if res >= 0 {
assert_eq!(res, 1); // We only used one fd, and cannot timeout.
debug_assert_eq!(res, 1); // We only used one fd, and cannot timeout.
return Ok(());
}
let err = crate::util_libc::last_os_error();

View file

@ -6,11 +6,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![allow(dead_code)]
use crate::error::ERRNO_NOT_POSITIVE;
use crate::util::LazyUsize;
use crate::Error;
use core::num::NonZeroU32;
use core::ptr::NonNull;
use crate::{util::LazyUsize, Error};
use core::{num::NonZeroU32, ptr::NonNull};
cfg_if! {
if #[cfg(any(target_os = "netbsd", target_os = "openbsd", target_os = "android"))] {
@ -23,6 +20,12 @@ cfg_if! {
use libc::__error as errno_location;
} else if #[cfg(target_os = "haiku")] {
use libc::_errnop as errno_location;
} else if #[cfg(all(target_os = "horizon", target_arch = "arm"))] {
extern "C" {
// Not provided by libc: https://github.com/rust-lang/libc/issues/1995
fn __errno() -> *mut libc::c_int;
}
use __errno as errno_location;
}
}
@ -43,7 +46,7 @@ pub fn last_os_error() -> Error {
if errno > 0 {
Error::from(NonZeroU32::new(errno as u32).unwrap())
} else {
ERRNO_NOT_POSITIVE
Error::ERRNO_NOT_POSITIVE
}
}
@ -109,14 +112,16 @@ cfg_if! {
// SAFETY: path must be null terminated, FD must be manually closed.
pub unsafe fn open_readonly(path: &str) -> Result<libc::c_int, Error> {
debug_assert!(path.as_bytes().last() == Some(&0));
debug_assert_eq!(path.as_bytes().last(), Some(&0));
loop {
let fd = open(path.as_ptr() as *const _, libc::O_RDONLY | libc::O_CLOEXEC);
if fd < 0 {
return Err(last_os_error());
if fd >= 0 {
return Ok(fd);
}
let err = last_os_error();
// We should try again if open() was interrupted.
if err.raw_os_error() != Some(libc::EINTR) {
return Err(err);
}
}
// O_CLOEXEC works on all Unix targets except for older Linux kernels (pre
// 2.6.23), so we also use an ioctl to make sure FD_CLOEXEC is set.
#[cfg(target_os = "linux")]
libc::ioctl(fd, libc::FIOCLEX);
Ok(fd)
}

View file

@ -7,8 +7,7 @@
// except according to those terms.
//! Implementation for VxWorks
use crate::error::{Error, RAND_SECURE_FATAL};
use crate::util_libc::last_os_error;
use crate::{util_libc::last_os_error, Error};
use core::sync::atomic::{AtomicBool, Ordering::Relaxed};
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
@ -16,7 +15,7 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
while !RNG_INIT.load(Relaxed) {
let ret = unsafe { libc::randSecure() };
if ret < 0 {
return Err(RAND_SECURE_FATAL);
return Err(Error::VXWORKS_RAND_SECURE);
} else if ret > 0 {
RNG_INIT.store(true, Relaxed);
break;

View file

@ -12,8 +12,12 @@ use core::num::NonZeroU32;
use wasi::random_get;
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
unsafe { random_get(dest.as_mut_ptr(), dest.len()) }.map_err(|e: wasi::Error| {
unsafe {
random_get(dest.as_mut_ptr(), dest.len()).map_err(|e: wasi::Error| {
// convert wasi's Error into getrandom's NonZeroU32 error
NonZeroU32::new(e.raw_error() as u32).unwrap().into()
// SAFETY: `wasi::Error` is `NonZeroU16` internally, so `e.raw_error()`
// will never return 0
NonZeroU32::new_unchecked(e.raw_error() as u32).into()
})
}
}

View file

@ -1,128 +0,0 @@
// 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.
//! Implementation for WASM via wasm-bindgen
extern crate std;
use core::cell::RefCell;
use core::mem;
use std::thread_local;
use js_sys::Uint8Array;
// We have to rename wasm_bindgen to bindgen in the Cargo.toml for backwards
// compatibility. We have to rename it back here or else the macros will break.
extern crate bindgen as wasm_bindgen;
use wasm_bindgen::prelude::*;
use crate::error::{BINDGEN_CRYPTO_UNDEF, BINDGEN_GRV_UNDEF};
use crate::Error;
const CHUNK_SIZE: usize = 256;
#[derive(Clone, Debug)]
enum RngSource {
Node(NodeCrypto),
Browser(BrowserCrypto, Uint8Array),
}
// JsValues are always per-thread, so we initialize RngSource for each thread.
// See: https://github.com/rustwasm/wasm-bindgen/pull/955
thread_local!(
static RNG_SOURCE: RefCell<Option<RngSource>> = RefCell::new(None);
);
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
assert_eq!(mem::size_of::<usize>(), 4);
RNG_SOURCE.with(|f| {
let mut source = f.borrow_mut();
if source.is_none() {
*source = Some(getrandom_init()?);
}
match source.as_ref().unwrap() {
RngSource::Node(n) => n.random_fill_sync(dest),
RngSource::Browser(crypto, buf) => {
// getRandomValues does not work with all types of WASM memory,
// so we initially write to browser memory to avoid exceptions.
for chunk in dest.chunks_mut(CHUNK_SIZE) {
// The chunk can be smaller than buf's length, so we call to
// JS to create a smaller view of buf without allocation.
let sub_buf = buf.subarray(0, chunk.len() as u32);
crypto.get_random_values(&sub_buf);
sub_buf.copy_to(chunk);
}
}
};
Ok(())
})
}
fn getrandom_init() -> Result<RngSource, Error> {
if let Ok(self_) = Global::get_self() {
// If `self` is defined then we're in a browser somehow (main window
// or web worker). We get `self.crypto` (called `msCrypto` on IE), so we
// can call `crypto.getRandomValues`. If `crypto` isn't defined, we
// assume we're in an older web browser and the OS RNG isn't available.
let crypto: BrowserCrypto = match (self_.crypto(), self_.ms_crypto()) {
(crypto, _) if !crypto.is_undefined() => crypto.into(),
(_, crypto) if !crypto.is_undefined() => crypto.into(),
_ => return Err(BINDGEN_CRYPTO_UNDEF),
};
// Test if `crypto.getRandomValues` is undefined as well
if crypto.get_random_values_fn().is_undefined() {
return Err(BINDGEN_GRV_UNDEF);
}
let buf = Uint8Array::new_with_length(CHUNK_SIZE as u32);
return Ok(RngSource::Browser(crypto, buf));
}
return Ok(RngSource::Node(MODULE.require("crypto")));
}
#[wasm_bindgen]
extern "C" {
type Global;
#[wasm_bindgen(getter, catch, static_method_of = Global, js_class = self, js_name = self)]
fn get_self() -> Result<Self_, JsValue>;
type Self_;
#[wasm_bindgen(method, getter, js_name = "msCrypto", structural)]
fn ms_crypto(me: &Self_) -> JsValue;
#[wasm_bindgen(method, getter, structural)]
fn crypto(me: &Self_) -> JsValue;
#[derive(Clone, Debug)]
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)]
fn get_random_values_fn(me: &BrowserCrypto) -> JsValue;
#[wasm_bindgen(method, js_name = getRandomValues, structural)]
fn get_random_values(me: &BrowserCrypto, buf: &Uint8Array);
#[derive(Clone, Debug)]
type NodeCrypto;
#[wasm_bindgen(method, js_name = randomFillSync, structural)]
fn random_fill_sync(me: &NodeCrypto, buf: &mut [u8]);
type NodeModule;
#[wasm_bindgen(js_name = module)]
static MODULE: NodeModule;
#[wasm_bindgen(method)]
fn require(this: &NodeModule, s: &str) -> NodeCrypto;
}

View file

@ -1,114 +0,0 @@
// 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.
//! Implementation for WASM via stdweb
extern crate std;
use core::mem;
use stdweb::js;
use stdweb::unstable::TryInto;
use stdweb::web::error::Error as WebError;
use crate::error::{STDWEB_NO_RNG, STDWEB_RNG_FAILED};
use crate::Error;
use std::sync::Once;
#[derive(Clone, Copy, Debug)]
enum RngSource {
Browser,
Node,
}
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
assert_eq!(mem::size_of::<usize>(), 4);
static ONCE: Once = Once::new();
static mut RNG_SOURCE: Result<RngSource, Error> = Ok(RngSource::Node);
// SAFETY: RNG_SOURCE is only written once, before being read.
ONCE.call_once(|| unsafe {
RNG_SOURCE = getrandom_init();
});
getrandom_fill(unsafe { RNG_SOURCE }?, dest)
}
fn getrandom_init() -> Result<RngSource, 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(RngSource::Browser)
} else if ty == 2 {
Ok(RngSource::Node)
} else {
unreachable!()
}
} else {
let _err: WebError = js! { return @{ result }.error }.try_into().unwrap();
error!("getrandom unavailable: {}", _err);
Err(STDWEB_NO_RNG)
}
}
fn getrandom_fill(source: RngSource, dest: &mut [u8]) -> Result<(), Error> {
for chunk in dest.chunks_mut(65536) {
let len = chunk.len() as u32;
let ptr = chunk.as_mut_ptr() as i32;
let result = match source {
RngSource::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 };
}
},
RngSource::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 {
let _err: WebError = js! { return @{ result }.error }.try_into().unwrap();
error!("getrandom failed: {}", _err);
return Err(STDWEB_RNG_FAILED);
}
}
Ok(())
}

View file

@ -6,20 +6,42 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Implementation for Windows
use crate::{error::RTL_GEN_RANDOM_FAILED, Error};
use crate::Error;
use core::{ffi::c_void, num::NonZeroU32, ptr};
const BCRYPT_USE_SYSTEM_PREFERRED_RNG: u32 = 0x00000002;
#[link(name = "bcrypt")]
extern "system" {
#[link_name = "SystemFunction036"]
fn RtlGenRandom(RandomBuffer: *mut u8, RandomBufferLength: u32) -> u8;
fn BCryptGenRandom(
hAlgorithm: *mut c_void,
pBuffer: *mut u8,
cbBuffer: u32,
dwFlags: u32,
) -> u32;
}
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
// Prevent overflow of u32
for chunk in dest.chunks_mut(u32::max_value() as usize) {
let ret = unsafe { RtlGenRandom(chunk.as_mut_ptr(), chunk.len() as u32) };
if ret == 0 {
return Err(RTL_GEN_RANDOM_FAILED);
let ret = unsafe {
BCryptGenRandom(
ptr::null_mut(),
chunk.as_mut_ptr(),
chunk.len() as u32,
BCRYPT_USE_SYSTEM_PREFERRED_RNG,
)
};
// NTSTATUS codes use the two highest bits for severity status.
if ret >> 30 == 0b11 {
// We zeroize the highest bit, so the error code will reside
// inside the range designated for OS codes.
let code = ret ^ (1 << 31);
// SAFETY: the second highest bit is always equal to one,
// so it's impossible to get zero. Unfortunately the type
// system does not have a way to express this yet.
let code = unsafe { NonZeroU32::new_unchecked(code) };
return Err(Error::from(code));
}
}
Ok(())

View file

@ -1,59 +0,0 @@
// 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.
//! Implementation for Windows UWP targets. After deprecation of Windows XP
//! and Vista, this can supersede the `RtlGenRandom`-based implementation.
use crate::Error;
use core::{ffi::c_void, num::NonZeroU32, ptr};
const BCRYPT_USE_SYSTEM_PREFERRED_RNG: u32 = 0x00000002;
extern "system" {
fn BCryptGenRandom(
hAlgorithm: *mut c_void,
pBuffer: *mut u8,
cbBuffer: u32,
dwFlags: u32,
) -> u32;
}
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
// Prevent overflow of u32
for chunk in dest.chunks_mut(u32::max_value() as usize) {
let ret = unsafe {
BCryptGenRandom(
ptr::null_mut(),
chunk.as_mut_ptr(),
chunk.len() as u32,
BCRYPT_USE_SYSTEM_PREFERRED_RNG,
)
};
// NTSTATUS codes use two highest bits for severity status
match ret >> 30 {
0b01 => {
info!("BCryptGenRandom: information code 0x{:08X}", ret);
}
0b10 => {
warn!("BCryptGenRandom: warning code 0x{:08X}", ret);
}
0b11 => {
error!("BCryptGenRandom: failed with 0x{:08X}", ret);
// We zeroize the highest bit, so the error code will reside
// inside the range of designated for OS codes.
let code = ret ^ (1 << 31);
// SAFETY: the second highest bit is always equal to one,
// so it's impossible to get zero. Unfortunately compiler
// is not smart enough to figure out it yet.
let code = unsafe { NonZeroU32::new_unchecked(code) };
return Err(Error::from(code));
}
_ => (),
}
}
Ok(())
}

View file

@ -1,26 +1,24 @@
#[cfg(feature = "wasm-bindgen")]
use wasm_bindgen_test::*;
use super::getrandom_impl;
use getrandom::getrandom;
#[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
use wasm_bindgen_test::wasm_bindgen_test as test;
#[cfg(feature = "test-in-browser")]
wasm_bindgen_test_configure!(run_in_browser);
wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);
#[cfg_attr(feature = "wasm-bindgen", wasm_bindgen_test)]
#[test]
fn test_zero() {
// Test that APIs are happy with zero-length requests
getrandom(&mut [0u8; 0]).unwrap();
getrandom_impl(&mut [0u8; 0]).unwrap();
}
#[cfg_attr(feature = "wasm-bindgen", wasm_bindgen_test)]
#[test]
fn test_diff() {
let mut v1 = [0u8; 1000];
getrandom(&mut v1).unwrap();
getrandom_impl(&mut v1).unwrap();
let mut v2 = [0u8; 1000];
getrandom(&mut v2).unwrap();
getrandom_impl(&mut v2).unwrap();
let mut n_diff_bits = 0;
for i in 0..v1.len() {
@ -31,18 +29,18 @@ fn test_diff() {
assert!(n_diff_bits >= v1.len() as u32);
}
#[cfg_attr(feature = "wasm-bindgen", wasm_bindgen_test)]
#[test]
fn test_huge() {
let mut huge = [0u8; 100_000];
getrandom(&mut huge).unwrap();
getrandom_impl(&mut huge).unwrap();
}
// On WASM, the thread API always fails/panics
#[cfg(not(target_arch = "wasm32"))]
#[test]
fn test_multithreading() {
use std::sync::mpsc::channel;
use std::thread;
extern crate std;
use std::{sync::mpsc::channel, thread, vec};
let mut txs = vec![];
for _ in 0..20 {
@ -55,7 +53,7 @@ fn test_multithreading() {
let mut v = [0u8; 1000];
for _ in 0..100 {
getrandom(&mut v).unwrap();
getrandom_impl(&mut v).unwrap();
thread::yield_now();
}
});

View file

@ -0,0 +1,50 @@
// Test that a custom handler works on wasm32-unknown-unknown
#![cfg(all(
target_arch = "wasm32",
target_os = "unknown",
feature = "custom",
not(feature = "js")
))]
use wasm_bindgen_test::wasm_bindgen_test as test;
#[cfg(feature = "test-in-browser")]
wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);
use core::{
num::NonZeroU32,
sync::atomic::{AtomicU8, Ordering},
};
use getrandom::{getrandom, register_custom_getrandom, Error};
fn len7_err() -> Error {
NonZeroU32::new(Error::INTERNAL_START + 7).unwrap().into()
}
fn super_insecure_rng(buf: &mut [u8]) -> Result<(), Error> {
// Length 7 buffers return a custom error
if buf.len() == 7 {
return Err(len7_err());
}
// Otherwise, increment an atomic counter
static COUNTER: AtomicU8 = AtomicU8::new(0);
for b in buf {
*b = COUNTER.fetch_add(1, Ordering::Relaxed);
}
Ok(())
}
register_custom_getrandom!(super_insecure_rng);
#[test]
fn custom_rng_output() {
let mut buf = [0u8; 4];
assert_eq!(getrandom(&mut buf), Ok(()));
assert_eq!(buf, [0, 1, 2, 3]);
assert_eq!(getrandom(&mut buf), Ok(()));
assert_eq!(buf, [4, 5, 6, 7]);
}
#[test]
fn rng_err_output() {
assert_eq!(getrandom(&mut [0; 7]), Err(len7_err()));
}

View file

@ -0,0 +1,11 @@
// Don't test on custom wasm32-unknown-unknown
#![cfg(not(all(
target_arch = "wasm32",
target_os = "unknown",
feature = "custom",
not(feature = "js")
)))]
// Use the normal getrandom implementation on this architecture.
use getrandom::getrandom as getrandom_impl;
mod common;

View file

@ -0,0 +1,15 @@
// We only test the RDRAND-based RNG source on supported architectures.
#![cfg(any(target_arch = "x86_64", target_arch = "x86"))]
// rdrand.rs expects to be part of the getrandom main crate, so we need these
// additional imports to get rdrand.rs to compile.
use getrandom::Error;
#[macro_use]
extern crate cfg_if;
#[path = "../src/rdrand.rs"]
mod rdrand;
#[path = "../src/util.rs"]
mod util;
use rdrand::getrandom_inner as getrandom_impl;
mod common;

View file

@ -1 +1 @@
{"files":{"CHANGELOG.md":"28794454ddd6739a1c0cfc6df90a25af3a6a62827d7f7aaea3ee39440b9ab87b","COPYRIGHT":"90eb64f0279b0d9432accfa6023ff803bc4965212383697eee27a0f426d5f8d5","Cargo.lock":"ee32a72318ee8c6986509e36ae276406b622897cb82324c3f0e39551f0edc2cb","Cargo.toml":"4bc436e4b01131f4809c2d3dbdd3ede6987135d3fb53f718cd4a85cafa240224","LICENSE-APACHE":"aaff376532ea30a0cd5330b9502ad4a4c8bf769c539c87ffe78819d188a18ebf","LICENSE-MIT":"209fbbe0ad52d9235e37badf9cadfe4dbdc87203179c0899e738b39ade42177b","README.md":"cc7af91db7807de40503b3033ea596aeb78a89c0997894ffd0e56c2fb06eab36","SECURITY.md":"b1c8e24e88bd81bb65bad212b1176d18a73f5191ae650a75784954a74acc31d4","benches/generators.rs":"361886b55d31449e7a649518e5a751eff4494cad8f3e247aee741dddd82d99a4","benches/misc.rs":"6fa587fb3bab8502b7dd88805a4255c5fc6b42b8b3f5d8eb727af1b80b0ebe29","benches/seq.rs":"bdc6c92a8cedb5ff41ac028618053eaf5bf4c7be8b16c83c79e9467039381302","benches/weighted.rs":"3649964f75cd6cb4e50134fbb14e09fb995ca6667cb34f99d0bd27a9429de3ea","examples/monte-carlo.rs":"e55087f1e1f48d723ffc49fb107f5846c163a5e0c97206cd43a261cbdf6bb1b4","examples/monty-hall.rs":"c079293ec0633717b4d903c63f9db166c2a0fe6c8ba9a98f084fb4975fccbc07","rustfmt.toml":"a582a93dc6492d36daae52df7800e369887ba0984d68d98f70b99ca870fed268","src/distributions/bernoulli.rs":"fa81935ea2091d43d373bb7f2f579522a5beae33c9aa9598fe8490298753eba7","src/distributions/binomial.rs":"667f4f2cddb7994aa68926dbdda4482c24ce28f9d392d2a439a9eb675bfe04be","src/distributions/cauchy.rs":"bf55d4535960136351938a92254d4429689c20ebba051808c171f818adbb1191","src/distributions/dirichlet.rs":"ef28a435d9fa6b2f8d953613135cf1be7905f3909edd86b65be4e77685dd9c47","src/distributions/exponential.rs":"0419f25e369b66226ecaaf500395bf3b0decc5f90aedba1151553085774129bf","src/distributions/float.rs":"8dc11e2e4ae743e19e7799da02862480f4499789d8c58c47fbeca5f7930d7cb9","src/distributions/gamma.rs":"bfa848d6165e653d6e461e5b92f49bb119c6f9e259ffe7d7b8fbb34234d611d1","src/distributions/integer.rs":"3eb86fe2a1aca9125463cc581245b498d8c23c0f80422e5496582d2763e605fc","src/distributions/mod.rs":"d2a2b3e36f2f8bdeb93ffc1f3032175b6a062f485e6bf78502401aa854c4fb24","src/distributions/normal.rs":"2ef7e174877f7ccb7c4ff5cbce5dc24eaad0cc700fad33a6d3c20b52ed8f4bcb","src/distributions/other.rs":"e0a6f5e2d6699e460267f463c95797781daf347bff9192b7af7630a18885290c","src/distributions/pareto.rs":"2c1fee43a4b408e9da32abec384542a243b96c5303371a63d0fc2f1baaa02c64","src/distributions/poisson.rs":"ec123c26b0029cb96325e2551e6c82c9b7f7a41c933cc3f40f6f6f6ac7990cef","src/distributions/triangular.rs":"4be8ba5eccdda8ab90319325381ff6952caf59261b59a7a6f79f8867ac426249","src/distributions/uniform.rs":"5a1af322eb2b6cca701bd0a14247b4387e78686318fd01f3213d0f3252cbea18","src/distributions/unit_circle.rs":"36d8640cb8b26fcdb1b7d4d6c0b349316117f9300f480304c8a15d9d148f5937","src/distributions/unit_sphere.rs":"4ecc4260d4e4cc3ebea679a29d2ec343a54d56016c37b2632d78e888a92cb584","src/distributions/utils.rs":"6478e01b2bd0de99e917373f3c86db1142ea10c67488691cbc10af29891ac6dc","src/distributions/weibull.rs":"9b5acc5981a44309820d3a1fd3fff17984590aeebb41a1cdf5098890ad1dec04","src/distributions/weighted/alias_method.rs":"6172aad0d461f6816a944dec00aac09e943fd13123ec518184995658538de7ed","src/distributions/weighted/mod.rs":"54386cf92d39c69b38208bc9b0e2f74949512784a43684d63523bee03c1cc8bc","src/distributions/ziggurat_tables.rs":"2994bb821a60681e0d7a2bb45fcdcbea1040aa775c9aab2c80a7161d753d1ad0","src/lib.rs":"588e35ffc5c859b588d99de6d331251939440383b09da92b1017ddced19a3f41","src/prelude.rs":"cb49fcfc4f0d3b6eaa43c00a667dd3456e6a321e98eee17320ec4a703d6faf4b","src/rngs/adapter/mod.rs":"851918de58eda79c0cb3f2c0756fb756a7769f35115a77a5ae2025e05b4c1d93","src/rngs/adapter/read.rs":"c162cd131c9ed4868415360f627aba17046d4acdae6b7cdc9c75a41e60757caa","src/rngs/adapter/reseeding.rs":"93d2fbf62d1a5765437c4360b94a2df69921fb9cd5b704c4c2023f53eb15ee03","src/rngs/entropy.rs":"a7a07e1f23c45332994eb0b76d250f68a2394048ab6fe3c6691fef719e30fb42","src/rngs/mock.rs":"d1ac752afa589bc3925067f98fe6c13223bda6c3e22b85abe22e4cd60e22bf90","src/rngs/mod.rs":"9ae5e9aa965d3393ef90983ab85834599432c9fc2c1d40de1b9237ab3fc91eb1","src/rngs/small.rs":"8cc5d1ae357554181b4c5fa978e95b667147c251f8431881da66b97ff584224c","src/rngs/std.rs":"82117975ada00199c8ca3677fc4e00bb8b574c50cd321e04b37d0c7542fa0b30","src/rngs/thread.rs":"ccb98ead28d49f6e35d6e50150cbd89579409fcfd792565aceb03e716447de9b","src/seq/index.rs":"4f2566bd9c189fc68a68fc1ad913c6efe3d3ea0699b1b1e110df9d51725c5b3d","src/seq/mod.rs":"26707ad8595093746852799c1d2eee159b69044abfedfcbfe26263a25f8035fa"},"package":"6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"}
{"files":{"CHANGELOG.md":"76b505678de234d2eef751593feec6d9debb76c20d45564a9f23c9e9783dbc63","COPYRIGHT":"90eb64f0279b0d9432accfa6023ff803bc4965212383697eee27a0f426d5f8d5","Cargo.toml":"9bb028fb3b697653beb433ddcf4c1292b3db10ea5ed27a695df6e4e604ba6d4b","LICENSE-APACHE":"35242e7a83f69875e6edeff02291e688c97caafe2f8902e4e19b49d3e78b4cab","LICENSE-MIT":"209fbbe0ad52d9235e37badf9cadfe4dbdc87203179c0899e738b39ade42177b","README.md":"ddb5a1fa9442c6cab92a3510365937e729f839c94b97e75d3f0430bf3a4dd2bd","src/distributions/bernoulli.rs":"437e61c41f73b6fffad11a65cc45d05df198ab05b37328eba687a9779b86948a","src/distributions/distribution.rs":"36086233c9682eb16874ba87bb1ec39db71559c5ce2ca618dc8c6bd9710d3b3a","src/distributions/float.rs":"ef894cbfeab9c734894468175c4553100b4a261f431047f2bbc4949aa43e2ccd","src/distributions/integer.rs":"a380e0627c97cfad0d94e0fdfb4dad73060d23073cc1d379f06c4dbd2a4fc2db","src/distributions/mod.rs":"f87a133e704e38ad554c8b4f62497d6320c74ef7d37df7871c61bde48d200b5b","src/distributions/other.rs":"e60568f8eadc0594636641a2070e53f5127fb532a74101ed4767f424a6e92622","src/distributions/slice.rs":"94f5abfe602679e980e4561bb03dcac28bbd3bb5f7bd2821f396a6293c0878db","src/distributions/uniform.rs":"9eb0769b7c268c2e4f502ede0d779cb1ab5243d70a1fb39f2f5e316bcf9586e2","src/distributions/utils.rs":"41304f5e2d74e750fc62f7871443c6e9d510a6c99be4614fb5c756682e0344d7","src/distributions/weighted.rs":"ae019d9b688e33cb912c9a04668cce3e7df86abab994db88478c6c339f98222f","src/distributions/weighted_index.rs":"874d1db2e258d9c049be08ae80b72ec2c75af0f2571f83091a26a3f6c747a6f0","src/lib.rs":"a773ff7b0dad376e5ef23661c40b7a96df4233fef90dab303db93f209aee314f","src/prelude.rs":"2f2132d74ce9f70513224baad3b161b1585a639f9136a254cdb0e7f8ffceb25b","src/rng.rs":"5d9b55069197f9f98298e8d930b13d8c65ab2701660bfbf52d83c6d7d7aff8c6","src/rngs/adapter/mod.rs":"28318871529da61dccc0fe8c0bcafa99b133c721d4bb506fa34d0831f4ca2639","src/rngs/adapter/read.rs":"b044061c46d0b8e6a4f25c69d3e8bb6f9df08cd8df9b5eae131a1d4934020e03","src/rngs/adapter/reseeding.rs":"89abebade9bca847889155ac3357c0021d2c6181dd47478332a644820ade0c6e","src/rngs/mock.rs":"0074abe04cf84b1263218f50140931fa4188f4e0a43fe3205556a00e4c36d1e9","src/rngs/mod.rs":"a6dec3d19e1726ba05f130ab9b20719d79177b8c1584cdd7b5f37b9996315ed3","src/rngs/small.rs":"a8e61c6e0bad62f06db1325e3b93eff1d4aa9e82cf0316fbfd02da2ef5b85b83","src/rngs/std.rs":"3cee48bf1fea18b84f585680a947f3aeea949b756cc37d99217291f9759be7c9","src/rngs/thread.rs":"c3cc07465bf02d08182afc47a40e50095d7c83633e09dcd071974b2a902e6fce","src/rngs/xoshiro128plusplus.rs":"deca2450a2d5ea826ca6f47cccb9ee06daeac38799a30a107b78c5dae78ae30c","src/rngs/xoshiro256plusplus.rs":"d7e214f8288041cede7ef26e829dd2196f7b4843455d7f1b9a3ef080d570bc5f","src/seq/index.rs":"5247833f7bfc8c5c11337ce7dc0a55a6979ea664ddddd70b6e2b9598058ab44d","src/seq/mod.rs":"dd97a635e89e1d50153c57ec03d8a346a063486998ef14ca4fdc60659f1612fb"},"package":"34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"}

View file

@ -8,6 +8,107 @@ 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.8.5] - 2021-08-20
### Fixes
- Fix build on non-32/64-bit architectures (#1144)
- Fix "min_const_gen" feature for `no_std` (#1173)
- Check `libc::pthread_atfork` return value with panic on error (#1178)
- More robust reseeding in case `ReseedingRng` is used from a fork handler (#1178)
- Fix nightly: remove unused `slice_partition_at_index` feature (#1215)
- Fix nightly + `simd_support`: update `packed_simd` (#1216)
### Rngs
- `StdRng`: Switch from HC128 to ChaCha12 on emscripten (#1142).
We now use ChaCha12 on all platforms.
### Documentation
- Added docs about rand's use of const generics (#1150)
- Better random chars example (#1157)
## [0.8.4] - 2021-06-15
### Additions
- Use const-generics to support arrays of all sizes (#1104)
- Implement `Clone` and `Copy` for `Alphanumeric` (#1126)
- Add `Distribution::map` to derive a distribution using a closure (#1129)
- Add `Slice` distribution (#1107)
- Add `DistString` trait with impls for `Standard` and `Alphanumeric` (#1133)
### Other
- Reorder asserts in `Uniform` float distributions for easier debugging of non-finite arguments
(#1094, #1108)
- Add range overflow check in `Uniform` float distributions (#1108)
- Deprecate `rngs::adapter::ReadRng` (#1130)
## [0.8.3] - 2021-01-25
### Fixes
- Fix `no-std` + `alloc` build by gating `choose_multiple_weighted` on `std` (#1088)
## [0.8.2] - 2021-01-12
### Fixes
- Fix panic in `UniformInt::sample_single_inclusive` and `Rng::gen_range` when
providing a full integer range (eg `0..=MAX`) (#1087)
## [0.8.1] - 2020-12-31
### Other
- Enable all stable features in the playground (#1081)
## [0.8.0] - 2020-12-18
### Platform support
- The minimum supported Rust version is now 1.36 (#1011)
- `getrandom` updated to v0.2 (#1041)
- Remove `wasm-bindgen` and `stdweb` feature flags. For details of WASM support,
see the [getrandom documentation](https://docs.rs/getrandom/latest). (#948)
- `ReadRng::next_u32` and `next_u64` now use little-Endian conversion instead
of native-Endian, affecting results on Big-Endian platforms (#1061)
- The `nightly` feature no longer implies the `simd_support` feature (#1048)
- Fix `simd_support` feature to work on current nightlies (#1056)
### Rngs
- `ThreadRng` is no longer `Copy` to enable safe usage within thread-local destructors (#1035)
- `gen_range(a, b)` was replaced with `gen_range(a..b)`. `gen_range(a..=b)` is
also supported. Note that `a` and `b` can no longer be references or SIMD types. (#744, #1003)
- Replace `AsByteSliceMut` with `Fill` and add support for `[bool], [char], [f32], [f64]` (#940)
- Restrict `rand::rngs::adapter` to `std` (#1027; see also #928)
- `StdRng`: add new `std_rng` feature flag (enabled by default, but might need
to be used if disabling default crate features) (#948)
- `StdRng`: Switch from ChaCha20 to ChaCha12 for better performance (#1028)
- `SmallRng`: Replace PCG algorithm with xoshiro{128,256}++ (#1038)
### Sequences
- Add `IteratorRandom::choose_stable` as an alternative to `choose` which does
not depend on size hints (#1057)
- Improve accuracy and performance of `IteratorRandom::choose` (#1059)
- Implement `IntoIterator` for `IndexVec`, replacing the `into_iter` method (#1007)
- Add value stability tests for `seq` module (#933)
### Misc
- Support `PartialEq` and `Eq` for `StdRng`, `SmallRng` and `StepRng` (#979)
- Added a `serde1` feature and added Serialize/Deserialize to `UniformInt` and `WeightedIndex` (#974)
- Drop some unsafe code (#962, #963, #1011)
- Reduce packaged crate size (#983)
- Migrate to GitHub Actions from Travis+AppVeyor (#1073)
### Distributions
- `Alphanumeric` samples bytes instead of chars (#935)
- `Uniform` now supports `char`, enabling `rng.gen_range('A'..='Z')` (#1068)
- Add `UniformSampler::sample_single_inclusive` (#1003)
#### Weighted sampling
- Implement weighted sampling without replacement (#976, #1013)
- `rand::distributions::alias_method::WeightedIndex` was moved to `rand_distr::WeightedAliasIndex`.
The simpler alternative `rand::distribution::WeightedIndex` remains. (#945)
- Improve treatment of rounding errors in `WeightedIndex::update_weights` (#956)
- `WeightedIndex`: return error on NaN instead of panic (#1005)
### Documentation
- Document types supported by `random` (#994)
- Document notes on password generation (#995)
- Note that `SmallRng` may not be the best choice for performance and in some
other cases (#1038)
- Use `doc(cfg)` to annotate feature-gated items (#1019)
- Adjust README (#1065)
## [0.7.3] - 2020-01-10
### Fixes
- The `Bernoulli` distribution constructors now reports an error on NaN and on
@ -40,7 +141,7 @@ when updating from `rand 0.7.0` without also updating `rand_core`.
- Fix or squelch issues from Clippy lints (#840)
### Additions
- Add a `no_std` target to CI to continously evaluate `no_std` status (#844)
- Add a `no_std` target to CI to continuously evaluate `no_std` status (#844)
- `WeightedIndex`: allow adjusting a sub-set of weights (#866)
## [0.7.0] - 2019-06-28
@ -400,7 +501,7 @@ when updating from `rand 0.7.0` without also updating `rand_core`.
## [0.3.14] - 2016-02-13
### Fixed
- Inline definitions from winapi/advapi32, wich decreases build times
- Inline definitions from winapi/advapi32, which decreases build times
## [0.3.13] - 2016-01-09
@ -595,4 +696,4 @@ when updating from `rand 0.7.0` without also updating `rand_core`.
## [0.10-pre] - 2014-03-02
### Added
- Seperate `rand` out of the standard library
- Separate `rand` out of the standard library

388
third_party/rust/rand/Cargo.lock generated vendored
View file

@ -1,388 +0,0 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "base-x"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bumpalo"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "c2-chacha"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "cfg-if"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "discard"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "getrandom"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"stdweb 0.4.18 (registry+https://github.com/rust-lang/crates.io-index)",
"wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"wasm-bindgen 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "itoa"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "libc"
version = "0.2.62"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "log"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "packed_simd"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ppv-lite86"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "proc-macro2"
version = "0.4.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "proc-macro2"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "quote"
version = "0.6.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "quote"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand"
version = "0.7.3"
dependencies = [
"getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"packed_simd 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_pcg 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_chacha"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_core"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_hc"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_pcg"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand_core 0.5.1 (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"
dependencies = [
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ryu"
version = "1.0.0"
source = "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"
dependencies = [
"semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "semver-parser"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "serde"
version = "1.0.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "serde_derive"
version = "1.0.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_json"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "sha1"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "stdweb"
version = "0.4.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"discard 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
"stdweb-derive 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"stdweb-internal-macros 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
"stdweb-internal-runtime 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"wasm-bindgen 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "stdweb-derive"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "stdweb-internal-macros"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"base-x 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
"sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "stdweb-internal-runtime"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "syn"
version = "0.15.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "syn"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "unicode-xid"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unicode-xid"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "wasi"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "wasm-bindgen"
version = "0.2.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
"wasm-bindgen-macro 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bumpalo 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
"wasm-bindgen-shared 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"wasm-bindgen-macro-support 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
"wasm-bindgen-backend 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
"wasm-bindgen-shared 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum base-x 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "76f4eae81729e69bb1819a26c6caac956cc429238388091f98cb6cd858f16443"
"checksum bumpalo 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ad807f2fc2bf185eeb98ff3a901bd46dc5ad58163d0fa4577ba0d25674d71708"
"checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101"
"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33"
"checksum discard 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0"
"checksum getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "473a1265acc8ff1e808cd0a1af8cee3c2ee5200916058a2ca113c29f2d903571"
"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f"
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
"checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba"
"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
"checksum packed_simd 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a85ea9fc0d4ac0deb6fe7911d38786b32fc11119afd9e9d38b84ff691ce64220"
"checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b"
"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
"checksum proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e98a83a9f9b331f54b924e68a66acb1bb35cb01fb0a23645139967abefb697e8"
"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1"
"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
"checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853"
"checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
"checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
"checksum rand_pcg 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429"
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
"checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997"
"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 serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)" = "f4473e8506b213730ff2061073b48fa51dcc66349219e2e7c5608f0296a1d95a"
"checksum serde_derive 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)" = "11e410fde43e157d789fc290d26bc940778ad0fdd47836426fbac36573710dbb"
"checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704"
"checksum sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d"
"checksum stdweb 0.4.18 (registry+https://github.com/rust-lang/crates.io-index)" = "a68c0ce28cf7400ed022e18da3c4591e14e1df02c70e93573cc59921b3923aeb"
"checksum stdweb-derive 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0e21ebd9179de08f2300a65454268a17ea3de204627458588c84319c4def3930"
"checksum stdweb-internal-macros 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "e68f7d08b76979a43e93fe043b66d2626e35d41d68b0b85519202c6dd8ac59fa"
"checksum stdweb-internal-runtime 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d52317523542cc0af5b7e31017ad0f7d1e78da50455e38d5657cd17754f617da"
"checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5"
"checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf"
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
"checksum wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b89c3ce4ce14bdc6fb6beaf9ec7928ca331de5df7e5ea278375642a2f478570d"
"checksum wasm-bindgen 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)" = "dcddca308b16cd93c2b67b126c688e5467e4ef2e28200dc7dfe4ae284f2faefc"
"checksum wasm-bindgen-backend 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)" = "f805d9328b5fc7e5c6399960fd1889271b9b58ae17bdb2417472156cc9fafdd0"
"checksum wasm-bindgen-macro 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)" = "3ff88201a482abfc63921621f6cb18eb1efd74f136b05e5841e7f8ca434539e9"
"checksum wasm-bindgen-macro-support 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)" = "6a433d89ecdb9f77d46fcf00c8cf9f3467b7de9954d8710c175f61e2e245bb0e"
"checksum wasm-bindgen-shared 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)" = "d41fc1bc3570cdf8d108c15e014045fd45a95bb5eb36605f96a90461fc34027d"

View file

@ -3,23 +3,22 @@
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g., crates.io) dependencies
# to registry (e.g., crates.io) dependencies.
#
# If you believe there's an error in this file please file an
# issue against the rust-lang/cargo repository. If you're
# editing this file be aware that the upstream Cargo.toml
# will likely look very different (and much more reasonable)
# If you are reading this file be aware that the original Cargo.toml
# will likely look very different (and much more reasonable).
# See Cargo.toml.orig for the original contents.
[package]
edition = "2018"
name = "rand"
version = "0.7.3"
version = "0.8.5"
authors = ["The Rand Project Developers", "The Rust Project Developers"]
exclude = ["/utils/*", "/.travis.yml", "/appveyor.yml", ".gitignore"]
include = ["src/", "LICENSE-*", "README.md", "CHANGELOG.md", "COPYRIGHT"]
autobenches = true
description = "Random number generators and other randomness functionality.\n"
homepage = "https://crates.io/crates/rand"
documentation = "https://rust-random.github.io/rand/"
homepage = "https://rust-random.github.io/book"
documentation = "https://docs.rs/rand"
readme = "README.md"
keywords = ["random", "rng"]
categories = ["algorithms", "no-std"]
@ -27,54 +26,50 @@ license = "MIT OR Apache-2.0"
repository = "https://github.com/rust-random/rand"
[package.metadata.docs.rs]
all-features = true
[dependencies.getrandom_package]
version = "0.1.1"
optional = true
package = "getrandom"
rustdoc-args = ["--cfg", "doc_cfg"]
[package.metadata.playground]
features = ["small_rng", "serde1"]
[dependencies.log]
version = "0.4.4"
optional = true
[dependencies.packed_simd]
version = "0.3"
version = "0.3.7"
features = ["into_bits"]
optional = true
package = "packed_simd_2"
[dependencies.rand_chacha]
version = "0.3.0"
optional = true
default-features = false
[dependencies.rand_core]
version = "0.5.1"
version = "0.6.0"
[dependencies.rand_pcg]
version = "0.2"
[dependencies.serde]
version = "1.0.103"
features = ["derive"]
optional = true
[dev-dependencies.rand_hc]
version = "0.2"
[dev-dependencies.bincode]
version = "1.2.1"
[dev-dependencies.rand_pcg]
version = "0.2"
version = "0.3.0"
[features]
alloc = ["rand_core/alloc"]
default = ["std"]
getrandom = ["getrandom_package", "rand_core/getrandom"]
nightly = ["simd_support"]
serde1 = []
default = ["std", "std_rng"]
getrandom = ["rand_core/getrandom"]
min_const_gen = []
nightly = []
serde1 = ["serde", "rand_core/serde1"]
simd_support = ["packed_simd"]
small_rng = ["rand_pcg"]
small_rng = []
std = ["rand_core/std", "rand_chacha/std", "alloc", "getrandom", "libc"]
stdweb = ["getrandom_package/stdweb"]
wasm-bindgen = ["getrandom_package/wasm-bindgen"]
[target."cfg(not(target_os = \"emscripten\"))".dependencies.rand_chacha]
version = "0.2.1"
default-features = false
[target."cfg(target_os = \"emscripten\")".dependencies.rand_hc]
version = "0.2"
std_rng = ["rand_chacha"]
[target."cfg(unix)".dependencies.libc]
version = "0.2.22"
optional = true
default-features = false
[badges.appveyor]
repository = "rust-random/rand"
[badges.travis-ci]
repository = "rust-random/rand"

View file

@ -174,28 +174,3 @@ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
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.

View file

@ -1,26 +1,47 @@
# Rand
[![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)
[![Test Status](https://github.com/rust-random/rand/workflows/Tests/badge.svg?event=push)](https://github.com/rust-random/rand/actions)
[![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://img.shields.io/badge/api-master-yellow.svg)](https://rust-random.github.io/rand/rand)
[![API](https://docs.rs/rand/badge.svg)](https://docs.rs/rand)
[![Minimum rustc version](https://img.shields.io/badge/rustc-1.32+-lightgray.svg)](https://github.com/rust-random/rand#rust-version-requirements)
[![Minimum rustc version](https://img.shields.io/badge/rustc-1.36+-lightgray.svg)](https://github.com/rust-random/rand#rust-version-requirements)
A Rust library for random number generation.
A Rust library for random number generation, featuring:
Rand provides utilities to generate random numbers, to convert them to useful
types and distributions, and some randomness-related algorithms.
- Easy random value generation and usage via the [`Rng`](https://docs.rs/rand/*/rand/trait.Rng.html),
[`SliceRandom`](https://docs.rs/rand/*/rand/seq/trait.SliceRandom.html) and
[`IteratorRandom`](https://docs.rs/rand/*/rand/seq/trait.IteratorRandom.html) traits
- Secure seeding via the [`getrandom` crate](https://crates.io/crates/getrandom)
and fast, convenient generation via [`thread_rng`](https://docs.rs/rand/*/rand/fn.thread_rng.html)
- A modular design built over [`rand_core`](https://crates.io/crates/rand_core)
([see the book](https://rust-random.github.io/book/crates.html))
- Fast implementations of the best-in-class [cryptographic](https://rust-random.github.io/book/guide-rngs.html#cryptographically-secure-pseudo-random-number-generators-csprngs) and
[non-cryptographic](https://rust-random.github.io/book/guide-rngs.html#basic-pseudo-random-number-generators-prngs) generators
- A flexible [`distributions`](https://docs.rs/rand/*/rand/distributions/index.html) module
- Samplers for a large number of random number distributions via our own
[`rand_distr`](https://docs.rs/rand_distr) and via
the [`statrs`](https://docs.rs/statrs/0.13.0/statrs/)
- [Portably reproducible output](https://rust-random.github.io/book/portability.html)
- `#[no_std]` compatibility (partial)
- *Many* performance optimisations
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`.
It's also worth pointing out what `rand` *is not*:
- Small. Most low-level crates are small, but the higher-level `rand` and
`rand_distr` each contain a lot of functionality.
- Simple (implementation). We have a strong focus on correctness, speed and flexibility, but
not simplicity. If you prefer a small-and-simple library, there are
alternatives including [fastrand](https://crates.io/crates/fastrand)
and [oorandom](https://crates.io/crates/oorandom).
- Slow. We take performance seriously, with considerations also for set-up
time of new distributions, commonly-used parameters, and parameters of the
current sampler.
Documentation:
- [The Rust Rand Book](https://rust-random.github.io/book)
- [API reference (master)](https://rust-random.github.io/rand)
- [API reference (master branch)](https://rust-random.github.io/rand)
- [API reference (docs.rs)](https://docs.rs/rand)
@ -30,7 +51,7 @@ Add this to your `Cargo.toml`:
```toml
[dependencies]
rand = "0.7"
rand = "0.8.4"
```
To get started using Rand, see [The Book](https://rust-random.github.io/book).
@ -38,6 +59,27 @@ To get started using Rand, see [The Book](https://rust-random.github.io/book).
## Versions
Rand is *mature* (suitable for general usage, with infrequent breaking releases
which minimise breakage) but not yet at 1.0. We maintain compatibility with
pinned versions of the Rust compiler (see below).
Current Rand versions are:
- Version 0.7 was released in June 2019, moving most non-uniform distributions
to an external crate, moving `from_entropy` to `SeedableRng`, and many small
changes and fixes.
- Version 0.8 was released in December 2020 with many small changes.
A detailed [changelog](CHANGELOG.md) is available for releases.
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).
Rand has not yet reached 1.0 implying some breaking changes may arrive in the
future ([SemVer](https://semver.org/) allows each 0.x.0 release to include
breaking changes), but is considered *mature*: breaking changes are minimised
and breaking releases are infrequent.
Rand libs have inter-dependencies and make use of the
[semver trick](https://github.com/dtolnay/semver-trick/) in order to make traits
compatible across crate versions. (This is especially important for `RngCore`
@ -47,26 +89,6 @@ depending on the *next* lib version (e.g. `rand_core` versions `0.2.2` and
`rand_core_0_3_0::SeedableRng` are distinct, incompatible traits, which can
cause build errors. Usually, running `cargo update` is enough to fix any issues.
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.7 was released in June 2019, moving most non-uniform distributions
to an external crate, moving `from_entropy` to `SeedableRng`, and many small
changes and fixes.
- 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.
A detailed [changelog](CHANGELOG.md) is available.
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).
### Yanked versions
Some versions of Rand crates have been yanked ("unreleased"). Where this occurs,
@ -75,14 +97,14 @@ issue tracker with the keyword `yank` *should* uncover the motivation.
### Rust version requirements
Since version 0.7, Rand requires **Rustc version 1.32 or greater**.
Rand 0.5 requires Rustc 1.22 or greater while versions
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.
Since version 0.8, Rand requires **Rustc version 1.36 or greater**.
Rand 0.7 requires Rustc 1.32 or greater while versions 0.5 require Rustc 1.22 or
greater, and 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.
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
Continuous Integration (CI) will always test the minimum supported Rustc version
(the MSRV). The current policy is that this can be updated in any
Rand release if required, but the change must be noted in the changelog.
## Crate Features
@ -90,26 +112,28 @@ Rand release if required, but the change must be noted in the changelog.
Rand is built with these features enabled by default:
- `std` enables functionality dependent on the `std` lib
- `alloc` (implied by `std`) enables functionality requiring an allocator (when using this feature in `no_std`, Rand requires Rustc version 1.36 or greater)
- `alloc` (implied by `std`) enables functionality requiring an allocator
- `getrandom` (implied by `std`) is an optional dependency providing the code
behind `rngs::OsRng`
- `std_rng` enables inclusion of `StdRng`, `thread_rng` and `random`
(the latter two *also* require that `std` be enabled)
Optionally, the following dependencies can be enabled:
- `log` enables logging via the `log` crate
- `stdweb` implies `getrandom/stdweb` to enable
`getrandom` support on `wasm32-unknown-unknown`
(will be removed in rand 0.8; activate via `getrandom` crate instead)
- `wasm-bindgen` implies `getrandom/wasm-bindgen` to enable
`getrandom` support on `wasm32-unknown-unknown`
(will be removed in rand 0.8; activate via `getrandom` crate instead)
Additionally, these features configure Rand:
- `small_rng` enables inclusion of the `SmallRng` PRNG
- `nightly` enables all experimental features
- `nightly` enables some optimizations requiring nightly Rust
- `simd_support` (experimental) enables sampling of SIMD values
(uniformly random SIMD integers and floats)
(uniformly random SIMD integers and floats), requiring nightly Rust
- `min_const_gen` enables generating random arrays of
any size using min-const-generics, requiring Rust ≥ 1.51.
Note that nightly features are not stable and therefore not all library and
compiler versions will be compatible. This is especially true of Rand's
experimental `simd_support` feature.
Rand supports limited functionality in `no_std` mode (enabled via
`default-features = false`). In this case, `OsRng` and `from_entropy` are
@ -117,6 +141,14 @@ unavailable (unless `getrandom` is enabled), large parts of `seq` are
unavailable (unless `alloc` is enabled), and `thread_rng` and `random` are
unavailable.
### WASM support
The WASM target `wasm32-unknown-unknown` is not *automatically* supported by
`rand` or `getrandom`. To solve this, either use a different target such as
`wasm32-wasi` or add a direct dependency on `getrandom` with the `js` feature
(if the target supports JavaScript). See
[getrandom#WebAssembly support](https://docs.rs/getrandom/latest/getrandom/#webassembly-support).
# License
Rand is distributed under the terms of both the MIT license and the

View file

@ -1,69 +0,0 @@
# Security Policy
## No guarantees
Support is provided on a best-effort bases only.
No binding guarantees can be provided.
## Security premises
Rand provides the trait `rand_core::CryptoRng` aka `rand::CryptoRng` as a marker
trait. Generators implementating `RngCore` *and* `CryptoRng`, and given the
additional constraints that:
- Instances of seedable RNGs (those implementing `SeedableRng`) are
constructed with cryptographically secure seed values
- The state (memory) of the RNG and its seed value are not be exposed
are expected to provide the following:
- An attacker can gain no advantage over chance (50% for each bit) in
predicting the RNG output, even with full knowledge of all prior outputs.
For some RNGs, notably `OsRng`, `ThreadRng` and those wrapped by `ReseedingRng`,
we provide limited mitigations against side-channel attacks:
- After a process fork on Unix, there is an upper-bound on the number of bits
output by the RNG before the processes diverge, after which outputs from
each process's RNG are uncorrelated
- After the state (memory) of an RNG is leaked, there is an upper-bound on the
number of bits of output by the RNG before prediction of output by an
observer again becomes computationally-infeasible
Additionally, derivations from such an RNG (including the `Rng` trait,
implementations of the `Distribution` trait, and `seq` algorithms) should not
introduce signficant bias other than that expected from the operation in
question (e.g. bias from a weighted distribution).
## Supported Versions
We will attempt to uphold these premises in the following crate versions,
provided that only the latest patch version is used, and with potential
exceptions for theoretical issues without a known exploit:
| Crate | Versions | Exceptions |
| ----- | -------- | ---------- |
| `rand` | 0.7 | |
| `rand` | 0.5, 0.6 | Jitter |
| `rand` | 0.4 | Jitter, ISAAC |
| `rand_core` | 0.2 - 0.5 | |
| `rand_chacha` | 0.1 - 0.2 | |
| `rand_hc` | 0.1 - 0.2 | |
Explanation of exceptions:
- Jitter: `JitterRng` is used as an entropy source when the primary source
fails; this source may not be secure against side-channel attacks, see #699.
- ISAAC: the [ISAAC](https://burtleburtle.net/bob/rand/isaacafa.html) RNG used
to implement `thread_rng` is difficult to analyse and thus cannot provide
strong assertions of security.
## Known issues
In `rand` version 0.3 (0.3.18 and later), if `OsRng` fails, `thread_rng` is
seeded from the system time in an insecure manner.
## Reporting a Vulnerability
To report a vulnerability, [open a new issue](https://github.com/rust-random/rand/issues/new).
Once the issue is resolved, the vulnerability should be [reported to RustSec](https://github.com/RustSec/advisory-db/blob/master/CONTRIBUTING.md).

View file

@ -1,165 +0,0 @@
// 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;
const RAND_BENCH_N: u64 = 1000;
const BYTES_LEN: usize = 1024;
use std::mem::size_of;
use test::{black_box, Bencher};
use rand::prelude::*;
use rand::rngs::adapter::ReseedingRng;
use rand::rngs::{mock::StepRng, OsRng};
use rand_chacha::{ChaCha12Rng, ChaCha20Core, ChaCha20Rng, ChaCha8Rng};
use rand_hc::Hc128Rng;
use rand_pcg::{Pcg32, Pcg64, Pcg64Mcg};
macro_rules! gen_bytes {
($fnn:ident, $gen:expr) => {
#[bench]
fn $fnn(b: &mut Bencher) {
let mut rng = $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;
}
};
}
gen_bytes!(gen_bytes_step, StepRng::new(0, 1));
gen_bytes!(gen_bytes_pcg32, Pcg32::from_entropy());
gen_bytes!(gen_bytes_pcg64, Pcg64::from_entropy());
gen_bytes!(gen_bytes_pcg64mcg, Pcg64Mcg::from_entropy());
gen_bytes!(gen_bytes_chacha8, ChaCha8Rng::from_entropy());
gen_bytes!(gen_bytes_chacha12, ChaCha12Rng::from_entropy());
gen_bytes!(gen_bytes_chacha20, ChaCha20Rng::from_entropy());
gen_bytes!(gen_bytes_hc128, Hc128Rng::from_entropy());
gen_bytes!(gen_bytes_std, StdRng::from_entropy());
#[cfg(feature = "small_rng")]
gen_bytes!(gen_bytes_small, SmallRng::from_entropy());
gen_bytes!(gen_bytes_os, OsRng);
macro_rules! gen_uint {
($fnn:ident, $ty:ty, $gen:expr) => {
#[bench]
fn $fnn(b: &mut Bencher) {
let mut rng = $gen;
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;
}
};
}
gen_uint!(gen_u32_step, u32, StepRng::new(0, 1));
gen_uint!(gen_u32_pcg32, u32, Pcg32::from_entropy());
gen_uint!(gen_u32_pcg64, u32, Pcg64::from_entropy());
gen_uint!(gen_u32_pcg64mcg, u32, Pcg64Mcg::from_entropy());
gen_uint!(gen_u32_chacha8, u32, ChaCha8Rng::from_entropy());
gen_uint!(gen_u32_chacha12, u32, ChaCha12Rng::from_entropy());
gen_uint!(gen_u32_chacha20, u32, ChaCha20Rng::from_entropy());
gen_uint!(gen_u32_hc128, u32, Hc128Rng::from_entropy());
gen_uint!(gen_u32_std, u32, StdRng::from_entropy());
#[cfg(feature = "small_rng")]
gen_uint!(gen_u32_small, u32, SmallRng::from_entropy());
gen_uint!(gen_u32_os, u32, OsRng);
gen_uint!(gen_u64_step, u64, StepRng::new(0, 1));
gen_uint!(gen_u64_pcg32, u64, Pcg32::from_entropy());
gen_uint!(gen_u64_pcg64, u64, Pcg64::from_entropy());
gen_uint!(gen_u64_pcg64mcg, u64, Pcg64Mcg::from_entropy());
gen_uint!(gen_u64_chacha8, u64, ChaCha8Rng::from_entropy());
gen_uint!(gen_u64_chacha12, u64, ChaCha12Rng::from_entropy());
gen_uint!(gen_u64_chacha20, u64, ChaCha20Rng::from_entropy());
gen_uint!(gen_u64_hc128, u64, Hc128Rng::from_entropy());
gen_uint!(gen_u64_std, u64, StdRng::from_entropy());
#[cfg(feature = "small_rng")]
gen_uint!(gen_u64_small, u64, SmallRng::from_entropy());
gen_uint!(gen_u64_os, u64, OsRng);
macro_rules! init_gen {
($fnn:ident, $gen:ident) => {
#[bench]
fn $fnn(b: &mut Bencher) {
let mut rng = Pcg32::from_entropy();
b.iter(|| {
let r2 = $gen::from_rng(&mut rng).unwrap();
r2
});
}
};
}
init_gen!(init_pcg32, Pcg32);
init_gen!(init_pcg64, Pcg64);
init_gen!(init_pcg64mcg, Pcg64Mcg);
init_gen!(init_hc128, Hc128Rng);
init_gen!(init_chacha, ChaCha20Rng);
const RESEEDING_BYTES_LEN: usize = 1024 * 1024;
const RESEEDING_BENCH_N: u64 = 16;
macro_rules! reseeding_bytes {
($fnn:ident, $thresh:expr) => {
#[bench]
fn $fnn(b: &mut Bencher) {
let mut rng = ReseedingRng::new(ChaCha20Core::from_entropy(), $thresh * 1024, OsRng);
let mut buf = [0u8; RESEEDING_BYTES_LEN];
b.iter(|| {
for _ in 0..RESEEDING_BENCH_N {
rng.fill_bytes(&mut buf);
black_box(&buf);
}
});
b.bytes = RESEEDING_BYTES_LEN as u64 * RESEEDING_BENCH_N;
}
};
}
reseeding_bytes!(reseeding_chacha20_4k, 4);
reseeding_bytes!(reseeding_chacha20_16k, 16);
reseeding_bytes!(reseeding_chacha20_32k, 32);
reseeding_bytes!(reseeding_chacha20_64k, 64);
reseeding_bytes!(reseeding_chacha20_256k, 256);
reseeding_bytes!(reseeding_chacha20_1M, 1024);
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);

View file

@ -1,140 +0,0 @@
// 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;
const RAND_BENCH_N: u64 = 1000;
use test::Bencher;
use rand::distributions::{Bernoulli, Distribution, Standard};
use rand::prelude::*;
use rand_pcg::{Pcg32, Pcg64Mcg};
#[bench]
fn misc_gen_bool_const(b: &mut Bencher) {
let mut rng = Pcg32::from_rng(&mut thread_rng()).unwrap();
b.iter(|| {
let mut accum = true;
for _ in 0..crate::RAND_BENCH_N {
accum ^= rng.gen_bool(0.18);
}
accum
})
}
#[bench]
fn misc_gen_bool_var(b: &mut Bencher) {
let mut rng = Pcg32::from_rng(&mut thread_rng()).unwrap();
b.iter(|| {
let mut accum = true;
let mut p = 0.18;
for _ in 0..crate::RAND_BENCH_N {
accum ^= rng.gen_bool(p);
p += 0.0001;
}
accum
})
}
#[bench]
fn misc_gen_ratio_const(b: &mut Bencher) {
let mut rng = Pcg32::from_rng(&mut thread_rng()).unwrap();
b.iter(|| {
let mut accum = true;
for _ in 0..crate::RAND_BENCH_N {
accum ^= rng.gen_ratio(2, 3);
}
accum
})
}
#[bench]
fn misc_gen_ratio_var(b: &mut Bencher) {
let mut rng = Pcg32::from_rng(&mut thread_rng()).unwrap();
b.iter(|| {
let mut accum = true;
for i in 2..(crate::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 = Pcg32::from_rng(&mut thread_rng()).unwrap();
b.iter(|| {
let d = rand::distributions::Bernoulli::new(0.18).unwrap();
let mut accum = true;
for _ in 0..crate::RAND_BENCH_N {
accum ^= rng.sample(d);
}
accum
})
}
#[bench]
fn misc_bernoulli_var(b: &mut Bencher) {
let mut rng = Pcg32::from_rng(&mut thread_rng()).unwrap();
b.iter(|| {
let mut accum = true;
let mut p = 0.18;
for _ in 0..crate::RAND_BENCH_N {
let d = Bernoulli::new(p).unwrap();
accum ^= rng.sample(d);
p += 0.0001;
}
accum
})
}
#[bench]
fn gen_1k_iter_repeat(b: &mut Bencher) {
use std::iter;
let mut rng = Pcg64Mcg::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) {
let mut rng = Pcg64Mcg::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 = Pcg64Mcg::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 = Pcg64Mcg::from_rng(&mut thread_rng()).unwrap();
let mut buf = [0u64; 128];
b.iter(|| {
rng.fill(&mut buf[..]);
buf
});
b.bytes = 1024;
}

View file

@ -1,179 +0,0 @@
// 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;
use test::Bencher;
use rand::prelude::*;
use rand::seq::*;
use std::mem::size_of;
// We force use of 32-bit RNG since seq code is optimised for use with 32-bit
// generators on all platforms.
use rand_pcg::Pcg32 as SmallRng;
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 * crate::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 * crate::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);

View file

@ -1,36 +0,0 @@
// Copyright 2019 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;
use rand::distributions::WeightedIndex;
use rand::Rng;
use test::Bencher;
#[bench]
fn weighted_index_creation(b: &mut Bencher) {
let mut rng = rand::thread_rng();
let weights = [1u32, 2, 4, 0, 5, 1, 7, 1, 2, 3, 4, 5, 6, 7];
b.iter(|| {
let distr = WeightedIndex::new(weights.to_vec()).unwrap();
rng.sample(distr)
})
}
#[bench]
fn weighted_index_modification(b: &mut Bencher) {
let mut rng = rand::thread_rng();
let weights = [1u32, 2, 3, 0, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7];
let mut distr = WeightedIndex::new(weights.to_vec()).unwrap();
b.iter(|| {
distr.update_weights(&[(2, &4), (5, &1)]).unwrap();
rng.sample(&distr)
})
}

View file

@ -1,51 +0,0 @@
// 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")]
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)
);
}

View file

@ -1,123 +0,0 @@
// 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")]
use rand::distributions::{Distribution, Uniform};
use rand::Rng;
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
);
}

View file

@ -1,32 +0,0 @@
# This rustfmt file is added for configuration, but in practice much of our
# code is hand-formatted, frequently with more readable results.
# Comments:
normalize_comments = true
wrap_comments = false
comment_width = 90 # small excess is okay but prefer 80
# Arguments:
use_small_heuristics = "Default"
# TODO: single line functions only where short, please?
# https://github.com/rust-lang/rustfmt/issues/3358
fn_single_line = false
fn_args_layout = "Compressed"
overflow_delimited_expr = true
where_single_line = true
# enum_discrim_align_threshold = 20
# struct_field_align_threshold = 20
# Compatibility:
edition = "2018" # we require compatibility back to 1.32.0
# Misc:
inline_attribute_width = 80
blank_lines_upper_bound = 2
reorder_impl_items = true
# report_todo = "Unnumbered"
# report_fixme = "Unnumbered"
# Ignored files:
ignore = []

View file

@ -12,6 +12,8 @@ use crate::distributions::Distribution;
use crate::Rng;
use core::{fmt, u64};
#[cfg(feature = "serde1")]
use serde::{Serialize, Deserialize};
/// The Bernoulli distribution.
///
/// This is a special case of the Binomial distribution where `n = 1`.
@ -31,7 +33,8 @@ use core::{fmt, u64};
/// 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)]
#[derive(Clone, Copy, Debug, PartialEq)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct Bernoulli {
/// Probability of success, relative to the maximal integer.
p_int: u64,
@ -46,7 +49,7 @@ pub struct Bernoulli {
// `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
// Also there is a 100% theoretical concern: if someone consistently 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
@ -93,7 +96,7 @@ impl Bernoulli {
/// 2<sup>-64</sup> in `[0, 1]` can be represented as a `f64`.)
#[inline]
pub fn new(p: f64) -> Result<Bernoulli, BernoulliError> {
if !(p >= 0.0 && p < 1.0) {
if !(0.0..1.0).contains(&p) {
if p == 1.0 {
return Ok(Bernoulli { p_int: ALWAYS_TRUE });
}
@ -143,8 +146,20 @@ mod test {
use crate::distributions::Distribution;
use crate::Rng;
#[test]
#[cfg(feature="serde1")]
fn test_serializing_deserializing_bernoulli() {
let coin_flip = Bernoulli::new(0.5).unwrap();
let de_coin_flip : Bernoulli = bincode::deserialize(&bincode::serialize(&coin_flip).unwrap()).unwrap();
assert_eq!(coin_flip.p_int, de_coin_flip.p_int);
}
#[test]
fn test_trivial() {
// We prefer to be explicit here.
#![allow(clippy::bool_assert_comparison)]
let mut r = crate::test::rng(1);
let always_false = Bernoulli::new(0.0).unwrap();
let always_true = Bernoulli::new(1.0).unwrap();
@ -196,4 +211,9 @@ mod test {
true, false, false, true, false, false, true, true, true, true
]);
}
#[test]
fn bernoulli_distributions_can_be_compared() {
assert_eq!(Bernoulli::new(1.0), Bernoulli::new(1.0));
}
}

View file

@ -1,321 +0,0 @@
// 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.
#![allow(deprecated)]
#![allow(clippy::all)]
use crate::distributions::{Distribution, Uniform};
use crate::Rng;
/// 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`.
#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
#[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 }
}
}
/// Convert a `f64` to an `i64`, panicing on overflow.
// In the future (Rust 1.34), this might be replaced with `TryFrom`.
fn f64_to_i64(x: f64) -> i64 {
assert!(x < (::std::i64::MAX as f64));
x as i64
}
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;
}
// The 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 };
let result;
let q = 1. - p;
// For small n * min(p, 1 - p), the BINV algorithm based on the inverse
// transformation of the binomial distribution is efficient. Otherwise,
// the BTPE algorithm is used.
//
// Voratas Kachitvichyanukul and Bruce W. Schmeiser. 1988. Binomial
// random variate generation. Commun. ACM 31, 2 (February 1988),
// 216-222. http://dx.doi.org/10.1145/42372.42381
// Threshold for prefering the BINV algorithm. The paper suggests 10,
// Ranlib uses 30, and GSL uses 14.
const BINV_THRESHOLD: f64 = 10.;
if (self.n as f64) * p < BINV_THRESHOLD && self.n <= (::std::i32::MAX as u64) {
// Use the BINV algorithm.
let s = p / q;
let a = ((self.n + 1) as f64) * s;
let mut r = q.powi(self.n as i32);
let mut u: f64 = rng.gen();
let mut x = 0;
while u > r as f64 {
u -= r;
x += 1;
r *= a / (x as f64) - s;
}
result = x;
} else {
// Use the BTPE algorithm.
// Threshold for using the squeeze algorithm. This can be freely
// chosen based on performance. Ranlib and GSL use 20.
const SQUEEZE_THRESHOLD: i64 = 20;
// Step 0: Calculate constants as functions of `n` and `p`.
let n = self.n as f64;
let np = n * p;
let npq = np * q;
let f_m = np + p;
let m = f64_to_i64(f_m);
// radius of triangle region, since height=1 also area of region
let p1 = (2.195 * npq.sqrt() - 4.6 * q).floor() + 0.5;
// tip of triangle
let x_m = (m as f64) + 0.5;
// left edge of triangle
let x_l = x_m - p1;
// right edge of triangle
let x_r = x_m + p1;
let c = 0.134 + 20.5 / (15.3 + (m as f64));
// p1 + area of parallelogram region
let p2 = p1 * (1. + 2. * c);
fn lambda(a: f64) -> f64 {
a * (1. + 0.5 * a)
}
let lambda_l = lambda((f_m - x_l) / (f_m - x_l * p));
let lambda_r = lambda((x_r - f_m) / (x_r * q));
// p1 + area of left tail
let p3 = p2 + c / lambda_l;
// p1 + area of right tail
let p4 = p3 + c / lambda_r;
// return value
let mut y: i64;
let gen_u = Uniform::new(0., p4);
let gen_v = Uniform::new(0., 1.);
loop {
// Step 1: Generate `u` for selecting the region. If region 1 is
// selected, generate a triangularly distributed variate.
let u = gen_u.sample(rng);
let mut v = gen_v.sample(rng);
if !(u > p1) {
y = f64_to_i64(x_m - p1 * v + u);
break;
}
if !(u > p2) {
// Step 2: Region 2, parallelograms. Check if region 2 is
// used. If so, generate `y`.
let x = x_l + (u - p1) / c;
v = v * c + 1.0 - (x - x_m).abs() / p1;
if v > 1. {
continue;
} else {
y = f64_to_i64(x);
}
} else if !(u > p3) {
// Step 3: Region 3, left exponential tail.
y = f64_to_i64(x_l + v.ln() / lambda_l);
if y < 0 {
continue;
} else {
v *= (u - p2) * lambda_l;
}
} else {
// Step 4: Region 4, right exponential tail.
y = f64_to_i64(x_r - v.ln() / lambda_r);
if y > 0 && (y as u64) > self.n {
continue;
} else {
v *= (u - p3) * lambda_r;
}
}
// Step 5: Acceptance/rejection comparison.
// Step 5.0: Test for appropriate method of evaluating f(y).
let k = (y - m).abs();
if !(k > SQUEEZE_THRESHOLD && (k as f64) < 0.5 * npq - 1.) {
// Step 5.1: Evaluate f(y) via the recursive relationship. Start the
// search from the mode.
let s = p / q;
let a = s * (n + 1.);
let mut f = 1.0;
if m < y {
let mut i = m;
loop {
i += 1;
f *= a / (i as f64) - s;
if i == y {
break;
}
}
} else if m > y {
let mut i = y;
loop {
i += 1;
f /= a / (i as f64) - s;
if i == m {
break;
}
}
}
if v > f {
continue;
} else {
break;
}
}
// Step 5.2: Squeezing. Check the value of ln(v) againts upper and
// lower bound of ln(f(y)).
let k = k as f64;
let rho = (k / npq) * ((k * (k / 3. + 0.625) + 1. / 6.) / npq + 0.5);
let t = -0.5 * k * k / npq;
let alpha = v.ln();
if alpha < t - rho {
break;
}
if alpha > t + rho {
continue;
}
// Step 5.3: Final acceptance/rejection test.
let x1 = (y + 1) as f64;
let f1 = (m + 1) as f64;
let z = (f64_to_i64(n) + 1 - m) as f64;
let w = (f64_to_i64(n) - y + 1) as f64;
fn stirling(a: f64) -> f64 {
let a2 = a * a;
(13860. - (462. - (132. - (99. - 140. / a2) / a2) / a2) / a2) / a / 166320.
}
if alpha
> x_m * (f1 / x1).ln()
+ (n - (m as f64) + 0.5) * (z / w).ln()
+ ((y - m) as f64) * (w * p / (x1 * q)).ln()
// We use the signs from the GSL implementation, which are
// different than the ones in the reference. According to
// the GSL authors, the new signs were verified to be
// correct by one of the original designers of the
// algorithm.
+ stirling(f1)
+ stirling(z)
- stirling(x1)
- stirling(w)
{
continue;
}
break;
}
assert!(y >= 0);
result = y as u64;
}
// Invert the result for p < 0.5.
if p != self.p {
self.n - result
} else {
result
}
}
}
#[cfg(test)]
mod test {
use super::Binomial;
use crate::distributions::Distribution;
use crate::Rng;
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,
"mean: {}, expected_mean: {}",
mean,
expected_mean
);
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,
"variance: {}, expected_variance: {}",
variance,
expected_variance
);
}
#[test]
#[cfg_attr(miri, ignore)] // Miri is too slow
fn test_binomial() {
let mut rng = crate::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 = crate::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);
}
}

View file

@ -1,99 +0,0 @@
// 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.
#![allow(deprecated)]
#![allow(clippy::all)]
use crate::distributions::Distribution;
use crate::Rng;
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))`
#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
#[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 super::Cauchy;
use crate::distributions::Distribution;
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_averages() {
// NOTE: given that the variance and mean are undefined,
// this test does not have any rigorous statistical meaning.
let cauchy = Cauchy::new(10.0, 5.0);
let mut rng = crate::test::rng(123);
let mut numbers: [f64; 1000] = [0.0; 1000];
let mut sum = 0.0;
for i in 0..1000 {
numbers[i] = cauchy.sample(&mut rng);
sum += numbers[i];
}
let median = median(&mut numbers);
println!("Cauchy median: {}", median);
assert!((median - 10.0).abs() < 0.4); // not 100% certain, but probable enough
let mean = sum / 1000.0;
println!("Cauchy mean: {}", mean);
// for a Cauchy distribution the mean should not converge
assert!((mean - 10.0).abs() > 0.4); // 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);
}
}

View file

@ -1,126 +0,0 @@
// 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.
#![allow(deprecated)]
#![allow(clippy::all)]
use crate::distributions::gamma::Gamma;
use crate::distributions::Distribution;
use crate::Rng;
/// 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.
#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
#[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 crate::distributions::Distribution;
#[test]
fn test_dirichlet() {
let d = Dirichlet::new(vec![1.0, 2.0, 3.0]);
let mut rng = crate::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 = crate::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);
}
}

View file

@ -0,0 +1,272 @@
// 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
// 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.
//! Distribution trait and associates
use crate::Rng;
use core::iter;
#[cfg(feature = "alloc")]
use alloc::string::String;
/// 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.
///
/// Implementations are typically expected to be portable with reproducible
/// results when used with a PRNG with fixed seed; see the
/// [portability chapter](https://rust-random.github.io/book/portability.html)
/// of The Rust Rand Book. In some cases this does not apply, e.g. the `usize`
/// type requires different sampling on 32-bit and 64-bit machines.
///
/// [`sample_iter`]: Distribution::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.
///
/// Note that this function takes `self` by value. This works since
/// `Distribution<T>` is impl'd for `&D` where `D: Distribution<T>`,
/// however borrowing is not automatic hence `distr.sample_iter(...)` may
/// need to be replaced with `(&distr).sample_iter(...)` to borrow or
/// `(&*distr).sample_iter(...)` to reborrow an existing reference.
///
/// # 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)
/// .map(char::from)
/// .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<R>(self, rng: R) -> DistIter<Self, R, T>
where
R: Rng,
Self: Sized,
{
DistIter {
distr: self,
rng,
phantom: ::core::marker::PhantomData,
}
}
/// Create a distribution of values of 'S' by mapping the output of `Self`
/// through the closure `F`
///
/// # Example
///
/// ```
/// use rand::thread_rng;
/// use rand::distributions::{Distribution, Uniform};
///
/// let mut rng = thread_rng();
///
/// let die = Uniform::new_inclusive(1, 6);
/// let even_number = die.map(|num| num % 2 == 0);
/// while !even_number.sample(&mut rng) {
/// println!("Still odd; rolling again!");
/// }
/// ```
fn map<F, S>(self, func: F) -> DistMap<Self, F, T, S>
where
F: Fn(T) -> S,
Self: Sized,
{
DistMap {
distr: self,
func,
phantom: ::core::marker::PhantomData,
}
}
}
impl<'a, T, D: Distribution<T>> Distribution<T> for &'a D {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> T {
(*self).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.
///
/// [`sample_iter`]: Distribution::sample_iter
#[derive(Debug)]
pub struct DistIter<D, R, T> {
distr: D,
rng: R,
phantom: ::core::marker::PhantomData<T>,
}
impl<D, R, T> Iterator for DistIter<D, R, T>
where
D: Distribution<T>,
R: Rng,
{
type Item = T;
#[inline(always)]
fn next(&mut self) -> Option<T> {
// Here, self.rng may be a reference, but we must take &mut anyway.
// Even if sample could take an R: Rng by value, we would need to do this
// since Rng is not copyable and we cannot enforce that this is "reborrowable".
Some(self.distr.sample(&mut self.rng))
}
fn size_hint(&self) -> (usize, Option<usize>) {
(usize::max_value(), None)
}
}
impl<D, R, T> iter::FusedIterator for DistIter<D, R, T>
where
D: Distribution<T>,
R: Rng,
{
}
#[cfg(features = "nightly")]
impl<D, R, T> iter::TrustedLen for DistIter<D, R, T>
where
D: Distribution<T>,
R: Rng,
{
}
/// A distribution of values of type `S` derived from the distribution `D`
/// by mapping its output of type `T` through the closure `F`.
///
/// This `struct` is created by the [`Distribution::map`] method.
/// See its documentation for more.
#[derive(Debug)]
pub struct DistMap<D, F, T, S> {
distr: D,
func: F,
phantom: ::core::marker::PhantomData<fn(T) -> S>,
}
impl<D, F, T, S> Distribution<S> for DistMap<D, F, T, S>
where
D: Distribution<T>,
F: Fn(T) -> S,
{
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> S {
(self.func)(self.distr.sample(rng))
}
}
/// `String` sampler
///
/// Sampling a `String` of random characters is not quite the same as collecting
/// a sequence of chars. This trait contains some helpers.
#[cfg(feature = "alloc")]
pub trait DistString {
/// Append `len` random chars to `string`
fn append_string<R: Rng + ?Sized>(&self, rng: &mut R, string: &mut String, len: usize);
/// Generate a `String` of `len` random chars
#[inline]
fn sample_string<R: Rng + ?Sized>(&self, rng: &mut R, len: usize) -> String {
let mut s = String::new();
self.append_string(rng, &mut s, len);
s
}
}
#[cfg(test)]
mod tests {
use crate::distributions::{Distribution, Uniform};
use crate::Rng;
#[test]
fn test_distributions_iter() {
use crate::distributions::Open01;
let mut rng = crate::test::rng(210);
let distr = Open01;
let mut iter = Distribution::<f32>::sample_iter(distr, &mut rng);
let mut sum: f32 = 0.;
for _ in 0..100 {
sum += iter.next().unwrap();
}
assert!(0. < sum && sum < 100.);
}
#[test]
fn test_distributions_map() {
let dist = Uniform::new_inclusive(0, 5).map(|val| val + 15);
let mut rng = crate::test::rng(212);
let val = dist.sample(&mut rng);
assert!((15..=20).contains(&val));
}
#[test]
fn test_make_an_iter() {
fn ten_dice_rolls_other_than_five<R: Rng>(
rng: &mut R,
) -> impl Iterator<Item = i32> + '_ {
Uniform::new_inclusive(1, 6)
.sample_iter(rng)
.filter(|x| *x != 5)
.take(10)
}
let mut rng = crate::test::rng(211);
let mut count = 0;
for val in ten_dice_rolls_other_than_five(&mut rng) {
assert!((1..=6).contains(&val) && val != 5);
count += 1;
}
assert_eq!(count, 10);
}
#[test]
#[cfg(feature = "alloc")]
fn test_dist_string() {
use core::str;
use crate::distributions::{Alphanumeric, DistString, Standard};
let mut rng = crate::test::rng(213);
let s1 = Alphanumeric.sample_string(&mut rng, 20);
assert_eq!(s1.len(), 20);
assert_eq!(str::from_utf8(s1.as_bytes()), Ok(s1.as_str()));
let s2 = Standard.sample_string(&mut rng, 20);
assert_eq!(s2.chars().count(), 20);
assert_eq!(str::from_utf8(s2.as_bytes()), Ok(s2.as_str()));
}
}

View file

@ -1,114 +0,0 @@
// 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 exponential distribution.
#![allow(deprecated)]
use crate::distributions::utils::ziggurat;
use crate::distributions::{ziggurat_tables, Distribution};
use crate::Rng;
/// 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.
///
/// [^1]: Jurgen A. Doornik (2005). [*An Improved Ziggurat Method to
/// Generate Normal Random Samples*](
/// https://www.doornik.com/research/ziggurat.pdf).
/// Nuffield College, Oxford
#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
#[derive(Clone, Copy, Debug)]
pub struct Exp1;
// This could be done via `-rng.gen::<f64>().ln()` but that is slower.
impl Distribution<f64> for Exp1 {
#[inline]
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
#[inline]
fn pdf(x: f64) -> f64 {
(-x).exp()
}
#[inline]
fn zero_case<R: Rng + ?Sized>(rng: &mut R, _u: f64) -> f64 {
ziggurat_tables::ZIG_EXP_R - rng.gen::<f64>().ln()
}
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`.
///
/// Note that [`Exp1`](crate::distributions::Exp1) is an optimised implementation for `lambda = 1`.
#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
#[derive(Clone, Copy, Debug)]
pub struct Exp {
/// `lambda` stored as `1/lambda`, since this is what we scale by.
lambda_inverse: f64,
}
impl Exp {
/// Construct a new `Exp` with the given shape parameter
/// `lambda`. Panics if `lambda <= 0`.
#[inline]
pub fn new(lambda: f64) -> Exp {
assert!(lambda > 0.0, "Exp::new called with `lambda` <= 0");
Exp {
lambda_inverse: 1.0 / lambda,
}
}
}
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 super::Exp;
use crate::distributions::Distribution;
#[test]
fn test_exp() {
let exp = Exp::new(10.0);
let mut rng = crate::test::rng(221);
for _ in 0..1000 {
assert!(exp.sample(&mut rng) >= 0.0);
}
}
#[test]
#[should_panic]
fn test_exp_invalid_lambda_zero() {
Exp::new(0.0);
}
#[test]
#[should_panic]
fn test_exp_invalid_lambda_neg() {
Exp::new(-10.0);
}
}

View file

@ -14,6 +14,9 @@ use crate::Rng;
use core::mem;
#[cfg(feature = "simd_support")] use packed_simd::*;
#[cfg(feature = "serde1")]
use serde::{Serialize, Deserialize};
/// A distribution to sample floating point numbers uniformly in the half-open
/// interval `(0, 1]`, i.e. including 1 but not 0.
///
@ -39,6 +42,7 @@ use core::mem;
/// [`Open01`]: crate::distributions::Open01
/// [`Uniform`]: crate::distributions::uniform::Uniform
#[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct OpenClosed01;
/// A distribution to sample floating point numbers uniformly in the open
@ -65,6 +69,7 @@ pub struct OpenClosed01;
/// [`OpenClosed01`]: crate::distributions::OpenClosed01
/// [`Uniform`]: crate::distributions::uniform::Uniform
#[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct Open01;
@ -73,7 +78,7 @@ pub struct Open01;
pub trait IntoFloat {
type F;
/// Helper method to combine the fraction and a contant exponent into a
/// Helper method to combine the fraction and a constant exponent into a
/// float.
///
/// Only the least significant bits of `self` may be set, 23 for `f32` and

View file

@ -1,373 +0,0 @@
// 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 Gamma and derived distributions.
#![allow(deprecated)]
use self::ChiSquaredRepr::*;
use self::GammaRepr::*;
use crate::distributions::normal::StandardNormal;
use crate::distributions::{Distribution, Exp, Open01};
use crate::Rng;
/// The Gamma distribution `Gamma(shape, scale)` distribution.
///
/// The density function of this distribution is
///
/// ```text
/// f(x) = x^(k - 1) * exp(-x / θ) / (Γ(k) * θ^k)
/// ```
///
/// 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],
/// falling back to directly sampling from an Exponential for `shape
/// == 1`, and using the boosting technique described in that paper for
/// `shape < 1`.
///
/// [^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)
#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
#[derive(Clone, Copy, Debug)]
pub struct Gamma {
repr: GammaRepr,
}
#[derive(Clone, Copy, Debug)]
enum GammaRepr {
Large(GammaLargeShape),
One(Exp),
Small(GammaSmallShape),
}
// These two helpers could be made public, but saving the
// match-on-Gamma-enum branch from using them directly (e.g. if one
// knows that the shape is always > 1) doesn't appear to be much
// faster.
/// Gamma distribution where the shape parameter is less than 1.
///
/// Note, samples from this require a compulsory floating-point `pow`
/// call, which makes it significantly slower than sampling from a
/// gamma distribution where the shape parameter is greater than or
/// equal to 1.
///
/// See `Gamma` for sampling from a Gamma distribution with general
/// shape parameters.
#[derive(Clone, Copy, Debug)]
struct GammaSmallShape {
inv_shape: f64,
large_shape: GammaLargeShape,
}
/// Gamma distribution where the shape parameter is larger than 1.
///
/// See `Gamma` for sampling from a Gamma distribution with general
/// shape parameters.
#[derive(Clone, Copy, Debug)]
struct GammaLargeShape {
scale: f64,
c: f64,
d: f64,
}
impl Gamma {
/// Construct an object representing the `Gamma(shape, scale)`
/// distribution.
///
/// Panics if `shape <= 0` or `scale <= 0`.
#[inline]
pub fn new(shape: f64, scale: f64) -> Gamma {
assert!(shape > 0.0, "Gamma::new called with shape <= 0");
assert!(scale > 0.0, "Gamma::new called with scale <= 0");
let repr = if shape == 1.0 {
One(Exp::new(1.0 / scale))
} else if shape < 1.0 {
Small(GammaSmallShape::new_raw(shape, scale))
} else {
Large(GammaLargeShape::new_raw(shape, scale))
};
Gamma { repr }
}
}
impl GammaSmallShape {
fn new_raw(shape: f64, scale: f64) -> GammaSmallShape {
GammaSmallShape {
inv_shape: 1. / shape,
large_shape: GammaLargeShape::new_raw(shape + 1.0, scale),
}
}
}
impl GammaLargeShape {
fn new_raw(shape: f64, scale: f64) -> GammaLargeShape {
let d = shape - 1. / 3.;
GammaLargeShape {
scale,
c: 1. / (9. * d).sqrt(),
d,
}
}
}
impl Distribution<f64> for Gamma {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
match self.repr {
Small(ref g) => g.sample(rng),
One(ref g) => g.sample(rng),
Large(ref g) => g.sample(rng),
}
}
}
impl Distribution<f64> for GammaSmallShape {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
let u: f64 = rng.sample(Open01);
self.large_shape.sample(rng) * u.powf(self.inv_shape)
}
}
impl Distribution<f64> for GammaLargeShape {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
loop {
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 u: f64 = rng.sample(Open01);
let x_sqr = x * x;
if u < 1.0 - 0.0331 * x_sqr * x_sqr
|| u.ln() < 0.5 * x_sqr + self.d * (1.0 - v + v.ln())
{
return self.d * v * self.scale;
}
}
}
}
/// The chi-squared distribution `χ²(k)`, where `k` is the degrees of
/// freedom.
///
/// For `k > 0` integral, this distribution is the sum of the squares
/// of `k` independent standard normal random variables. For other
/// `k`, this uses the equivalent characterisation
/// `χ²(k) = Gamma(k/2, 2)`.
#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
#[derive(Clone, Copy, Debug)]
pub struct ChiSquared {
repr: ChiSquaredRepr,
}
#[derive(Clone, Copy, Debug)]
enum ChiSquaredRepr {
// k == 1, Gamma(alpha, ..) is particularly slow for alpha < 1,
// e.g. when alpha = 1/2 as it would be for this case, so special-
// casing and using the definition of N(0,1)^2 is faster.
DoFExactlyOne,
DoFAnythingElse(Gamma),
}
impl ChiSquared {
/// Create a new chi-squared distribution with degrees-of-freedom
/// `k`. Panics if `k < 0`.
pub fn new(k: f64) -> ChiSquared {
let repr = if k == 1.0 {
DoFExactlyOne
} else {
assert!(k > 0.0, "ChiSquared::new called with `k` < 0");
DoFAnythingElse(Gamma::new(0.5 * k, 2.0))
};
ChiSquared { repr }
}
}
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 norm = rng.sample(StandardNormal);
norm * norm
}
DoFAnythingElse(ref g) => g.sample(rng),
}
}
}
/// The Fisher F distribution `F(m, n)`.
///
/// This distribution is equivalent to the ratio of two normalised
/// chi-squared distributions, that is, `F(m,n) = (χ²(m)/m) /
/// (χ²(n)/n)`.
#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
#[derive(Clone, Copy, Debug)]
pub struct FisherF {
numer: ChiSquared,
denom: ChiSquared,
// denom_dof / numer_dof so that this can just be a straight
// multiplication, rather than a division.
dof_ratio: f64,
}
impl FisherF {
/// Create a new `FisherF` distribution, with the given
/// parameter. Panics if either `m` or `n` are not positive.
pub fn new(m: f64, n: f64) -> FisherF {
assert!(m > 0.0, "FisherF::new called with `m < 0`");
assert!(n > 0.0, "FisherF::new called with `n < 0`");
FisherF {
numer: ChiSquared::new(m),
denom: ChiSquared::new(n),
dof_ratio: n / m,
}
}
}
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
}
}
/// The Student t distribution, `t(nu)`, where `nu` is the degrees of
/// freedom.
#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
#[derive(Clone, Copy, Debug)]
pub struct StudentT {
chi: ChiSquared,
dof: f64,
}
impl StudentT {
/// Create a new Student t distribution with `n` degrees of
/// freedom. Panics if `n <= 0`.
pub fn new(n: f64) -> StudentT {
assert!(n > 0.0, "StudentT::new called with `n <= 0`");
StudentT {
chi: ChiSquared::new(n),
dof: n,
}
}
}
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`.
#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
#[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 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 super::{Beta, ChiSquared, FisherF, StudentT};
use crate::distributions::Distribution;
const N: u32 = 100;
#[test]
fn test_chi_squared_one() {
let chi = ChiSquared::new(1.0);
let mut rng = crate::test::rng(201);
for _ in 0..N {
chi.sample(&mut rng);
}
}
#[test]
fn test_chi_squared_small() {
let chi = ChiSquared::new(0.5);
let mut rng = crate::test::rng(202);
for _ in 0..N {
chi.sample(&mut rng);
}
}
#[test]
fn test_chi_squared_large() {
let chi = ChiSquared::new(30.0);
let mut rng = crate::test::rng(203);
for _ in 0..N {
chi.sample(&mut rng);
}
}
#[test]
#[should_panic]
fn test_chi_squared_invalid_dof() {
ChiSquared::new(-1.0);
}
#[test]
fn test_f() {
let f = FisherF::new(2.0, 32.0);
let mut rng = crate::test::rng(204);
for _ in 0..N {
f.sample(&mut rng);
}
}
#[test]
fn test_t() {
let t = StudentT::new(11.0);
let mut rng = crate::test::rng(205);
for _ in 0..N {
t.sample(&mut rng);
}
}
#[test]
fn test_beta() {
let beta = Beta::new(1.0, 2.0);
let mut rng = crate::test::rng(201);
for _ in 0..N {
beta.sample(&mut rng);
}
}
#[test]
#[should_panic]
fn test_beta_invalid_dof() {
Beta::new(0., 0.);
}
}

View file

@ -10,11 +10,12 @@
use crate::distributions::{Distribution, Standard};
use crate::Rng;
#[cfg(all(target_arch = "x86", feature = "nightly"))] use core::arch::x86::*;
#[cfg(all(target_arch = "x86_64", feature = "nightly"))]
use core::arch::x86_64::*;
#[cfg(not(target_os = "emscripten"))] use core::num::NonZeroU128;
use core::num::{NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize};
#[cfg(all(target_arch = "x86", feature = "simd_support"))]
use core::arch::x86::{__m128i, __m256i};
#[cfg(all(target_arch = "x86_64", feature = "simd_support"))]
use core::arch::x86_64::{__m128i, __m256i};
use core::num::{NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize,
NonZeroU128};
#[cfg(feature = "simd_support")] use packed_simd::*;
impl Distribution<u8> for Standard {
@ -45,7 +46,6 @@ impl Distribution<u64> for Standard {
}
}
#[cfg(not(target_os = "emscripten"))]
impl Distribution<u128> for Standard {
#[inline]
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u128 {
@ -85,7 +85,6 @@ 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(not(target_os = "emscripten"))]
impl_int_from_uint! { i128, u128 }
impl_int_from_uint! { isize, usize }
@ -107,7 +106,6 @@ impl_nzint!(NonZeroU8, NonZeroU8::new);
impl_nzint!(NonZeroU16, NonZeroU16::new);
impl_nzint!(NonZeroU32, NonZeroU32::new);
impl_nzint!(NonZeroU64, NonZeroU64::new);
#[cfg(not(target_os = "emscripten"))]
impl_nzint!(NonZeroU128, NonZeroU128::new);
impl_nzint!(NonZeroUsize, NonZeroUsize::new);
@ -155,10 +153,9 @@ simd_impl!(256, u8x32, i8x32, u16x16, i16x16, u32x8, i32x8, u64x4, i64x4,);
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),);
simd_impl!((__m128i, u8x16), (__m256i, u8x32),);
#[cfg(test)]
mod tests {
@ -173,7 +170,6 @@ mod tests {
rng.sample::<i16, _>(Standard);
rng.sample::<i32, _>(Standard);
rng.sample::<i64, _>(Standard);
#[cfg(not(target_os = "emscripten"))]
rng.sample::<i128, _>(Standard);
rng.sample::<usize, _>(Standard);
@ -181,7 +177,6 @@ mod tests {
rng.sample::<u16, _>(Standard);
rng.sample::<u32, _>(Standard);
rng.sample::<u64, _>(Standard);
#[cfg(not(target_os = "emscripten"))]
rng.sample::<u128, _>(Standard);
}

View file

@ -11,11 +11,11 @@
//!
//! 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, e.g. [`Rng::gen`], [`Rng::gen_range`] and
//! of course [`Rng::sample`].
//! functionality of the [`Rng`] trait, e.g. [`Rng::gen`] and of course
//! [`Rng::sample`].
//!
//! Abstractly, a [probability distribution] describes the probability of
//! occurance of each value in its sample space.
//! occurrence 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`)
@ -54,16 +54,16 @@
//! 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
//! Values may be sampled from this distribution using [`Rng::sample(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`].
//! `Uniform` object than to call [`Rng::sample(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`].
//! documentation in the [`uniform`] module). Doing so enables generation of
//! values of type `T` with [`Rng::sample(Range)`].
//!
//! ## Open and half-open ranges
//!
@ -79,7 +79,7 @@
//! the [`Bernoulli`] distribution (this is used by [`Rng::gen_bool`]).
//!
//! For weighted sampling from a sequence of discrete values, use the
//! [`weighted`] module.
//! [`WeightedIndex`] distribution.
//!
//! This crate no longer includes other non-uniform distributions; instead
//! it is recommended that you use either [`rand_distr`] or [`statrs`].
@ -93,201 +93,43 @@
//! [`rand_distr`]: https://crates.io/crates/rand_distr
//! [`statrs`]: https://crates.io/crates/statrs
use crate::Rng;
use core::iter;
pub use self::bernoulli::{Bernoulli, BernoulliError};
pub use self::float::{Open01, OpenClosed01};
pub use self::other::Alphanumeric;
#[doc(inline)] pub use self::uniform::Uniform;
#[cfg(feature = "alloc")]
pub use self::weighted::{WeightedError, WeightedIndex};
// The following are all deprecated after being moved to rand_distr
#[allow(deprecated)]
#[cfg(feature = "std")]
pub use self::binomial::Binomial;
#[allow(deprecated)]
#[cfg(feature = "std")]
pub use self::cauchy::Cauchy;
#[allow(deprecated)]
#[cfg(feature = "std")]
pub use self::dirichlet::Dirichlet;
#[allow(deprecated)]
#[cfg(feature = "std")]
pub use self::exponential::{Exp, Exp1};
#[allow(deprecated)]
#[cfg(feature = "std")]
pub use self::gamma::{Beta, ChiSquared, FisherF, Gamma, StudentT};
#[allow(deprecated)]
#[cfg(feature = "std")]
pub use self::normal::{LogNormal, Normal, StandardNormal};
#[allow(deprecated)]
#[cfg(feature = "std")]
pub use self::pareto::Pareto;
#[allow(deprecated)]
#[cfg(feature = "std")]
pub use self::poisson::Poisson;
#[allow(deprecated)]
#[cfg(feature = "std")]
pub use self::triangular::Triangular;
#[allow(deprecated)]
#[cfg(feature = "std")]
pub use self::unit_circle::UnitCircle;
#[allow(deprecated)]
#[cfg(feature = "std")]
pub use self::unit_sphere::UnitSphereSurface;
#[allow(deprecated)]
#[cfg(feature = "std")]
pub use self::weibull::Weibull;
mod bernoulli;
#[cfg(feature = "std")] mod binomial;
#[cfg(feature = "std")] mod cauchy;
#[cfg(feature = "std")] mod dirichlet;
#[cfg(feature = "std")] mod exponential;
#[cfg(feature = "std")] mod gamma;
#[cfg(feature = "std")] mod normal;
#[cfg(feature = "std")] mod pareto;
#[cfg(feature = "std")] mod poisson;
#[cfg(feature = "std")] mod triangular;
pub mod uniform;
#[cfg(feature = "std")] mod unit_circle;
#[cfg(feature = "std")] mod unit_sphere;
#[cfg(feature = "std")] mod weibull;
#[cfg(feature = "alloc")] pub mod weighted;
mod distribution;
mod float;
mod integer;
mod other;
mod slice;
mod utils;
#[cfg(feature = "alloc")]
mod weighted_index;
#[doc(hidden)]
pub mod hidden_export {
pub use super::float::IntoFloat; // used by rand_distr
}
mod integer;
mod other;
mod utils;
#[cfg(feature = "std")] mod ziggurat_tables;
pub mod uniform;
#[deprecated(
since = "0.8.0",
note = "use rand::distributions::{WeightedIndex, WeightedError} instead"
)]
#[cfg(feature = "alloc")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
pub mod weighted;
/// 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.
///
/// Implementations are typically expected to be portable with reproducible
/// results when used with a PRNG with fixed seed; see the
/// [portability chapter](https://rust-random.github.io/book/portability.html)
/// of The Rust Rand Book. In some cases this does not apply, e.g. the `usize`
/// type requires different sampling on 32-bit and 64-bit machines.
///
/// [`sample_iter`]: Distribution::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.
///
/// Note that this function takes `self` by value. This works since
/// `Distribution<T>` is impl'd for `&D` where `D: Distribution<T>`,
/// however borrowing is not automatic hence `distr.sample_iter(...)` may
/// need to be replaced with `(&distr).sample_iter(...)` to borrow or
/// `(&*distr).sample_iter(...)` to reborrow an existing reference.
///
/// # Example
///
/// ```
/// use rand::thread_rng;
/// use rand::distributions::{Distribution, Alphanumeric, Uniform, Standard};
///
/// let rng = thread_rng();
///
/// // Vec of 16 x f32:
/// let v: Vec<f32> = Standard.sample_iter(rng).take(16).collect();
///
/// // String:
/// let s: String = Alphanumeric.sample_iter(rng).take(7).collect();
///
/// // Dice-rolling:
/// let die_range = Uniform::new_inclusive(1, 6);
/// let mut roll_die = die_range.sample_iter(rng);
/// while roll_die.next().unwrap() != 6 {
/// println!("Not a 6; rolling again!");
/// }
/// ```
fn sample_iter<R>(self, rng: R) -> DistIter<Self, R, T>
where
R: Rng,
Self: Sized,
{
DistIter {
distr: self,
rng,
phantom: ::core::marker::PhantomData,
}
}
}
impl<'a, T, D: Distribution<T>> Distribution<T> for &'a D {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> T {
(*self).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.
///
/// [`sample_iter`]: Distribution::sample_iter
#[derive(Debug)]
pub struct DistIter<D, R, T> {
distr: D,
rng: R,
phantom: ::core::marker::PhantomData<T>,
}
impl<D, R, T> Iterator for DistIter<D, R, T>
where
D: Distribution<T>,
R: Rng,
{
type Item = T;
#[inline(always)]
fn next(&mut self) -> Option<T> {
// Here, self.rng may be a reference, but we must take &mut anyway.
// Even if sample could take an R: Rng by value, we would need to do this
// since Rng is not copyable and we cannot enforce that this is "reborrowable".
Some(self.distr.sample(&mut self.rng))
}
fn size_hint(&self) -> (usize, Option<usize>) {
(usize::max_value(), None)
}
}
impl<D, R, T> iter::FusedIterator for DistIter<D, R, T>
where
D: Distribution<T>,
R: Rng,
{
}
#[cfg(features = "nightly")]
impl<D, R, T> iter::TrustedLen for DistIter<D, R, T>
where
D: Distribution<T>,
R: Rng,
{
}
pub use self::bernoulli::{Bernoulli, BernoulliError};
pub use self::distribution::{Distribution, DistIter, DistMap};
#[cfg(feature = "alloc")]
pub use self::distribution::DistString;
pub use self::float::{Open01, OpenClosed01};
pub use self::other::Alphanumeric;
pub use self::slice::Slice;
#[doc(inline)]
pub use self::uniform::Uniform;
#[cfg(feature = "alloc")]
pub use self::weighted_index::{WeightedError, WeightedIndex};
#[allow(unused)]
use crate::Rng;
/// A generic random value distribution, implemented for many primitive types.
/// Usually generates values with a numerically uniform distribution, and with a
@ -316,7 +158,13 @@ where
/// * Tuples (up to 12 elements): each element is generated sequentially.
/// * Arrays (up to 32 elements): each element is generated sequentially;
/// see also [`Rng::fill`] which supports arbitrary array length for integer
/// types and tends to be faster for `u32` and smaller types.
/// and float types and tends to be faster for `u32` and smaller types.
/// When using `rustc` ≥ 1.51, enable the `min_const_gen` feature to support
/// arrays larger than 32 elements.
/// Note that [`Rng::fill`] and `Standard`'s array support are *not* equivalent:
/// the former is optimised for integer types (using fewer RNG calls for
/// element types smaller than the RNG word size), while the latter supports
/// any element type supported by `Standard`.
/// * `Option<T>` first generates a `bool`, and if true generates and returns
/// `Some(value)` where `value: T`, otherwise returning `None`.
///
@ -359,48 +207,12 @@ where
/// 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).
/// samples from `(0, 1]` and `Rng::gen_range(0..1)` which also samples from
/// `[0, 1)`. Note that `Open01` uses 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).
///
/// [`Uniform`]: uniform::Uniform
#[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
pub struct Standard;
#[cfg(all(test, feature = "std"))]
mod tests {
use super::{Distribution, Uniform};
use crate::Rng;
#[test]
fn test_distributions_iter() {
use crate::distributions::Open01;
let mut rng = crate::test::rng(210);
let distr = Open01;
let results: Vec<f32> = distr.sample_iter(&mut rng).take(100).collect();
println!("{:?}", results);
}
#[test]
fn test_make_an_iter() {
fn ten_dice_rolls_other_than_five<'a, R: Rng>(
rng: &'a mut R,
) -> impl Iterator<Item = i32> + 'a {
Uniform::new_inclusive(1, 6)
.sample_iter(rng)
.filter(|x| *x != 5)
.take(10)
}
let mut rng = crate::test::rng(211);
let mut count = 0;
for val in ten_dice_rolls_other_than_five(&mut rng) {
assert!(val >= 1 && val <= 6 && val != 5);
count += 1;
}
assert_eq!(count, 10);
}
}

View file

@ -1,177 +0,0 @@
// 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 normal and derived distributions.
#![allow(deprecated)]
use crate::distributions::utils::ziggurat;
use crate::distributions::{ziggurat_tables, Distribution, Open01};
use crate::Rng;
/// 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.
///
/// [^1]: Jurgen A. Doornik (2005). [*An Improved Ziggurat Method to
/// Generate Normal Random Samples*](
/// https://www.doornik.com/research/ziggurat.pdf).
/// Nuffield College, Oxford
#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
#[derive(Clone, Copy, Debug)]
pub struct 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 + ?Sized>(rng: &mut R, u: f64) -> f64 {
// compute a random number in the tail by hand
// strange initial conditions, because the loop is not
// do-while, so the condition should be true on the first
// run, they get overwritten anyway (0 < 1, so these are
// good).
let mut x = 1.0f64;
let mut y = 0.0f64;
while -2.0 * y < x * x {
let x_: f64 = rng.sample(Open01);
let y_: f64 = rng.sample(Open01);
x = x_.ln() / ziggurat_tables::ZIG_NORM_R;
y = y_.ln();
}
if u < 0.0 {
x - ziggurat_tables::ZIG_NORM_R
} else {
ziggurat_tables::ZIG_NORM_R - x
}
}
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.
///
/// Note that [`StandardNormal`] is an optimised implementation for mean 0, and
/// standard deviation 1.
///
/// [`StandardNormal`]: crate::distributions::StandardNormal
#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
#[derive(Clone, Copy, Debug)]
pub struct Normal {
mean: f64,
std_dev: f64,
}
impl Normal {
/// Construct a new `Normal` distribution with the given mean and
/// standard deviation.
///
/// # Panics
///
/// Panics if `std_dev < 0`.
#[inline]
pub fn new(mean: f64, std_dev: f64) -> Normal {
assert!(std_dev >= 0.0, "Normal::new called with `std_dev` < 0");
Normal { mean, std_dev }
}
}
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
}
}
/// 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.
#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
#[derive(Clone, Copy, Debug)]
pub struct LogNormal {
norm: Normal,
}
impl LogNormal {
/// Construct a new `LogNormal` distribution with the given mean
/// and standard deviation.
///
/// # Panics
///
/// Panics if `std_dev < 0`.
#[inline]
pub fn new(mean: f64, std_dev: f64) -> LogNormal {
assert!(std_dev >= 0.0, "LogNormal::new called with `std_dev` < 0");
LogNormal {
norm: Normal::new(mean, std_dev),
}
}
}
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 super::{LogNormal, Normal};
use crate::distributions::Distribution;
#[test]
fn test_normal() {
let norm = Normal::new(10.0, 10.0);
let mut rng = crate::test::rng(210);
for _ in 0..1000 {
norm.sample(&mut rng);
}
}
#[test]
#[should_panic]
fn test_normal_invalid_sd() {
Normal::new(10.0, -1.0);
}
#[test]
fn test_log_normal() {
let lnorm = LogNormal::new(10.0, 10.0);
let mut rng = crate::test::rng(211);
for _ in 0..1000 {
lnorm.sample(&mut rng);
}
}
#[test]
#[should_panic]
fn test_log_normal_invalid_sd() {
LogNormal::new(10.0, -1.0);
}
}

View file

@ -10,30 +10,62 @@
use core::char;
use core::num::Wrapping;
#[cfg(feature = "alloc")]
use alloc::string::String;
use crate::distributions::{Distribution, Standard, Uniform};
#[cfg(feature = "alloc")]
use crate::distributions::DistString;
use crate::Rng;
#[cfg(feature = "serde1")]
use serde::{Serialize, Deserialize};
#[cfg(feature = "min_const_gen")]
use core::mem::{self, MaybeUninit};
// ----- Sampling distributions -----
/// Sample a `char`, uniformly distributed over ASCII letters and numbers:
/// Sample a `u8`, 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();
/// let chars: String = (0..7).map(|_| rng.sample(Alphanumeric) as char).collect();
/// println!("Random chars: {}", chars);
/// ```
#[derive(Debug)]
///
/// The [`DistString`] trait provides an easier method of generating
/// a random `String`, and offers more efficient allocation:
/// ```
/// use rand::distributions::{Alphanumeric, DistString};
/// let string = Alphanumeric.sample_string(&mut rand::thread_rng(), 16);
/// println!("Random string: {}", string);
/// ```
///
/// # Passwords
///
/// Users sometimes ask whether it is safe to use a string of random characters
/// as a password. In principle, all RNGs in Rand implementing `CryptoRng` are
/// suitable as a source of randomness for generating passwords (if they are
/// properly seeded), but it is more conservative to only use randomness
/// directly from the operating system via the `getrandom` crate, or the
/// corresponding bindings of a crypto library.
///
/// When generating passwords or keys, it is important to consider the threat
/// model and in some cases the memorability of the password. This is out of
/// scope of the Rand project, and therefore we defer to the following
/// references:
///
/// - [Wikipedia article on Password Strength](https://en.wikipedia.org/wiki/Password_strength)
/// - [Diceware for generating memorable passwords](https://en.wikipedia.org/wiki/Diceware)
#[derive(Debug, Clone, Copy)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct Alphanumeric;
@ -60,8 +92,21 @@ impl Distribution<char> for Standard {
}
}
impl Distribution<char> for Alphanumeric {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> char {
/// Note: the `String` is potentially left with excess capacity; optionally the
/// user may call `string.shrink_to_fit()` afterwards.
#[cfg(feature = "alloc")]
impl DistString for Standard {
fn append_string<R: Rng + ?Sized>(&self, rng: &mut R, s: &mut String, len: usize) {
// A char is encoded with at most four bytes, thus this reservation is
// guaranteed to be sufficient. We do not shrink_to_fit afterwards so
// that repeated usage on the same `String` buffer does not reallocate.
s.reserve(4 * len);
s.extend(Distribution::<char>::sample_iter(self, rng).take(len));
}
}
impl Distribution<u8> for Alphanumeric {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u8 {
const RANGE: u32 = 26 + 26 + 10;
const GEN_ASCII_STR_CHARSET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
abcdefghijklmnopqrstuvwxyz\
@ -73,12 +118,22 @@ impl Distribution<char> for Alphanumeric {
loop {
let var = rng.next_u32() >> (32 - 6);
if var < RANGE {
return GEN_ASCII_STR_CHARSET[var as usize] as char;
return GEN_ASCII_STR_CHARSET[var as usize];
}
}
}
}
#[cfg(feature = "alloc")]
impl DistString for Alphanumeric {
fn append_string<R: Rng + ?Sized>(&self, rng: &mut R, string: &mut String, len: usize) {
unsafe {
let v = string.as_mut_vec();
v.extend(self.sample_iter(rng).take(len));
}
}
}
impl Distribution<bool> for Standard {
#[inline]
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> bool {
@ -134,6 +189,24 @@ 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}
#[cfg(feature = "min_const_gen")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "min_const_gen")))]
impl<T, const N: usize> Distribution<[T; N]> for Standard
where Standard: Distribution<T>
{
#[inline]
fn sample<R: Rng + ?Sized>(&self, _rng: &mut R) -> [T; N] {
let mut buff: [MaybeUninit<T>; N] = unsafe { MaybeUninit::uninit().assume_init() };
for elem in &mut buff {
*elem = MaybeUninit::new(_rng.gen());
}
unsafe { mem::transmute_copy::<_, _>(&buff) }
}
}
#[cfg(not(feature = "min_const_gen"))]
macro_rules! array_impl {
// recursive, given at least one type parameter:
{$n:expr, $t:ident, $($ts:ident,)*} => {
@ -154,6 +227,7 @@ macro_rules! array_impl {
};
}
#[cfg(not(feature = "min_const_gen"))]
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
@ -184,7 +258,7 @@ where Standard: Distribution<T>
mod tests {
use super::*;
use crate::RngCore;
#[cfg(all(not(feature = "std"), feature = "alloc"))] use alloc::string::String;
#[cfg(feature = "alloc")] use alloc::string::String;
#[test]
fn test_misc() {
@ -206,7 +280,7 @@ mod tests {
.map(|()| rng.gen::<char>())
.take(1000)
.collect();
assert!(word.len() != 0);
assert!(!word.is_empty());
}
#[test]
@ -217,12 +291,12 @@ mod tests {
// 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') );
let c: char = rng.sample(Alphanumeric).into();
incorrect |= !(('0'..='9').contains(&c) ||
('A'..='Z').contains(&c) ||
('a'..='z').contains(&c) );
}
assert!(incorrect == false);
assert!(!incorrect);
}
#[test]
@ -245,7 +319,7 @@ mod tests {
'\u{ed692}',
'\u{35888}',
]);
test_samples(&Alphanumeric, 'a', &['h', 'm', 'e', '3', 'M']);
test_samples(&Alphanumeric, 0, &[104, 109, 101, 51, 77]);
test_samples(&Standard, false, &[true, true, false, true, false]);
test_samples(&Standard, None as Option<bool>, &[
Some(true),

View file

@ -1,70 +0,0 @@
// 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.
#![allow(deprecated)]
use crate::distributions::{Distribution, OpenClosed01};
use crate::Rng;
/// Samples floating-point numbers according to the Pareto distribution
#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
#[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 super::Pareto;
use crate::distributions::Distribution;
#[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 = crate::test::rng(1);
for _ in 0..1000 {
let r = d.sample(&mut rng);
assert!(r >= scale);
}
}
}

View file

@ -1,151 +0,0 @@
// 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.
#![allow(deprecated)]
use crate::distributions::utils::log_gamma;
use crate::distributions::{Cauchy, Distribution};
use crate::Rng;
/// The Poisson distribution `Poisson(lambda)`.
///
/// This distribution has a density function:
/// `f(k) = lambda^k * exp(-lambda) / k!` for `k >= 0`.
#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
#[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 super::Poisson;
use crate::distributions::Distribution;
#[test]
#[cfg_attr(miri, ignore)] // Miri is too slow
fn test_poisson_10() {
let poisson = Poisson::new(10.0);
let mut rng = crate::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 = crate::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);
}
}

View file

@ -0,0 +1,117 @@
// Copyright 2021 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 crate::distributions::{Distribution, Uniform};
/// A distribution to sample items uniformly from a slice.
///
/// [`Slice::new`] constructs a distribution referencing a slice and uniformly
/// samples references from the items in the slice. It may do extra work up
/// front to make sampling of multiple values faster; if only one sample from
/// the slice is required, [`SliceRandom::choose`] can be more efficient.
///
/// Steps are taken to avoid bias which might be present in naive
/// implementations; for example `slice[rng.gen() % slice.len()]` samples from
/// the slice, but may be more likely to select numbers in the low range than
/// other values.
///
/// This distribution samples with replacement; each sample is independent.
/// Sampling without replacement requires state to be retained, and therefore
/// cannot be handled by a distribution; you should instead consider methods
/// on [`SliceRandom`], such as [`SliceRandom::choose_multiple`].
///
/// # Example
///
/// ```
/// use rand::Rng;
/// use rand::distributions::Slice;
///
/// let vowels = ['a', 'e', 'i', 'o', 'u'];
/// let vowels_dist = Slice::new(&vowels).unwrap();
/// let rng = rand::thread_rng();
///
/// // build a string of 10 vowels
/// let vowel_string: String = rng
/// .sample_iter(&vowels_dist)
/// .take(10)
/// .collect();
///
/// println!("{}", vowel_string);
/// assert_eq!(vowel_string.len(), 10);
/// assert!(vowel_string.chars().all(|c| vowels.contains(&c)));
/// ```
///
/// For a single sample, [`SliceRandom::choose`][crate::seq::SliceRandom::choose]
/// may be preferred:
///
/// ```
/// use rand::seq::SliceRandom;
///
/// let vowels = ['a', 'e', 'i', 'o', 'u'];
/// let mut rng = rand::thread_rng();
///
/// println!("{}", vowels.choose(&mut rng).unwrap())
/// ```
///
/// [`SliceRandom`]: crate::seq::SliceRandom
/// [`SliceRandom::choose`]: crate::seq::SliceRandom::choose
/// [`SliceRandom::choose_multiple`]: crate::seq::SliceRandom::choose_multiple
#[derive(Debug, Clone, Copy)]
pub struct Slice<'a, T> {
slice: &'a [T],
range: Uniform<usize>,
}
impl<'a, T> Slice<'a, T> {
/// Create a new `Slice` instance which samples uniformly from the slice.
/// Returns `Err` if the slice is empty.
pub fn new(slice: &'a [T]) -> Result<Self, EmptySlice> {
match slice.len() {
0 => Err(EmptySlice),
len => Ok(Self {
slice,
range: Uniform::new(0, len),
}),
}
}
}
impl<'a, T> Distribution<&'a T> for Slice<'a, T> {
fn sample<R: crate::Rng + ?Sized>(&self, rng: &mut R) -> &'a T {
let idx = self.range.sample(rng);
debug_assert!(
idx < self.slice.len(),
"Uniform::new(0, {}) somehow returned {}",
self.slice.len(),
idx
);
// Safety: at construction time, it was ensured that the slice was
// non-empty, and that the `Uniform` range produces values in range
// for the slice
unsafe { self.slice.get_unchecked(idx) }
}
}
/// Error type indicating that a [`Slice`] distribution was improperly
/// constructed with an empty slice.
#[derive(Debug, Clone, Copy)]
pub struct EmptySlice;
impl core::fmt::Display for EmptySlice {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(
f,
"Tried to create a `distributions::Slice` with an empty slice"
)
}
}
#[cfg(feature = "std")]
impl std::error::Error for EmptySlice {}

View file

@ -1,83 +0,0 @@
// 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.
#![allow(deprecated)]
use crate::distributions::{Distribution, Standard};
use crate::Rng;
/// The triangular distribution.
#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
#[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 super::Triangular;
use crate::distributions::Distribution;
#[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 = crate::test::rng(1);
for _ in 0..1000 {
norm.sample(&mut rng);
}
}
}

View file

@ -1,4 +1,4 @@
// Copyright 2018 Developers of the Rand project.
// Copyright 2018-2020 Developers of the Rand project.
// Copyright 2017 The Rust Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
@ -34,7 +34,7 @@
//! let side = Uniform::new(-10.0, 10.0);
//!
//! // sample between 1 and 10 points
//! for _ in 0..rng.gen_range(1, 11) {
//! for _ in 0..rng.gen_range(1..=10) {
//! // 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);
@ -80,7 +80,10 @@
//! where B1: SampleBorrow<Self::X> + Sized,
//! B2: SampleBorrow<Self::X> + Sized
//! {
//! UniformSampler::new(low, high)
//! UniformMyF32(UniformFloat::<f32>::new_inclusive(
//! low.borrow().0,
//! high.borrow().0,
//! ))
//! }
//! fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X {
//! MyF32(self.0.sample(rng))
@ -103,26 +106,29 @@
//! [`UniformDuration`]: crate::distributions::uniform::UniformDuration
//! [`SampleBorrow::borrow`]: crate::distributions::uniform::SampleBorrow::borrow
#[cfg(not(feature = "std"))] use core::time::Duration;
#[cfg(feature = "std")] use std::time::Duration;
use core::time::Duration;
use core::ops::{Range, RangeInclusive};
use crate::distributions::float::IntoFloat;
use crate::distributions::utils::{BoolAsSIMD, FloatAsSIMD, FloatSIMDUtils, WideningMultiply};
use crate::distributions::Distribution;
use crate::Rng;
use crate::{Rng, RngCore};
#[cfg(not(feature = "std"))]
#[allow(unused_imports)] // rustc doesn't detect that this is actually used
use crate::distributions::utils::Float;
#[cfg(feature = "simd_support")] use packed_simd::*;
#[cfg(feature = "serde1")]
use serde::{Serialize, Deserialize};
/// 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.
/// work up front to make sampling of multiple values faster. If only one sample
/// from the range is required, [`Rng::gen_range`] can be more efficient.
///
/// When sampling from a constant range, many calculations can happen at
/// compile-time and all methods should be fast; for floating-point ranges and
@ -137,7 +143,7 @@ use crate::distributions::utils::Float;
/// 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
/// `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
@ -145,7 +151,6 @@ use crate::distributions::utils::Float;
/// ```
/// use rand::distributions::{Distribution, Uniform};
///
/// fn main() {
/// let between = Uniform::from(10..10000);
/// let mut rng = rand::thread_rng();
/// let mut sum = 0;
@ -153,12 +158,24 @@ use crate::distributions::utils::Float;
/// sum += between.sample(&mut rng);
/// }
/// println!("{}", sum);
/// }
/// ```
///
/// For a single sample, [`Rng::gen_range`] may be preferred:
///
/// ```
/// use rand::Rng;
///
/// let mut rng = rand::thread_rng();
/// println!("{}", rng.gen_range(0..10));
/// ```
///
/// [`new`]: Uniform::new
/// [`new_inclusive`]: Uniform::new_inclusive
#[derive(Clone, Copy, Debug)]
/// [`Rng::gen_range`]: Rng::gen_range
#[derive(Clone, Copy, Debug, PartialEq)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde1", serde(bound(serialize = "X::Sampler: Serialize")))]
#[cfg_attr(feature = "serde1", serde(bound(deserialize = "X::Sampler: Deserialize<'de>")))]
pub struct Uniform<X: SampleUniform>(X::Sampler);
impl<X: SampleUniform> Uniform<X> {
@ -265,20 +282,38 @@ pub trait UniformSampler: Sized {
let uniform: Self = UniformSampler::new(low, high);
uniform.sample(rng)
}
/// Sample a single value uniformly from a range with inclusive lower bound
/// and inclusive upper bound `[low, high]`.
///
/// By default this is implemented using
/// `UniformSampler::new_inclusive(low, high).sample(rng)`. However, for
/// some types more optimal implementations for single usage may be provided
/// via this method.
/// Results may not be identical.
fn sample_single_inclusive<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_inclusive(low, high);
uniform.sample(rng)
}
}
impl<X: SampleUniform> From<::core::ops::Range<X>> for Uniform<X> {
impl<X: SampleUniform> From<Range<X>> for Uniform<X> {
fn from(r: ::core::ops::Range<X>) -> Uniform<X> {
Uniform::new(r.start, r.end)
}
}
impl<X: SampleUniform> From<::core::ops::RangeInclusive<X>> for Uniform<X> {
impl<X: SampleUniform> From<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.
@ -307,6 +342,43 @@ where Borrowed: SampleUniform
}
}
/// Range that supports generating a single sample efficiently.
///
/// Any type implementing this trait can be used to specify the sampled range
/// for `Rng::gen_range`.
pub trait SampleRange<T> {
/// Generate a sample from the given range.
fn sample_single<R: RngCore + ?Sized>(self, rng: &mut R) -> T;
/// Check whether the range is empty.
fn is_empty(&self) -> bool;
}
impl<T: SampleUniform + PartialOrd> SampleRange<T> for Range<T> {
#[inline]
fn sample_single<R: RngCore + ?Sized>(self, rng: &mut R) -> T {
T::Sampler::sample_single(self.start, self.end, rng)
}
#[inline]
fn is_empty(&self) -> bool {
!(self.start < self.end)
}
}
impl<T: SampleUniform + PartialOrd> SampleRange<T> for RangeInclusive<T> {
#[inline]
fn sample_single<R: RngCore + ?Sized>(self, rng: &mut R) -> T {
T::Sampler::sample_single_inclusive(self.start(), self.end(), rng)
}
#[inline]
fn is_empty(&self) -> bool {
!(self.start() <= self.end())
}
}
////////////////////////////////////////////////////////////////////////////////
// What follows are all back-ends.
@ -346,7 +418,8 @@ where Borrowed: SampleUniform
/// 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.
#[derive(Clone, Copy, Debug)]
#[derive(Clone, Copy, Debug, PartialEq)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct UniformInt<X> {
low: X,
range: X,
@ -404,13 +477,14 @@ macro_rules! uniform_int_impl {
};
UniformInt {
low: low,
low,
// These are really $unsigned values, but store as $ty:
range: range as $ty,
z: ints_to_reject as $unsigned as $ty,
}
}
#[inline]
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X {
let range = self.range as $unsigned as $u_large;
if range > 0 {
@ -429,6 +503,7 @@ macro_rules! uniform_int_impl {
}
}
#[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,
@ -437,7 +512,25 @@ macro_rules! uniform_int_impl {
let low = *low_b.borrow();
let high = *high_b.borrow();
assert!(low < high, "UniformSampler::sample_single: low >= high");
let range = high.wrapping_sub(low) as $unsigned as $u_large;
Self::sample_single_inclusive(low, high - 1, rng)
}
#[inline]
fn sample_single_inclusive<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, "UniformSampler::sample_single_inclusive: low > high");
let range = high.wrapping_sub(low).wrapping_add(1) as $unsigned as $u_large;
// If the above resulted in wrap-around to 0, the range is $ty::MIN..=$ty::MAX,
// and any integer will do.
if range == 0 {
return rng.gen();
}
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
@ -467,7 +560,6 @@ uniform_int_impl! { i8, u8, u32 }
uniform_int_impl! { i16, u16, u32 }
uniform_int_impl! { i32, u32, u32 }
uniform_int_impl! { i64, u64, u64 }
#[cfg(not(target_os = "emscripten"))]
uniform_int_impl! { i128, u128, u128 }
uniform_int_impl! { isize, usize, usize }
uniform_int_impl! { u8, u8, u32 }
@ -475,10 +567,9 @@ uniform_int_impl! { u16, u16, u32 }
uniform_int_impl! { u32, u32, u32 }
uniform_int_impl! { u64, u64, u64 }
uniform_int_impl! { usize, usize, usize }
#[cfg(not(target_os = "emscripten"))]
uniform_int_impl! { u128, u128, u128 }
#[cfg(all(feature = "simd_support", feature = "nightly"))]
#[cfg(feature = "simd_support")]
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
@ -535,7 +626,7 @@ macro_rules! uniform_simd_int_impl {
let zone = unsigned_max - ints_to_reject;
UniformInt {
low: low,
low,
// These are really $unsigned values, but store as $ty:
range: range.cast(),
z: zone.cast(),
@ -585,7 +676,7 @@ macro_rules! uniform_simd_int_impl {
};
}
#[cfg(all(feature = "simd_support", feature = "nightly"))]
#[cfg(feature = "simd_support")]
uniform_simd_int_impl! {
(u64x2, i64x2),
(u64x4, i64x4),
@ -593,7 +684,7 @@ uniform_simd_int_impl! {
u64
}
#[cfg(all(feature = "simd_support", feature = "nightly"))]
#[cfg(feature = "simd_support")]
uniform_simd_int_impl! {
(u32x2, i32x2),
(u32x4, i32x4),
@ -602,7 +693,7 @@ uniform_simd_int_impl! {
u32
}
#[cfg(all(feature = "simd_support", feature = "nightly"))]
#[cfg(feature = "simd_support")]
uniform_simd_int_impl! {
(u16x2, i16x2),
(u16x4, i16x4),
@ -612,7 +703,7 @@ uniform_simd_int_impl! {
u16
}
#[cfg(all(feature = "simd_support", feature = "nightly"))]
#[cfg(feature = "simd_support")]
uniform_simd_int_impl! {
(u8x2, i8x2),
(u8x4, i8x4),
@ -623,6 +714,78 @@ uniform_simd_int_impl! {
u8
}
impl SampleUniform for char {
type Sampler = UniformChar;
}
/// The back-end implementing [`UniformSampler`] for `char`.
///
/// Unless you are implementing [`UniformSampler`] for your own type, this type
/// should not be used directly, use [`Uniform`] instead.
///
/// This differs from integer range sampling since the range `0xD800..=0xDFFF`
/// are used for surrogate pairs in UCS and UTF-16, and consequently are not
/// valid Unicode code points. We must therefore avoid sampling values in this
/// range.
#[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct UniformChar {
sampler: UniformInt<u32>,
}
/// UTF-16 surrogate range start
const CHAR_SURROGATE_START: u32 = 0xD800;
/// UTF-16 surrogate range size
const CHAR_SURROGATE_LEN: u32 = 0xE000 - CHAR_SURROGATE_START;
/// Convert `char` to compressed `u32`
fn char_to_comp_u32(c: char) -> u32 {
match c as u32 {
c if c >= CHAR_SURROGATE_START => c - CHAR_SURROGATE_LEN,
c => c,
}
}
impl UniformSampler for UniformChar {
type X = char;
#[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 = char_to_comp_u32(*low_b.borrow());
let high = char_to_comp_u32(*high_b.borrow());
let sampler = UniformInt::<u32>::new(low, high);
UniformChar { sampler }
}
#[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 = char_to_comp_u32(*low_b.borrow());
let high = char_to_comp_u32(*high_b.borrow());
let sampler = UniformInt::<u32>::new_inclusive(low, high);
UniformChar { sampler }
}
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X {
let mut x = self.sampler.sample(rng);
if x >= CHAR_SURROGATE_START {
x += CHAR_SURROGATE_LEN;
}
// SAFETY: x must not be in surrogate range or greater than char::MAX.
// This relies on range constructors which accept char arguments.
// Validity of input char values is assumed.
unsafe { core::char::from_u32_unchecked(x) }
}
}
/// The back-end implementing [`UniformSampler`] for floating-point types.
///
@ -643,7 +806,8 @@ uniform_simd_int_impl! {
/// [`new`]: UniformSampler::new
/// [`new_inclusive`]: UniformSampler::new_inclusive
/// [`Standard`]: crate::distributions::Standard
#[derive(Clone, Copy, Debug)]
#[derive(Clone, Copy, Debug, PartialEq)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct UniformFloat<X> {
low: X,
scale: X,
@ -665,16 +829,21 @@ macro_rules! uniform_float_impl {
{
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"
debug_assert!(
low.all_finite(),
"Uniform::new called with `low` non-finite."
);
debug_assert!(
high.all_finite(),
"Uniform::new called with `high` non-finite."
);
assert!(low.all_lt(high), "Uniform::new called with `low >= high`");
let max_rand = <$ty>::splat(
(::core::$u_scalar::MAX >> $bits_to_discard).into_float_with_exponent(0) - 1.0,
);
let mut scale = high - low;
assert!(scale.all_finite(), "Uniform::new: range overflow");
loop {
let mask = (scale * max_rand + low).ge_mask(high);
@ -696,19 +865,24 @@ macro_rules! uniform_float_impl {
{
let low = *low_b.borrow();
let high = *high_b.borrow();
debug_assert!(
low.all_finite(),
"Uniform::new_inclusive called with `low` non-finite."
);
debug_assert!(
high.all_finite(),
"Uniform::new_inclusive called with `high` non-finite."
);
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;
assert!(scale.all_finite(), "Uniform::new_inclusive: range overflow");
loop {
let mask = (scale * max_rand + low).gt_mask(high);
@ -747,11 +921,20 @@ macro_rules! uniform_float_impl {
{
let low = *low_b.borrow();
let high = *high_b.borrow();
debug_assert!(
low.all_finite(),
"UniformSampler::sample_single called with `low` non-finite."
);
debug_assert!(
high.all_finite(),
"UniformSampler::sample_single called with `high` non-finite."
);
assert!(
low.all_lt(high),
"UniformSampler::sample_single: low >= high"
);
let mut scale = high - low;
assert!(scale.all_finite(), "UniformSampler::sample_single: range overflow");
loop {
// Generate a value in the range [1, 2)
@ -837,12 +1020,14 @@ uniform_float_impl! { f64x8, u64x8, f64, u64, 64 - 52 }
/// Unless you are implementing [`UniformSampler`] for your own types, this type
/// should not be used directly, use [`Uniform`] instead.
#[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct UniformDuration {
mode: UniformDurationMode,
offset: u32,
}
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
enum UniformDurationMode {
Small {
secs: u64,
@ -947,7 +1132,7 @@ impl UniformSampler for UniformDuration {
max_nanos,
secs,
} => {
// constant folding means this is at least as fast as `gen_range`
// constant folding means this is at least as fast as `Rng::sample(Range)`
let nano_range = Uniform::new(0, 1_000_000_000);
loop {
let s = secs.sample(rng);
@ -967,6 +1152,56 @@ mod tests {
use super::*;
use crate::rngs::mock::StepRng;
#[test]
#[cfg(feature = "serde1")]
fn test_serialization_uniform_duration() {
let distr = UniformDuration::new(Duration::from_secs(10), Duration::from_secs(60));
let de_distr: UniformDuration = bincode::deserialize(&bincode::serialize(&distr).unwrap()).unwrap();
assert_eq!(
distr.offset, de_distr.offset
);
match (distr.mode, de_distr.mode) {
(UniformDurationMode::Small {secs: a_secs, nanos: a_nanos}, UniformDurationMode::Small {secs, nanos}) => {
assert_eq!(a_secs, secs);
assert_eq!(a_nanos.0.low, nanos.0.low);
assert_eq!(a_nanos.0.range, nanos.0.range);
assert_eq!(a_nanos.0.z, nanos.0.z);
}
(UniformDurationMode::Medium {nanos: a_nanos} , UniformDurationMode::Medium {nanos}) => {
assert_eq!(a_nanos.0.low, nanos.0.low);
assert_eq!(a_nanos.0.range, nanos.0.range);
assert_eq!(a_nanos.0.z, nanos.0.z);
}
(UniformDurationMode::Large {max_secs:a_max_secs, max_nanos:a_max_nanos, secs:a_secs}, UniformDurationMode::Large {max_secs, max_nanos, secs} ) => {
assert_eq!(a_max_secs, max_secs);
assert_eq!(a_max_nanos, max_nanos);
assert_eq!(a_secs.0.low, secs.0.low);
assert_eq!(a_secs.0.range, secs.0.range);
assert_eq!(a_secs.0.z, secs.0.z);
}
_ => panic!("`UniformDurationMode` was not serialized/deserialized correctly")
}
}
#[test]
#[cfg(feature = "serde1")]
fn test_uniform_serialization() {
let unit_box: Uniform<i32> = Uniform::new(-1, 1);
let de_unit_box: Uniform<i32> = bincode::deserialize(&bincode::serialize(&unit_box).unwrap()).unwrap();
assert_eq!(unit_box.0.low, de_unit_box.0.low);
assert_eq!(unit_box.0.range, de_unit_box.0.range);
assert_eq!(unit_box.0.z, de_unit_box.0.z);
let unit_box: Uniform<f32> = Uniform::new(-1., 1.);
let de_unit_box: Uniform<f32> = bincode::deserialize(&bincode::serialize(&unit_box).unwrap()).unwrap();
assert_eq!(unit_box.0.low, de_unit_box.0.low);
assert_eq!(unit_box.0.scale, de_unit_box.0.scale);
}
#[should_panic]
#[test]
fn test_uniform_bad_limits_equal_int() {
@ -991,7 +1226,7 @@ mod tests {
#[test]
#[cfg_attr(miri, ignore)] // Miri is too slow
fn test_integers() {
#[cfg(not(target_os = "emscripten"))] use core::{i128, u128};
use core::{i128, u128};
use core::{i16, i32, i64, i8, isize};
use core::{u16, u32, u64, u8, usize};
@ -1024,9 +1259,14 @@ mod tests {
}
for _ in 0..1000 {
let v: $ty = rng.gen_range(low, high);
let v = <$ty as SampleUniform>::Sampler::sample_single(low, high, &mut rng);
assert!($le(low, v) && $lt(v, high));
}
for _ in 0..1000 {
let v = <$ty as SampleUniform>::Sampler::sample_single_inclusive(low, high, &mut rng);
assert!($le(low, v) && $le(v, high));
}
}
}};
@ -1054,11 +1294,9 @@ mod tests {
);)*
}};
}
t!(i8, i16, i32, i64, isize, u8, u16, u32, u64, usize);
#[cfg(not(target_os = "emscripten"))]
t!(i128, u128);
t!(i8, i16, i32, i64, isize, u8, u16, u32, u64, usize, i128, u128);
#[cfg(all(feature = "simd_support", feature = "nightly"))]
#[cfg(feature = "simd_support")]
{
t!(u8x2, u8x4, u8x8, u8x16, u8x32, u8x64 => u8);
t!(i8x2, i8x4, i8x8, i8x16, i8x32, i8x64 => i8);
@ -1071,6 +1309,27 @@ mod tests {
}
}
#[test]
#[cfg_attr(miri, ignore)] // Miri is too slow
fn test_char() {
let mut rng = crate::test::rng(891);
let mut max = core::char::from_u32(0).unwrap();
for _ in 0..100 {
let c = rng.gen_range('A'..='Z');
assert!(('A'..='Z').contains(&c));
max = max.max(c);
}
assert_eq!(max, 'Z');
let d = Uniform::new(
core::char::from_u32(0xD7F0).unwrap(),
core::char::from_u32(0xE010).unwrap(),
);
for _ in 0..100 {
let c = d.sample(&mut rng);
assert!((c as u32) < 0xD800 || (c as u32) > 0xDFFF);
}
}
#[test]
#[cfg_attr(miri, ignore)] // Miri is too slow
fn test_floats() {
@ -1088,12 +1347,8 @@ mod tests {
(-<$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),
(0.1 * ::core::$f_scalar::MAX, ::core::$f_scalar::MAX),
(-::core::$f_scalar::MAX * 0.2, ::core::$f_scalar::MAX * 0.7),
];
for &(low_scalar, high_scalar) in v.iter() {
for lane in 0..<$ty>::lanes() {
@ -1106,7 +1361,8 @@ mod tests {
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);
let v = <$ty as SampleUniform>::Sampler
::sample_single(low, high, &mut rng).extract(lane);
assert!(low_scalar <= v && v < high_scalar);
}
@ -1117,7 +1373,9 @@ mod tests {
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_eq!(<$ty as SampleUniform>::Sampler
::sample_single(low, high, &mut zero_rng)
.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);
@ -1130,7 +1388,9 @@ mod tests {
(-1i64 << $bits_shifted) as u64,
);
assert!(
lowering_max_rng.gen_range(low, high).extract(lane) < high_scalar
<$ty as SampleUniform>::Sampler
::sample_single(low, high, &mut lowering_max_rng)
.extract(lane) < high_scalar
);
}
}
@ -1167,6 +1427,19 @@ mod tests {
}
}
#[test]
#[should_panic]
fn test_float_overflow() {
let _ = Uniform::from(::core::f64::MIN..::core::f64::MAX);
}
#[test]
#[should_panic]
fn test_float_overflow_single() {
let mut rng = crate::test::rng(252);
rng.gen_range(::core::f64::MIN..::core::f64::MAX);
}
#[test]
#[cfg(all(
feature = "std",
@ -1178,7 +1451,7 @@ mod tests {
use std::panic::catch_unwind;
fn range<T: SampleUniform>(low: T, high: T) {
let mut rng = crate::test::rng(253);
rng.gen_range(low, high);
T::Sampler::sample_single(low, high, &mut rng);
}
macro_rules! t {
@ -1232,9 +1505,6 @@ mod tests {
#[test]
#[cfg_attr(miri, ignore)] // Miri is too slow
fn test_durations() {
#[cfg(not(feature = "std"))] use core::time::Duration;
#[cfg(feature = "std")] use std::time::Duration;
let mut rng = crate::test::rng(253);
let v = &[
@ -1377,4 +1647,12 @@ mod tests {
],
);
}
#[test]
fn uniform_distributions_can_be_compared() {
assert_eq!(Uniform::new(1.0, 2.0), Uniform::new(1.0, 2.0));
// To cover UniformInt
assert_eq!(Uniform::new(1 as u32, 2 as u32), Uniform::new(1 as u32, 2 as u32));
}
}

View file

@ -1,102 +0,0 @@
// 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.
#![allow(deprecated)]
#![allow(clippy::all)]
use crate::distributions::{Distribution, Uniform};
use crate::Rng;
/// Samples uniformly from the edge of the unit circle in two dimensions.
///
/// Implemented via a method by von Neumann[^1].
///
/// [^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.
#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
#[derive(Clone, Copy, Debug)]
pub struct UnitCircle;
impl UnitCircle {
/// Construct a new `UnitCircle` distribution.
#[inline]
pub fn new() -> UnitCircle {
UnitCircle
}
}
impl Distribution<[f64; 2]> for UnitCircle {
#[inline]
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> [f64; 2] {
let uniform = Uniform::new(-1., 1.);
let mut x1;
let mut x2;
let mut sum;
loop {
x1 = uniform.sample(rng);
x2 = 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 super::UnitCircle;
use crate::distributions::Distribution;
/// 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 = crate::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 = crate::test::rng(2);
let expected = [
[-0.9965658683520504, -0.08280380447614634],
[-0.9790853270389644, -0.20345004884984505],
[-0.8449189758898707, 0.5348943112253227],
];
let samples = [
UnitCircle.sample(&mut rng),
UnitCircle.sample(&mut rng),
UnitCircle.sample(&mut rng),
];
assert_eq!(samples, expected);
}
}

View file

@ -1,97 +0,0 @@
// 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.
#![allow(deprecated)]
#![allow(clippy::all)]
use crate::distributions::{Distribution, Uniform};
use crate::Rng;
/// Samples uniformly from the surface of the unit sphere in three dimensions.
///
/// Implemented via a method by Marsaglia[^1].
///
/// [^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.
#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
#[derive(Clone, Copy, Debug)]
pub struct UnitSphereSurface;
impl UnitSphereSurface {
/// Construct a new `UnitSphereSurface` distribution.
#[inline]
pub fn new() -> UnitSphereSurface {
UnitSphereSurface
}
}
impl Distribution<[f64; 3]> for UnitSphereSurface {
#[inline]
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> [f64; 3] {
let uniform = Uniform::new(-1., 1.);
loop {
let (x1, x2) = (uniform.sample(rng), 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 super::UnitSphereSurface;
use crate::distributions::Distribution;
/// 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 = crate::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 = crate::test::rng(2);
let expected = [
[0.03247542860231647, -0.7830477442152738, 0.6211131755296027],
[-0.09978440840914075, 0.9706650829833128, -0.21875184231323952],
[0.2735582468624679, 0.9435374242279655, -0.1868234852870203],
];
let samples = [
UnitSphereSurface.sample(&mut rng),
UnitSphereSurface.sample(&mut rng),
UnitSphereSurface.sample(&mut rng),
];
assert_eq!(samples, expected);
}
}

View file

@ -8,12 +8,10 @@
//! Math helper functions
#[cfg(feature = "std")] use crate::distributions::ziggurat_tables;
#[cfg(feature = "std")] use crate::Rng;
#[cfg(feature = "simd_support")] use packed_simd::*;
pub trait WideningMultiply<RHS = Self> {
pub(crate) trait WideningMultiply<RHS = Self> {
type Output;
fn wmul(self, x: RHS) -> Self::Output;
@ -58,7 +56,6 @@ macro_rules! wmul_impl {
wmul_impl! { u8, u16, 8 }
wmul_impl! { u16, u32, 16 }
wmul_impl! { u32, u64, 32 }
#[cfg(not(target_os = "emscripten"))]
wmul_impl! { u64, u128, 64 }
// This code is a translation of the __mulddi3 function in LLVM's
@ -122,9 +119,6 @@ macro_rules! wmul_impl_large {
)+
};
}
#[cfg(target_os = "emscripten")]
wmul_impl_large! { u64, 32 }
#[cfg(not(target_os = "emscripten"))]
wmul_impl_large! { u128, 64 }
macro_rules! wmul_impl_usize {
@ -140,12 +134,14 @@ macro_rules! wmul_impl_usize {
}
};
}
#[cfg(target_pointer_width = "16")]
wmul_impl_usize! { u16 }
#[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"))]
#[cfg(feature = "simd_support")]
mod simd_wmul {
use super::*;
#[cfg(target_arch = "x86")] use core::arch::x86::*;
@ -161,9 +157,8 @@ mod simd_wmul {
}
wmul_impl! { (u16x2, u32x2),, 16 }
#[cfg(not(target_feature = "sse2"))]
wmul_impl! { (u16x4, u32x4),, 16 }
#[cfg(not(target_feature = "sse4.2"))]
#[cfg(not(target_feature = "sse2"))]
wmul_impl! { (u16x8, u32x8),, 16 }
#[cfg(not(target_feature = "avx2"))]
wmul_impl! { (u16x16, u32x16),, 16 }
@ -189,8 +184,6 @@ mod simd_wmul {
}
#[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 }
@ -210,9 +203,6 @@ mod simd_wmul {
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 {
@ -243,6 +233,8 @@ pub(crate) trait FloatSIMDUtils {
/// Implement functions available in std builds but missing from core primitives
#[cfg(not(std))]
// False positive: We are following `std` here.
#[allow(clippy::wrong_self_convention)]
pub(crate) trait Float: Sized {
fn is_nan(self) -> bool;
fn is_infinite(self) -> bool;
@ -435,113 +427,3 @@ macro_rules! simd_impl {
#[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 crate::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;
}
}
}

View file

@ -1,67 +0,0 @@
// 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.
#![allow(deprecated)]
use crate::distributions::{Distribution, OpenClosed01};
use crate::Rng;
/// Samples floating-point numbers according to the Weibull distribution
#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
#[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 super::Weibull;
use crate::distributions::Distribution;
#[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 = crate::test::rng(1);
for _ in 0..1000 {
let r = d.sample(&mut rng);
assert!(r >= 0.);
}
}
}

View file

@ -0,0 +1,47 @@
// 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.
//! Weighted index sampling
//!
//! This module is deprecated. Use [`crate::distributions::WeightedIndex`] and
//! [`crate::distributions::WeightedError`] instead.
pub use super::{WeightedIndex, WeightedError};
#[allow(missing_docs)]
#[deprecated(since = "0.8.0", note = "moved to rand_distr crate")]
pub mod alias_method {
// This module exists to provide a deprecation warning which minimises
// compile errors, but still fails to compile if ever used.
use core::marker::PhantomData;
use alloc::vec::Vec;
use super::WeightedError;
#[derive(Debug)]
pub struct WeightedIndex<W: Weight> {
_phantom: PhantomData<W>,
}
impl<W: Weight> WeightedIndex<W> {
pub fn new(_weights: Vec<W>) -> Result<Self, WeightedError> {
Err(WeightedError::NoItem)
}
}
pub trait Weight {}
macro_rules! impl_weight {
() => {};
($T:ident, $($more:ident,)*) => {
impl Weight for $T {}
impl_weight!($($more,)*);
};
}
impl_weight!(f64, f32,);
impl_weight!(u8, u16, u32, u64, usize,);
impl_weight!(i8, i16, i32, i64, isize,);
impl_weight!(u128, i128,);
}

View file

@ -1,517 +0,0 @@
//! This module contains an implementation of alias method for sampling random
//! indices with probabilities proportional to a collection of weights.
use super::WeightedError;
#[cfg(not(feature = "std"))] use crate::alloc::vec;
#[cfg(not(feature = "std"))] use crate::alloc::vec::Vec;
use crate::distributions::uniform::SampleUniform;
use crate::distributions::Distribution;
use crate::distributions::Uniform;
use crate::Rng;
use core::fmt;
use core::iter::Sum;
use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
/// A distribution using weighted sampling to pick a discretely selected item.
///
/// Sampling a [`WeightedIndex<W>`] distribution returns the index of a randomly
/// selected element from the vector used to create the [`WeightedIndex<W>`].
/// The chance of a given element being picked is proportional to the value of
/// the element. The weights can have any type `W` for which a implementation of
/// [`Weight`] exists.
///
/// # Performance
///
/// Given that `n` is the number of items in the vector used to create an
/// [`WeightedIndex<W>`], [`WeightedIndex<W>`] will require `O(n)` amount of
/// memory. More specifically it takes up some constant amount of memory plus
/// the vector used to create it and a [`Vec<u32>`] with capacity `n`.
///
/// Time complexity for the creation of a [`WeightedIndex<W>`] is `O(n)`.
/// Sampling is `O(1)`, it makes a call to [`Uniform<u32>::sample`] and a call
/// to [`Uniform<W>::sample`].
///
/// # Example
///
/// ```
/// use rand::distributions::weighted::alias_method::WeightedIndex;
/// use rand::prelude::*;
///
/// let choices = vec!['a', 'b', 'c'];
/// let weights = vec![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).collect()).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);
/// }
/// ```
///
/// [`WeightedIndex<W>`]: crate::distributions::weighted::alias_method::WeightedIndex
/// [`Weight`]: crate::distributions::weighted::alias_method::Weight
/// [`Vec<u32>`]: Vec
/// [`Uniform<u32>::sample`]: Distribution::sample
/// [`Uniform<W>::sample`]: Distribution::sample
pub struct WeightedIndex<W: Weight> {
aliases: Vec<u32>,
no_alias_odds: Vec<W>,
uniform_index: Uniform<u32>,
uniform_within_weight_sum: Uniform<W>,
}
impl<W: Weight> WeightedIndex<W> {
/// Creates a new [`WeightedIndex`].
///
/// Returns an error if:
/// - The vector is empty.
/// - The vector is longer than `u32::MAX`.
/// - For any weight `w`: `w < 0` or `w > max` where `max = W::MAX /
/// weights.len()`.
/// - The sum of weights is zero.
pub fn new(weights: Vec<W>) -> Result<Self, WeightedError> {
let n = weights.len();
if n == 0 {
return Err(WeightedError::NoItem);
} else if n > ::core::u32::MAX as usize {
return Err(WeightedError::TooMany);
}
let n = n as u32;
let max_weight_size = W::try_from_u32_lossy(n)
.map(|n| W::MAX / n)
.unwrap_or(W::ZERO);
if !weights
.iter()
.all(|&w| W::ZERO <= w && w <= max_weight_size)
{
return Err(WeightedError::InvalidWeight);
}
// The sum of weights will represent 100% of no alias odds.
let weight_sum = Weight::sum(weights.as_slice());
// Prevent floating point overflow due to rounding errors.
let weight_sum = if weight_sum > W::MAX {
W::MAX
} else {
weight_sum
};
if weight_sum == W::ZERO {
return Err(WeightedError::AllWeightsZero);
}
// `weight_sum` would have been zero if `try_from_lossy` causes an error here.
let n_converted = W::try_from_u32_lossy(n).unwrap();
let mut no_alias_odds = weights;
for odds in no_alias_odds.iter_mut() {
*odds *= n_converted;
// Prevent floating point overflow due to rounding errors.
*odds = if *odds > W::MAX { W::MAX } else { *odds };
}
/// This struct is designed to contain three data structures at once,
/// sharing the same memory. More precisely it contains two linked lists
/// and an alias map, which will be the output of this method. To keep
/// the three data structures from getting in each other's way, it must
/// be ensured that a single index is only ever in one of them at the
/// same time.
struct Aliases {
aliases: Vec<u32>,
smalls_head: u32,
bigs_head: u32,
}
impl Aliases {
fn new(size: u32) -> Self {
Aliases {
aliases: vec![0; size as usize],
smalls_head: ::core::u32::MAX,
bigs_head: ::core::u32::MAX,
}
}
fn push_small(&mut self, idx: u32) {
self.aliases[idx as usize] = self.smalls_head;
self.smalls_head = idx;
}
fn push_big(&mut self, idx: u32) {
self.aliases[idx as usize] = self.bigs_head;
self.bigs_head = idx;
}
fn pop_small(&mut self) -> u32 {
let popped = self.smalls_head;
self.smalls_head = self.aliases[popped as usize];
popped
}
fn pop_big(&mut self) -> u32 {
let popped = self.bigs_head;
self.bigs_head = self.aliases[popped as usize];
popped
}
fn smalls_is_empty(&self) -> bool {
self.smalls_head == ::core::u32::MAX
}
fn bigs_is_empty(&self) -> bool {
self.bigs_head == ::core::u32::MAX
}
fn set_alias(&mut self, idx: u32, alias: u32) {
self.aliases[idx as usize] = alias;
}
}
let mut aliases = Aliases::new(n);
// Split indices into those with small weights and those with big weights.
for (index, &odds) in no_alias_odds.iter().enumerate() {
if odds < weight_sum {
aliases.push_small(index as u32);
} else {
aliases.push_big(index as u32);
}
}
// Build the alias map by finding an alias with big weight for each index with
// small weight.
while !aliases.smalls_is_empty() && !aliases.bigs_is_empty() {
let s = aliases.pop_small();
let b = aliases.pop_big();
aliases.set_alias(s, b);
no_alias_odds[b as usize] =
no_alias_odds[b as usize] - weight_sum + no_alias_odds[s as usize];
if no_alias_odds[b as usize] < weight_sum {
aliases.push_small(b);
} else {
aliases.push_big(b);
}
}
// The remaining indices should have no alias odds of about 100%. This is due to
// numeric accuracy. Otherwise they would be exactly 100%.
while !aliases.smalls_is_empty() {
no_alias_odds[aliases.pop_small() as usize] = weight_sum;
}
while !aliases.bigs_is_empty() {
no_alias_odds[aliases.pop_big() as usize] = weight_sum;
}
// Prepare distributions for sampling. Creating them beforehand improves
// sampling performance.
let uniform_index = Uniform::new(0, n);
let uniform_within_weight_sum = Uniform::new(W::ZERO, weight_sum);
Ok(Self {
aliases: aliases.aliases,
no_alias_odds,
uniform_index,
uniform_within_weight_sum,
})
}
}
impl<W: Weight> Distribution<usize> for WeightedIndex<W> {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> usize {
let candidate = rng.sample(self.uniform_index);
if rng.sample(&self.uniform_within_weight_sum) < self.no_alias_odds[candidate as usize] {
candidate as usize
} else {
self.aliases[candidate as usize] as usize
}
}
}
impl<W: Weight> fmt::Debug for WeightedIndex<W>
where
W: fmt::Debug,
Uniform<W>: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("WeightedIndex")
.field("aliases", &self.aliases)
.field("no_alias_odds", &self.no_alias_odds)
.field("uniform_index", &self.uniform_index)
.field("uniform_within_weight_sum", &self.uniform_within_weight_sum)
.finish()
}
}
impl<W: Weight> Clone for WeightedIndex<W>
where Uniform<W>: Clone
{
fn clone(&self) -> Self {
Self {
aliases: self.aliases.clone(),
no_alias_odds: self.no_alias_odds.clone(),
uniform_index: self.uniform_index.clone(),
uniform_within_weight_sum: self.uniform_within_weight_sum.clone(),
}
}
}
/// Trait that must be implemented for weights, that are used with
/// [`WeightedIndex`]. Currently no guarantees on the correctness of
/// [`WeightedIndex`] are given for custom implementations of this trait.
pub trait Weight:
Sized
+ Copy
+ SampleUniform
+ PartialOrd
+ Add<Output = Self>
+ AddAssign
+ Sub<Output = Self>
+ SubAssign
+ Mul<Output = Self>
+ MulAssign
+ Div<Output = Self>
+ DivAssign
+ Sum
{
/// Maximum number representable by `Self`.
const MAX: Self;
/// Element of `Self` equivalent to 0.
const ZERO: Self;
/// Produce an instance of `Self` from a `u32` value, or return `None` if
/// out of range. Loss of precision (where `Self` is a floating point type)
/// is acceptable.
fn try_from_u32_lossy(n: u32) -> Option<Self>;
/// Sums all values in slice `values`.
fn sum(values: &[Self]) -> Self {
values.iter().map(|x| *x).sum()
}
}
macro_rules! impl_weight_for_float {
($T: ident) => {
impl Weight for $T {
const MAX: Self = ::core::$T::MAX;
const ZERO: Self = 0.0;
fn try_from_u32_lossy(n: u32) -> Option<Self> {
Some(n as $T)
}
fn sum(values: &[Self]) -> Self {
pairwise_sum(values)
}
}
};
}
/// In comparison to naive accumulation, the pairwise sum algorithm reduces
/// rounding errors when there are many floating point values.
fn pairwise_sum<T: Weight>(values: &[T]) -> T {
if values.len() <= 32 {
values.iter().map(|x| *x).sum()
} else {
let mid = values.len() / 2;
let (a, b) = values.split_at(mid);
pairwise_sum(a) + pairwise_sum(b)
}
}
macro_rules! impl_weight_for_int {
($T: ident) => {
impl Weight for $T {
const MAX: Self = ::core::$T::MAX;
const ZERO: Self = 0;
fn try_from_u32_lossy(n: u32) -> Option<Self> {
let n_converted = n as Self;
if n_converted >= Self::ZERO && n_converted as u32 == n {
Some(n_converted)
} else {
None
}
}
}
};
}
impl_weight_for_float!(f64);
impl_weight_for_float!(f32);
impl_weight_for_int!(usize);
#[cfg(not(target_os = "emscripten"))]
impl_weight_for_int!(u128);
impl_weight_for_int!(u64);
impl_weight_for_int!(u32);
impl_weight_for_int!(u16);
impl_weight_for_int!(u8);
impl_weight_for_int!(isize);
#[cfg(not(target_os = "emscripten"))]
impl_weight_for_int!(i128);
impl_weight_for_int!(i64);
impl_weight_for_int!(i32);
impl_weight_for_int!(i16);
impl_weight_for_int!(i8);
#[cfg(test)]
mod test {
use super::*;
#[test]
#[cfg_attr(miri, ignore)] // Miri is too slow
fn test_weighted_index_f32() {
test_weighted_index(f32::into);
// Floating point special cases
assert_eq!(
WeightedIndex::new(vec![::core::f32::INFINITY]).unwrap_err(),
WeightedError::InvalidWeight
);
assert_eq!(
WeightedIndex::new(vec![-0_f32]).unwrap_err(),
WeightedError::AllWeightsZero
);
assert_eq!(
WeightedIndex::new(vec![-1_f32]).unwrap_err(),
WeightedError::InvalidWeight
);
assert_eq!(
WeightedIndex::new(vec![-::core::f32::INFINITY]).unwrap_err(),
WeightedError::InvalidWeight
);
assert_eq!(
WeightedIndex::new(vec![::core::f32::NAN]).unwrap_err(),
WeightedError::InvalidWeight
);
}
#[cfg(not(target_os = "emscripten"))]
#[test]
#[cfg_attr(miri, ignore)] // Miri is too slow
fn test_weighted_index_u128() {
test_weighted_index(|x: u128| x as f64);
}
#[cfg(all(rustc_1_26, not(target_os = "emscripten")))]
#[test]
#[cfg_attr(miri, ignore)] // Miri is too slow
fn test_weighted_index_i128() {
test_weighted_index(|x: i128| x as f64);
// Signed integer special cases
assert_eq!(
WeightedIndex::new(vec![-1_i128]).unwrap_err(),
WeightedError::InvalidWeight
);
assert_eq!(
WeightedIndex::new(vec![::core::i128::MIN]).unwrap_err(),
WeightedError::InvalidWeight
);
}
#[test]
#[cfg_attr(miri, ignore)] // Miri is too slow
fn test_weighted_index_u8() {
test_weighted_index(u8::into);
}
#[test]
#[cfg_attr(miri, ignore)] // Miri is too slow
fn test_weighted_index_i8() {
test_weighted_index(i8::into);
// Signed integer special cases
assert_eq!(
WeightedIndex::new(vec![-1_i8]).unwrap_err(),
WeightedError::InvalidWeight
);
assert_eq!(
WeightedIndex::new(vec![::core::i8::MIN]).unwrap_err(),
WeightedError::InvalidWeight
);
}
fn test_weighted_index<W: Weight, F: Fn(W) -> f64>(w_to_f64: F)
where WeightedIndex<W>: fmt::Debug {
const NUM_WEIGHTS: u32 = 10;
const ZERO_WEIGHT_INDEX: u32 = 3;
const NUM_SAMPLES: u32 = 15000;
let mut rng = crate::test::rng(0x9c9fa0b0580a7031);
let weights = {
let mut weights = Vec::with_capacity(NUM_WEIGHTS as usize);
let random_weight_distribution = crate::distributions::Uniform::new_inclusive(
W::ZERO,
W::MAX / W::try_from_u32_lossy(NUM_WEIGHTS).unwrap(),
);
for _ in 0..NUM_WEIGHTS {
weights.push(rng.sample(&random_weight_distribution));
}
weights[ZERO_WEIGHT_INDEX as usize] = W::ZERO;
weights
};
let weight_sum = weights.iter().map(|w| *w).sum::<W>();
let expected_counts = weights
.iter()
.map(|&w| w_to_f64(w) / w_to_f64(weight_sum) * NUM_SAMPLES as f64)
.collect::<Vec<f64>>();
let weight_distribution = WeightedIndex::new(weights).unwrap();
let mut counts = vec![0; NUM_WEIGHTS as usize];
for _ in 0..NUM_SAMPLES {
counts[rng.sample(&weight_distribution)] += 1;
}
assert_eq!(counts[ZERO_WEIGHT_INDEX as usize], 0);
for (count, expected_count) in counts.into_iter().zip(expected_counts) {
let difference = (count as f64 - expected_count).abs();
let max_allowed_difference = NUM_SAMPLES as f64 / NUM_WEIGHTS as f64 * 0.1;
assert!(difference <= max_allowed_difference);
}
assert_eq!(
WeightedIndex::<W>::new(vec![]).unwrap_err(),
WeightedError::NoItem
);
assert_eq!(
WeightedIndex::new(vec![W::ZERO]).unwrap_err(),
WeightedError::AllWeightsZero
);
assert_eq!(
WeightedIndex::new(vec![W::MAX, W::MAX]).unwrap_err(),
WeightedError::InvalidWeight
);
}
#[test]
fn value_stability() {
fn test_samples<W: Weight>(weights: Vec<W>, buf: &mut [usize], expected: &[usize]) {
assert_eq!(buf.len(), expected.len());
let distr = WeightedIndex::new(weights).unwrap();
let mut rng = crate::test::rng(0x9c9fa0b0580a7031);
for r in buf.iter_mut() {
*r = rng.sample(&distr);
}
assert_eq!(buf, expected);
}
let mut buf = [0; 10];
test_samples(vec![1i32, 1, 1, 1, 1, 1, 1, 1, 1], &mut buf, &[
6, 5, 7, 5, 8, 7, 6, 2, 3, 7,
]);
test_samples(vec![0.7f32, 0.1, 0.1, 0.1], &mut buf, &[
2, 0, 0, 0, 0, 0, 0, 0, 1, 3,
]);
test_samples(vec![1.0f64, 0.999, 0.998, 0.997], &mut buf, &[
2, 1, 2, 3, 2, 1, 3, 2, 1, 1,
]);
}
}

View file

@ -7,16 +7,6 @@
// except according to those terms.
//! Weighted index sampling
//!
//! This module provides two implementations for sampling indices:
//!
//! * [`WeightedIndex`] allows `O(log N)` sampling
//! * [`alias_method::WeightedIndex`] allows `O(1)` sampling, but with
//! much greater set-up cost
//!
//! [`alias_method::WeightedIndex`]: alias_method/struct.WeightedIndex.html
pub mod alias_method;
use crate::distributions::uniform::{SampleBorrow, SampleUniform, UniformSampler};
use crate::distributions::Distribution;
@ -25,10 +15,12 @@ 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 crate::alloc::vec::Vec;
use alloc::vec::Vec;
/// A distribution using weighted sampling to pick a discretely selected
/// item.
#[cfg(feature = "serde1")]
use serde::{Serialize, Deserialize};
/// A distribution using weighted sampling of discrete items
///
/// Sampling a `WeightedIndex` distribution returns the index of a randomly
/// selected element from the iterator used when the `WeightedIndex` was
@ -38,6 +30,11 @@ use core::fmt;
///
/// # Performance
///
/// Time complexity of sampling from `WeightedIndex` is `O(log N)` where
/// `N` is the number of weights. As an alternative,
/// [`rand_distr::weighted_alias`](https://docs.rs/rand_distr/*/rand_distr/weighted_alias/index.html)
/// supports `O(1)` sampling, but with much higher initialisation cost.
///
/// 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.
///
@ -46,15 +43,12 @@ use core::fmt;
/// `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.
/// types, [`Uniform<X>`] doesn't allocate any memory.
///
/// Sampling from `WeightedIndex` will result in a single call to
/// `Uniform<X>::sample` (method of the [`Distribution`] trait), which typically
/// will request a single value from the underlying [`RngCore`], though the
/// exact number depends on the implementaiton of `Uniform<X>::sample`.
/// exact number depends on the implementation of `Uniform<X>::sample`.
///
/// # Example
///
@ -79,9 +73,11 @@ use core::fmt;
/// }
/// ```
///
/// [`Uniform<X>`]: crate::distributions::uniform::Uniform
/// [`Uniform<X>`]: crate::distributions::Uniform
/// [`RngCore`]: crate::RngCore
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
pub struct WeightedIndex<X: SampleUniform + PartialOrd> {
cumulative_weights: Vec<X>,
total_weight: X,
@ -107,13 +103,15 @@ impl<X: SampleUniform + PartialOrd> WeightedIndex<X> {
let mut total_weight: X = iter.next().ok_or(WeightedError::NoItem)?.borrow().clone();
let zero = <X as Default>::default();
if total_weight < zero {
if !(total_weight >= zero) {
return Err(WeightedError::InvalidWeight);
}
let mut weights = Vec::<X>::with_capacity(iter.size_hint().0);
for w in iter {
if *w.borrow() < zero {
// Note that `!(w >= x)` is not equivalent to `w < x` for partially
// ordered types due to NaNs which are equal to nothing.
if !(w.borrow() >= &zero) {
return Err(WeightedError::InvalidWeight);
}
weights.push(total_weight.clone());
@ -163,10 +161,10 @@ impl<X: SampleUniform + PartialOrd> WeightedIndex<X> {
return Err(WeightedError::InvalidWeight);
}
}
if *w < zero {
if !(*w >= zero) {
return Err(WeightedError::InvalidWeight);
}
if i >= self.cumulative_weights.len() + 1 {
if i > self.cumulative_weights.len() {
return Err(WeightedError::TooMany);
}
@ -183,7 +181,7 @@ impl<X: SampleUniform + PartialOrd> WeightedIndex<X> {
total_weight += w;
prev_i = Some(i);
}
if total_weight == zero {
if total_weight <= zero {
return Err(WeightedError::AllWeightsZero);
}
@ -245,6 +243,47 @@ where X: SampleUniform + PartialOrd
mod test {
use super::*;
#[cfg(feature = "serde1")]
#[test]
fn test_weightedindex_serde1() {
let weighted_index = WeightedIndex::new(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]).unwrap();
let ser_weighted_index = bincode::serialize(&weighted_index).unwrap();
let de_weighted_index: WeightedIndex<i32> =
bincode::deserialize(&ser_weighted_index).unwrap();
assert_eq!(
de_weighted_index.cumulative_weights,
weighted_index.cumulative_weights
);
assert_eq!(de_weighted_index.total_weight, weighted_index.total_weight);
}
#[test]
fn test_accepting_nan(){
assert_eq!(
WeightedIndex::new(&[core::f32::NAN, 0.5]).unwrap_err(),
WeightedError::InvalidWeight,
);
assert_eq!(
WeightedIndex::new(&[core::f32::NAN]).unwrap_err(),
WeightedError::InvalidWeight,
);
assert_eq!(
WeightedIndex::new(&[0.5, core::f32::NAN]).unwrap_err(),
WeightedError::InvalidWeight,
);
assert_eq!(
WeightedIndex::new(&[0.5, 7.0])
.unwrap()
.update_weights(&[(0, &core::f32::NAN)])
.unwrap_err(),
WeightedError::InvalidWeight,
)
}
#[test]
#[cfg_attr(miri, ignore)] // Miri is too slow
fn test_weightedindex() {
@ -379,16 +418,22 @@ mod test {
2, 2, 1, 3, 2, 1, 3, 3, 2, 1,
]);
}
#[test]
fn weighted_index_distributions_can_be_compared() {
assert_eq!(WeightedIndex::new(&[1, 2]), WeightedIndex::new(&[1, 2]));
}
}
/// Error type returned from `WeightedIndex::new`.
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum WeightedError {
/// The provided weight collection contains no items.
NoItem,
/// A weight is either less than zero, greater than the supported maximum or
/// otherwise invalid.
/// A weight is either less than zero, greater than the supported maximum,
/// NaN, or otherwise invalid.
InvalidWeight,
/// All items in the provided weight collection are zero.
@ -399,15 +444,15 @@ pub enum WeightedError {
}
#[cfg(feature = "std")]
impl ::std::error::Error for WeightedError {}
impl std::error::Error for WeightedError {}
impl fmt::Display for WeightedError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
WeightedError::NoItem => write!(f, "No weights provided."),
WeightedError::InvalidWeight => write!(f, "A weight is invalid."),
WeightedError::AllWeightsZero => write!(f, "All weights are zero."),
WeightedError::TooMany => write!(f, "Too many weights (hit u32::MAX)"),
}
f.write_str(match *self {
WeightedError::NoItem => "No weights provided in distribution",
WeightedError::InvalidWeight => "A weight is invalid in distribution",
WeightedError::AllWeightsZero => "All weights are zero in distribution",
WeightedError::TooMany => "Too many weights (hit u32::MAX) in distribution",
})
}
}

View file

@ -1,283 +0,0 @@
// 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.
// Tables for distributions which are sampled using the ziggurat
// algorithm. Autogenerated by `ziggurat_tables.py`.
pub type ZigTable = &'static [f64; 257];
pub const ZIG_NORM_R: f64 = 3.654152885361008796;
#[rustfmt::skip]
pub static ZIG_NORM_X: [f64; 257] =
[3.910757959537090045, 3.654152885361008796, 3.449278298560964462, 3.320244733839166074,
3.224575052047029100, 3.147889289517149969, 3.083526132001233044, 3.027837791768635434,
2.978603279880844834, 2.934366867207854224, 2.894121053612348060, 2.857138730872132548,
2.822877396825325125, 2.790921174000785765, 2.760944005278822555, 2.732685359042827056,
2.705933656121858100, 2.680514643284522158, 2.656283037575502437, 2.633116393630324570,
2.610910518487548515, 2.589575986706995181, 2.569035452680536569, 2.549221550323460761,
2.530075232158516929, 2.511544441625342294, 2.493583041269680667, 2.476149939669143318,
2.459208374333311298, 2.442725318198956774, 2.426670984935725972, 2.411018413899685520,
2.395743119780480601, 2.380822795170626005, 2.366237056715818632, 2.351967227377659952,
2.337996148795031370, 2.324308018869623016, 2.310888250599850036, 2.297723348901329565,
2.284800802722946056, 2.272108990226823888, 2.259637095172217780, 2.247375032945807760,
2.235313384928327984, 2.223443340090905718, 2.211756642882544366, 2.200245546609647995,
2.188902771624720689, 2.177721467738641614, 2.166695180352645966, 2.155817819875063268,
2.145083634046203613, 2.134487182844320152, 2.124023315687815661, 2.113687150684933957,
2.103474055713146829, 2.093379631137050279, 2.083399693996551783, 2.073530263516978778,
2.063767547809956415, 2.054107931648864849, 2.044547965215732788, 2.035084353727808715,
2.025713947862032960, 2.016433734904371722, 2.007240830558684852, 1.998132471356564244,
1.989106007615571325, 1.980158896898598364, 1.971288697931769640, 1.962493064942461896,
1.953769742382734043, 1.945116560006753925, 1.936531428273758904, 1.928012334050718257,
1.919557336591228847, 1.911164563769282232, 1.902832208548446369, 1.894558525668710081,
1.886341828534776388, 1.878180486290977669, 1.870072921069236838, 1.862017605397632281,
1.854013059758148119, 1.846057850283119750, 1.838150586580728607, 1.830289919680666566,
1.822474540091783224, 1.814703175964167636, 1.806974591348693426, 1.799287584547580199,
1.791640986550010028, 1.784033659547276329, 1.776464495522344977, 1.768932414909077933,
1.761436365316706665, 1.753975320315455111, 1.746548278279492994, 1.739154261283669012,
1.731792314050707216, 1.724461502945775715, 1.717160915015540690, 1.709889657069006086,
1.702646854797613907, 1.695431651932238548, 1.688243209434858727, 1.681080704722823338,
1.673943330923760353, 1.666830296159286684, 1.659740822855789499, 1.652674147080648526,
1.645629517902360339, 1.638606196773111146, 1.631603456932422036, 1.624620582830568427,
1.617656869570534228, 1.610711622367333673, 1.603784156023583041, 1.596873794420261339,
1.589979870021648534, 1.583101723393471438, 1.576238702733332886, 1.569390163412534456,
1.562555467528439657, 1.555733983466554893, 1.548925085471535512, 1.542128153226347553,
1.535342571438843118, 1.528567729435024614, 1.521803020758293101, 1.515047842773992404,
1.508301596278571965, 1.501563685112706548, 1.494833515777718391, 1.488110497054654369,
1.481394039625375747, 1.474683555695025516, 1.467978458615230908, 1.461278162507407830,
1.454582081885523293, 1.447889631277669675, 1.441200224845798017, 1.434513276002946425,
1.427828197027290358, 1.421144398672323117, 1.414461289772464658, 1.407778276843371534,
1.401094763676202559, 1.394410150925071257, 1.387723835686884621, 1.381035211072741964,
1.374343665770030531, 1.367648583594317957, 1.360949343030101844, 1.354245316759430606,
1.347535871177359290, 1.340820365893152122, 1.334098153216083604, 1.327368577624624679,
1.320630975217730096, 1.313884673146868964, 1.307128989027353860, 1.300363230327433728,
1.293586693733517645, 1.286798664489786415, 1.279998415710333237, 1.273185207661843732,
1.266358287014688333, 1.259516886060144225, 1.252660221891297887, 1.245787495544997903,
1.238897891102027415, 1.231990574742445110, 1.225064693752808020, 1.218119375481726552,
1.211153726239911244, 1.204166830140560140, 1.197157747875585931, 1.190125515422801650,
1.183069142678760732, 1.175987612011489825, 1.168879876726833800, 1.161744859441574240,
1.154581450355851802, 1.147388505416733873, 1.140164844363995789, 1.132909248648336975,
1.125620459211294389, 1.118297174115062909, 1.110938046009249502, 1.103541679420268151,
1.096106627847603487, 1.088631390649514197, 1.081114409698889389, 1.073554065787871714,
1.065948674757506653, 1.058296483326006454, 1.050595664586207123, 1.042844313139370538,
1.035040439828605274, 1.027181966030751292, 1.019266717460529215, 1.011292417434978441,
1.003256679539591412, 0.995156999629943084, 0.986990747093846266, 0.978755155288937750,
0.970447311058864615, 0.962064143217605250, 0.953602409875572654, 0.945058684462571130,
0.936429340280896860, 0.927710533396234771, 0.918898183643734989, 0.909987953490768997,
0.900975224455174528, 0.891855070726792376, 0.882622229578910122, 0.873271068082494550,
0.863795545546826915, 0.854189171001560554, 0.844444954902423661, 0.834555354079518752,
0.824512208745288633, 0.814306670128064347, 0.803929116982664893, 0.793369058833152785,
0.782615023299588763, 0.771654424216739354, 0.760473406422083165, 0.749056662009581653,
0.737387211425838629, 0.725446140901303549, 0.713212285182022732, 0.700661841097584448,
0.687767892786257717, 0.674499822827436479, 0.660822574234205984, 0.646695714884388928,
0.632072236375024632, 0.616896989996235545, 0.601104617743940417, 0.584616766093722262,
0.567338257040473026, 0.549151702313026790, 0.529909720646495108, 0.509423329585933393,
0.487443966121754335, 0.463634336771763245, 0.437518402186662658, 0.408389134588000746,
0.375121332850465727, 0.335737519180459465, 0.286174591747260509, 0.215241895913273806,
0.000000000000000000];
#[rustfmt::skip]
pub static ZIG_NORM_F: [f64; 257] =
[0.000477467764586655, 0.001260285930498598, 0.002609072746106363, 0.004037972593371872,
0.005522403299264754, 0.007050875471392110, 0.008616582769422917, 0.010214971439731100,
0.011842757857943104, 0.013497450601780807, 0.015177088307982072, 0.016880083152595839,
0.018605121275783350, 0.020351096230109354, 0.022117062707379922, 0.023902203305873237,
0.025705804008632656, 0.027527235669693315, 0.029365939758230111, 0.031221417192023690,
0.033093219458688698, 0.034980941461833073, 0.036884215688691151, 0.038802707404656918,
0.040736110656078753, 0.042684144916619378, 0.044646552251446536, 0.046623094902089664,
0.048613553216035145, 0.050617723861121788, 0.052635418276973649, 0.054666461325077916,
0.056710690106399467, 0.058767952921137984, 0.060838108349751806, 0.062921024437977854,
0.065016577971470438, 0.067124653828023989, 0.069245144397250269, 0.071377949059141965,
0.073522973714240991, 0.075680130359194964, 0.077849336702372207, 0.080030515814947509,
0.082223595813495684, 0.084428509570654661, 0.086645194450867782, 0.088873592068594229,
0.091113648066700734, 0.093365311913026619, 0.095628536713353335, 0.097903279039215627,
0.100189498769172020, 0.102487158942306270, 0.104796225622867056, 0.107116667775072880,
0.109448457147210021, 0.111791568164245583, 0.114145977828255210, 0.116511665626037014,
0.118888613443345698, 0.121276805485235437, 0.123676228202051403, 0.126086870220650349,
0.128508722280473636, 0.130941777174128166, 0.133386029692162844, 0.135841476571757352,
0.138308116449064322, 0.140785949814968309, 0.143274978974047118, 0.145775208006537926,
0.148286642733128721, 0.150809290682410169, 0.153343161060837674, 0.155888264725064563,
0.158444614156520225, 0.161012223438117663, 0.163591108232982951, 0.166181285765110071,
0.168782774801850333, 0.171395595638155623, 0.174019770082499359, 0.176655321444406654,
0.179302274523530397, 0.181960655600216487, 0.184630492427504539, 0.187311814224516926,
0.190004651671193070, 0.192709036904328807, 0.195425003514885592, 0.198152586546538112,
0.200891822495431333, 0.203642749311121501, 0.206405406398679298, 0.209179834621935651,
0.211966076307852941, 0.214764175252008499, 0.217574176725178370, 0.220396127481011589,
0.223230075764789593, 0.226076071323264877, 0.228934165415577484, 0.231804410825248525,
0.234686861873252689, 0.237581574432173676, 0.240488605941449107, 0.243408015423711988,
0.246339863502238771, 0.249284212419516704, 0.252241126056943765, 0.255210669955677150,
0.258192911338648023, 0.261187919133763713, 0.264195763998317568, 0.267216518344631837,
0.270250256366959984, 0.273297054069675804, 0.276356989296781264, 0.279430141762765316,
0.282516593084849388, 0.285616426816658109, 0.288729728483353931, 0.291856585618280984,
0.294997087801162572, 0.298151326697901342, 0.301319396102034120, 0.304501391977896274,
0.307697412505553769, 0.310907558127563710, 0.314131931597630143, 0.317370638031222396,
0.320623784958230129, 0.323891482377732021, 0.327173842814958593, 0.330470981380537099,
0.333783015832108509, 0.337110066638412809, 0.340452257045945450, 0.343809713148291340,
0.347182563958251478, 0.350570941482881204, 0.353974980801569250, 0.357394820147290515,
0.360830600991175754, 0.364282468130549597, 0.367750569780596226, 0.371235057669821344,
0.374736087139491414, 0.378253817247238111, 0.381788410875031348, 0.385340034841733958,
0.388908860020464597, 0.392495061461010764, 0.396098818517547080, 0.399720314981931668,
0.403359739222868885, 0.407017284331247953, 0.410693148271983222, 0.414387534042706784,
0.418100649839684591, 0.421832709231353298, 0.425583931339900579, 0.429354541031341519,
0.433144769114574058, 0.436954852549929273, 0.440785034667769915, 0.444635565397727750,
0.448506701509214067, 0.452398706863882505, 0.456311852680773566, 0.460246417814923481,
0.464202689050278838, 0.468180961407822172, 0.472181538469883255, 0.476204732721683788,
0.480250865911249714, 0.484320269428911598, 0.488413284707712059, 0.492530263646148658,
0.496671569054796314, 0.500837575128482149, 0.505028667945828791, 0.509245245998136142,
0.513487720749743026, 0.517756517232200619, 0.522052074674794864, 0.526374847174186700,
0.530725304406193921, 0.535103932383019565, 0.539511234259544614, 0.543947731192649941,
0.548413963257921133, 0.552910490428519918, 0.557437893621486324, 0.561996775817277916,
0.566587763258951771, 0.571211506738074970, 0.575868682975210544, 0.580559996103683473,
0.585286179266300333, 0.590047996335791969, 0.594846243770991268, 0.599681752622167719,
0.604555390700549533, 0.609468064928895381, 0.614420723892076803, 0.619414360609039205,
0.624450015550274240, 0.629528779928128279, 0.634651799290960050, 0.639820277456438991,
0.645035480824251883, 0.650298743114294586, 0.655611470583224665, 0.660975147780241357,
0.666391343912380640, 0.671861719900766374, 0.677388036222513090, 0.682972161648791376,
0.688616083008527058, 0.694321916130032579, 0.700091918140490099, 0.705928501336797409,
0.711834248882358467, 0.717811932634901395, 0.723864533472881599, 0.729995264565802437,
0.736207598131266683, 0.742505296344636245, 0.748892447223726720, 0.755373506511754500,
0.761953346841546475, 0.768637315803334831, 0.775431304986138326, 0.782341832659861902,
0.789376143571198563, 0.796542330428254619, 0.803849483176389490, 0.811307874318219935,
0.818929191609414797, 0.826726833952094231, 0.834716292992930375, 0.842915653118441077,
0.851346258465123684, 0.860033621203008636, 0.869008688043793165, 0.878309655816146839,
0.887984660763399880, 0.898095921906304051, 0.908726440060562912, 0.919991505048360247,
0.932060075968990209, 0.945198953453078028, 0.959879091812415930, 0.977101701282731328,
1.000000000000000000];
pub const ZIG_EXP_R: f64 = 7.697117470131050077;
#[rustfmt::skip]
pub static ZIG_EXP_X: [f64; 257] =
[8.697117470131052741, 7.697117470131050077, 6.941033629377212577, 6.478378493832569696,
6.144164665772472667, 5.882144315795399869, 5.666410167454033697, 5.482890627526062488,
5.323090505754398016, 5.181487281301500047, 5.054288489981304089, 4.938777085901250530,
4.832939741025112035, 4.735242996601741083, 4.644491885420085175, 4.559737061707351380,
4.480211746528421912, 4.405287693473573185, 4.334443680317273007, 4.267242480277365857,
4.203313713735184365, 4.142340865664051464, 4.084051310408297830, 4.028208544647936762,
3.974606066673788796, 3.923062500135489739, 3.873417670399509127, 3.825529418522336744,
3.779270992411667862, 3.734528894039797375, 3.691201090237418825, 3.649195515760853770,
3.608428813128909507, 3.568825265648337020, 3.530315889129343354, 3.492837654774059608,
3.456332821132760191, 3.420748357251119920, 3.386035442460300970, 3.352149030900109405,
3.319047470970748037, 3.286692171599068679, 3.255047308570449882, 3.224079565286264160,
3.193757903212240290, 3.164053358025972873, 3.134938858084440394, 3.106389062339824481,
3.078380215254090224, 3.050890016615455114, 3.023897504455676621, 2.997382949516130601,
2.971327759921089662, 2.945714394895045718, 2.920526286512740821, 2.895747768600141825,
2.871364012015536371, 2.847360965635188812, 2.823725302450035279, 2.800444370250737780,
2.777506146439756574, 2.754899196562344610, 2.732612636194700073, 2.710636095867928752,
2.688959688741803689, 2.667573980773266573, 2.646469963151809157, 2.625639026797788489,
2.605072938740835564, 2.584763820214140750, 2.564704126316905253, 2.544886627111869970,
2.525304390037828028, 2.505950763528594027, 2.486819361740209455, 2.467904050297364815,
2.449198932978249754, 2.430698339264419694, 2.412396812688870629, 2.394289099921457886,
2.376370140536140596, 2.358635057409337321, 2.341079147703034380, 2.323697874390196372,
2.306486858283579799, 2.289441870532269441, 2.272558825553154804, 2.255833774367219213,
2.239262898312909034, 2.222842503111036816, 2.206569013257663858, 2.190438966723220027,
2.174449009937774679, 2.158595893043885994, 2.142876465399842001, 2.127287671317368289,
2.111826546019042183, 2.096490211801715020, 2.081275874393225145, 2.066180819490575526,
2.051202409468584786, 2.036338080248769611, 2.021585338318926173, 2.006941757894518563,
1.992404978213576650, 1.977972700957360441, 1.963642687789548313, 1.949412758007184943,
1.935280786297051359, 1.921244700591528076, 1.907302480018387536, 1.893452152939308242,
1.879691795072211180, 1.866019527692827973, 1.852433515911175554, 1.838931967018879954,
1.825513128903519799, 1.812175288526390649, 1.798916770460290859, 1.785735935484126014,
1.772631179231305643, 1.759600930889074766, 1.746643651946074405, 1.733757834985571566,
1.720942002521935299, 1.708194705878057773, 1.695514524101537912, 1.682900062917553896,
1.670349953716452118, 1.657862852574172763, 1.645437439303723659, 1.633072416535991334,
1.620766508828257901, 1.608518461798858379, 1.596327041286483395, 1.584191032532688892,
1.572109239386229707, 1.560080483527888084, 1.548103603714513499, 1.536177455041032092,
1.524300908219226258, 1.512472848872117082, 1.500692176842816750, 1.488957805516746058,
1.477268661156133867, 1.465623682245745352, 1.454021818848793446, 1.442462031972012504,
1.430943292938879674, 1.419464582769983219, 1.408024891569535697, 1.396623217917042137,
1.385258568263121992, 1.373929956328490576, 1.362636402505086775, 1.351376933258335189,
1.340150580529504643, 1.328956381137116560, 1.317793376176324749, 1.306660610415174117,
1.295557131686601027, 1.284481990275012642, 1.273434238296241139, 1.262412929069615330,
1.251417116480852521, 1.240445854334406572, 1.229498195693849105, 1.218573192208790124,
1.207669893426761121, 1.196787346088403092, 1.185924593404202199, 1.175080674310911677,
1.164254622705678921, 1.153445466655774743, 1.142652227581672841, 1.131873919411078511,
1.121109547701330200, 1.110358108727411031, 1.099618588532597308, 1.088889961938546813,
1.078171191511372307, 1.067461226479967662, 1.056759001602551429, 1.046063435977044209,
1.035373431790528542, 1.024687873002617211, 1.014005623957096480, 1.003325527915696735,
0.992646405507275897, 0.981967053085062602, 0.971286240983903260, 0.960602711668666509,
0.949915177764075969, 0.939222319955262286, 0.928522784747210395, 0.917815182070044311,
0.907098082715690257, 0.896370015589889935, 0.885629464761751528, 0.874874866291025066,
0.864104604811004484, 0.853317009842373353, 0.842510351810368485, 0.831682837734273206,
0.820832606554411814, 0.809957724057418282, 0.799056177355487174, 0.788125868869492430,
0.777164609759129710, 0.766170112735434672, 0.755139984181982249, 0.744071715500508102,
0.732962673584365398, 0.721810090308756203, 0.710611050909655040, 0.699362481103231959,
0.688061132773747808, 0.676703568029522584, 0.665286141392677943, 0.653804979847664947,
0.642255960424536365, 0.630634684933490286, 0.618936451394876075, 0.607156221620300030,
0.595288584291502887, 0.583327712748769489, 0.571267316532588332, 0.559100585511540626,
0.546820125163310577, 0.534417881237165604, 0.521885051592135052, 0.509211982443654398,
0.496388045518671162, 0.483401491653461857, 0.470239275082169006, 0.456886840931420235,
0.443327866073552401, 0.429543940225410703, 0.415514169600356364, 0.401214678896277765,
0.386617977941119573, 0.371692145329917234, 0.356399760258393816, 0.340696481064849122,
0.324529117016909452, 0.307832954674932158, 0.290527955491230394, 0.272513185478464703,
0.253658363385912022, 0.233790483059674731, 0.212671510630966620, 0.189958689622431842,
0.165127622564187282, 0.137304980940012589, 0.104838507565818778, 0.063852163815001570,
0.000000000000000000];
#[rustfmt::skip]
pub static ZIG_EXP_F: [f64; 257] =
[0.000167066692307963, 0.000454134353841497, 0.000967269282327174, 0.001536299780301573,
0.002145967743718907, 0.002788798793574076, 0.003460264777836904, 0.004157295120833797,
0.004877655983542396, 0.005619642207205489, 0.006381905937319183, 0.007163353183634991,
0.007963077438017043, 0.008780314985808977, 0.009614413642502212, 0.010464810181029981,
0.011331013597834600, 0.012212592426255378, 0.013109164931254991, 0.014020391403181943,
0.014945968011691148, 0.015885621839973156, 0.016839106826039941, 0.017806200410911355,
0.018786700744696024, 0.019780424338009740, 0.020787204072578114, 0.021806887504283581,
0.022839335406385240, 0.023884420511558174, 0.024942026419731787, 0.026012046645134221,
0.027094383780955803, 0.028188948763978646, 0.029295660224637411, 0.030414443910466622,
0.031545232172893622, 0.032687963508959555, 0.033842582150874358, 0.035009037697397431,
0.036187284781931443, 0.037377282772959382, 0.038578995503074871, 0.039792391023374139,
0.041017441380414840, 0.042254122413316254, 0.043502413568888197, 0.044762297732943289,
0.046033761076175184, 0.047316792913181561, 0.048611385573379504, 0.049917534282706379,
0.051235237055126281, 0.052564494593071685, 0.053905310196046080, 0.055257689676697030,
0.056621641283742870, 0.057997175631200659, 0.059384305633420280, 0.060783046445479660,
0.062193415408541036, 0.063615431999807376, 0.065049117786753805, 0.066494496385339816,
0.067951593421936643, 0.069420436498728783, 0.070901055162371843, 0.072393480875708752,
0.073897746992364746, 0.075413888734058410, 0.076941943170480517, 0.078481949201606435,
0.080033947542319905, 0.081597980709237419, 0.083174093009632397, 0.084762330532368146,
0.086362741140756927, 0.087975374467270231, 0.089600281910032886, 0.091237516631040197,
0.092887133556043569, 0.094549189376055873, 0.096223742550432825, 0.097910853311492213,
0.099610583670637132, 0.101322997425953631, 0.103048160171257702, 0.104786139306570145,
0.106537004050001632, 0.108300825451033755, 0.110077676405185357, 0.111867631670056283,
0.113670767882744286, 0.115487163578633506, 0.117316899211555525, 0.119160057175327641,
0.121016721826674792, 0.122886979509545108, 0.124770918580830933, 0.126668629437510671,
0.128580204545228199, 0.130505738468330773, 0.132445327901387494, 0.134399071702213602,
0.136367070926428829, 0.138349428863580176, 0.140346251074862399, 0.142357645432472146,
0.144383722160634720, 0.146424593878344889, 0.148480375643866735, 0.150551185001039839,
0.152637142027442801, 0.154738369384468027, 0.156854992369365148, 0.158987138969314129,
0.161134939917591952, 0.163298528751901734, 0.165478041874935922, 0.167673618617250081,
0.169885401302527550, 0.172113535315319977, 0.174358169171353411, 0.176619454590494829,
0.178897546572478278, 0.181192603475496261, 0.183504787097767436, 0.185834262762197083,
0.188181199404254262, 0.190545769663195363, 0.192928149976771296, 0.195328520679563189,
0.197747066105098818, 0.200183974691911210, 0.202639439093708962, 0.205113656293837654,
0.207606827724221982, 0.210119159388988230, 0.212650861992978224, 0.215202151075378628,
0.217773247148700472, 0.220364375843359439, 0.222975768058120111, 0.225607660116683956,
0.228260293930716618, 0.230933917169627356, 0.233628783437433291, 0.236345152457059560,
0.239083290262449094, 0.241843469398877131, 0.244625969131892024, 0.247431075665327543,
0.250259082368862240, 0.253110290015629402, 0.255985007030415324, 0.258883549749016173,
0.261806242689362922, 0.264753418835062149, 0.267725419932044739, 0.270722596799059967,
0.273745309652802915, 0.276793928448517301, 0.279868833236972869, 0.282970414538780746,
0.286099073737076826, 0.289255223489677693, 0.292439288161892630, 0.295651704281261252,
0.298892921015581847, 0.302163400675693528, 0.305463619244590256, 0.308794066934560185,
0.312155248774179606, 0.315547685227128949, 0.318971912844957239, 0.322428484956089223,
0.325917972393556354, 0.329440964264136438, 0.332998068761809096, 0.336589914028677717,
0.340217149066780189, 0.343880444704502575, 0.347580494621637148, 0.351318016437483449,
0.355093752866787626, 0.358908472948750001, 0.362762973354817997, 0.366658079781514379,
0.370594648435146223, 0.374573567615902381, 0.378595759409581067, 0.382662181496010056,
0.386773829084137932, 0.390931736984797384, 0.395136981833290435, 0.399390684475231350,
0.403694012530530555, 0.408048183152032673, 0.412454465997161457, 0.416914186433003209,
0.421428728997616908, 0.425999541143034677, 0.430628137288459167, 0.435316103215636907,
0.440065100842354173, 0.444876873414548846, 0.449753251162755330, 0.454696157474615836,
0.459707615642138023, 0.464789756250426511, 0.469944825283960310, 0.475175193037377708,
0.480483363930454543, 0.485871987341885248, 0.491343869594032867, 0.496901987241549881,
0.502549501841348056, 0.508289776410643213, 0.514126393814748894, 0.520063177368233931,
0.526104213983620062, 0.532253880263043655, 0.538516872002862246, 0.544898237672440056,
0.551403416540641733, 0.558038282262587892, 0.564809192912400615, 0.571723048664826150,
0.578787358602845359, 0.586010318477268366, 0.593400901691733762, 0.600968966365232560,
0.608725382079622346, 0.616682180915207878, 0.624852738703666200, 0.633251994214366398,
0.641896716427266423, 0.650805833414571433, 0.660000841079000145, 0.669506316731925177,
0.679350572264765806, 0.689566496117078431, 0.700192655082788606, 0.711274760805076456,
0.722867659593572465, 0.735038092431424039, 0.747868621985195658, 0.761463388849896838,
0.775956852040116218, 0.791527636972496285, 0.808421651523009044, 0.826993296643051101,
0.847785500623990496, 0.871704332381204705, 0.900469929925747703, 0.938143680862176477,
1.000000000000000000];

View file

@ -37,7 +37,7 @@
//!
//! # The Book
//!
//! For the user guide and futher documentation, please read
//! For the user guide and further documentation, please read
//! [The Rust Rand Book](https://rust-random.github.io/book).
#![doc(
@ -48,15 +48,16 @@
#![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 = "simd_support", feature = "nightly"), feature(stdsimd))]
#![no_std]
#![cfg_attr(feature = "simd_support", feature(stdsimd))]
#![cfg_attr(doc_cfg, feature(doc_cfg))]
#![allow(
clippy::excessive_precision,
clippy::unreadable_literal,
clippy::float_cmp
clippy::float_cmp,
clippy::neg_cmp_op_on_partial_ord,
)]
#[cfg(all(feature = "alloc", not(feature = "std")))] extern crate alloc;
#[cfg(feature = "std")] extern crate std;
#[cfg(feature = "alloc")] extern crate alloc;
#[allow(unused)]
macro_rules! trace { ($($x:tt)*) => (
@ -92,418 +93,20 @@ macro_rules! error { ($($x:tt)*) => (
// Re-exports from rand_core
pub use rand_core::{CryptoRng, Error, RngCore, SeedableRng};
// Public exports
#[cfg(feature = "std")] pub use crate::rngs::thread::thread_rng;
// Public modules
pub mod distributions;
pub mod prelude;
mod rng;
pub mod rngs;
pub mod seq;
// Public exports
#[cfg(all(feature = "std", feature = "std_rng"))]
pub use crate::rngs::thread::thread_rng;
pub use rng::{Fill, Rng};
use crate::distributions::uniform::{SampleBorrow, SampleUniform, UniformSampler};
#[cfg(all(feature = "std", feature = "std_rng"))]
use crate::distributions::{Distribution, Standard};
use core::num::Wrapping;
use core::{mem, slice};
/// An automatically-implemented extension trait on [`RngCore`] providing high-level
/// generic methods for sampling values and other convenience methods.
///
/// This is the primary trait to use when generating random values.
///
/// # Generic usage
///
/// The basic pattern is `fn foo<R: Rng + ?Sized>(rng: &mut R)`. Some
/// things are worth noting here:
///
/// - 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)`.
///
/// 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.
///
/// 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());
/// ```
pub trait Rng: RngCore {
/// Return a random value supporting the [`Standard`] distribution.
///
/// # Example
///
/// ```
/// use rand::{thread_rng, Rng};
///
/// let mut rng = thread_rng();
/// let x: u32 = rng.gen();
/// println!("{}", x);
/// println!("{:?}", rng.gen::<(f64, bool)>());
/// ```
///
/// # Arrays and tuples
///
/// The `rng.gen()` method is able to generate arrays (up to 32 elements)
/// and tuples (up to 12 elements), so long as all element types can be
/// generated.
///
/// For arrays of integers, especially for those with small element types
/// (< 64 bit), it will likely be faster to instead use [`Rng::fill`].
///
/// ```
/// use rand::{thread_rng, Rng};
///
/// let mut rng = thread_rng();
/// let tuple: (u8, i32, char) = rng.gen(); // arbitrary tuple support
///
/// let arr1: [f32; 32] = rng.gen(); // array construction
/// let mut arr2 = [0u8; 128];
/// rng.fill(&mut arr2); // array fill
/// ```
///
/// [`Standard`]: distributions::Standard
#[inline]
fn gen<T>(&mut self) -> T
where Standard: Distribution<T> {
Standard.sample(self)
}
/// Generate a random value in the range [`low`, `high`), i.e. inclusive of
/// `low` and exclusive of `high`.
///
/// 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.
///
/// # Panics
///
/// Panics if `low >= high`.
///
/// # Example
///
/// ```
/// use rand::{thread_rng, Rng};
///
/// 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);
/// ```
///
/// [`Uniform`]: distributions::uniform::Uniform
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)
}
/// Sample a new value, using the given distribution.
///
/// ### Example
///
/// ```
/// use rand::{thread_rng, Rng};
/// use rand::distributions::Uniform;
///
/// let mut rng = thread_rng();
/// 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));
/// ```
fn sample<T, D: Distribution<T>>(&mut self, distr: D) -> T {
distr.sample(self)
}
/// Create an iterator that generates values using the given distribution.
///
/// Note that this function takes its arguments by value. This works since
/// `(&mut R): Rng where R: Rng` and
/// `(&D): Distribution where D: Distribution`,
/// however borrowing is not automatic hence `rng.sample_iter(...)` may
/// need to be replaced with `(&mut rng).sample_iter(...)`.
///
/// # Example
///
/// ```
/// use rand::{thread_rng, Rng};
/// use rand::distributions::{Alphanumeric, Uniform, Standard};
///
/// let rng = thread_rng();
///
/// // Vec of 16 x f32:
/// let v: Vec<f32> = rng.sample_iter(Standard).take(16).collect();
///
/// // String:
/// let s: String = rng.sample_iter(Alphanumeric).take(7).collect();
///
/// // Combined values
/// println!("{:?}", rng.sample_iter(Standard).take(5)
/// .collect::<Vec<(f64, bool)>>());
///
/// // 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 sample_iter<T, D>(self, distr: D) -> distributions::DistIter<D, Self, T>
where
D: Distribution<T>,
Self: Sized,
{
distr.sample_iter(self)
}
/// 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
///
/// ```
/// use rand::{thread_rng, Rng};
///
/// let mut arr = [0i8; 20];
/// thread_rng().fill(&mut arr[..]);
/// ```
///
/// [`fill_bytes`]: RngCore::fill_bytes
/// [`try_fill`]: Rng::try_fill
fn fill<T: AsByteSliceMut + ?Sized>(&mut self, dest: &mut T) {
self.fill_bytes(dest.as_byte_slice_mut());
dest.to_le();
}
/// 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 is identical to [`fill`] except that it uses [`try_fill_bytes`]
/// internally and forwards RNG errors.
///
/// # Example
///
/// ```
/// # use rand::Error;
/// use rand::{thread_rng, Rng};
///
/// # fn try_inner() -> Result<(), Error> {
/// let mut arr = [0u64; 4];
/// thread_rng().try_fill(&mut arr[..])?;
/// # Ok(())
/// # }
///
/// # try_inner().unwrap()
/// ```
///
/// [`try_fill_bytes`]: RngCore::try_fill_bytes
/// [`fill`]: Rng::fill
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 bool with a probability `p` of being true.
///
/// See also the [`Bernoulli`] distribution, which may be faster if
/// sampling from the same probability repeatedly.
///
/// # Example
///
/// ```
/// use rand::{thread_rng, Rng};
///
/// let mut rng = thread_rng();
/// println!("{}", rng.gen_bool(1.0 / 3.0));
/// ```
///
/// # Panics
///
/// If `p < 0` or `p > 1`.
///
/// [`Bernoulli`]: distributions::bernoulli::Bernoulli
#[inline]
fn gen_bool(&mut self, p: f64) -> bool {
let d = distributions::Bernoulli::new(p).unwrap();
self.sample(d)
}
/// 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.
///
/// # Panics
///
/// If `denominator == 0` or `numerator > denominator`.
///
/// # Example
///
/// ```
/// use rand::{thread_rng, Rng};
///
/// let mut rng = thread_rng();
/// println!("{}", rng.gen_ratio(2, 3));
/// ```
///
/// [`Bernoulli`]: distributions::bernoulli::Bernoulli
#[inline]
fn gen_ratio(&mut self, numerator: u32, denominator: u32) -> bool {
let d = distributions::Bernoulli::from_ratio(numerator, denominator).unwrap();
self.sample(d)
}
}
impl<R: RngCore + ?Sized> Rng for R {}
/// Trait for casting types to byte slices
///
/// This is used by the [`Rng::fill`] and [`Rng::try_fill`] methods.
pub trait AsByteSliceMut {
/// Return a mutable reference to self as a byte slice
fn as_byte_slice_mut(&mut self) -> &mut [u8];
/// Call `to_le` on each element (i.e. byte-swap on Big Endian platforms).
fn to_le(&mut self);
}
impl AsByteSliceMut for [u8] {
fn as_byte_slice_mut(&mut self) -> &mut [u8] {
self
}
fn to_le(&mut self) {}
}
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(self.as_mut_ptr()
as *mut u8,
self.len() * mem::size_of::<$t>()
)
}
}
}
fn to_le(&mut self) {
for x in self {
*x = x.to_le();
}
}
}
impl AsByteSliceMut for [Wrapping<$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(self.as_mut_ptr()
as *mut u8,
self.len() * mem::size_of::<$t>()
)
}
}
}
fn to_le(&mut self) {
for x in self {
*x = Wrapping(x.0.to_le());
}
}
}
};
($t:ty, $($tt:ty,)*) => {
impl_as_byte_slice!($t);
// TODO: this could replace above impl once Rust #32463 is fixed
// impl_as_byte_slice!(Wrapping<$t>);
impl_as_byte_slice!($($tt,)*);
}
}
impl_as_byte_slice!(u16, u32, u64, usize,);
#[cfg(not(target_os = "emscripten"))]
impl_as_byte_slice!(u128);
impl_as_byte_slice!(i8, i16, i32, i64, isize,);
#[cfg(not(target_os = "emscripten"))]
impl_as_byte_slice!(i128);
macro_rules! impl_as_byte_slice_arrays {
($n:expr,) => {};
($n:expr, $N:ident) => {
impl<T> AsByteSliceMut for [T; $n] where [T]: AsByteSliceMut {
fn as_byte_slice_mut(&mut self) -> &mut [u8] {
self[..].as_byte_slice_mut()
}
fn to_le(&mut self) {
self[..].to_le()
}
}
};
($n:expr, $N:ident, $($NN:ident,)*) => {
impl_as_byte_slice_arrays!($n, $N);
impl_as_byte_slice_arrays!($n - 1, $($NN,)*);
};
(!div $n:expr,) => {};
(!div $n:expr, $N:ident, $($NN:ident,)*) => {
impl_as_byte_slice_arrays!($n, $N);
impl_as_byte_slice_arrays!(!div $n / 2, $($NN,)*);
};
}
#[rustfmt::skip]
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,);
/// Generates a random value using the thread-local random number generator.
///
@ -511,6 +114,33 @@ impl_as_byte_slice_arrays!(!div 4096, N,N,N,N,N,N,N,);
/// documentation of the entropy source and [`Standard`] for documentation of
/// distributions and type-specific generation.
///
/// # Provided implementations
///
/// The following types have provided implementations that
/// 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.
///
/// Also supported is the generation of the following
/// compound types where all component types are supported:
///
/// * Tuples (up to 12 elements): each element is generated sequentially.
/// * Arrays (up to 32 elements): each element is generated sequentially;
/// see also [`Rng::fill`] which supports arbitrary array length for integer
/// types and tends to be faster for `u32` and smaller types.
/// * `Option<T>` first generates a `bool`, and if true generates and returns
/// `Some(value)` where `value: T`, otherwise returning `None`.
///
/// # Examples
///
/// ```
@ -547,7 +177,8 @@ impl_as_byte_slice_arrays!(!div 4096, N,N,N,N,N,N,N,);
/// ```
///
/// [`Standard`]: distributions::Standard
#[cfg(feature = "std")]
#[cfg(all(feature = "std", feature = "std_rng"))]
#[cfg_attr(doc_cfg, doc(cfg(all(feature = "std", feature = "std_rng"))))]
#[inline]
pub fn random<T>() -> T
where Standard: Distribution<T> {
@ -557,8 +188,6 @@ where Standard: Distribution<T> {
#[cfg(test)]
mod test {
use super::*;
use crate::rngs::mock::StepRng;
#[cfg(all(not(feature = "std"), feature = "alloc"))] use alloc::boxed::Box;
/// Construct a deterministic RNG with the given seed
pub fn rng(seed: u64) -> impl RngCore {
@ -569,131 +198,12 @@ mod test {
}
#[test]
fn test_fill_bytes_default() {
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 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() {
if byte == 0 {
panic!("byte {} of {} is zero", i, n)
}
}
}
}
#[test]
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);
// Check equivalence using wrapped arrays
let mut warray = [Wrapping(0u32); 2];
rng.fill(&mut warray[..]);
assert_eq!(array[0], warray[0].0);
assert_eq!(array[1], warray[1].0);
}
#[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(-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 = rng(102);
r.gen_range(5, -2);
}
#[test]
#[should_panic]
fn test_gen_range_panic_usize() {
let mut r = rng(103);
r.gen_range(5, 2);
}
#[test]
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_rng_trait_object() {
use crate::distributions::{Distribution, Standard};
let mut rng = rng(109);
let mut r = &mut rng as &mut dyn 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 = "alloc")]
fn test_rng_boxed_trait() {
use crate::distributions::{Distribution, Standard};
let rng = rng(110);
let mut r = Box::new(rng) as Box<dyn 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")]
#[cfg(all(feature = "std", feature = "std_rng"))]
fn test_random() {
// not sure how to test this aside from just getting some values
let _n: usize = random();
let _f: f32 = random();
let _o: Option<Option<i8>> = random();
#[allow(clippy::type_complexity)]
let _many: (
(),
(usize, isize, Option<(u32, (bool,))>),
@ -701,23 +211,4 @@ mod test {
(f32, (f64, (f64,))),
) = random();
}
#[test]
#[cfg_attr(miri, ignore)] // Miri is too slow
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);
}
}

View file

@ -22,12 +22,13 @@
#[cfg(feature = "small_rng")]
#[doc(no_inline)]
pub use crate::rngs::SmallRng;
#[cfg(feature = "std_rng")]
#[doc(no_inline)] pub use crate::rngs::StdRng;
#[doc(no_inline)]
#[cfg(feature = "std")]
#[cfg(all(feature = "std", feature = "std_rng"))]
pub use crate::rngs::ThreadRng;
#[doc(no_inline)] pub use crate::seq::{IteratorRandom, SliceRandom};
#[doc(no_inline)]
#[cfg(feature = "std")]
#[cfg(all(feature = "std", feature = "std_rng"))]
pub use crate::{random, thread_rng};
#[doc(no_inline)] pub use crate::{CryptoRng, Rng, RngCore, SeedableRng};

600
third_party/rust/rand/src/rng.rs vendored Normal file
View file

@ -0,0 +1,600 @@
// 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
// 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.
//! [`Rng`] trait
use rand_core::{Error, RngCore};
use crate::distributions::uniform::{SampleRange, SampleUniform};
use crate::distributions::{self, Distribution, Standard};
use core::num::Wrapping;
use core::{mem, slice};
/// An automatically-implemented extension trait on [`RngCore`] providing high-level
/// generic methods for sampling values and other convenience methods.
///
/// This is the primary trait to use when generating random values.
///
/// # Generic usage
///
/// The basic pattern is `fn foo<R: Rng + ?Sized>(rng: &mut R)`. Some
/// things are worth noting here:
///
/// - 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 dyn RngCore`. Without
/// this it would be necessary to write `foo(&mut r)`.
///
/// 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.
///
/// 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());
/// ```
pub trait Rng: RngCore {
/// Return a random value supporting the [`Standard`] distribution.
///
/// # Example
///
/// ```
/// use rand::{thread_rng, Rng};
///
/// let mut rng = thread_rng();
/// let x: u32 = rng.gen();
/// println!("{}", x);
/// println!("{:?}", rng.gen::<(f64, bool)>());
/// ```
///
/// # Arrays and tuples
///
/// The `rng.gen()` method is able to generate arrays (up to 32 elements)
/// and tuples (up to 12 elements), so long as all element types can be
/// generated.
/// When using `rustc` ≥ 1.51, enable the `min_const_gen` feature to support
/// arrays larger than 32 elements.
///
/// For arrays of integers, especially for those with small element types
/// (< 64 bit), it will likely be faster to instead use [`Rng::fill`].
///
/// ```
/// use rand::{thread_rng, Rng};
///
/// let mut rng = thread_rng();
/// let tuple: (u8, i32, char) = rng.gen(); // arbitrary tuple support
///
/// let arr1: [f32; 32] = rng.gen(); // array construction
/// let mut arr2 = [0u8; 128];
/// rng.fill(&mut arr2); // array fill
/// ```
///
/// [`Standard`]: distributions::Standard
#[inline]
fn gen<T>(&mut self) -> T
where Standard: Distribution<T> {
Standard.sample(self)
}
/// Generate a random value in the given range.
///
/// 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.
///
/// Only `gen_range(low..high)` and `gen_range(low..=high)` are supported.
///
/// # Panics
///
/// Panics if the range is empty.
///
/// # Example
///
/// ```
/// use rand::{thread_rng, Rng};
///
/// let mut rng = thread_rng();
///
/// // Exclusive range
/// let n: u32 = rng.gen_range(0..10);
/// println!("{}", n);
/// let m: f64 = rng.gen_range(-40.0..1.3e5);
/// println!("{}", m);
///
/// // Inclusive range
/// let n: u32 = rng.gen_range(0..=10);
/// println!("{}", n);
/// ```
///
/// [`Uniform`]: distributions::uniform::Uniform
fn gen_range<T, R>(&mut self, range: R) -> T
where
T: SampleUniform,
R: SampleRange<T>
{
assert!(!range.is_empty(), "cannot sample empty range");
range.sample_single(self)
}
/// Sample a new value, using the given distribution.
///
/// ### Example
///
/// ```
/// use rand::{thread_rng, Rng};
/// use rand::distributions::Uniform;
///
/// let mut rng = thread_rng();
/// 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));
/// ```
fn sample<T, D: Distribution<T>>(&mut self, distr: D) -> T {
distr.sample(self)
}
/// Create an iterator that generates values using the given distribution.
///
/// Note that this function takes its arguments by value. This works since
/// `(&mut R): Rng where R: Rng` and
/// `(&D): Distribution where D: Distribution`,
/// however borrowing is not automatic hence `rng.sample_iter(...)` may
/// need to be replaced with `(&mut rng).sample_iter(...)`.
///
/// # Example
///
/// ```
/// use rand::{thread_rng, Rng};
/// use rand::distributions::{Alphanumeric, Uniform, Standard};
///
/// let mut rng = thread_rng();
///
/// // Vec of 16 x f32:
/// let v: Vec<f32> = (&mut rng).sample_iter(Standard).take(16).collect();
///
/// // String:
/// let s: String = (&mut rng).sample_iter(Alphanumeric)
/// .take(7)
/// .map(char::from)
/// .collect();
///
/// // Combined values
/// println!("{:?}", (&mut rng).sample_iter(Standard).take(5)
/// .collect::<Vec<(f64, bool)>>());
///
/// // Dice-rolling:
/// let die_range = Uniform::new_inclusive(1, 6);
/// let mut roll_die = (&mut rng).sample_iter(die_range);
/// while roll_die.next().unwrap() != 6 {
/// println!("Not a 6; rolling again!");
/// }
/// ```
fn sample_iter<T, D>(self, distr: D) -> distributions::DistIter<D, Self, T>
where
D: Distribution<T>,
Self: Sized,
{
distr.sample_iter(self)
}
/// Fill any type implementing [`Fill`] with random data
///
/// The distribution is expected to be uniform with portable results, but
/// this cannot be guaranteed for third-party implementations.
///
/// This is identical to [`try_fill`] except that it panics on error.
///
/// # Example
///
/// ```
/// use rand::{thread_rng, Rng};
///
/// let mut arr = [0i8; 20];
/// thread_rng().fill(&mut arr[..]);
/// ```
///
/// [`fill_bytes`]: RngCore::fill_bytes
/// [`try_fill`]: Rng::try_fill
fn fill<T: Fill + ?Sized>(&mut self, dest: &mut T) {
dest.try_fill(self).unwrap_or_else(|_| panic!("Rng::fill failed"))
}
/// Fill any type implementing [`Fill`] with random data
///
/// The distribution is expected to be uniform with portable results, but
/// this cannot be guaranteed for third-party implementations.
///
/// This is identical to [`fill`] except that it forwards errors.
///
/// # Example
///
/// ```
/// # use rand::Error;
/// use rand::{thread_rng, Rng};
///
/// # fn try_inner() -> Result<(), Error> {
/// let mut arr = [0u64; 4];
/// thread_rng().try_fill(&mut arr[..])?;
/// # Ok(())
/// # }
///
/// # try_inner().unwrap()
/// ```
///
/// [`try_fill_bytes`]: RngCore::try_fill_bytes
/// [`fill`]: Rng::fill
fn try_fill<T: Fill + ?Sized>(&mut self, dest: &mut T) -> Result<(), Error> {
dest.try_fill(self)
}
/// Return a bool with a probability `p` of being true.
///
/// See also the [`Bernoulli`] distribution, which may be faster if
/// sampling from the same probability repeatedly.
///
/// # Example
///
/// ```
/// use rand::{thread_rng, Rng};
///
/// let mut rng = thread_rng();
/// println!("{}", rng.gen_bool(1.0 / 3.0));
/// ```
///
/// # Panics
///
/// If `p < 0` or `p > 1`.
///
/// [`Bernoulli`]: distributions::Bernoulli
#[inline]
fn gen_bool(&mut self, p: f64) -> bool {
let d = distributions::Bernoulli::new(p).unwrap();
self.sample(d)
}
/// 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.
///
/// # Panics
///
/// If `denominator == 0` or `numerator > denominator`.
///
/// # Example
///
/// ```
/// use rand::{thread_rng, Rng};
///
/// let mut rng = thread_rng();
/// println!("{}", rng.gen_ratio(2, 3));
/// ```
///
/// [`Bernoulli`]: distributions::Bernoulli
#[inline]
fn gen_ratio(&mut self, numerator: u32, denominator: u32) -> bool {
let d = distributions::Bernoulli::from_ratio(numerator, denominator).unwrap();
self.sample(d)
}
}
impl<R: RngCore + ?Sized> Rng for R {}
/// Types which may be filled with random data
///
/// This trait allows arrays to be efficiently filled with random data.
///
/// Implementations are expected to be portable across machines unless
/// clearly documented otherwise (see the
/// [Chapter on Portability](https://rust-random.github.io/book/portability.html)).
pub trait Fill {
/// Fill self with random data
fn try_fill<R: Rng + ?Sized>(&mut self, rng: &mut R) -> Result<(), Error>;
}
macro_rules! impl_fill_each {
() => {};
($t:ty) => {
impl Fill for [$t] {
fn try_fill<R: Rng + ?Sized>(&mut self, rng: &mut R) -> Result<(), Error> {
for elt in self.iter_mut() {
*elt = rng.gen();
}
Ok(())
}
}
};
($t:ty, $($tt:ty,)*) => {
impl_fill_each!($t);
impl_fill_each!($($tt,)*);
};
}
impl_fill_each!(bool, char, f32, f64,);
impl Fill for [u8] {
fn try_fill<R: Rng + ?Sized>(&mut self, rng: &mut R) -> Result<(), Error> {
rng.try_fill_bytes(self)
}
}
macro_rules! impl_fill {
() => {};
($t:ty) => {
impl Fill for [$t] {
#[inline(never)] // in micro benchmarks, this improves performance
fn try_fill<R: Rng + ?Sized>(&mut self, rng: &mut R) -> Result<(), Error> {
if self.len() > 0 {
rng.try_fill_bytes(unsafe {
slice::from_raw_parts_mut(self.as_mut_ptr()
as *mut u8,
self.len() * mem::size_of::<$t>()
)
})?;
for x in self {
*x = x.to_le();
}
}
Ok(())
}
}
impl Fill for [Wrapping<$t>] {
#[inline(never)]
fn try_fill<R: Rng + ?Sized>(&mut self, rng: &mut R) -> Result<(), Error> {
if self.len() > 0 {
rng.try_fill_bytes(unsafe {
slice::from_raw_parts_mut(self.as_mut_ptr()
as *mut u8,
self.len() * mem::size_of::<$t>()
)
})?;
for x in self {
*x = Wrapping(x.0.to_le());
}
}
Ok(())
}
}
};
($t:ty, $($tt:ty,)*) => {
impl_fill!($t);
// TODO: this could replace above impl once Rust #32463 is fixed
// impl_fill!(Wrapping<$t>);
impl_fill!($($tt,)*);
}
}
impl_fill!(u16, u32, u64, usize, u128,);
impl_fill!(i8, i16, i32, i64, isize, i128,);
#[cfg_attr(doc_cfg, doc(cfg(feature = "min_const_gen")))]
#[cfg(feature = "min_const_gen")]
impl<T, const N: usize> Fill for [T; N]
where [T]: Fill
{
fn try_fill<R: Rng + ?Sized>(&mut self, rng: &mut R) -> Result<(), Error> {
self[..].try_fill(rng)
}
}
#[cfg(not(feature = "min_const_gen"))]
macro_rules! impl_fill_arrays {
($n:expr,) => {};
($n:expr, $N:ident) => {
impl<T> Fill for [T; $n] where [T]: Fill {
fn try_fill<R: Rng + ?Sized>(&mut self, rng: &mut R) -> Result<(), Error> {
self[..].try_fill(rng)
}
}
};
($n:expr, $N:ident, $($NN:ident,)*) => {
impl_fill_arrays!($n, $N);
impl_fill_arrays!($n - 1, $($NN,)*);
};
(!div $n:expr,) => {};
(!div $n:expr, $N:ident, $($NN:ident,)*) => {
impl_fill_arrays!($n, $N);
impl_fill_arrays!(!div $n / 2, $($NN,)*);
};
}
#[cfg(not(feature = "min_const_gen"))]
#[rustfmt::skip]
impl_fill_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,);
#[cfg(not(feature = "min_const_gen"))]
impl_fill_arrays!(!div 4096, N,N,N,N,N,N,N,);
#[cfg(test)]
mod test {
use super::*;
use crate::test::rng;
use crate::rngs::mock::StepRng;
#[cfg(feature = "alloc")] use alloc::boxed::Box;
#[test]
fn test_fill_bytes_default() {
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 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() {
if byte == 0 {
panic!("byte {} of {} is zero", i, n)
}
}
}
}
#[test]
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);
// Check equivalence using wrapped arrays
let mut warray = [Wrapping(0u32); 2];
rng.fill(&mut warray[..]);
assert_eq!(array[0], warray[0].0);
assert_eq!(array[1], warray[1].0);
// Check equivalence for generated floats
let mut array = [0f32; 2];
rng.fill(&mut array);
let gen: [f32; 2] = rng.gen();
assert_eq!(array, gen);
}
#[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_int() {
let mut r = rng(101);
for _ in 0..1000 {
let a = r.gen_range(-4711..17);
assert!((-4711..17).contains(&a));
let a: i8 = r.gen_range(-3..42);
assert!((-3..42).contains(&a));
let a: u16 = r.gen_range(10..99);
assert!((10..99).contains(&a));
let a: i32 = r.gen_range(-100..2000);
assert!((-100..2000).contains(&a));
let a: u32 = r.gen_range(12..=24);
assert!((12..=24).contains(&a));
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]
fn test_gen_range_float() {
let mut r = rng(101);
for _ in 0..1000 {
let a = r.gen_range(-4.5..1.7);
assert!((-4.5..1.7).contains(&a));
let a = r.gen_range(-1.1..=-0.3);
assert!((-1.1..=-0.3).contains(&a));
assert_eq!(r.gen_range(0.0f32..=0.0), 0.);
assert_eq!(r.gen_range(-11.0..=-11.0), -11.);
assert_eq!(r.gen_range(3_000_000.0..=3_000_000.0), 3_000_000.);
}
}
#[test]
#[should_panic]
fn test_gen_range_panic_int() {
#![allow(clippy::reversed_empty_ranges)]
let mut r = rng(102);
r.gen_range(5..-2);
}
#[test]
#[should_panic]
fn test_gen_range_panic_usize() {
#![allow(clippy::reversed_empty_ranges)]
let mut r = rng(103);
r.gen_range(5..2);
}
#[test]
fn test_gen_bool() {
#![allow(clippy::bool_assert_comparison)]
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_rng_trait_object() {
use crate::distributions::{Distribution, Standard};
let mut rng = rng(109);
let mut r = &mut rng as &mut dyn 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 = "alloc")]
fn test_rng_boxed_trait() {
use crate::distributions::{Distribution, Standard};
let rng = rng(110);
let mut r = Box::new(rng) as Box<dyn RngCore>;
r.next_u32();
r.gen::<i32>();
assert_eq!(r.gen_range(0..1), 0);
let _c: u8 = Standard.sample(&mut r);
}
#[test]
#[cfg_attr(miri, ignore)] // Miri is too slow
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);
}
}

View file

@ -8,8 +8,9 @@
//! Wrappers / adapters forming RNGs
#[cfg(feature = "std")] mod read;
mod read;
mod reseeding;
#[cfg(feature = "std")] pub use self::read::{ReadError, ReadRng};
#[allow(deprecated)]
pub use self::read::{ReadError, ReadRng};
pub use self::reseeding::ReseedingRng;

View file

@ -9,6 +9,8 @@
//! A wrapper around any Read to treat it as an RNG.
#![allow(deprecated)]
use std::fmt;
use std::io::Read;
@ -30,20 +32,10 @@ use rand_core::{impls, Error, RngCore};
/// 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`]: crate::rngs::OsRng
/// [`try_fill_bytes`]: RngCore::try_fill_bytes
#[derive(Debug)]
#[deprecated(since="0.8.4", note="removal due to lack of usage")]
pub struct ReadRng<R> {
reader: R,
}
@ -86,6 +78,7 @@ impl<R: Read> RngCore for ReadRng<R> {
/// `ReadRng` error type
#[derive(Debug)]
#[deprecated(since="0.8.4")]
pub struct ReadError(std::io::Error);
impl fmt::Display for ReadError {
@ -103,6 +96,8 @@ impl std::error::Error for ReadError {
#[cfg(test)]
mod test {
use std::println;
use super::ReadRng;
use crate::RngCore;
@ -110,24 +105,24 @@ mod test {
fn test_reader_rng_u64() {
// transmute from the target to avoid endianness concerns.
#[rustfmt::skip]
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 v = [0u8, 0, 0, 0, 0, 0, 0, 1,
0, 4, 0, 0, 3, 0, 0, 2,
5, 0, 0, 0, 0, 0, 0, 0];
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());
assert_eq!(rng.next_u64(), 1 << 56);
assert_eq!(rng.next_u64(), (2 << 56) + (3 << 32) + (4 << 8));
assert_eq!(rng.next_u64(), 5);
}
#[test]
fn test_reader_rng_u32() {
let v = vec![0u8, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3];
let v = [0u8, 0, 0, 1, 0, 0, 2, 0, 3, 0, 0, 0];
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());
assert_eq!(rng.next_u32(), 1 << 24);
assert_eq!(rng.next_u32(), 2 << 16);
assert_eq!(rng.next_u32(), 3);
}
#[test]

View file

@ -22,10 +22,10 @@ use rand_core::{CryptoRng, Error, RngCore, SeedableRng};
///
/// - 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 ChaCha and Hc128 this is a maximum of
/// 15 `u32` values before reseeding.
/// - When a process is forked on UNIX, the RNGs in both the parent and child
/// processes will be reseeded just before the next call to
/// [`BlockRngCore::generate`], i.e. "soon". For ChaCha and Hc128 this is a
/// maximum of fifteen `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?
@ -43,6 +43,12 @@ use rand_core::{CryptoRng, Error, RngCore, SeedableRng};
/// Use [`ReseedingRng::new`] with a `threshold` of `0` to disable reseeding
/// after a fixed number of generated bytes.
///
/// # Limitations
///
/// It is recommended that a `ReseedingRng` (including `ThreadRng`) not be used
/// from a fork handler.
/// Use `OsRng` or `getrandom`, or defer your use of the RNG until later.
///
/// # Error handling
///
/// Although unlikely, reseeding the wrapped PRNG can fail. `ReseedingRng` will
@ -279,7 +285,7 @@ where
}
#[cfg(all(unix, feature = "std", not(target_os = "emscripten")))]
#[cfg(all(unix, not(target_os = "emscripten")))]
mod fork {
use core::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Once;
@ -310,13 +316,21 @@ mod fork {
pub fn register_fork_handler() {
static REGISTER: Once = Once::new();
REGISTER.call_once(|| unsafe {
libc::pthread_atfork(None, None, Some(fork_handler));
REGISTER.call_once(|| {
// Bump the counter before and after forking (see #1169):
let ret = unsafe { libc::pthread_atfork(
Some(fork_handler),
Some(fork_handler),
Some(fork_handler),
) };
if ret != 0 {
panic!("libc::pthread_atfork failed with code {}", ret);
}
});
}
}
#[cfg(not(all(unix, feature = "std", not(target_os = "emscripten"))))]
#[cfg(not(all(unix, not(target_os = "emscripten"))))]
mod fork {
pub fn get_fork_counter() -> usize {
0
@ -325,6 +339,7 @@ mod fork {
}
#[cfg(feature = "std_rng")]
#[cfg(test)]
mod test {
use super::ReseedingRng;
@ -354,6 +369,8 @@ mod test {
#[test]
fn test_clone_reseeding() {
#![allow(clippy::redundant_clone)]
let mut zero = StepRng::new(0, 0);
let rng = Core::from_rng(&mut zero).unwrap();
let mut rng1 = ReseedingRng::new(rng, 32 * 4, zero);

View file

@ -1,76 +0,0 @@
// 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
#![allow(deprecated)] // whole module is deprecated
use crate::rngs::OsRng;
use rand_core::{CryptoRng, Error, RngCore};
/// An interface returning random data from external source(s), provided
/// specifically for securely seeding algorithmic generators (PRNGs).
///
/// This is deprecated. It is suggested you use [`rngs::OsRng`] instead.
///
/// [`rngs::OsRng`]: crate::rngs::OsRng
#[derive(Debug)]
#[deprecated(since = "0.7.0", note = "use rngs::OsRng instead")]
pub struct EntropyRng {
source: OsRng,
}
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: OsRng }
}
}
impl Default for EntropyRng {
fn default() -> Self {
EntropyRng::new()
}
}
impl RngCore for EntropyRng {
fn next_u32(&mut self) -> u32 {
self.source.next_u32()
}
fn next_u64(&mut self) -> u64 {
self.source.next_u64()
}
fn fill_bytes(&mut self, dest: &mut [u8]) {
self.source.fill_bytes(dest)
}
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
self.source.try_fill_bytes(dest)
}
}
impl CryptoRng for EntropyRng {}
#[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
}
}

View file

@ -10,6 +10,9 @@
use rand_core::{impls, Error, RngCore};
#[cfg(feature = "serde1")]
use serde::{Serialize, Deserialize};
/// A simple implementation of `RngCore` for testing purposes.
///
/// This generates an arithmetic sequence (i.e. adds a constant each step)
@ -24,7 +27,8 @@ use rand_core::{impls, Error, RngCore};
/// let sample: [u64; 3] = my_rng.gen();
/// assert_eq!(sample, [2, 3, 4]);
/// ```
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct StepRng {
v: u64,
a: u64,
@ -65,3 +69,19 @@ impl RngCore for StepRng {
Ok(())
}
}
#[cfg(test)]
mod tests {
#[test]
#[cfg(feature = "serde1")]
fn test_serialization_step_rng() {
use super::StepRng;
let some_rng = StepRng::new(42, 7);
let de_some_rng: StepRng =
bincode::deserialize(&bincode::serialize(&some_rng).unwrap()).unwrap();
assert_eq!(some_rng.v, de_some_rng.v);
assert_eq!(some_rng.a, de_some_rng.a);
}
}

View file

@ -58,7 +58,7 @@
//! is local, it is typically much faster than [`OsRng`]. It should be
//! secure, though the paranoid may prefer [`OsRng`].
//! - [`StdRng`] is a CSPRNG chosen for good performance and trust of security
//! (based on reviews, maturity and usage). The current algorithm is ChaCha20,
//! (based on reviews, maturity and usage). The current algorithm is ChaCha12,
//! which is well established and rigorously analysed.
//! [`StdRng`] provides the algorithm used by [`ThreadRng`] but without
//! periodic reseeding.
@ -96,21 +96,24 @@
//! [`rand_xoshiro`]: https://crates.io/crates/rand_xoshiro
//! [`rng` tag]: https://crates.io/keywords/rng
pub mod adapter;
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
#[cfg(feature = "std")] pub mod adapter;
#[cfg(feature = "std")] mod entropy;
pub mod mock; // Public so we don't export `StepRng` directly, making it a bit
// more clear it is intended for testing.
#[cfg(feature = "small_rng")] mod small;
mod std;
#[cfg(feature = "std")] pub(crate) mod thread;
#[allow(deprecated)]
#[cfg(feature = "std")]
pub use self::entropy::EntropyRng;
#[cfg(all(feature = "small_rng", target_pointer_width = "64"))]
mod xoshiro256plusplus;
#[cfg(all(feature = "small_rng", not(target_pointer_width = "64")))]
mod xoshiro128plusplus;
#[cfg(feature = "small_rng")] mod small;
#[cfg(feature = "std_rng")] mod std;
#[cfg(all(feature = "std", feature = "std_rng"))] pub(crate) mod thread;
#[cfg(feature = "small_rng")] pub use self::small::SmallRng;
pub use self::std::StdRng;
#[cfg(feature = "std")] pub use self::thread::ThreadRng;
#[cfg(feature = "std_rng")] pub use self::std::StdRng;
#[cfg(all(feature = "std", feature = "std_rng"))] pub use self::thread::ThreadRng;
#[cfg_attr(doc_cfg, doc(cfg(feature = "getrandom")))]
#[cfg(feature = "getrandom")] pub use rand_core::OsRng;

View file

@ -10,33 +10,36 @@
use rand_core::{Error, RngCore, SeedableRng};
#[cfg(all(not(target_os = "emscripten"), target_pointer_width = "64"))]
type Rng = rand_pcg::Pcg64Mcg;
#[cfg(not(all(not(target_os = "emscripten"), target_pointer_width = "64")))]
type Rng = rand_pcg::Pcg32;
#[cfg(target_pointer_width = "64")]
type Rng = super::xoshiro256plusplus::Xoshiro256PlusPlus;
#[cfg(not(target_pointer_width = "64"))]
type Rng = super::xoshiro128plusplus::Xoshiro128PlusPlus;
/// A small-state, fast non-crypto PRNG
///
/// `SmallRng` may be a good choice when a PRNG with small state, cheap
/// initialization, good statistical quality and good performance are required.
/// It is **not** a good choice when security against prediction or
/// reproducibility are important.
///
/// This PRNG is **feature-gated**: to use, you must enable the crate feature
/// `small_rng`.
/// Note that depending on the application, [`StdRng`] may be faster on many
/// modern platforms while providing higher-quality randomness. Furthermore,
/// `SmallRng` is **not** a good choice when:
/// - Security against prediction is important. Use [`StdRng`] instead.
/// - Seeds with many zeros are provided. In such cases, it takes `SmallRng`
/// about 10 samples to produce 0 and 1 bits with equal probability. Either
/// provide seeds with an approximately equal number of 0 and 1 (for example
/// by using [`SeedableRng::from_entropy`] or [`SeedableRng::seed_from_u64`]),
/// or use [`StdRng`] instead.
///
/// The algorithm is deterministic but should not be considered reproducible
/// due to dependence on platform and possible replacement in future
/// library versions. For a reproducible generator, use a named PRNG from an
/// external crate, e.g. [rand_pcg] or [rand_chacha].
/// external crate, e.g. [rand_xoshiro] or [rand_chacha].
/// Refer also to [The Book](https://rust-random.github.io/book/guide-rngs.html).
///
/// 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 [`StdRng`].
/// The current algorithm is [`Pcg64Mcg`](rand_pcg::Pcg64Mcg) on 64-bit
/// platforms and [`Pcg32`](rand_pcg::Pcg32) on 32-bit platforms. Both are
/// implemented by the [rand_pcg] crate.
/// 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 [`StdRng`]. The current algorithm is
/// `Xoshiro256PlusPlus` on 64-bit platforms and `Xoshiro128PlusPlus` on 32-bit
/// platforms. Both are also implemented by the [rand_xoshiro] crate.
///
/// # Examples
///
@ -72,8 +75,9 @@ type Rng = rand_pcg::Pcg32;
/// [`StdRng`]: crate::rngs::StdRng
/// [`thread_rng`]: crate::thread_rng
/// [rand_chacha]: https://crates.io/crates/rand_chacha
/// [rand_pcg]: https://crates.io/crates/rand_pcg
#[derive(Clone, Debug)]
/// [rand_xoshiro]: https://crates.io/crates/rand_xoshiro
#[cfg_attr(doc_cfg, doc(cfg(feature = "small_rng")))]
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct SmallRng(Rng);
impl RngCore for SmallRng {

View file

@ -10,21 +10,17 @@
use crate::{CryptoRng, Error, RngCore, SeedableRng};
#[cfg(all(any(test, feature = "std"), not(target_os = "emscripten")))]
pub(crate) use rand_chacha::ChaCha20Core as Core;
#[cfg(all(any(test, feature = "std"), target_os = "emscripten"))]
pub(crate) use rand_hc::Hc128Core as Core;
pub(crate) use rand_chacha::ChaCha12Core as Core;
#[cfg(not(target_os = "emscripten"))] use rand_chacha::ChaCha20Rng as Rng;
#[cfg(target_os = "emscripten")] use rand_hc::Hc128Rng as Rng;
use rand_chacha::ChaCha12Rng as Rng;
/// 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 is the ChaCha block cipher with 20 rounds.
/// This may change as new evidence of cipher security and performance
/// becomes available.
/// The current algorithm used is the ChaCha block cipher with 12 rounds. Please
/// see this relevant [rand issue] for the discussion. This may change as new
/// evidence of cipher security and performance becomes available.
///
/// The algorithm is deterministic but should not be considered reproducible
/// due to dependence on configuration and possible replacement in future
@ -32,7 +28,9 @@ pub(crate) use rand_hc::Hc128Core as Core;
/// the [rand_chacha] crate directly.
///
/// [rand_chacha]: https://crates.io/crates/rand_chacha
#[derive(Clone, Debug)]
/// [rand issue]: https://github.com/rust-random/rand/issues/932
#[cfg_attr(doc_cfg, doc(cfg(feature = "std_rng")))]
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct StdRng(Rng);
impl RngCore for StdRng {
@ -87,9 +85,6 @@ mod test {
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];
#[cfg(any(feature = "stdrng_strong", not(feature = "stdrng_fast")))]
let target = [3950704604716924505, 5573172343717151650];
#[cfg(all(not(feature = "stdrng_strong"), feature = "stdrng_fast"))]
let target = [10719222850664546238, 14064965282130556830];
let mut rng0 = StdRng::from_seed(seed);

View file

@ -8,8 +8,9 @@
//! Thread-local random number generator
use std::cell::UnsafeCell;
use std::ptr::NonNull;
use core::cell::UnsafeCell;
use std::rc::Rc;
use std::thread_local;
use super::std::Core;
use crate::rngs::adapter::ReseedingRng;
@ -32,41 +33,47 @@ use crate::{CryptoRng, Error, RngCore, SeedableRng};
// Number of generated bytes after which to reseed `ThreadRng`.
// According to benchmarks, reseeding has a noticable impact with thresholds
// According to benchmarks, reseeding has a noticeable impact with thresholds
// of 32 kB and less. We choose 64 kB to avoid significant overhead.
const THREAD_RNG_RESEED_THRESHOLD: u64 = 1024 * 64;
/// The type returned by [`thread_rng`], essentially just a reference to the
/// PRNG in thread-local memory.
/// A reference to the thread-local generator
///
/// `ThreadRng` uses the same PRNG as [`StdRng`] for security and performance.
/// As hinted by the name, the generator is thread-local. `ThreadRng` is a
/// handle to this generator and thus supports `Copy`, but not `Send` or `Sync`.
/// An instance can be obtained via [`thread_rng`] or via `ThreadRng::default()`.
/// This handle is safe to use everywhere (including thread-local destructors),
/// though it is recommended not to use inside a fork handler.
/// The handle cannot be passed between threads (is not `Send` or `Sync`).
///
/// `ThreadRng` uses the same PRNG as [`StdRng`] for security and performance
/// and is automatically seeded from [`OsRng`].
///
/// Unlike `StdRng`, `ThreadRng` uses the [`ReseedingRng`] wrapper to reseed
/// the PRNG from fresh entropy every 64 kiB of random data.
/// [`OsRng`] is used to provide seed data.
///
/// the PRNG from fresh entropy every 64 kiB of random data as well as after a
/// fork on Unix (though not quite immediately; see documentation of
/// [`ReseedingRng`]).
/// Note that the reseeding is done as an extra precaution against side-channel
/// attacks and mis-use (e.g. if somehow weak entropy were supplied initially).
/// The PRNG algorithms used are assumed to be secure.
///
/// [`ReseedingRng`]: crate::rngs::adapter::ReseedingRng
/// [`StdRng`]: crate::rngs::StdRng
#[derive(Copy, Clone, Debug)]
#[cfg_attr(doc_cfg, doc(cfg(all(feature = "std", feature = "std_rng"))))]
#[derive(Clone, Debug)]
pub struct ThreadRng {
// inner raw pointer implies type is neither Send nor Sync
rng: NonNull<ReseedingRng<Core, OsRng>>,
// Rc is explicitly !Send and !Sync
rng: Rc<UnsafeCell<ReseedingRng<Core, OsRng>>>,
}
thread_local!(
static THREAD_RNG_KEY: UnsafeCell<ReseedingRng<Core, OsRng>> = {
// We require Rc<..> to avoid premature freeing when thread_rng is used
// within thread-local destructors. See #968.
static THREAD_RNG_KEY: Rc<UnsafeCell<ReseedingRng<Core, OsRng>>> = {
let r = Core::from_rng(OsRng).unwrap_or_else(|err|
panic!("could not initialize thread_rng: {}", err));
let rng = ReseedingRng::new(r,
THREAD_RNG_RESEED_THRESHOLD,
OsRng);
UnsafeCell::new(rng)
Rc::new(UnsafeCell::new(rng))
}
);
@ -77,10 +84,10 @@ thread_local!(
/// `ThreadRng::default()` equivalent.
///
/// For more information see [`ThreadRng`].
#[cfg_attr(doc_cfg, doc(cfg(all(feature = "std", feature = "std_rng"))))]
pub fn thread_rng() -> ThreadRng {
let raw = THREAD_RNG_KEY.with(|t| t.get());
let nn = NonNull::new(raw).unwrap();
ThreadRng { rng: nn }
let rng = THREAD_RNG_KEY.with(|t| t.clone());
ThreadRng { rng }
}
impl Default for ThreadRng {
@ -92,20 +99,32 @@ impl Default for ThreadRng {
impl RngCore for ThreadRng {
#[inline(always)]
fn next_u32(&mut self) -> u32 {
unsafe { self.rng.as_mut().next_u32() }
// SAFETY: We must make sure to stop using `rng` before anyone else
// creates another mutable reference
let rng = unsafe { &mut *self.rng.get() };
rng.next_u32()
}
#[inline(always)]
fn next_u64(&mut self) -> u64 {
unsafe { self.rng.as_mut().next_u64() }
// SAFETY: We must make sure to stop using `rng` before anyone else
// creates another mutable reference
let rng = unsafe { &mut *self.rng.get() };
rng.next_u64()
}
fn fill_bytes(&mut self, dest: &mut [u8]) {
unsafe { self.rng.as_mut().fill_bytes(dest) }
// SAFETY: We must make sure to stop using `rng` before anyone else
// creates another mutable reference
let rng = unsafe { &mut *self.rng.get() };
rng.fill_bytes(dest)
}
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
unsafe { self.rng.as_mut().try_fill_bytes(dest) }
// SAFETY: We must make sure to stop using `rng` before anyone else
// creates another mutable reference
let rng = unsafe { &mut *self.rng.get() };
rng.try_fill_bytes(dest)
}
}
@ -119,6 +138,6 @@ mod test {
use crate::Rng;
let mut r = crate::thread_rng();
r.gen::<i32>();
assert_eq!(r.gen_range(0, 1), 0);
assert_eq!(r.gen_range(0..1), 0);
}
}

View file

@ -0,0 +1,118 @@
// 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="serde1")] use serde::{Serialize, Deserialize};
use rand_core::impls::{next_u64_via_u32, fill_bytes_via_next};
use rand_core::le::read_u32_into;
use rand_core::{SeedableRng, RngCore, Error};
/// A xoshiro128++ random number generator.
///
/// The xoshiro128++ algorithm is not suitable for cryptographic purposes, but
/// is very fast and has excellent statistical properties.
///
/// The algorithm used here is translated from [the `xoshiro128plusplus.c`
/// reference source code](http://xoshiro.di.unimi.it/xoshiro128plusplus.c) by
/// David Blackman and Sebastiano Vigna.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))]
pub struct Xoshiro128PlusPlus {
s: [u32; 4],
}
impl SeedableRng for Xoshiro128PlusPlus {
type Seed = [u8; 16];
/// Create a new `Xoshiro128PlusPlus`. If `seed` is entirely 0, it will be
/// mapped to a different seed.
#[inline]
fn from_seed(seed: [u8; 16]) -> Xoshiro128PlusPlus {
if seed.iter().all(|&x| x == 0) {
return Self::seed_from_u64(0);
}
let mut state = [0; 4];
read_u32_into(&seed, &mut state);
Xoshiro128PlusPlus { s: state }
}
/// Create a new `Xoshiro128PlusPlus` from a `u64` seed.
///
/// This uses the SplitMix64 generator internally.
fn seed_from_u64(mut state: u64) -> Self {
const PHI: u64 = 0x9e3779b97f4a7c15;
let mut seed = Self::Seed::default();
for chunk in seed.as_mut().chunks_mut(8) {
state = state.wrapping_add(PHI);
let mut z = state;
z = (z ^ (z >> 30)).wrapping_mul(0xbf58476d1ce4e5b9);
z = (z ^ (z >> 27)).wrapping_mul(0x94d049bb133111eb);
z = z ^ (z >> 31);
chunk.copy_from_slice(&z.to_le_bytes());
}
Self::from_seed(seed)
}
}
impl RngCore for Xoshiro128PlusPlus {
#[inline]
fn next_u32(&mut self) -> u32 {
let result_starstar = self.s[0]
.wrapping_add(self.s[3])
.rotate_left(7)
.wrapping_add(self.s[0]);
let t = self.s[1] << 9;
self.s[2] ^= self.s[0];
self.s[3] ^= self.s[1];
self.s[1] ^= self.s[2];
self.s[0] ^= self.s[3];
self.s[2] ^= t;
self.s[3] = self.s[3].rotate_left(11);
result_starstar
}
#[inline]
fn next_u64(&mut self) -> u64 {
next_u64_via_u32(self)
}
#[inline]
fn fill_bytes(&mut self, dest: &mut [u8]) {
fill_bytes_via_next(self, dest);
}
#[inline]
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
self.fill_bytes(dest);
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn reference() {
let mut rng = Xoshiro128PlusPlus::from_seed(
[1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0]);
// These values were produced with the reference implementation:
// http://xoshiro.di.unimi.it/xoshiro128plusplus.c
let expected = [
641, 1573767, 3222811527, 3517856514, 836907274, 4247214768,
3867114732, 1355841295, 495546011, 621204420,
];
for &e in &expected {
assert_eq!(rng.next_u32(), e);
}
}
}

View file

@ -0,0 +1,122 @@
// 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="serde1")] use serde::{Serialize, Deserialize};
use rand_core::impls::fill_bytes_via_next;
use rand_core::le::read_u64_into;
use rand_core::{SeedableRng, RngCore, Error};
/// A xoshiro256++ random number generator.
///
/// The xoshiro256++ algorithm is not suitable for cryptographic purposes, but
/// is very fast and has excellent statistical properties.
///
/// The algorithm used here is translated from [the `xoshiro256plusplus.c`
/// reference source code](http://xoshiro.di.unimi.it/xoshiro256plusplus.c) by
/// David Blackman and Sebastiano Vigna.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))]
pub struct Xoshiro256PlusPlus {
s: [u64; 4],
}
impl SeedableRng for Xoshiro256PlusPlus {
type Seed = [u8; 32];
/// Create a new `Xoshiro256PlusPlus`. If `seed` is entirely 0, it will be
/// mapped to a different seed.
#[inline]
fn from_seed(seed: [u8; 32]) -> Xoshiro256PlusPlus {
if seed.iter().all(|&x| x == 0) {
return Self::seed_from_u64(0);
}
let mut state = [0; 4];
read_u64_into(&seed, &mut state);
Xoshiro256PlusPlus { s: state }
}
/// Create a new `Xoshiro256PlusPlus` from a `u64` seed.
///
/// This uses the SplitMix64 generator internally.
fn seed_from_u64(mut state: u64) -> Self {
const PHI: u64 = 0x9e3779b97f4a7c15;
let mut seed = Self::Seed::default();
for chunk in seed.as_mut().chunks_mut(8) {
state = state.wrapping_add(PHI);
let mut z = state;
z = (z ^ (z >> 30)).wrapping_mul(0xbf58476d1ce4e5b9);
z = (z ^ (z >> 27)).wrapping_mul(0x94d049bb133111eb);
z = z ^ (z >> 31);
chunk.copy_from_slice(&z.to_le_bytes());
}
Self::from_seed(seed)
}
}
impl RngCore for Xoshiro256PlusPlus {
#[inline]
fn next_u32(&mut self) -> u32 {
// The lowest bits have some linear dependencies, so we use the
// upper bits instead.
(self.next_u64() >> 32) as u32
}
#[inline]
fn next_u64(&mut self) -> u64 {
let result_plusplus = self.s[0]
.wrapping_add(self.s[3])
.rotate_left(23)
.wrapping_add(self.s[0]);
let t = self.s[1] << 17;
self.s[2] ^= self.s[0];
self.s[3] ^= self.s[1];
self.s[1] ^= self.s[2];
self.s[0] ^= self.s[3];
self.s[2] ^= t;
self.s[3] = self.s[3].rotate_left(45);
result_plusplus
}
#[inline]
fn fill_bytes(&mut self, dest: &mut [u8]) {
fill_bytes_via_next(self, dest);
}
#[inline]
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
self.fill_bytes(dest);
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn reference() {
let mut rng = Xoshiro256PlusPlus::from_seed(
[1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0,
3, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0]);
// These values were produced with the reference implementation:
// http://xoshiro.di.unimi.it/xoshiro256plusplus.c
let expected = [
41943041, 58720359, 3588806011781223, 3591011842654386,
9228616714210784205, 9973669472204895162, 14011001112246962877,
12406186145184390807, 15849039046786891736, 10450023813501588000,
];
for &e in &expected {
assert_eq!(rng.next_u64(), e);
}
}
}

View file

@ -10,22 +10,26 @@
#[cfg(feature = "alloc")] use core::slice;
#[cfg(all(feature = "alloc", not(feature = "std")))]
use crate::alloc::vec::{self, Vec};
#[cfg(feature = "std")] use std::vec;
#[cfg(feature = "alloc")] use alloc::vec::{self, Vec};
// BTreeMap is not as fast in tests, but better than nothing.
#[cfg(all(feature = "alloc", not(feature = "std")))]
use crate::alloc::collections::BTreeSet;
use alloc::collections::BTreeSet;
#[cfg(feature = "std")] use std::collections::HashSet;
#[cfg(feature = "std")]
use crate::distributions::WeightedError;
#[cfg(feature = "alloc")]
use crate::distributions::{uniform::SampleUniform, Distribution, Uniform};
use crate::Rng;
use crate::{Rng, distributions::{uniform::SampleUniform, Distribution, Uniform}};
#[cfg(feature = "serde1")]
use serde::{Serialize, Deserialize};
/// A vector of indices.
///
/// Multiple internal representations are possible.
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub enum IndexVec {
#[doc(hidden)]
U32(Vec<u32>),
@ -81,10 +85,15 @@ impl IndexVec {
IndexVec::USize(ref v) => IndexVecIter::USize(v.iter()),
}
}
}
impl IntoIterator for IndexVec {
type Item = usize;
type IntoIter = IndexVecIntoIter;
/// Convert into an iterator over the indices as a sequence of `usize` values
#[inline]
pub fn into_iter(self) -> IndexVecIntoIter {
fn into_iter(self) -> IndexVecIntoIter {
match self {
IndexVec::U32(v) => IndexVecIntoIter::U32(v.into_iter()),
IndexVec::USize(v) => IndexVecIntoIter::USize(v.into_iter()),
@ -249,6 +258,154 @@ where R: Rng + ?Sized {
}
}
/// Randomly sample exactly `amount` distinct indices from `0..length`, and
/// return them in an arbitrary order (there is no guarantee of shuffling or
/// ordering). The weights are to be provided by the input function `weights`,
/// which will be called once for each index.
///
/// 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.
///
/// This implementation uses `O(length + amount)` space and `O(length)` time
/// if the "nightly" feature is enabled, or `O(length)` space and
/// `O(length + amount * log length)` time otherwise.
///
/// Panics if `amount > length`.
#[cfg(feature = "std")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
pub fn sample_weighted<R, F, X>(
rng: &mut R, length: usize, weight: F, amount: usize,
) -> Result<IndexVec, WeightedError>
where
R: Rng + ?Sized,
F: Fn(usize) -> X,
X: Into<f64>,
{
if length > (core::u32::MAX as usize) {
sample_efraimidis_spirakis(rng, length, weight, amount)
} else {
assert!(amount <= core::u32::MAX as usize);
let amount = amount as u32;
let length = length as u32;
sample_efraimidis_spirakis(rng, length, weight, amount)
}
}
/// Randomly sample exactly `amount` distinct indices from `0..length`, and
/// return them in an arbitrary order (there is no guarantee of shuffling or
/// ordering). The weights are to be provided by the input function `weights`,
/// which will be called once for each index.
///
/// This implementation uses the algorithm described by Efraimidis and Spirakis
/// in this paper: https://doi.org/10.1016/j.ipl.2005.11.003
/// It uses `O(length + amount)` space and `O(length)` time if the
/// "nightly" feature is enabled, or `O(length)` space and `O(length
/// + amount * log length)` time otherwise.
///
/// Panics if `amount > length`.
#[cfg(feature = "std")]
fn sample_efraimidis_spirakis<R, F, X, N>(
rng: &mut R, length: N, weight: F, amount: N,
) -> Result<IndexVec, WeightedError>
where
R: Rng + ?Sized,
F: Fn(usize) -> X,
X: Into<f64>,
N: UInt,
IndexVec: From<Vec<N>>,
{
if amount == N::zero() {
return Ok(IndexVec::U32(Vec::new()));
}
if amount > length {
panic!("`amount` of samples must be less than or equal to `length`");
}
struct Element<N> {
index: N,
key: f64,
}
impl<N> PartialOrd for Element<N> {
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
self.key.partial_cmp(&other.key)
}
}
impl<N> Ord for Element<N> {
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
// partial_cmp will always produce a value,
// because we check that the weights are not nan
self.partial_cmp(other).unwrap()
}
}
impl<N> PartialEq for Element<N> {
fn eq(&self, other: &Self) -> bool {
self.key == other.key
}
}
impl<N> Eq for Element<N> {}
#[cfg(feature = "nightly")]
{
let mut candidates = Vec::with_capacity(length.as_usize());
let mut index = N::zero();
while index < length {
let weight = weight(index.as_usize()).into();
if !(weight >= 0.) {
return Err(WeightedError::InvalidWeight);
}
let key = rng.gen::<f64>().powf(1.0 / weight);
candidates.push(Element { index, key });
index += N::one();
}
// Partially sort the array to find the `amount` elements with the greatest
// keys. Do this by using `select_nth_unstable` to put the elements with
// the *smallest* keys at the beginning of the list in `O(n)` time, which
// provides equivalent information about the elements with the *greatest* keys.
let (_, mid, greater)
= candidates.select_nth_unstable(length.as_usize() - amount.as_usize());
let mut result: Vec<N> = Vec::with_capacity(amount.as_usize());
result.push(mid.index);
for element in greater {
result.push(element.index);
}
Ok(IndexVec::from(result))
}
#[cfg(not(feature = "nightly"))]
{
use alloc::collections::BinaryHeap;
// Partially sort the array such that the `amount` elements with the largest
// keys are first using a binary max heap.
let mut candidates = BinaryHeap::with_capacity(length.as_usize());
let mut index = N::zero();
while index < length {
let weight = weight(index.as_usize()).into();
if !(weight >= 0.) {
return Err(WeightedError::InvalidWeight);
}
let key = rng.gen::<f64>().powf(1.0 / weight);
candidates.push(Element { index, key });
index += N::one();
}
let mut result: Vec<N> = Vec::with_capacity(amount.as_usize());
while result.len() < amount.as_usize() {
result.push(candidates.pop().unwrap().index);
}
Ok(IndexVec::from(result))
}
}
/// Randomly sample exactly `amount` indices from `0..length`, using Floyd's
/// combination algorithm.
///
@ -265,7 +422,7 @@ where R: Rng + ?Sized {
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);
let t = rng.gen_range(0..=j);
if floyd_shuffle {
if let Some(pos) = indices.iter().position(|&x| x == t) {
indices.insert(pos, j);
@ -281,7 +438,7 @@ where R: Rng + ?Sized {
// 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);
indices.swap(i as usize, rng.gen_range(0..=i) as usize);
}
}
IndexVec::from(indices)
@ -305,7 +462,7 @@ where R: Rng + ?Sized {
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);
let j: u32 = rng.gen_range(i..length);
indices.swap(i as usize, j as usize);
}
indices.truncate(amount as usize);
@ -313,8 +470,10 @@ where R: Rng + ?Sized {
IndexVec::from(indices)
}
trait UInt: Copy + PartialOrd + Ord + PartialEq + Eq + SampleUniform + core::hash::Hash {
trait UInt: Copy + PartialOrd + Ord + PartialEq + Eq + SampleUniform
+ core::hash::Hash + core::ops::AddAssign {
fn zero() -> Self;
fn one() -> Self;
fn as_usize(self) -> usize;
}
impl UInt for u32 {
@ -323,6 +482,11 @@ impl UInt for u32 {
0
}
#[inline]
fn one() -> Self {
1
}
#[inline]
fn as_usize(self) -> usize {
self as usize
@ -334,6 +498,11 @@ impl UInt for usize {
0
}
#[inline]
fn one() -> Self {
1
}
#[inline]
fn as_usize(self) -> usize {
self
@ -376,8 +545,24 @@ where
#[cfg(test)]
mod test {
use super::*;
#[cfg(all(feature = "alloc", not(feature = "std")))] use crate::alloc::vec;
#[cfg(feature = "std")] use std::vec;
#[test]
#[cfg(feature = "serde1")]
fn test_serialization_index_vec() {
let some_index_vec = IndexVec::from(vec![254_usize, 234, 2, 1]);
let de_some_index_vec: IndexVec = bincode::deserialize(&bincode::serialize(&some_index_vec).unwrap()).unwrap();
match (some_index_vec, de_some_index_vec) {
(IndexVec::U32(a), IndexVec::U32(b)) => {
assert_eq!(a, b);
},
(IndexVec::USize(a), IndexVec::USize(b)) => {
assert_eq!(a, b);
},
_ => {panic!("failed to seralize/deserialize `IndexVec`")}
}
}
#[cfg(feature = "alloc")] use alloc::vec;
#[test]
fn test_sample_boundaries() {
@ -435,4 +620,59 @@ mod test {
assert!(v1.iter().all(|e| e < length));
assert_eq!(v1, v2);
}
#[cfg(feature = "std")]
#[test]
fn test_sample_weighted() {
let seed_rng = crate::test::rng;
for &(amount, len) in &[(0, 10), (5, 10), (10, 10)] {
let v = sample_weighted(&mut seed_rng(423), len, |i| i as f64, amount).unwrap();
match v {
IndexVec::U32(mut indices) => {
assert_eq!(indices.len(), amount);
indices.sort_unstable();
indices.dedup();
assert_eq!(indices.len(), amount);
for &i in &indices {
assert!((i as usize) < len);
}
},
IndexVec::USize(_) => panic!("expected `IndexVec::U32`"),
}
}
}
#[test]
fn value_stability_sample() {
let do_test = |length, amount, values: &[u32]| {
let mut buf = [0u32; 8];
let mut rng = crate::test::rng(410);
let res = sample(&mut rng, length, amount);
let len = res.len().min(buf.len());
for (x, y) in res.into_iter().zip(buf.iter_mut()) {
*y = x as u32;
}
assert_eq!(
&buf[0..len],
values,
"failed sampling {}, {}",
length,
amount
);
};
do_test(10, 6, &[8, 0, 3, 5, 9, 6]); // floyd
do_test(25, 10, &[18, 15, 14, 9, 0, 13, 5, 24]); // floyd
do_test(300, 8, &[30, 283, 150, 1, 73, 13, 285, 35]); // floyd
do_test(300, 80, &[31, 289, 248, 154, 5, 78, 19, 286]); // inplace
do_test(300, 180, &[31, 289, 248, 154, 5, 78, 19, 286]); // inplace
do_test(1_000_000, 8, &[
103717, 963485, 826422, 509101, 736394, 807035, 5327, 632573,
]); // floyd
do_test(1_000_000, 180, &[
103718, 963490, 826426, 509103, 736396, 807036, 5327, 632573,
]); // rejection
}
}

View file

@ -17,19 +17,21 @@
//!
//! Also see:
//!
//! * [`crate::distributions::weighted`] module which provides
//! implementations of weighted index sampling.
//! * [`crate::distributions::WeightedIndex`] distribution which provides
//! weighted index sampling.
//!
//! In order to make results reproducible across 32-64 bit architectures, all
//! `usize` indices are sampled as a `u32` where possible (also providing a
//! small performance boost in some cases).
#[cfg(feature = "alloc")] pub mod index;
#[cfg(feature = "alloc")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
pub mod index;
#[cfg(feature = "alloc")] use core::ops::Index;
#[cfg(all(feature = "alloc", not(feature = "std")))] use crate::alloc::vec::Vec;
#[cfg(feature = "alloc")] use alloc::vec::Vec;
#[cfg(feature = "alloc")]
use crate::distributions::uniform::{SampleBorrow, SampleUniform};
@ -44,13 +46,11 @@ use crate::Rng;
/// ```
/// use rand::seq::SliceRandom;
///
/// fn main() {
/// let mut rng = rand::thread_rng();
/// let mut bytes = "Hello, random!".to_string().into_bytes();
/// bytes.shuffle(&mut rng);
/// let str = String::from_utf8(bytes).unwrap();
/// println!("{}", str);
/// }
/// ```
/// Example output (non-deterministic):
/// ```none
@ -111,6 +111,7 @@ pub trait SliceRandom {
/// }
/// ```
#[cfg(feature = "alloc")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
fn choose_multiple<R>(&self, rng: &mut R, amount: usize) -> SliceChooseIter<Self, Self::Item>
where R: Rng + ?Sized;
@ -138,6 +139,7 @@ pub trait SliceRandom {
/// [`choose_weighted_mut`]: SliceRandom::choose_weighted_mut
/// [`distributions::weighted`]: crate::distributions::weighted
#[cfg(feature = "alloc")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
fn choose_weighted<R, F, B, X>(
&self, rng: &mut R, weight: F,
) -> Result<&Self::Item, WeightedError>
@ -165,6 +167,7 @@ pub trait SliceRandom {
/// [`choose_weighted`]: SliceRandom::choose_weighted
/// [`distributions::weighted`]: crate::distributions::weighted
#[cfg(feature = "alloc")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
fn choose_weighted_mut<R, F, B, X>(
&mut self, rng: &mut R, weight: F,
) -> Result<&mut Self::Item, WeightedError>
@ -178,6 +181,50 @@ pub trait SliceRandom {
+ Clone
+ Default;
/// Similar to [`choose_multiple`], but where the likelihood of each element's
/// inclusion in the output may be specified. The elements are returned in an
/// arbitrary, unspecified order.
///
/// The specified function `weight` maps each item `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)`.
///
/// If all of the weights are equal, even if they are all zero, each element has
/// an equal likelihood of being selected.
///
/// The complexity of this method depends on the feature `partition_at_index`.
/// If the feature is enabled, then for slices of length `n`, the complexity
/// is `O(n)` space and `O(n)` time. Otherwise, the complexity is `O(n)` space and
/// `O(n * log amount)` time.
///
/// # Example
///
/// ```
/// use rand::prelude::*;
///
/// let choices = [('a', 2), ('b', 1), ('c', 1)];
/// let mut rng = thread_rng();
/// // First Draw * Second Draw = total odds
/// // -----------------------
/// // (50% * 50%) + (25% * 67%) = 41.7% chance that the output is `['a', 'b']` in some order.
/// // (50% * 50%) + (25% * 67%) = 41.7% chance that the output is `['a', 'c']` in some order.
/// // (25% * 33%) + (25% * 33%) = 16.6% chance that the output is `['b', 'c']` in some order.
/// println!("{:?}", choices.choose_multiple_weighted(&mut rng, 2, |item| item.1).unwrap().collect::<Vec<_>>());
/// ```
/// [`choose_multiple`]: SliceRandom::choose_multiple
//
// Note: this is feature-gated on std due to usage of f64::powf.
// If necessary, we may use alloc+libm as an alternative (see PR #1089).
#[cfg(feature = "std")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
fn choose_multiple_weighted<R, F, X>(
&self, rng: &mut R, amount: usize, weight: F,
) -> Result<SliceChooseIter<Self, Self::Item>, WeightedError>
where
R: Rng + ?Sized,
F: Fn(&Self::Item) -> X,
X: Into<f64>;
/// Shuffle a mutable slice in place.
///
/// For slices of length `n`, complexity is `O(n)`.
@ -222,18 +269,17 @@ pub trait SliceRandom {
/// Extension trait on iterators, providing random sampling methods.
///
/// This trait is implemented on all sized iterators, providing methods for
/// This trait is implemented on all iterators `I` where `I: Iterator + Sized`
/// and provides methods for
/// choosing one or more elements. You must `use` this trait:
///
/// ```
/// use rand::seq::IteratorRandom;
///
/// fn main() {
/// let mut rng = rand::thread_rng();
///
/// let faces = "😀😎😐😕😠😢";
/// println!("I am {}!", faces.chars().choose(&mut rng).unwrap());
/// }
/// ```
/// Example output (non-deterministic):
/// ```none
@ -250,14 +296,20 @@ pub trait IteratorRandom: Iterator + Sized {
/// available, complexity is `O(n)` where `n` is the iterator length.
/// Partial hints (where `lower > 0`) also improve performance.
///
/// For slices, prefer [`SliceRandom::choose`] which guarantees `O(1)`
/// performance.
/// Note that the output values and the number of RNG samples used
/// depends on size hints. In particular, `Iterator` combinators that don't
/// change the values yielded but change the size hints may result in
/// `choose` returning different elements. If you want consistent results
/// and RNG usage consider using [`IteratorRandom::choose_stable`].
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;
// Handling for this condition outside the loop allows the optimizer to eliminate the loop
// when the Iterator is an ExactSizeIterator. This has a large performance impact on e.g.
// seq_iter_choose_from_1000.
if upper == Some(lower) {
return if lower == 0 {
None
@ -289,8 +341,7 @@ pub trait IteratorRandom: Iterator + Sized {
return result;
}
consumed += 1;
let denom = consumed as f64; // accurate to 2^53 elements
if rng.gen_bool(1.0 / denom) {
if gen_index(rng, consumed) == 0 {
result = elem;
}
}
@ -301,6 +352,64 @@ pub trait IteratorRandom: Iterator + Sized {
}
}
/// Choose one element at random from the iterator.
///
/// Returns `None` if and only if the iterator is empty.
///
/// This method is very similar to [`choose`] except that the result
/// only depends on the length of the iterator and the values produced by
/// `rng`. Notably for any iterator of a given length this will make the
/// same requests to `rng` and if the same sequence of values are produced
/// the same index will be selected from `self`. This may be useful if you
/// need consistent results no matter what type of iterator you are working
/// with. If you do not need this stability prefer [`choose`].
///
/// Note that this method still uses [`Iterator::size_hint`] to skip
/// constructing elements where possible, however the selection and `rng`
/// calls are the same in the face of this optimization. If you want to
/// force every element to be created regardless call `.inspect(|e| ())`.
///
/// [`choose`]: IteratorRandom::choose
fn choose_stable<R>(mut self, rng: &mut R) -> Option<Self::Item>
where R: Rng + ?Sized {
let mut consumed = 0;
let mut result = None;
loop {
// Currently the only way to skip elements is `nth()`. So we need to
// store what index to access next here.
// This should be replaced by `advance_by()` once it is stable:
// https://github.com/rust-lang/rust/issues/77404
let mut next = 0;
let (lower, _) = self.size_hint();
if lower >= 2 {
let highest_selected = (0..lower)
.filter(|ix| gen_index(rng, consumed+ix+1) == 0)
.last();
consumed += lower;
next = lower;
if let Some(ix) = highest_selected {
result = self.nth(ix);
next -= ix + 1;
debug_assert!(result.is_some(), "iterator shorter than size_hint().0");
}
}
let elem = self.nth(next);
if elem.is_none() {
return result
}
if gen_index(rng, consumed+1) == 0 {
result = elem;
}
consumed += 1;
}
}
/// Collects values at random from the iterator into a supplied buffer
/// until that buffer is filled.
///
@ -353,6 +462,7 @@ pub trait IteratorRandom: Iterator + Sized {
/// Complexity is `O(n)` where `n` is the length of the iterator.
/// For slices, prefer [`SliceRandom::choose_multiple`].
#[cfg(feature = "alloc")]
#[cfg_attr(doc_cfg, doc(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);
@ -450,6 +560,29 @@ impl<T> SliceRandom for [T] {
Ok(&mut self[distr.sample(rng)])
}
#[cfg(feature = "std")]
fn choose_multiple_weighted<R, F, X>(
&self, rng: &mut R, amount: usize, weight: F,
) -> Result<SliceChooseIter<Self, Self::Item>, WeightedError>
where
R: Rng + ?Sized,
F: Fn(&Self::Item) -> X,
X: Into<f64>,
{
let amount = ::core::cmp::min(amount, self.len());
Ok(SliceChooseIter {
slice: self,
_phantom: Default::default(),
indices: index::sample_weighted(
rng,
self.len(),
|idx| weight(&self[idx]).into(),
amount,
)?
.into_iter(),
})
}
fn shuffle<R>(&mut self, rng: &mut R)
where R: Rng + ?Sized {
for i in (1..self.len()).rev() {
@ -487,6 +620,7 @@ impl<I> IteratorRandom for I where I: Iterator + Sized {}
/// This struct is created by
/// [`SliceRandom::choose_multiple`](trait.SliceRandom.html#tymethod.choose_multiple).
#[cfg(feature = "alloc")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
#[derive(Debug)]
pub struct SliceChooseIter<'a, S: ?Sized + 'a, T: 'a> {
slice: &'a S,
@ -524,9 +658,9 @@ impl<'a, S: Index<usize, Output = T> + ?Sized + 'a, T: 'a> ExactSizeIterator
#[inline]
fn gen_index<R: Rng + ?Sized>(rng: &mut R, ubound: usize) -> usize {
if ubound <= (core::u32::MAX as usize) {
rng.gen_range(0, ubound as u32) as usize
rng.gen_range(0..ubound as u32) as usize
} else {
rng.gen_range(0, ubound)
rng.gen_range(0..ubound)
}
}
@ -567,6 +701,40 @@ mod test {
assert_eq!(v.choose_mut(&mut r), None);
}
#[test]
fn value_stability_slice() {
let mut r = crate::test::rng(413);
let chars = [
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
];
let mut nums = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
assert_eq!(chars.choose(&mut r), Some(&'l'));
assert_eq!(nums.choose_mut(&mut r), Some(&mut 10));
#[cfg(feature = "alloc")]
assert_eq!(
&chars
.choose_multiple(&mut r, 8)
.cloned()
.collect::<Vec<char>>(),
&['d', 'm', 'b', 'n', 'c', 'k', 'h', 'e']
);
#[cfg(feature = "alloc")]
assert_eq!(chars.choose_weighted(&mut r, |_| 1), Ok(&'f'));
#[cfg(feature = "alloc")]
assert_eq!(nums.choose_weighted_mut(&mut r, |_| 1), Ok(&mut 5));
let mut r = crate::test::rng(414);
nums.shuffle(&mut r);
assert_eq!(nums, [9, 5, 3, 10, 7, 12, 8, 11, 6, 4, 0, 2, 1]);
nums = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
let res = nums.partial_shuffle(&mut r, 6);
assert_eq!(res.0, &mut [7, 4, 8, 6, 9, 3]);
assert_eq!(res.1, &mut [0, 1, 2, 12, 11, 5, 10]);
}
#[derive(Clone)]
struct UnhintedIterator<I: Iterator + Clone> {
iter: I,
@ -689,6 +857,103 @@ mod test {
assert_eq!(UnhintedIterator { iter: 0..0 }.choose(r), None);
}
#[test]
#[cfg_attr(miri, ignore)] // Miri is too slow
fn test_iterator_choose_stable() {
let r = &mut crate::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_stable(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]
#[cfg_attr(miri, ignore)] // Miri is too slow
fn test_iterator_choose_stable_stability() {
fn test_iter(iter: impl Iterator<Item = usize> + Clone) -> [i32; 9] {
let r = &mut crate::test::rng(109);
let mut chosen = [0i32; 9];
for _ in 0..1000 {
let picked = iter.clone().choose_stable(r).unwrap();
chosen[picked] += 1;
}
chosen
}
let reference = test_iter(0..9);
assert_eq!(test_iter([0, 1, 2, 3, 4, 5, 6, 7, 8].iter().cloned()), reference);
#[cfg(feature = "alloc")]
assert_eq!(test_iter((0..9).collect::<Vec<_>>().into_iter()), reference);
assert_eq!(test_iter(UnhintedIterator { iter: 0..9 }), reference);
assert_eq!(test_iter(ChunkHintedIterator {
iter: 0..9,
chunk_size: 4,
chunk_remaining: 4,
hint_total_size: false,
}), reference);
assert_eq!(test_iter(ChunkHintedIterator {
iter: 0..9,
chunk_size: 4,
chunk_remaining: 4,
hint_total_size: true,
}), reference);
assert_eq!(test_iter(WindowHintedIterator {
iter: 0..9,
window_size: 2,
hint_total_size: false,
}), reference);
assert_eq!(test_iter(WindowHintedIterator {
iter: 0..9,
window_size: 2,
hint_total_size: true,
}), reference);
}
#[test]
#[cfg_attr(miri, ignore)] // Miri is too slow
fn test_shuffle() {
@ -726,8 +991,8 @@ mod test {
move_last(&mut arr, pos);
assert_eq!(arr[3], i);
}
for i in 0..4 {
assert_eq!(arr[i], i);
for (i, &a) in arr.iter().enumerate() {
assert_eq!(a, i);
}
counts[permutation] += 1;
}
@ -847,4 +1112,245 @@ mod test {
Err(WeightedError::InvalidWeight)
);
}
#[test]
fn value_stability_choose() {
fn choose<I: Iterator<Item = u32>>(iter: I) -> Option<u32> {
let mut rng = crate::test::rng(411);
iter.choose(&mut rng)
}
assert_eq!(choose([].iter().cloned()), None);
assert_eq!(choose(0..100), Some(33));
assert_eq!(choose(UnhintedIterator { iter: 0..100 }), Some(40));
assert_eq!(
choose(ChunkHintedIterator {
iter: 0..100,
chunk_size: 32,
chunk_remaining: 32,
hint_total_size: false,
}),
Some(39)
);
assert_eq!(
choose(ChunkHintedIterator {
iter: 0..100,
chunk_size: 32,
chunk_remaining: 32,
hint_total_size: true,
}),
Some(39)
);
assert_eq!(
choose(WindowHintedIterator {
iter: 0..100,
window_size: 32,
hint_total_size: false,
}),
Some(90)
);
assert_eq!(
choose(WindowHintedIterator {
iter: 0..100,
window_size: 32,
hint_total_size: true,
}),
Some(90)
);
}
#[test]
fn value_stability_choose_stable() {
fn choose<I: Iterator<Item = u32>>(iter: I) -> Option<u32> {
let mut rng = crate::test::rng(411);
iter.choose_stable(&mut rng)
}
assert_eq!(choose([].iter().cloned()), None);
assert_eq!(choose(0..100), Some(40));
assert_eq!(choose(UnhintedIterator { iter: 0..100 }), Some(40));
assert_eq!(
choose(ChunkHintedIterator {
iter: 0..100,
chunk_size: 32,
chunk_remaining: 32,
hint_total_size: false,
}),
Some(40)
);
assert_eq!(
choose(ChunkHintedIterator {
iter: 0..100,
chunk_size: 32,
chunk_remaining: 32,
hint_total_size: true,
}),
Some(40)
);
assert_eq!(
choose(WindowHintedIterator {
iter: 0..100,
window_size: 32,
hint_total_size: false,
}),
Some(40)
);
assert_eq!(
choose(WindowHintedIterator {
iter: 0..100,
window_size: 32,
hint_total_size: true,
}),
Some(40)
);
}
#[test]
fn value_stability_choose_multiple() {
fn do_test<I: Iterator<Item = u32>>(iter: I, v: &[u32]) {
let mut rng = crate::test::rng(412);
let mut buf = [0u32; 8];
assert_eq!(iter.choose_multiple_fill(&mut rng, &mut buf), v.len());
assert_eq!(&buf[0..v.len()], v);
}
do_test(0..4, &[0, 1, 2, 3]);
do_test(0..8, &[0, 1, 2, 3, 4, 5, 6, 7]);
do_test(0..100, &[58, 78, 80, 92, 43, 8, 96, 7]);
#[cfg(feature = "alloc")]
{
fn do_test<I: Iterator<Item = u32>>(iter: I, v: &[u32]) {
let mut rng = crate::test::rng(412);
assert_eq!(iter.choose_multiple(&mut rng, v.len()), v);
}
do_test(0..4, &[0, 1, 2, 3]);
do_test(0..8, &[0, 1, 2, 3, 4, 5, 6, 7]);
do_test(0..100, &[58, 78, 80, 92, 43, 8, 96, 7]);
}
}
#[test]
#[cfg(feature = "std")]
fn test_multiple_weighted_edge_cases() {
use super::*;
let mut rng = crate::test::rng(413);
// Case 1: One of the weights is 0
let choices = [('a', 2), ('b', 1), ('c', 0)];
for _ in 0..100 {
let result = choices
.choose_multiple_weighted(&mut rng, 2, |item| item.1)
.unwrap()
.collect::<Vec<_>>();
assert_eq!(result.len(), 2);
assert!(!result.iter().any(|val| val.0 == 'c'));
}
// Case 2: All of the weights are 0
let choices = [('a', 0), ('b', 0), ('c', 0)];
assert_eq!(choices
.choose_multiple_weighted(&mut rng, 2, |item| item.1)
.unwrap().count(), 2);
// Case 3: Negative weights
let choices = [('a', -1), ('b', 1), ('c', 1)];
assert_eq!(
choices
.choose_multiple_weighted(&mut rng, 2, |item| item.1)
.unwrap_err(),
WeightedError::InvalidWeight
);
// Case 4: Empty list
let choices = [];
assert_eq!(choices
.choose_multiple_weighted(&mut rng, 0, |_: &()| 0)
.unwrap().count(), 0);
// Case 5: NaN weights
let choices = [('a', core::f64::NAN), ('b', 1.0), ('c', 1.0)];
assert_eq!(
choices
.choose_multiple_weighted(&mut rng, 2, |item| item.1)
.unwrap_err(),
WeightedError::InvalidWeight
);
// Case 6: +infinity weights
let choices = [('a', core::f64::INFINITY), ('b', 1.0), ('c', 1.0)];
for _ in 0..100 {
let result = choices
.choose_multiple_weighted(&mut rng, 2, |item| item.1)
.unwrap()
.collect::<Vec<_>>();
assert_eq!(result.len(), 2);
assert!(result.iter().any(|val| val.0 == 'a'));
}
// Case 7: -infinity weights
let choices = [('a', core::f64::NEG_INFINITY), ('b', 1.0), ('c', 1.0)];
assert_eq!(
choices
.choose_multiple_weighted(&mut rng, 2, |item| item.1)
.unwrap_err(),
WeightedError::InvalidWeight
);
// Case 8: -0 weights
let choices = [('a', -0.0), ('b', 1.0), ('c', 1.0)];
assert!(choices
.choose_multiple_weighted(&mut rng, 2, |item| item.1)
.is_ok());
}
#[test]
#[cfg(feature = "std")]
fn test_multiple_weighted_distributions() {
use super::*;
// The theoretical probabilities of the different outcomes are:
// AB: 0.5 * 0.5 = 0.250
// AC: 0.5 * 0.5 = 0.250
// BA: 0.25 * 0.67 = 0.167
// BC: 0.25 * 0.33 = 0.082
// CA: 0.25 * 0.67 = 0.167
// CB: 0.25 * 0.33 = 0.082
let choices = [('a', 2), ('b', 1), ('c', 1)];
let mut rng = crate::test::rng(414);
let mut results = [0i32; 3];
let expected_results = [4167, 4167, 1666];
for _ in 0..10000 {
let result = choices
.choose_multiple_weighted(&mut rng, 2, |item| item.1)
.unwrap()
.collect::<Vec<_>>();
assert_eq!(result.len(), 2);
match (result[0].0, result[1].0) {
('a', 'b') | ('b', 'a') => {
results[0] += 1;
}
('a', 'c') | ('c', 'a') => {
results[1] += 1;
}
('b', 'c') | ('c', 'b') => {
results[2] += 1;
}
(_, _) => panic!("unexpected result"),
}
}
let mut diffs = results
.iter()
.zip(&expected_results)
.map(|(a, b)| (a - b).abs());
assert!(!diffs.any(|deviation| deviation > 100));
}
}

View file

@ -1 +1 @@
{"files":{"CHANGELOG.md":"cfa5a57b442ab6da8e03c4b5f82e63a74c97a999edfbf7841646d4612f399206","COPYRIGHT":"90eb64f0279b0d9432accfa6023ff803bc4965212383697eee27a0f426d5f8d5","Cargo.toml":"254d87eb2174bd4375fba1b2818d7295d558721582af12f600241da250250310","LICENSE-APACHE":"aaff376532ea30a0cd5330b9502ad4a4c8bf769c539c87ffe78819d188a18ebf","LICENSE-MIT":"209fbbe0ad52d9235e37badf9cadfe4dbdc87203179c0899e738b39ade42177b","README.md":"5b6d753b28e14cc08a25aaa56c941f038c0e3d8e340129492c3e2824401bdd66","src/chacha.rs":"1ce534f0a3c6d3cd86aa077a56feb72969cbe4d37237ef6c698623a768a48f7f","src/guts.rs":"e8ff037f9461cdbdd8338927acfdef1497b11fa695fdd4247ec7f081bb5f459f","src/lib.rs":"a27fe2bff676a764d43d604a20cf30a41dc1c5ef4053eb41129d2479f5ae83fe"},"package":"f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"}
{"files":{"CHANGELOG.md":"deb20cd6e8be14e767b7fdea0e503ddd8226afd1253a5221aacc28a23d45db20","COPYRIGHT":"90eb64f0279b0d9432accfa6023ff803bc4965212383697eee27a0f426d5f8d5","Cargo.toml":"e2ef45f3c9d6f013da266b76ca1e1f664ad5fa1d526b46580a77fb311c659fd8","LICENSE-APACHE":"aaff376532ea30a0cd5330b9502ad4a4c8bf769c539c87ffe78819d188a18ebf","LICENSE-MIT":"209fbbe0ad52d9235e37badf9cadfe4dbdc87203179c0899e738b39ade42177b","README.md":"f4221f35b7086649fa77807e826af020b57eb65b19cb693482d4a7e1e4d80537","src/chacha.rs":"dfd79ed4762e8267148d1776381c71b898808014a4069cfafbc78177247d5fe9","src/guts.rs":"898fd129897fb44d15053044227307ee2bf416970adb8e63b4f5eabb7431aa1e","src/lib.rs":"a27fe2bff676a764d43d604a20cf30a41dc1c5ef4053eb41129d2479f5ae83fe"},"package":"e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"}

View file

@ -4,6 +4,19 @@ 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.1] - 2021-06-09
- add getters corresponding to existing setters: `get_seed`, `get_stream` (#1124)
- add serde support, gated by the `serde1` feature (#1124)
- ensure expected layout via `repr(transparent)` (#1120)
## [0.3.0] - 2020-12-08
- Bump `rand_core` version to 0.6.0
- Bump MSRV to 1.36 (#1011)
- Remove usage of deprecated feature "simd" of `ppv-lite86` (#979), then revert
this change (#1023) since SIMD is only enabled by default from `ppv-lite86 v0.2.10`
- impl PartialEq+Eq for ChaChaXRng and ChaChaXCore (#979)
- Fix panic on block counter wrap that was occurring in debug builds (#980)
## [0.2.2] - 2020-03-09
- Integrate `c2-chacha`, reducing dependency count (#931)
- Add CryptoRng to ChaChaXCore (#944)

View file

@ -13,30 +13,33 @@
[package]
edition = "2018"
name = "rand_chacha"
version = "0.2.2"
version = "0.3.1"
authors = ["The Rand Project Developers", "The Rust Project Developers", "The CryptoCorrosion Contributors"]
description = "ChaCha random number generator\n"
homepage = "https://crates.io/crates/rand_chacha"
documentation = "https://rust-random.github.io/rand/rand_chacha/"
homepage = "https://rust-random.github.io/book"
documentation = "https://docs.rs/rand_chacha"
readme = "README.md"
keywords = ["random", "rng", "chacha"]
categories = ["algorithms", "no-std"]
license = "MIT OR Apache-2.0"
repository = "https://github.com/rust-random/rand"
[dependencies.ppv-lite86]
version = "0.2.6"
version = "0.2.8"
features = ["simd"]
default-features = false
[dependencies.rand_core]
version = "0.5"
version = "0.6.0"
[dependencies.serde]
version = "1.0"
features = ["derive"]
optional = true
[dev-dependencies.serde_json]
version = "1.0"
[features]
default = ["std", "simd"]
default = ["std"]
serde1 = ["serde"]
simd = []
std = ["ppv-lite86/std"]
[badges.appveyor]
repository = "rust-random/rand"
[badges.travis-ci]
repository = "rust-random/rand"

View file

@ -1,12 +1,11 @@
# 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)
[![Test Status](https://github.com/rust-random/rand/workflows/Tests/badge.svg?event=push)](https://github.com/rust-random/rand/actions)
[![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.32+-lightgray.svg)](https://github.com/rust-random/rand#rust-version-requirements)
[![Minimum rustc version](https://img.shields.io/badge/rustc-1.36+-lightgray.svg)](https://github.com/rust-random/rand#rust-version-requirements)
A cryptographically secure random number generator that uses the ChaCha
algorithm.

View file

@ -16,9 +16,14 @@ use crate::guts::ChaCha;
use rand_core::block::{BlockRng, BlockRngCore};
use rand_core::{CryptoRng, Error, RngCore, SeedableRng};
const STREAM_PARAM_NONCE: u32 = 1;
const STREAM_PARAM_BLOCK: u32 = 0;
#[cfg(feature = "serde1")] use serde::{Serialize, Deserialize, Serializer, Deserializer};
// NB. this must remain consistent with some currently hard-coded numbers in this module
const BUF_BLOCKS: u8 = 4;
// number of 32-bit words per ChaCha block (fixed by algorithm definition)
const BLOCK_WORDS: u8 = 16;
#[repr(transparent)]
pub struct Array64<T>([T; 64]);
impl<T> Default for Array64<T>
where T: Default
@ -63,9 +68,9 @@ impl<T> fmt::Debug for Array64<T> {
}
macro_rules! chacha_impl {
($ChaChaXCore:ident, $ChaChaXRng:ident, $rounds:expr, $doc:expr) => {
($ChaChaXCore:ident, $ChaChaXRng:ident, $rounds:expr, $doc:expr, $abst:ident) => {
#[doc=$doc]
#[derive(Clone)]
#[derive(Clone, PartialEq, Eq)]
pub struct $ChaChaXCore {
state: ChaCha,
}
@ -187,10 +192,19 @@ macro_rules! chacha_impl {
/// byte-offset.
#[inline]
pub fn get_word_pos(&self) -> u128 {
let mut block = u128::from(self.rng.core.state.get_stream_param(STREAM_PARAM_BLOCK));
// counter is incremented *after* filling buffer
block -= 4;
(block << 4) + self.rng.index() as u128
let buf_start_block = {
let buf_end_block = self.rng.core.state.get_block_pos();
u64::wrapping_sub(buf_end_block, BUF_BLOCKS.into())
};
let (buf_offset_blocks, block_offset_words) = {
let buf_offset_words = self.rng.index() as u64;
let blocks_part = buf_offset_words / u64::from(BLOCK_WORDS);
let words_part = buf_offset_words % u64::from(BLOCK_WORDS);
(blocks_part, words_part)
};
let pos_block = u64::wrapping_add(buf_start_block, buf_offset_blocks);
let pos_block_words = u128::from(pos_block) * u128::from(BLOCK_WORDS);
pos_block_words + u128::from(block_offset_words)
}
/// Set the offset from the start of the stream, in 32-bit words.
@ -200,12 +214,12 @@ macro_rules! chacha_impl {
/// 60 bits.
#[inline]
pub fn set_word_pos(&mut self, word_offset: u128) {
let block = (word_offset >> 4) as u64;
let block = (word_offset / u128::from(BLOCK_WORDS)) as u64;
self.rng
.core
.state
.set_stream_param(STREAM_PARAM_BLOCK, block);
self.rng.generate_and_set((word_offset & 15) as usize);
.set_block_pos(block);
self.rng.generate_and_set((word_offset % u128::from(BLOCK_WORDS)) as usize);
}
/// Set the stream number.
@ -224,12 +238,30 @@ macro_rules! chacha_impl {
self.rng
.core
.state
.set_stream_param(STREAM_PARAM_NONCE, stream);
.set_nonce(stream);
if self.rng.index() != 64 {
let wp = self.get_word_pos();
self.set_word_pos(wp);
}
}
/// Get the stream number.
#[inline]
pub fn get_stream(&self) -> u64 {
self.rng
.core
.state
.get_nonce()
}
/// Get the seed.
#[inline]
pub fn get_seed(&self) -> [u8; 32] {
self.rng
.core
.state
.get_seed()
}
}
impl CryptoRng for $ChaChaXRng {}
@ -241,19 +273,132 @@ macro_rules! chacha_impl {
}
}
}
impl PartialEq<$ChaChaXRng> for $ChaChaXRng {
fn eq(&self, rhs: &$ChaChaXRng) -> bool {
let a: $abst::$ChaChaXRng = self.into();
let b: $abst::$ChaChaXRng = rhs.into();
a == b
}
}
impl Eq for $ChaChaXRng {}
#[cfg(feature = "serde1")]
impl Serialize for $ChaChaXRng {
fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
where S: Serializer {
$abst::$ChaChaXRng::from(self).serialize(s)
}
}
#[cfg(feature = "serde1")]
impl<'de> Deserialize<'de> for $ChaChaXRng {
fn deserialize<D>(d: D) -> Result<Self, D::Error> where D: Deserializer<'de> {
$abst::$ChaChaXRng::deserialize(d).map(|x| Self::from(&x))
}
}
chacha_impl!(ChaCha20Core, ChaCha20Rng, 10, "ChaCha with 20 rounds");
chacha_impl!(ChaCha12Core, ChaCha12Rng, 6, "ChaCha with 12 rounds");
chacha_impl!(ChaCha8Core, ChaCha8Rng, 4, "ChaCha with 8 rounds");
mod $abst {
#[cfg(feature = "serde1")] use serde::{Serialize, Deserialize};
// The abstract state of a ChaCha stream, independent of implementation choices. The
// comparison and serialization of this object is considered a semver-covered part of
// the API.
#[derive(Debug, PartialEq, Eq)]
#[cfg_attr(
feature = "serde1",
derive(Serialize, Deserialize),
)]
pub(crate) struct $ChaChaXRng {
seed: [u8; 32],
stream: u64,
word_pos: u128,
}
impl From<&super::$ChaChaXRng> for $ChaChaXRng {
// Forget all information about the input except what is necessary to determine the
// outputs of any sequence of pub API calls.
fn from(r: &super::$ChaChaXRng) -> Self {
Self {
seed: r.get_seed(),
stream: r.get_stream(),
word_pos: r.get_word_pos(),
}
}
}
impl From<&$ChaChaXRng> for super::$ChaChaXRng {
// Construct one of the possible concrete RNGs realizing an abstract state.
fn from(a: &$ChaChaXRng) -> Self {
use rand_core::SeedableRng;
let mut r = Self::from_seed(a.seed);
r.set_stream(a.stream);
r.set_word_pos(a.word_pos);
r
}
}
}
}
}
chacha_impl!(ChaCha20Core, ChaCha20Rng, 10, "ChaCha with 20 rounds", abstract20);
chacha_impl!(ChaCha12Core, ChaCha12Rng, 6, "ChaCha with 12 rounds", abstract12);
chacha_impl!(ChaCha8Core, ChaCha8Rng, 4, "ChaCha with 8 rounds", abstract8);
#[cfg(test)]
mod test {
use rand_core::{RngCore, SeedableRng};
#[cfg(feature = "serde1")] use super::{ChaCha20Rng, ChaCha12Rng, ChaCha8Rng};
type ChaChaRng = super::ChaCha20Rng;
#[cfg(feature = "serde1")]
#[test]
fn test_chacha_serde_roundtrip() {
let seed = [
1, 0, 52, 0, 0, 0, 0, 0, 1, 0, 10, 0, 22, 32, 0, 0, 2, 0, 55, 49, 0, 11, 0, 0, 3, 0, 0, 0, 0,
0, 2, 92,
];
let mut rng1 = ChaCha20Rng::from_seed(seed);
let mut rng2 = ChaCha12Rng::from_seed(seed);
let mut rng3 = ChaCha8Rng::from_seed(seed);
let encoded1 = serde_json::to_string(&rng1).unwrap();
let encoded2 = serde_json::to_string(&rng2).unwrap();
let encoded3 = serde_json::to_string(&rng3).unwrap();
let mut decoded1: ChaCha20Rng = serde_json::from_str(&encoded1).unwrap();
let mut decoded2: ChaCha12Rng = serde_json::from_str(&encoded2).unwrap();
let mut decoded3: ChaCha8Rng = serde_json::from_str(&encoded3).unwrap();
assert_eq!(rng1, decoded1);
assert_eq!(rng2, decoded2);
assert_eq!(rng3, decoded3);
assert_eq!(rng1.next_u32(), decoded1.next_u32());
assert_eq!(rng2.next_u32(), decoded2.next_u32());
assert_eq!(rng3.next_u32(), decoded3.next_u32());
}
// This test validates that:
// 1. a hard-coded serialization demonstrating the format at time of initial release can still
// be deserialized to a ChaChaRng
// 2. re-serializing the resultant object produces exactly the original string
//
// Condition 2 is stronger than necessary: an equivalent serialization (e.g. with field order
// permuted, or whitespace differences) would also be admissible, but would fail this test.
// However testing for equivalence of serialized data is difficult, and there shouldn't be any
// reason we need to violate the stronger-than-needed condition, e.g. by changing the field
// definition order.
#[cfg(feature = "serde1")]
#[test]
fn test_chacha_serde_format_stability() {
let j = r#"{"seed":[4,8,15,16,23,42,4,8,15,16,23,42,4,8,15,16,23,42,4,8,15,16,23,42,4,8,15,16,23,42,4,8],"stream":27182818284,"word_pos":314159265359}"#;
let r: ChaChaRng = serde_json::from_str(&j).unwrap();
let j1 = serde_json::to_string(&r).unwrap();
assert_eq!(j, j1);
}
#[test]
fn test_chacha_construction() {
let seed = [
@ -456,4 +601,32 @@ mod test {
assert_eq!(rng.next_u32(), clone.next_u32());
}
}
#[test]
fn test_chacha_word_pos_wrap_exact() {
use super::{BUF_BLOCKS, BLOCK_WORDS};
let mut rng = ChaChaRng::from_seed(Default::default());
// refilling the buffer in set_word_pos will wrap the block counter to 0
let last_block = (1 << 68) - u128::from(BUF_BLOCKS * BLOCK_WORDS);
rng.set_word_pos(last_block);
assert_eq!(rng.get_word_pos(), last_block);
}
#[test]
fn test_chacha_word_pos_wrap_excess() {
use super::BLOCK_WORDS;
let mut rng = ChaChaRng::from_seed(Default::default());
// refilling the buffer in set_word_pos will wrap the block counter past 0
let last_block = (1 << 68) - u128::from(BLOCK_WORDS);
rng.set_word_pos(last_block);
assert_eq!(rng.get_word_pos(), last_block);
}
#[test]
fn test_chacha_word_pos_zero() {
let mut rng = ChaChaRng::from_seed(Default::default());
assert_eq!(rng.get_word_pos(), 0);
rng.set_word_pos(0);
assert_eq!(rng.get_word_pos(), 0);
}
}

Some files were not shown because too many files have changed in this diff Show more