forked from mirrors/gecko-dev
Bug 1770894 - Force update rand to 0.8. r=emilio
Differential Revision: https://phabricator.services.mozilla.com/D147377
This commit is contained in:
parent
f05ced899f
commit
1cda4fe2c7
140 changed files with 4841 additions and 8599 deletions
64
Cargo.lock
generated
64
Cargo.lock
generated
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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" }
|
||||
|
||||
|
|
|
|||
21
build/rust/rand/Cargo.toml
Normal file
21
build/rust/rand/Cargo.toml
Normal 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
5
build/rust/rand/lib.rs
Normal 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::*;
|
||||
|
|
@ -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"}
|
||||
130
third_party/rust/getrandom/CHANGELOG.md
vendored
130
third_party/rust/getrandom/CHANGELOG.md
vendored
|
|
@ -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
|
||||
|
|
|
|||
60
third_party/rust/getrandom/Cargo.toml
vendored
60
third_party/rust/getrandom/Cargo.toml
vendored
|
|
@ -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
|
||||
|
|
|
|||
52
third_party/rust/getrandom/README.md
vendored
52
third_party/rust/getrandom/README.md
vendored
|
|
@ -1,10 +1,18 @@
|
|||
# getrandom
|
||||
|
||||
[](https://travis-ci.org/rust-random/getrandom)
|
||||
[](https://ci.appveyor.com/project/rust-random/getrandom)
|
||||
[](https://crates.io/crates/getrandom)
|
||||
[](https://docs.rs/getrandom)
|
||||
[](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
|
||||
|
||||
|
|
|
|||
1
third_party/rust/getrandom/benches/mod.rs
vendored
1
third_party/rust/getrandom/benches/mod.rs
vendored
|
|
@ -1,5 +1,4 @@
|
|||
#![feature(test)]
|
||||
extern crate getrandom;
|
||||
extern crate test;
|
||||
|
||||
#[bench]
|
||||
|
|
|
|||
19
third_party/rust/getrandom/build.rs
vendored
19
third_party/rust/getrandom/build.rs
vendored
|
|
@ -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
17
third_party/rust/getrandom/src/3ds.rs
vendored
Normal 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)
|
||||
})
|
||||
}
|
||||
11
third_party/rust/getrandom/src/bsd_arandom.rs
vendored
11
third_party/rust/getrandom/src/bsd_arandom.rs
vendored
|
|
@ -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(())
|
||||
}
|
||||
|
|
|
|||
25
third_party/rust/getrandom/src/cloudabi.rs
vendored
25
third_party/rust/getrandom/src/cloudabi.rs
vendored
|
|
@ -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
102
third_party/rust/getrandom/src/custom.rs
vendored
Normal 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)),
|
||||
}
|
||||
}
|
||||
26
third_party/rust/getrandom/src/dragonfly.rs
vendored
Normal file
26
third_party/rust/getrandom/src/dragonfly.rs
vendored
Normal 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)
|
||||
}
|
||||
}
|
||||
14
third_party/rust/getrandom/src/dummy.rs
vendored
14
third_party/rust/getrandom/src/dummy.rs
vendored
|
|
@ -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)
|
||||
}
|
||||
104
third_party/rust/getrandom/src/error.rs
vendored
104
third_party/rust/getrandom/src/error.rs
vendored
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
15
third_party/rust/getrandom/src/error_impls.rs
vendored
15
third_party/rust/getrandom/src/error_impls.rs
vendored
|
|
@ -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() {
|
||||
|
|
|
|||
26
third_party/rust/getrandom/src/espidf.rs
vendored
Normal file
26
third_party/rust/getrandom/src/espidf.rs
vendored
Normal 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(())
|
||||
}
|
||||
20
third_party/rust/getrandom/src/ios.rs
vendored
20
third_party/rust/getrandom/src/ios.rs
vendored
|
|
@ -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
129
third_party/rust/getrandom/src/js.rs
vendored
Normal 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;
|
||||
}
|
||||
353
third_party/rust/getrandom/src/lib.rs
vendored
353
third_party/rust/getrandom/src/lib.rs
vendored
|
|
@ -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 | `*‑apple‑darwin` | [`getentropy`][3] if available, otherwise [`/dev/random`][4] (identical to `/dev/urandom`)
|
||||
//! | iOS | `*‑apple‑ios` | [`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 | `*‑wrs‑vxworks‑*` | `randABytes` after checking entropy pool initialization with `randSecure`
|
||||
//! | ESP-IDF | `*‑espidf` | [`esp_fill_random`]
|
||||
//! | Emscripten | `*‑emscripten` | `/dev/random` (identical to `/dev/urandom`)
|
||||
//! | WASI | `wasm32‑wasi` | [`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§ion=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§ion=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(());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
11
third_party/rust/getrandom/src/macos.rs
vendored
11
third_party/rust/getrandom/src/macos.rs
vendored
|
|
@ -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(())
|
||||
|
|
|
|||
7
third_party/rust/getrandom/src/openbsd.rs
vendored
7
third_party/rust/getrandom/src/openbsd.rs
vendored
|
|
@ -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(())
|
||||
|
|
|
|||
31
third_party/rust/getrandom/src/rdrand.rs
vendored
31
third_party/rust/getrandom/src/rdrand.rs
vendored
|
|
@ -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 Developer’s 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
|
||||
|
|
|
|||
|
|
@ -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
26
third_party/rust/getrandom/src/solid.rs
vendored
Normal 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())
|
||||
}
|
||||
}
|
||||
22
third_party/rust/getrandom/src/use_file.rs
vendored
22
third_party/rust/getrandom/src/use_file.rs
vendored
|
|
@ -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();
|
||||
|
|
|
|||
33
third_party/rust/getrandom/src/util_libc.rs
vendored
33
third_party/rust/getrandom/src/util_libc.rs
vendored
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
5
third_party/rust/getrandom/src/vxworks.rs
vendored
5
third_party/rust/getrandom/src/vxworks.rs
vendored
|
|
@ -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;
|
||||
|
|
|
|||
8
third_party/rust/getrandom/src/wasi.rs
vendored
8
third_party/rust/getrandom/src/wasi.rs
vendored
|
|
@ -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()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
128
third_party/rust/getrandom/src/wasm32_bindgen.rs
vendored
128
third_party/rust/getrandom/src/wasm32_bindgen.rs
vendored
|
|
@ -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;
|
||||
}
|
||||
114
third_party/rust/getrandom/src/wasm32_stdweb.rs
vendored
114
third_party/rust/getrandom/src/wasm32_stdweb.rs
vendored
|
|
@ -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(())
|
||||
}
|
||||
36
third_party/rust/getrandom/src/windows.rs
vendored
36
third_party/rust/getrandom/src/windows.rs
vendored
|
|
@ -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(())
|
||||
|
|
|
|||
59
third_party/rust/getrandom/src/windows_uwp.rs
vendored
59
third_party/rust/getrandom/src/windows_uwp.rs
vendored
|
|
@ -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(())
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
});
|
||||
50
third_party/rust/getrandom/tests/custom.rs
vendored
Normal file
50
third_party/rust/getrandom/tests/custom.rs
vendored
Normal 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()));
|
||||
}
|
||||
11
third_party/rust/getrandom/tests/normal.rs
vendored
Normal file
11
third_party/rust/getrandom/tests/normal.rs
vendored
Normal 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;
|
||||
15
third_party/rust/getrandom/tests/rdrand.rs
vendored
Normal file
15
third_party/rust/getrandom/tests/rdrand.rs
vendored
Normal 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;
|
||||
2
third_party/rust/rand/.cargo-checksum.json
vendored
2
third_party/rust/rand/.cargo-checksum.json
vendored
|
|
@ -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"}
|
||||
107
third_party/rust/rand/CHANGELOG.md
vendored
107
third_party/rust/rand/CHANGELOG.md
vendored
|
|
@ -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
388
third_party/rust/rand/Cargo.lock
generated
vendored
|
|
@ -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"
|
||||
69
third_party/rust/rand/Cargo.toml
vendored
69
third_party/rust/rand/Cargo.toml
vendored
|
|
@ -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"
|
||||
|
|
|
|||
25
third_party/rust/rand/LICENSE-APACHE
vendored
25
third_party/rust/rand/LICENSE-APACHE
vendored
|
|
@ -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.
|
||||
|
|
|
|||
130
third_party/rust/rand/README.md
vendored
130
third_party/rust/rand/README.md
vendored
|
|
@ -1,26 +1,47 @@
|
|||
# Rand
|
||||
|
||||
[](https://travis-ci.org/rust-random/rand)
|
||||
[](https://ci.appveyor.com/project/rust-random/rand)
|
||||
[](https://github.com/rust-random/rand/actions)
|
||||
[](https://crates.io/crates/rand)
|
||||
[](https://rust-random.github.io/book/)
|
||||
[](https://rust-random.github.io/rand)
|
||||
[](https://rust-random.github.io/rand/rand)
|
||||
[](https://docs.rs/rand)
|
||||
[](https://github.com/rust-random/rand#rust-version-requirements)
|
||||
[](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
|
||||
|
|
|
|||
69
third_party/rust/rand/SECURITY.md
vendored
69
third_party/rust/rand/SECURITY.md
vendored
|
|
@ -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).
|
||||
165
third_party/rust/rand/benches/generators.rs
vendored
165
third_party/rust/rand/benches/generators.rs
vendored
|
|
@ -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);
|
||||
140
third_party/rust/rand/benches/misc.rs
vendored
140
third_party/rust/rand/benches/misc.rs
vendored
|
|
@ -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;
|
||||
}
|
||||
179
third_party/rust/rand/benches/seq.rs
vendored
179
third_party/rust/rand/benches/seq.rs
vendored
|
|
@ -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);
|
||||
36
third_party/rust/rand/benches/weighted.rs
vendored
36
third_party/rust/rand/benches/weighted.rs
vendored
|
|
@ -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)
|
||||
})
|
||||
}
|
||||
51
third_party/rust/rand/examples/monte-carlo.rs
vendored
51
third_party/rust/rand/examples/monte-carlo.rs
vendored
|
|
@ -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)
|
||||
);
|
||||
}
|
||||
123
third_party/rust/rand/examples/monty-hall.rs
vendored
123
third_party/rust/rand/examples/monty-hall.rs
vendored
|
|
@ -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
|
||||
);
|
||||
}
|
||||
32
third_party/rust/rand/rustfmt.toml
vendored
32
third_party/rust/rand/rustfmt.toml
vendored
|
|
@ -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 = []
|
||||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
321
third_party/rust/rand/src/distributions/binomial.rs
vendored
321
third_party/rust/rand/src/distributions/binomial.rs
vendored
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
126
third_party/rust/rand/src/distributions/dirichlet.rs
vendored
126
third_party/rust/rand/src/distributions/dirichlet.rs
vendored
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
272
third_party/rust/rand/src/distributions/distribution.rs
vendored
Normal file
272
third_party/rust/rand/src/distributions/distribution.rs
vendored
Normal 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()));
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
373
third_party/rust/rand/src/distributions/gamma.rs
vendored
373
third_party/rust/rand/src/distributions/gamma.rs
vendored
|
|
@ -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.);
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
286
third_party/rust/rand/src/distributions/mod.rs
vendored
286
third_party/rust/rand/src/distributions/mod.rs
vendored
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
177
third_party/rust/rand/src/distributions/normal.rs
vendored
177
third_party/rust/rand/src/distributions/normal.rs
vendored
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
110
third_party/rust/rand/src/distributions/other.rs
vendored
110
third_party/rust/rand/src/distributions/other.rs
vendored
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
151
third_party/rust/rand/src/distributions/poisson.rs
vendored
151
third_party/rust/rand/src/distributions/poisson.rs
vendored
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
117
third_party/rust/rand/src/distributions/slice.rs
vendored
Normal file
117
third_party/rust/rand/src/distributions/slice.rs
vendored
Normal 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 {}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
386
third_party/rust/rand/src/distributions/uniform.rs
vendored
386
third_party/rust/rand/src/distributions/uniform.rs
vendored
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
132
third_party/rust/rand/src/distributions/utils.rs
vendored
132
third_party/rust/rand/src/distributions/utils.rs
vendored
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.);
|
||||
}
|
||||
}
|
||||
}
|
||||
47
third_party/rust/rand/src/distributions/weighted.rs
vendored
Normal file
47
third_party/rust/rand/src/distributions/weighted.rs
vendored
Normal 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,);
|
||||
}
|
||||
|
|
@ -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,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
@ -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",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -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];
|
||||
599
third_party/rust/rand/src/lib.rs
vendored
599
third_party/rust/rand/src/lib.rs
vendored
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
5
third_party/rust/rand/src/prelude.rs
vendored
5
third_party/rust/rand/src/prelude.rs
vendored
|
|
@ -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
600
third_party/rust/rand/src/rng.rs
vendored
Normal 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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
37
third_party/rust/rand/src/rngs/adapter/read.rs
vendored
37
third_party/rust/rand/src/rngs/adapter/read.rs
vendored
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
76
third_party/rust/rand/src/rngs/entropy.rs
vendored
76
third_party/rust/rand/src/rngs/entropy.rs
vendored
|
|
@ -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
|
||||
}
|
||||
}
|
||||
22
third_party/rust/rand/src/rngs/mock.rs
vendored
22
third_party/rust/rand/src/rngs/mock.rs
vendored
|
|
@ -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);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
25
third_party/rust/rand/src/rngs/mod.rs
vendored
25
third_party/rust/rand/src/rngs/mod.rs
vendored
|
|
@ -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;
|
||||
|
|
|
|||
40
third_party/rust/rand/src/rngs/small.rs
vendored
40
third_party/rust/rand/src/rngs/small.rs
vendored
|
|
@ -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 {
|
||||
|
|
|
|||
21
third_party/rust/rand/src/rngs/std.rs
vendored
21
third_party/rust/rand/src/rngs/std.rs
vendored
|
|
@ -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);
|
||||
|
|
|
|||
67
third_party/rust/rand/src/rngs/thread.rs
vendored
67
third_party/rust/rand/src/rngs/thread.rs
vendored
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
118
third_party/rust/rand/src/rngs/xoshiro128plusplus.rs
vendored
Normal file
118
third_party/rust/rand/src/rngs/xoshiro128plusplus.rs
vendored
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
122
third_party/rust/rand/src/rngs/xoshiro256plusplus.rs
vendored
Normal file
122
third_party/rust/rand/src/rngs/xoshiro256plusplus.rs
vendored
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
266
third_party/rust/rand/src/seq/index.rs
vendored
266
third_party/rust/rand/src/seq/index.rs
vendored
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
540
third_party/rust/rand/src/seq/mod.rs
vendored
540
third_party/rust/rand/src/seq/mod.rs
vendored
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"}
|
||||
13
third_party/rust/rand_chacha/CHANGELOG.md
vendored
13
third_party/rust/rand_chacha/CHANGELOG.md
vendored
|
|
@ -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)
|
||||
|
|
|
|||
25
third_party/rust/rand_chacha/Cargo.toml
vendored
25
third_party/rust/rand_chacha/Cargo.toml
vendored
|
|
@ -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"
|
||||
|
|
|
|||
5
third_party/rust/rand_chacha/README.md
vendored
5
third_party/rust/rand_chacha/README.md
vendored
|
|
@ -1,12 +1,11 @@
|
|||
# rand_chacha
|
||||
|
||||
[](https://travis-ci.org/rust-random/rand)
|
||||
[](https://ci.appveyor.com/project/rust-random/rand)
|
||||
[](https://github.com/rust-random/rand/actions)
|
||||
[](https://crates.io/crates/rand_chacha)
|
||||
[](https://rust-random.github.io/book/)
|
||||
[](https://rust-random.github.io/rand/rand_chacha)
|
||||
[](https://docs.rs/rand_chacha)
|
||||
[](https://github.com/rust-random/rand#rust-version-requirements)
|
||||
[](https://github.com/rust-random/rand#rust-version-requirements)
|
||||
|
||||
A cryptographically secure random number generator that uses the ChaCha
|
||||
algorithm.
|
||||
|
|
|
|||
203
third_party/rust/rand_chacha/src/chacha.rs
vendored
203
third_party/rust/rand_chacha/src/chacha.rs
vendored
|
|
@ -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
Loading…
Reference in a new issue