diff --git a/Cargo.lock b/Cargo.lock index fed1edf4ce2f..5a2ed2028803 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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" diff --git a/Cargo.toml b/Cargo.toml index 3d661c65ebf9..807e9a1c166f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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" } diff --git a/build/rust/rand/Cargo.toml b/build/rust/rand/Cargo.toml new file mode 100644 index 000000000000..a934a92c4006 --- /dev/null +++ b/build/rust/rand/Cargo.toml @@ -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"] diff --git a/build/rust/rand/lib.rs b/build/rust/rand/lib.rs new file mode 100644 index 000000000000..14be7b7d8c66 --- /dev/null +++ b/build/rust/rand/lib.rs @@ -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::*; diff --git a/third_party/rust/getrandom/.cargo-checksum.json b/third_party/rust/getrandom/.cargo-checksum.json index 15526293475f..7bdcc1bc4ff2 100644 --- a/third_party/rust/getrandom/.cargo-checksum.json +++ b/third_party/rust/getrandom/.cargo-checksum.json @@ -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"} \ No newline at end of file +{"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"} \ No newline at end of file diff --git a/third_party/rust/getrandom/CHANGELOG.md b/third_party/rust/getrandom/CHANGELOG.md index 6de07983de05..4ab267ae06cd 100644 --- a/third_party/rust/getrandom/CHANGELOG.md +++ b/third_party/rust/getrandom/CHANGELOG.md @@ -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 diff --git a/third_party/rust/getrandom/Cargo.toml b/third_party/rust/getrandom/Cargo.toml index e3f413ae4243..0a664244e753 100644 --- a/third_party/rust/getrandom/Cargo.toml +++ b/third_party/rust/getrandom/Cargo.toml @@ -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 diff --git a/third_party/rust/getrandom/README.md b/third_party/rust/getrandom/README.md index 01bbfb5ef967..df2307b9ce31 100644 --- a/third_party/rust/getrandom/README.md +++ b/third_party/rust/getrandom/README.md @@ -1,10 +1,18 @@ # getrandom -[![Build Status](https://travis-ci.org/rust-random/getrandom.svg?branch=master)](https://travis-ci.org/rust-random/getrandom) -[![Build Status](https://ci.appveyor.com/api/projects/status/github/rust-random/getrandom?svg=true)](https://ci.appveyor.com/project/rust-random/getrandom) -[![Crate](https://img.shields.io/crates/v/getrandom.svg)](https://crates.io/crates/getrandom) -[![Documentation](https://docs.rs/getrandom/badge.svg)](https://docs.rs/getrandom) -[![Dependency status](https://deps.rs/repo/github/rust-random/getrandom/status.svg)](https://deps.rs/repo/github/rust-random/getrandom) +[![Build Status]][GitHub Actions] [![Crate]][crates.io] [![Documentation]][docs.rs] [![Dependency Status]][deps.rs] [![Downloads]][crates.io] [![License]][LICENSE-MIT] + +[GitHub Actions]: https://github.com/rust-random/getrandom/actions?query=workflow:Tests+branch:master +[Build Status]: https://github.com/rust-random/getrandom/workflows/Tests/badge.svg?branch=master +[crates.io]: https://crates.io/crates/getrandom +[Crate]: https://img.shields.io/crates/v/getrandom +[docs.rs]: https://docs.rs/getrandom +[Documentation]: https://docs.rs/getrandom/badge.svg +[deps.rs]: https://deps.rs/repo/github/rust-random/getrandom +[Dependency Status]: https://deps.rs/repo/github/rust-random/getrandom/status.svg +[Downloads]: https://img.shields.io/crates/d/getrandom +[LICENSE-MIT]: https://raw.githubusercontent.com/rust-random/getrandom/master/LICENSE-MIT +[License]: https://img.shields.io/crates/l/getrandom A Rust library for retrieving random data from (operating) system source. It is @@ -24,7 +32,7 @@ Add this to your `Cargo.toml`: ```toml [dependencies] -getrandom = "0.1" +getrandom = "0.2" ``` Then invoke the `getrandom` function: @@ -37,36 +45,14 @@ fn get_random_buf() -> Result<[u8; 32], getrandom::Error> { } ``` -## Features - -This library is `no_std` for every supported target. However, getting randomness -usually requires calling some external system API. This means most platforms -will require linking against system libraries (i.e. `libc` for Unix, -`Advapi32.dll` for Windows, Security framework on iOS, etc...). - -The `log` library is supported as an optional dependency. If enabled, error -reporting will be improved on some platforms. - -For the `wasm32-unknown-unknown` target, one of the following features should be -enabled: - -- [`wasm-bindgen`](https://crates.io/crates/wasm_bindgen) -- [`stdweb`](https://crates.io/crates/stdweb) - -By default, compiling `getrandom` for an unsupported target will result in -a compilation error. If you want to build an application which uses `getrandom` -for such target, you can either: -- Use [`[replace]`][replace] or [`[patch]`][patch] section in your `Cargo.toml` -to switch to a custom implementation with a support of your target. -- Enable the `dummy` feature to have getrandom use an implementation that always -fails at run-time on unsupported targets. - -[replace]: https://doc.rust-lang.org/cargo/reference/manifest.html#the-replace-section -[patch]: https://doc.rust-lang.org/cargo/reference/manifest.html#the-patch-section +For more information about supported targets, entropy sources, `no_std` targets, +crate features, WASM support and Custom RNGs see the +[`getrandom` documentation](https://docs.rs/getrandom/latest) and +[`getrandom::Error` documentation](https://docs.rs/getrandom/latest/getrandom/struct.Error.html). ## Minimum Supported Rust Version -This crate requires Rust 1.32.0 or later. +This crate requires Rust 1.34.0 or later. # License diff --git a/third_party/rust/getrandom/benches/mod.rs b/third_party/rust/getrandom/benches/mod.rs index 07953f135a36..a93e7206438d 100644 --- a/third_party/rust/getrandom/benches/mod.rs +++ b/third_party/rust/getrandom/benches/mod.rs @@ -1,5 +1,4 @@ #![feature(test)] -extern crate getrandom; extern crate test; #[bench] diff --git a/third_party/rust/getrandom/build.rs b/third_party/rust/getrandom/build.rs deleted file mode 100644 index 1beb4ed86bc2..000000000000 --- a/third_party/rust/getrandom/build.rs +++ /dev/null @@ -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"); - } -} diff --git a/third_party/rust/getrandom/src/3ds.rs b/third_party/rust/getrandom/src/3ds.rs new file mode 100644 index 000000000000..60305127e24e --- /dev/null +++ b/third_party/rust/getrandom/src/3ds.rs @@ -0,0 +1,17 @@ +// Copyright 2021 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , 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) + }) +} diff --git a/third_party/rust/getrandom/src/bsd_arandom.rs b/third_party/rust/getrandom/src/bsd_arandom.rs index eb564ffff897..f26f2609c36b 100644 --- a/third_party/rust/getrandom/src/bsd_arandom.rs +++ b/third_party/rust/getrandom/src/bsd_arandom.rs @@ -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(()) } diff --git a/third_party/rust/getrandom/src/cloudabi.rs b/third_party/rust/getrandom/src/cloudabi.rs deleted file mode 100644 index d3d09289b618..000000000000 --- a/third_party/rust/getrandom/src/cloudabi.rs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2018 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , 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 - } -} diff --git a/third_party/rust/getrandom/src/custom.rs b/third_party/rust/getrandom/src/custom.rs new file mode 100644 index 000000000000..6110b0563e27 --- /dev/null +++ b/third_party/rust/getrandom/src/custom.rs @@ -0,0 +1,102 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , 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)), + } +} diff --git a/third_party/rust/getrandom/src/dragonfly.rs b/third_party/rust/getrandom/src/dragonfly.rs new file mode 100644 index 000000000000..f27e906908e9 --- /dev/null +++ b/third_party/rust/getrandom/src/dragonfly.rs @@ -0,0 +1,26 @@ +// Copyright 2021 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , 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) + } +} diff --git a/third_party/rust/getrandom/src/dummy.rs b/third_party/rust/getrandom/src/dummy.rs deleted file mode 100644 index 0c24ba0fe568..000000000000 --- a/third_party/rust/getrandom/src/dummy.rs +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2018 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , 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) -} diff --git a/third_party/rust/getrandom/src/error.rs b/third_party/rust/getrandom/src/error.rs index 31ae24da7551..6615753768aa 100644 --- a/third_party/rust/getrandom/src/error.rs +++ b/third_party/rust/getrandom/src/error.rs @@ -5,10 +5,9 @@ // , 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`](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 { 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 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, } } diff --git a/third_party/rust/getrandom/src/error_impls.rs b/third_party/rust/getrandom/src/error_impls.rs index 007472e4156a..61f46d22797c 100644 --- a/third_party/rust/getrandom/src/error_impls.rs +++ b/third_party/rust/getrandom/src/error_impls.rs @@ -5,24 +5,13 @@ // , 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 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 for io::Error { fn from(err: Error) -> Self { match err.raw_os_error() { diff --git a/third_party/rust/getrandom/src/espidf.rs b/third_party/rust/getrandom/src/espidf.rs new file mode 100644 index 000000000000..dce8a2aa0998 --- /dev/null +++ b/third_party/rust/getrandom/src/espidf.rs @@ -0,0 +1,26 @@ +// Copyright 2021 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , 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(()) +} diff --git a/third_party/rust/getrandom/src/ios.rs b/third_party/rust/getrandom/src/ios.rs index 30c008c22800..226de16bd7eb 100644 --- a/third_party/rust/getrandom/src/ios.rs +++ b/third_party/rust/getrandom/src/ios.rs @@ -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(()) } diff --git a/third_party/rust/getrandom/src/js.rs b/third_party/rust/getrandom/src/js.rs new file mode 100644 index 000000000000..e910f2bc666e --- /dev/null +++ b/third_party/rust/getrandom/src/js.rs @@ -0,0 +1,129 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , 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 = 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 { + 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; + 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; +} diff --git a/third_party/rust/getrandom/src/lib.rs b/third_party/rust/getrandom/src/lib.rs index af55df58ad5a..888b9a51057a 100644 --- a/third_party/rust/getrandom/src/lib.rs +++ b/third_party/rust/getrandom/src/lib.rs @@ -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; - } 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; + 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 { - 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(()); } diff --git a/third_party/rust/getrandom/src/linux_android.rs b/third_party/rust/getrandom/src/linux_android.rs index a29feb5cec6d..5508fdd06ab3 100644 --- a/third_party/rust/getrandom/src/linux_android.rs +++ b/third_party/rust/getrandom/src/linux_android.rs @@ -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(); diff --git a/third_party/rust/getrandom/src/macos.rs b/third_party/rust/getrandom/src/macos.rs index c3bc53341357..585a35abd074 100644 --- a/third_party/rust/getrandom/src/macos.rs +++ b/third_party/rust/getrandom/src/macos.rs @@ -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(()) diff --git a/third_party/rust/getrandom/src/openbsd.rs b/third_party/rust/getrandom/src/openbsd.rs index e1ac179f2e04..c8d28b3d8882 100644 --- a/third_party/rust/getrandom/src/openbsd.rs +++ b/third_party/rust/getrandom/src/openbsd.rs @@ -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(()) diff --git a/third_party/rust/getrandom/src/rdrand.rs b/third_party/rust/getrandom/src/rdrand.rs index e4416821bafd..1df21e5d9d1e 100644 --- a/third_party/rust/getrandom/src/rdrand.rs +++ b/third_party/rust/getrandom/src/rdrand.rs @@ -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::(); +const WORD_SIZE: usize = mem::size_of::(); #[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 diff --git a/third_party/rust/getrandom/src/solaris_illumos.rs b/third_party/rust/getrandom/src/solaris_illumos.rs index 947312302c7d..2d1b767bb0c2 100644 --- a/third_party/rust/getrandom/src/solaris_illumos.rs +++ b/third_party/rust/getrandom/src/solaris_illumos.rs @@ -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")] diff --git a/third_party/rust/getrandom/src/solid.rs b/third_party/rust/getrandom/src/solid.rs new file mode 100644 index 000000000000..dc76aacbf3a0 --- /dev/null +++ b/third_party/rust/getrandom/src/solid.rs @@ -0,0 +1,26 @@ +// Copyright 2021 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , 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()) + } +} diff --git a/third_party/rust/getrandom/src/use_file.rs b/third_party/rust/getrandom/src/use_file.rs index 6e50955cd114..16c0216b67c1 100644 --- a/third_party/rust/getrandom/src/use_file.rs +++ b/third_party/rust/getrandom/src/use_file.rs @@ -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 { 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(); diff --git a/third_party/rust/getrandom/src/util_libc.rs b/third_party/rust/getrandom/src/util_libc.rs index 3cecb1dd674b..6df1cd7da80a 100644 --- a/third_party/rust/getrandom/src/util_libc.rs +++ b/third_party/rust/getrandom/src/util_libc.rs @@ -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 { - debug_assert!(path.as_bytes().last() == Some(&0)); - let fd = open(path.as_ptr() as *const _, libc::O_RDONLY | libc::O_CLOEXEC); - if fd < 0 { - return Err(last_os_error()); + 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 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) } diff --git a/third_party/rust/getrandom/src/vxworks.rs b/third_party/rust/getrandom/src/vxworks.rs index a2fe52ada851..6cb5d52fefa1 100644 --- a/third_party/rust/getrandom/src/vxworks.rs +++ b/third_party/rust/getrandom/src/vxworks.rs @@ -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; diff --git a/third_party/rust/getrandom/src/wasi.rs b/third_party/rust/getrandom/src/wasi.rs index 4674f43960b8..2d413e020cd8 100644 --- a/third_party/rust/getrandom/src/wasi.rs +++ b/third_party/rust/getrandom/src/wasi.rs @@ -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| { - // convert wasi's Error into getrandom's NonZeroU32 error - NonZeroU32::new(e.raw_error() as u32).unwrap().into() - }) + unsafe { + random_get(dest.as_mut_ptr(), dest.len()).map_err(|e: wasi::Error| { + // convert wasi's Error into getrandom's NonZeroU32 error + // SAFETY: `wasi::Error` is `NonZeroU16` internally, so `e.raw_error()` + // will never return 0 + NonZeroU32::new_unchecked(e.raw_error() as u32).into() + }) + } } diff --git a/third_party/rust/getrandom/src/wasm32_bindgen.rs b/third_party/rust/getrandom/src/wasm32_bindgen.rs deleted file mode 100644 index 77088ffa4d72..000000000000 --- a/third_party/rust/getrandom/src/wasm32_bindgen.rs +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright 2018 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , 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> = RefCell::new(None); -); - -pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { - assert_eq!(mem::size_of::(), 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 { - 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; - - 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; -} diff --git a/third_party/rust/getrandom/src/wasm32_stdweb.rs b/third_party/rust/getrandom/src/wasm32_stdweb.rs deleted file mode 100644 index 6e5e78a4a678..000000000000 --- a/third_party/rust/getrandom/src/wasm32_stdweb.rs +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright 2018 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , 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::(), 4); - static ONCE: Once = Once::new(); - static mut RNG_SOURCE: Result = 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 { - 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(()) -} diff --git a/third_party/rust/getrandom/src/windows.rs b/third_party/rust/getrandom/src/windows.rs index e1b8df6637e5..643badd07caa 100644 --- a/third_party/rust/getrandom/src/windows.rs +++ b/third_party/rust/getrandom/src/windows.rs @@ -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(()) diff --git a/third_party/rust/getrandom/src/windows_uwp.rs b/third_party/rust/getrandom/src/windows_uwp.rs deleted file mode 100644 index 586c6f61c240..000000000000 --- a/third_party/rust/getrandom/src/windows_uwp.rs +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2018 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , 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(()) -} diff --git a/third_party/rust/getrandom/tests/common.rs b/third_party/rust/getrandom/tests/common/mod.rs similarity index 66% rename from third_party/rust/getrandom/tests/common.rs rename to third_party/rust/getrandom/tests/common/mod.rs index b9859eeffe57..006f230d7cf2 100644 --- a/third_party/rust/getrandom/tests/common.rs +++ b/third_party/rust/getrandom/tests/common/mod.rs @@ -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(); } }); diff --git a/third_party/rust/getrandom/tests/custom.rs b/third_party/rust/getrandom/tests/custom.rs new file mode 100644 index 000000000000..62eae1d66193 --- /dev/null +++ b/third_party/rust/getrandom/tests/custom.rs @@ -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())); +} diff --git a/third_party/rust/getrandom/tests/normal.rs b/third_party/rust/getrandom/tests/normal.rs new file mode 100644 index 000000000000..5fff13b38e8b --- /dev/null +++ b/third_party/rust/getrandom/tests/normal.rs @@ -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; diff --git a/third_party/rust/getrandom/tests/rdrand.rs b/third_party/rust/getrandom/tests/rdrand.rs new file mode 100644 index 000000000000..4ff85c47f87b --- /dev/null +++ b/third_party/rust/getrandom/tests/rdrand.rs @@ -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; diff --git a/third_party/rust/rand/.cargo-checksum.json b/third_party/rust/rand/.cargo-checksum.json index 2caa32ef0920..6e76c5887de0 100644 --- a/third_party/rust/rand/.cargo-checksum.json +++ b/third_party/rust/rand/.cargo-checksum.json @@ -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"} \ No newline at end of file +{"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"} \ No newline at end of file diff --git a/third_party/rust/rand/CHANGELOG.md b/third_party/rust/rand/CHANGELOG.md index b519d4836d63..b0872af6d398 100644 --- a/third_party/rust/rand/CHANGELOG.md +++ b/third_party/rust/rand/CHANGELOG.md @@ -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 diff --git a/third_party/rust/rand/Cargo.lock b/third_party/rust/rand/Cargo.lock deleted file mode 100644 index a03987b58695..000000000000 --- a/third_party/rust/rand/Cargo.lock +++ /dev/null @@ -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" diff --git a/third_party/rust/rand/Cargo.toml b/third_party/rust/rand/Cargo.toml index 78a29b0e11f8..3f38081ee099 100644 --- a/third_party/rust/rand/Cargo.toml +++ b/third_party/rust/rand/Cargo.toml @@ -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" diff --git a/third_party/rust/rand/LICENSE-APACHE b/third_party/rust/rand/LICENSE-APACHE index 17d74680f8cf..494ad3bfdfe4 100644 --- a/third_party/rust/rand/LICENSE-APACHE +++ b/third_party/rust/rand/LICENSE-APACHE @@ -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. diff --git a/third_party/rust/rand/README.md b/third_party/rust/rand/README.md index c4bd676a98cf..44c2e4d518ed 100644 --- a/third_party/rust/rand/README.md +++ b/third_party/rust/rand/README.md @@ -1,26 +1,47 @@ # Rand -[![Build Status](https://travis-ci.org/rust-random/rand.svg?branch=master)](https://travis-ci.org/rust-random/rand) -[![Build Status](https://ci.appveyor.com/api/projects/status/github/rust-random/rand?svg=true)](https://ci.appveyor.com/project/rust-random/rand) +[![Test Status](https://github.com/rust-random/rand/workflows/Tests/badge.svg?event=push)](https://github.com/rust-random/rand/actions) [![Crate](https://img.shields.io/crates/v/rand.svg)](https://crates.io/crates/rand) [![Book](https://img.shields.io/badge/book-master-yellow.svg)](https://rust-random.github.io/book/) -[![API](https://img.shields.io/badge/api-master-yellow.svg)](https://rust-random.github.io/rand) +[![API](https://img.shields.io/badge/api-master-yellow.svg)](https://rust-random.github.io/rand/rand) [![API](https://docs.rs/rand/badge.svg)](https://docs.rs/rand) -[![Minimum rustc version](https://img.shields.io/badge/rustc-1.32+-lightgray.svg)](https://github.com/rust-random/rand#rust-version-requirements) +[![Minimum rustc version](https://img.shields.io/badge/rustc-1.36+-lightgray.svg)](https://github.com/rust-random/rand#rust-version-requirements) -A Rust library for random number generation. +A Rust library for random number generation, featuring: -Rand provides utilities to generate random numbers, to convert them to useful -types and distributions, and some randomness-related algorithms. +- Easy random value generation and usage via the [`Rng`](https://docs.rs/rand/*/rand/trait.Rng.html), + [`SliceRandom`](https://docs.rs/rand/*/rand/seq/trait.SliceRandom.html) and + [`IteratorRandom`](https://docs.rs/rand/*/rand/seq/trait.IteratorRandom.html) traits +- Secure seeding via the [`getrandom` crate](https://crates.io/crates/getrandom) + and fast, convenient generation via [`thread_rng`](https://docs.rs/rand/*/rand/fn.thread_rng.html) +- A modular design built over [`rand_core`](https://crates.io/crates/rand_core) + ([see the book](https://rust-random.github.io/book/crates.html)) +- Fast implementations of the best-in-class [cryptographic](https://rust-random.github.io/book/guide-rngs.html#cryptographically-secure-pseudo-random-number-generators-csprngs) and + [non-cryptographic](https://rust-random.github.io/book/guide-rngs.html#basic-pseudo-random-number-generators-prngs) generators +- A flexible [`distributions`](https://docs.rs/rand/*/rand/distributions/index.html) module +- Samplers for a large number of random number distributions via our own + [`rand_distr`](https://docs.rs/rand_distr) and via + the [`statrs`](https://docs.rs/statrs/0.13.0/statrs/) +- [Portably reproducible output](https://rust-random.github.io/book/portability.html) +- `#[no_std]` compatibility (partial) +- *Many* performance optimisations -The core random number generation traits of Rand live in the [rand_core]( -https://crates.io/crates/rand_core) crate but are also exposed here; RNG -implementations should prefer to use `rand_core` while most other users should -depend on `rand`. +It's also worth pointing out what `rand` *is not*: + +- Small. Most low-level crates are small, but the higher-level `rand` and + `rand_distr` each contain a lot of functionality. +- Simple (implementation). We have a strong focus on correctness, speed and flexibility, but + not simplicity. If you prefer a small-and-simple library, there are + alternatives including [fastrand](https://crates.io/crates/fastrand) + and [oorandom](https://crates.io/crates/oorandom). +- Slow. We take performance seriously, with considerations also for set-up + time of new distributions, commonly-used parameters, and parameters of the + current sampler. Documentation: + - [The Rust Rand Book](https://rust-random.github.io/book) -- [API reference (master)](https://rust-random.github.io/rand) +- [API reference (master branch)](https://rust-random.github.io/rand) - [API reference (docs.rs)](https://docs.rs/rand) @@ -30,7 +51,7 @@ Add this to your `Cargo.toml`: ```toml [dependencies] -rand = "0.7" +rand = "0.8.4" ``` To get started using Rand, see [The Book](https://rust-random.github.io/book). @@ -38,6 +59,27 @@ To get started using Rand, see [The Book](https://rust-random.github.io/book). ## Versions +Rand is *mature* (suitable for general usage, with infrequent breaking releases +which minimise breakage) but not yet at 1.0. We maintain compatibility with +pinned versions of the Rust compiler (see below). + +Current Rand versions are: + +- Version 0.7 was released in June 2019, moving most non-uniform distributions + to an external crate, moving `from_entropy` to `SeedableRng`, and many small + changes and fixes. +- Version 0.8 was released in December 2020 with many small changes. + +A detailed [changelog](CHANGELOG.md) is available for releases. + +When upgrading to the next minor series (especially 0.4 → 0.5), we recommend +reading the [Upgrade Guide](https://rust-random.github.io/book/update.html). + +Rand has not yet reached 1.0 implying some breaking changes may arrive in the +future ([SemVer](https://semver.org/) allows each 0.x.0 release to include +breaking changes), but is considered *mature*: breaking changes are minimised +and breaking releases are infrequent. + Rand libs have inter-dependencies and make use of the [semver trick](https://github.com/dtolnay/semver-trick/) in order to make traits compatible across crate versions. (This is especially important for `RngCore` @@ -47,26 +89,6 @@ depending on the *next* lib version (e.g. `rand_core` versions `0.2.2` and `rand_core_0_3_0::SeedableRng` are distinct, incompatible traits, which can cause build errors. Usually, running `cargo update` is enough to fix any issues. -The Rand lib is not yet stable, however we are careful to limit breaking changes -and warn via deprecation wherever possible. Patch versions never introduce -breaking changes. The following minor versions are supported: - -- Version 0.7 was released in June 2019, moving most non-uniform distributions - to an external crate, moving `from_entropy` to `SeedableRng`, and many small - changes and fixes. -- Version 0.6 was released in November 2018, redesigning the `seq` module, - moving most PRNGs to external crates, and many small changes. -- Version 0.5 was released in May 2018, as a major reorganisation - (introducing `RngCore` and `rand_core`, and deprecating `Rand` and the - previous distribution traits). -- Version 0.4 was released in December 2017, but contained almost no breaking - changes from the 0.3 series. - -A detailed [changelog](CHANGELOG.md) is available. - -When upgrading to the next minor series (especially 0.4 → 0.5), we recommend -reading the [Upgrade Guide](https://rust-random.github.io/book/update.html). - ### Yanked versions Some versions of Rand crates have been yanked ("unreleased"). Where this occurs, @@ -75,14 +97,14 @@ issue tracker with the keyword `yank` *should* uncover the motivation. ### Rust version requirements -Since version 0.7, Rand requires **Rustc version 1.32 or greater**. -Rand 0.5 requires Rustc 1.22 or greater while versions -0.4 and 0.3 (since approx. June 2017) require Rustc version 1.15 or -greater. Subsets of the Rand code may work with older Rust versions, but this -is not supported. +Since version 0.8, Rand requires **Rustc version 1.36 or greater**. +Rand 0.7 requires Rustc 1.32 or greater while versions 0.5 require Rustc 1.22 or +greater, and 0.4 and 0.3 (since approx. June 2017) require Rustc version 1.15 or +greater. Subsets of the Rand code may work with older Rust versions, but this is +not supported. -Travis CI always has a build with a pinned version of Rustc matching the oldest -supported Rust release. The current policy is that this can be updated in any +Continuous Integration (CI) will always test the minimum supported Rustc version +(the MSRV). The current policy is that this can be updated in any Rand release if required, but the change must be noted in the changelog. ## Crate Features @@ -90,26 +112,28 @@ Rand release if required, but the change must be noted in the changelog. Rand is built with these features enabled by default: - `std` enables functionality dependent on the `std` lib -- `alloc` (implied by `std`) enables functionality requiring an allocator (when using this feature in `no_std`, Rand requires Rustc version 1.36 or greater) +- `alloc` (implied by `std`) enables functionality requiring an allocator - `getrandom` (implied by `std`) is an optional dependency providing the code behind `rngs::OsRng` +- `std_rng` enables inclusion of `StdRng`, `thread_rng` and `random` + (the latter two *also* require that `std` be enabled) Optionally, the following dependencies can be enabled: - `log` enables logging via the `log` crate -- `stdweb` implies `getrandom/stdweb` to enable - `getrandom` support on `wasm32-unknown-unknown` - (will be removed in rand 0.8; activate via `getrandom` crate instead) -- `wasm-bindgen` implies `getrandom/wasm-bindgen` to enable - `getrandom` support on `wasm32-unknown-unknown` - (will be removed in rand 0.8; activate via `getrandom` crate instead) Additionally, these features configure Rand: - `small_rng` enables inclusion of the `SmallRng` PRNG -- `nightly` enables all experimental features +- `nightly` enables some optimizations requiring nightly Rust - `simd_support` (experimental) enables sampling of SIMD values - (uniformly random SIMD integers and floats) + (uniformly random SIMD integers and floats), requiring nightly Rust +- `min_const_gen` enables generating random arrays of + any size using min-const-generics, requiring Rust ≥ 1.51. + +Note that nightly features are not stable and therefore not all library and +compiler versions will be compatible. This is especially true of Rand's +experimental `simd_support` feature. Rand supports limited functionality in `no_std` mode (enabled via `default-features = false`). In this case, `OsRng` and `from_entropy` are @@ -117,6 +141,14 @@ unavailable (unless `getrandom` is enabled), large parts of `seq` are unavailable (unless `alloc` is enabled), and `thread_rng` and `random` are unavailable. +### WASM support + +The WASM target `wasm32-unknown-unknown` is not *automatically* supported by +`rand` or `getrandom`. To solve this, either use a different target such as +`wasm32-wasi` or add a direct dependency on `getrandom` with the `js` feature +(if the target supports JavaScript). See +[getrandom#WebAssembly support](https://docs.rs/getrandom/latest/getrandom/#webassembly-support). + # License Rand is distributed under the terms of both the MIT license and the diff --git a/third_party/rust/rand/SECURITY.md b/third_party/rust/rand/SECURITY.md deleted file mode 100644 index daedb78f0d30..000000000000 --- a/third_party/rust/rand/SECURITY.md +++ /dev/null @@ -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). diff --git a/third_party/rust/rand/benches/generators.rs b/third_party/rust/rand/benches/generators.rs deleted file mode 100644 index 3e264083d7da..000000000000 --- a/third_party/rust/rand/benches/generators.rs +++ /dev/null @@ -1,165 +0,0 @@ -// Copyright 2018 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , 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); diff --git a/third_party/rust/rand/benches/misc.rs b/third_party/rust/rand/benches/misc.rs deleted file mode 100644 index e46137f1981f..000000000000 --- a/third_party/rust/rand/benches/misc.rs +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright 2018 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , 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 = 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 = 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; -} diff --git a/third_party/rust/rand/benches/seq.rs b/third_party/rust/rand/benches/seq.rs deleted file mode 100644 index 7da2ff8a0fd9..000000000000 --- a/third_party/rust/rand/benches/seq.rs +++ /dev/null @@ -1,179 +0,0 @@ -// Copyright 2018 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , 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::() 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::() as u64 * crate::RAND_BENCH_N; -} - -#[derive(Clone)] -struct UnhintedIterator { - iter: I, -} -impl Iterator for UnhintedIterator { - type Item = I::Item; - - fn next(&mut self) -> Option { - self.iter.next() - } -} - -#[derive(Clone)] -struct WindowHintedIterator { - iter: I, - window_size: usize, -} -impl Iterator for WindowHintedIterator { - type Item = I::Item; - - fn next(&mut self) -> Option { - self.iter.next() - } - - fn size_hint(&self) -> (usize, Option) { - (std::cmp::min(self.iter.len(), self.window_size), None) - } -} - -#[bench] -fn seq_iter_unhinted_choose_from_1000(b: &mut Bencher) { - let mut rng = SmallRng::from_rng(thread_rng()).unwrap(); - let x: &[usize] = &[1; 1000]; - b.iter(|| { - UnhintedIterator { iter: x.iter() } - .choose(&mut rng) - .unwrap() - }) -} - -#[bench] -fn seq_iter_window_hinted_choose_from_1000(b: &mut Bencher) { - let mut rng = SmallRng::from_rng(thread_rng()).unwrap(); - let x: &[usize] = &[1; 1000]; - b.iter(|| { - WindowHintedIterator { - iter: x.iter(), - window_size: 7, - } - .choose(&mut rng) - }) -} - -#[bench] -fn seq_iter_choose_multiple_10_of_100(b: &mut Bencher) { - let mut rng = SmallRng::from_rng(thread_rng()).unwrap(); - let x: &[usize] = &[1; 100]; - b.iter(|| x.iter().cloned().choose_multiple(&mut rng, 10)) -} - -#[bench] -fn seq_iter_choose_multiple_fill_10_of_100(b: &mut Bencher) { - let mut rng = SmallRng::from_rng(thread_rng()).unwrap(); - let x: &[usize] = &[1; 100]; - let mut buf = [0; 10]; - b.iter(|| x.iter().cloned().choose_multiple_fill(&mut rng, &mut buf)) -} - -macro_rules! sample_indices { - ($name:ident, $fn:ident, $amount:expr, $length:expr) => { - #[bench] - fn $name(b: &mut Bencher) { - let mut rng = SmallRng::from_rng(thread_rng()).unwrap(); - b.iter(|| index::$fn(&mut rng, $length, $amount)) - } - }; -} - -sample_indices!(misc_sample_indices_1_of_1k, sample, 1, 1000); -sample_indices!(misc_sample_indices_10_of_1k, sample, 10, 1000); -sample_indices!(misc_sample_indices_100_of_1k, sample, 100, 1000); -sample_indices!(misc_sample_indices_100_of_1M, sample, 100, 1000_000); -sample_indices!(misc_sample_indices_100_of_1G, sample, 100, 1000_000_000); -sample_indices!(misc_sample_indices_200_of_1G, sample, 200, 1000_000_000); -sample_indices!(misc_sample_indices_400_of_1G, sample, 400, 1000_000_000); -sample_indices!(misc_sample_indices_600_of_1G, sample, 600, 1000_000_000); diff --git a/third_party/rust/rand/benches/weighted.rs b/third_party/rust/rand/benches/weighted.rs deleted file mode 100644 index 68722908a9ed..000000000000 --- a/third_party/rust/rand/benches/weighted.rs +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2019 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , 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) - }) -} diff --git a/third_party/rust/rand/examples/monte-carlo.rs b/third_party/rust/rand/examples/monte-carlo.rs deleted file mode 100644 index 70560d0fab98..000000000000 --- a/third_party/rust/rand/examples/monte-carlo.rs +++ /dev/null @@ -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 or the MIT license -// , 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) - ); -} diff --git a/third_party/rust/rand/examples/monty-hall.rs b/third_party/rust/rand/examples/monty-hall.rs deleted file mode 100644 index 30e2f44d1540..000000000000 --- a/third_party/rust/rand/examples/monty-hall.rs +++ /dev/null @@ -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 or the MIT license -// , 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(random_door: &Uniform, 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(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 { - (0..3).filter(|x| !blocked.contains(x)).collect() -} - -fn main() { - // The estimation will be more accurate with more simulations - let num_simulations = 10000; - - let mut rng = rand::thread_rng(); - let random_door = Uniform::new(0u32, 3); - - let (mut switch_wins, mut switch_losses) = (0, 0); - let (mut keep_wins, mut keep_losses) = (0, 0); - - println!("Running {} simulations...", num_simulations); - for _ in 0..num_simulations { - let result = simulate(&random_door, &mut rng); - - match (result.win, result.switch) { - (true, true) => switch_wins += 1, - (true, false) => keep_wins += 1, - (false, true) => switch_losses += 1, - (false, false) => keep_losses += 1, - } - } - - let total_switches = switch_wins + switch_losses; - let total_keeps = keep_wins + keep_losses; - - println!( - "Switched door {} times with {} wins and {} losses", - total_switches, switch_wins, switch_losses - ); - - println!( - "Kept our choice {} times with {} wins and {} losses", - total_keeps, keep_wins, keep_losses - ); - - // With a large number of simulations, the values should converge to - // 0.667 and 0.333 respectively. - println!( - "Estimated chance to win if we switch: {}", - switch_wins as f32 / total_switches as f32 - ); - println!( - "Estimated chance to win if we don't: {}", - keep_wins as f32 / total_keeps as f32 - ); -} diff --git a/third_party/rust/rand/rustfmt.toml b/third_party/rust/rand/rustfmt.toml deleted file mode 100644 index 6a2d9d482154..000000000000 --- a/third_party/rust/rand/rustfmt.toml +++ /dev/null @@ -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 = [] diff --git a/third_party/rust/rand/src/distributions/bernoulli.rs b/third_party/rust/rand/src/distributions/bernoulli.rs index a1fa86e14d4d..226db79fa9ce 100644 --- a/third_party/rust/rand/src/distributions/bernoulli.rs +++ b/third_party/rust/rand/src/distributions/bernoulli.rs @@ -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-64 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-64 in `[0, 1]` can be represented as a `f64`.) #[inline] pub fn new(p: f64) -> Result { - 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)); + } } diff --git a/third_party/rust/rand/src/distributions/binomial.rs b/third_party/rust/rand/src/distributions/binomial.rs deleted file mode 100644 index c096e4a86299..000000000000 --- a/third_party/rust/rand/src/distributions/binomial.rs +++ /dev/null @@ -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 or the MIT license -// , 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 for Binomial { - fn sample(&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(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::() / 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::() / 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); - } -} diff --git a/third_party/rust/rand/src/distributions/cauchy.rs b/third_party/rust/rand/src/distributions/cauchy.rs deleted file mode 100644 index dc54c98a35b6..000000000000 --- a/third_party/rust/rand/src/distributions/cauchy.rs +++ /dev/null @@ -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 or the MIT license -// , 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 for Cauchy { - fn sample(&self, rng: &mut R) -> f64 { - // sample from [0, 1) - let x = rng.gen::(); - // 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); - } -} diff --git a/third_party/rust/rand/src/distributions/dirichlet.rs b/third_party/rust/rand/src/distributions/dirichlet.rs deleted file mode 100644 index a75678a85046..000000000000 --- a/third_party/rust/rand/src/distributions/dirichlet.rs +++ /dev/null @@ -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 or the MIT license -// , 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, -} - -impl Dirichlet { - /// Construct a new `Dirichlet` with the given alpha parameter `alpha`. - /// - /// # Panics - /// - if `alpha.len() < 2` - #[inline] - pub fn new>>(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> for Dirichlet { - fn sample(&self, rng: &mut R) -> Vec { - 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 = 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 = samples - .into_iter() - .map(|x| { - assert!(x > 0.0); - x - }) - .collect(); - } - - #[test] - #[should_panic] - fn test_dirichlet_invalid_length() { - Dirichlet::new_with_param(0.5f64, 1); - } - - #[test] - #[should_panic] - fn test_dirichlet_invalid_alpha() { - Dirichlet::new_with_param(0.0f64, 2); - } -} diff --git a/third_party/rust/rand/src/distributions/distribution.rs b/third_party/rust/rand/src/distributions/distribution.rs new file mode 100644 index 000000000000..c5cf6a607b49 --- /dev/null +++ b/third_party/rust/rand/src/distributions/distribution.rs @@ -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 or the MIT license +// , 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 { + /// Generate a random value of `T`, using `rng` as the source of randomness. + fn sample(&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` is impl'd for `&D` where `D: Distribution`, + /// 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 = 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(self, rng: R) -> DistIter + 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(self, func: F) -> DistMap + where + F: Fn(T) -> S, + Self: Sized, + { + DistMap { + distr: self, + func, + phantom: ::core::marker::PhantomData, + } + } +} + +impl<'a, T, D: Distribution> Distribution for &'a D { + fn sample(&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 { + distr: D, + rng: R, + phantom: ::core::marker::PhantomData, +} + +impl Iterator for DistIter +where + D: Distribution, + R: Rng, +{ + type Item = T; + + #[inline(always)] + fn next(&mut self) -> Option { + // 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::max_value(), None) + } +} + +impl iter::FusedIterator for DistIter +where + D: Distribution, + R: Rng, +{ +} + +#[cfg(features = "nightly")] +impl iter::TrustedLen for DistIter +where + D: Distribution, + 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 { + distr: D, + func: F, + phantom: ::core::marker::PhantomData S>, +} + +impl Distribution for DistMap +where + D: Distribution, + F: Fn(T) -> S, +{ + fn sample(&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(&self, rng: &mut R, string: &mut String, len: usize); + + /// Generate a `String` of `len` random chars + #[inline] + fn sample_string(&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::::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( + rng: &mut R, + ) -> impl Iterator + '_ { + 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())); + } +} diff --git a/third_party/rust/rand/src/distributions/exponential.rs b/third_party/rust/rand/src/distributions/exponential.rs deleted file mode 100644 index 5fdf7aa74fb7..000000000000 --- a/third_party/rust/rand/src/distributions/exponential.rs +++ /dev/null @@ -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 or the MIT license -// , 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::().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::().ln()` but that is slower. -impl Distribution for Exp1 { - #[inline] - fn sample(&self, rng: &mut R) -> f64 { - #[inline] - fn pdf(x: f64) -> f64 { - (-x).exp() - } - #[inline] - fn zero_case(rng: &mut R, _u: f64) -> f64 { - ziggurat_tables::ZIG_EXP_R - rng.gen::().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 for Exp { - fn sample(&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); - } -} diff --git a/third_party/rust/rand/src/distributions/float.rs b/third_party/rust/rand/src/distributions/float.rs index 0a45f397743c..ce5946f7f017 100644 --- a/third_party/rust/rand/src/distributions/float.rs +++ b/third_party/rust/rand/src/distributions/float.rs @@ -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 diff --git a/third_party/rust/rand/src/distributions/gamma.rs b/third_party/rust/rand/src/distributions/gamma.rs deleted file mode 100644 index f19738dbe8eb..000000000000 --- a/third_party/rust/rand/src/distributions/gamma.rs +++ /dev/null @@ -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 or the MIT license -// , 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 for Gamma { - fn sample(&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 for GammaSmallShape { - fn sample(&self, rng: &mut R) -> f64 { - let u: f64 = rng.sample(Open01); - - self.large_shape.sample(rng) * u.powf(self.inv_shape) - } -} -impl Distribution for GammaLargeShape { - fn sample(&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 for ChiSquared { - fn sample(&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 for FisherF { - fn sample(&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 for StudentT { - fn sample(&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 for Beta { - fn sample(&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.); - } -} diff --git a/third_party/rust/rand/src/distributions/integer.rs b/third_party/rust/rand/src/distributions/integer.rs index f2db1f1c6238..19ce71599cb1 100644 --- a/third_party/rust/rand/src/distributions/integer.rs +++ b/third_party/rust/rand/src/distributions/integer.rs @@ -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 for Standard { @@ -45,7 +46,6 @@ impl Distribution for Standard { } } -#[cfg(not(target_os = "emscripten"))] impl Distribution for Standard { #[inline] fn sample(&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::(Standard); rng.sample::(Standard); rng.sample::(Standard); - #[cfg(not(target_os = "emscripten"))] rng.sample::(Standard); rng.sample::(Standard); @@ -181,7 +177,6 @@ mod tests { rng.sample::(Standard); rng.sample::(Standard); rng.sample::(Standard); - #[cfg(not(target_os = "emscripten"))] rng.sample::(Standard); } diff --git a/third_party/rust/rand/src/distributions/mod.rs b/third_party/rust/rand/src/distributions/mod.rs index 4e1b1a6e3a06..05ca80606b0b 100644 --- a/third_party/rust/rand/src/distributions/mod.rs +++ b/third_party/rust/rand/src/distributions/mod.rs @@ -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` 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`. 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` 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 { - /// Generate a random value of `T`, using `rng` as the source of randomness. - fn sample(&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` is impl'd for `&D` where `D: Distribution`, - /// 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 = 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(self, rng: R) -> DistIter - where - R: Rng, - Self: Sized, - { - DistIter { - distr: self, - rng, - phantom: ::core::marker::PhantomData, - } - } -} - -impl<'a, T, D: Distribution> Distribution for &'a D { - fn sample(&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 { - distr: D, - rng: R, - phantom: ::core::marker::PhantomData, -} - -impl Iterator for DistIter -where - D: Distribution, - R: Rng, -{ - type Item = T; - - #[inline(always)] - fn next(&mut self) -> Option { - // 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::max_value(), None) - } -} - -impl iter::FusedIterator for DistIter -where - D: Distribution, - R: Rng, -{ -} - -#[cfg(features = "nightly")] -impl iter::TrustedLen for DistIter -where - D: Distribution, - 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` 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 = 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 + '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); - } -} diff --git a/third_party/rust/rand/src/distributions/normal.rs b/third_party/rust/rand/src/distributions/normal.rs deleted file mode 100644 index ec62fa9abe99..000000000000 --- a/third_party/rust/rand/src/distributions/normal.rs +++ /dev/null @@ -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 or the MIT license -// , 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 for StandardNormal { - fn sample(&self, rng: &mut R) -> f64 { - #[inline] - fn pdf(x: f64) -> f64 { - (-x * x / 2.0).exp() - } - #[inline] - fn zero_case(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 for Normal { - fn sample(&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 for LogNormal { - fn sample(&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); - } -} diff --git a/third_party/rust/rand/src/distributions/other.rs b/third_party/rust/rand/src/distributions/other.rs index c95060e5104b..03802a76d5fe 100644 --- a/third_party/rust/rand/src/distributions/other.rs +++ b/third_party/rust/rand/src/distributions/other.rs @@ -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 for Standard { } } -impl Distribution for Alphanumeric { - fn sample(&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(&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::::sample_iter(self, rng).take(len)); + } +} + +impl Distribution for Alphanumeric { + fn sample(&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 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(&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 for Standard { #[inline] fn sample(&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 Distribution<[T; N]> for Standard +where Standard: Distribution +{ + #[inline] + fn sample(&self, _rng: &mut R) -> [T; N] { + let mut buff: [MaybeUninit; 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 Distribution> for Standard @@ -184,7 +258,7 @@ where Standard: Distribution 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::()) .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, &[ Some(true), diff --git a/third_party/rust/rand/src/distributions/pareto.rs b/third_party/rust/rand/src/distributions/pareto.rs deleted file mode 100644 index ac5473b8c84b..000000000000 --- a/third_party/rust/rand/src/distributions/pareto.rs +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2018 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , 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 xm 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 for Pareto { - fn sample(&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); - } - } -} diff --git a/third_party/rust/rand/src/distributions/poisson.rs b/third_party/rust/rand/src/distributions/poisson.rs deleted file mode 100644 index ce94d7542b36..000000000000 --- a/third_party/rust/rand/src/distributions/poisson.rs +++ /dev/null @@ -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 or the MIT license -// , 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 for Poisson { - fn sample(&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::(); - 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::() <= 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); - } -} diff --git a/third_party/rust/rand/src/distributions/slice.rs b/third_party/rust/rand/src/distributions/slice.rs new file mode 100644 index 000000000000..3302deb2a40b --- /dev/null +++ b/third_party/rust/rand/src/distributions/slice.rs @@ -0,0 +1,117 @@ +// Copyright 2021 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , 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, +} + +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 { + 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(&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 {} diff --git a/third_party/rust/rand/src/distributions/triangular.rs b/third_party/rust/rand/src/distributions/triangular.rs deleted file mode 100644 index 37be19867e8c..000000000000 --- a/third_party/rust/rand/src/distributions/triangular.rs +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2018 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , 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 for Triangular { - #[inline] - fn sample(&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); - } - } -} diff --git a/third_party/rust/rand/src/distributions/uniform.rs b/third_party/rust/rand/src/distributions/uniform.rs index 8584152f039f..261357b24564 100644 --- a/third_party/rust/rand/src/distributions/uniform.rs +++ b/third_party/rust/rand/src/distributions/uniform.rs @@ -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 + Sized, //! B2: SampleBorrow + Sized //! { -//! UniformSampler::new(low, high) +//! UniformMyF32(UniformFloat::::new_inclusive( +//! low.borrow().0, +//! high.borrow().0, +//! )) //! } //! fn sample(&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,20 +151,31 @@ 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; -/// for _ in 0..1000 { -/// sum += between.sample(&mut rng); -/// } -/// println!("{}", sum); +/// let between = Uniform::from(10..10000); +/// let mut rng = rand::thread_rng(); +/// let mut sum = 0; +/// for _ in 0..1000 { +/// sum += between.sample(&mut rng); /// } +/// println!("{}", sum); +/// ``` +/// +/// 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::Sampler); impl Uniform { @@ -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(low: B1, high: B2, rng: &mut R) + -> Self::X + where B1: SampleBorrow + Sized, + B2: SampleBorrow + Sized + { + let uniform: Self = UniformSampler::new_inclusive(low, high); + uniform.sample(rng) + } } -impl From<::core::ops::Range> for Uniform { +impl From> for Uniform { fn from(r: ::core::ops::Range) -> Uniform { Uniform::new(r.start, r.end) } } -impl From<::core::ops::RangeInclusive> for Uniform { +impl From> for Uniform { fn from(r: ::core::ops::RangeInclusive) -> Uniform { 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 { + /// Generate a sample from the given range. + fn sample_single(self, rng: &mut R) -> T; + + /// Check whether the range is empty. + fn is_empty(&self) -> bool; +} + +impl SampleRange for Range { + #[inline] + fn sample_single(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 SampleRange for RangeInclusive { + #[inline] + fn sample_single(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 { 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(&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(low_b: B1, high_b: B2, rng: &mut R) -> Self::X where B1: SampleBorrow + 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(low_b: B1, high_b: B2, rng: &mut R) -> Self::X + where + B1: SampleBorrow + Sized, + B2: SampleBorrow + 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, +} + +/// 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(low_b: B1, high_b: B2) -> Self + where + B1: SampleBorrow + Sized, + B2: SampleBorrow + Sized, + { + let low = char_to_comp_u32(*low_b.borrow()); + let high = char_to_comp_u32(*high_b.borrow()); + let sampler = UniformInt::::new(low, high); + UniformChar { sampler } + } + + #[inline] // if the range is constant, this helps LLVM to do the + // calculations at compile-time. + fn new_inclusive(low_b: B1, high_b: B2) -> Self + where + B1: SampleBorrow + Sized, + B2: SampleBorrow + Sized, + { + let low = char_to_comp_u32(*low_b.borrow()); + let high = char_to_comp_u32(*high_b.borrow()); + let sampler = UniformInt::::new_inclusive(low, high); + UniformChar { sampler } + } + + fn sample(&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 { 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 = Uniform::new(-1, 1); + let de_unit_box: Uniform = 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 = Uniform::new(-1., 1.); + let de_unit_box: Uniform = 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(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)); + } } diff --git a/third_party/rust/rand/src/distributions/unit_circle.rs b/third_party/rust/rand/src/distributions/unit_circle.rs deleted file mode 100644 index 37885d8eb8e4..000000000000 --- a/third_party/rust/rand/src/distributions/unit_circle.rs +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright 2018 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , 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(&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); - } -} diff --git a/third_party/rust/rand/src/distributions/unit_sphere.rs b/third_party/rust/rand/src/distributions/unit_sphere.rs deleted file mode 100644 index 5b8c8ad55f8a..000000000000 --- a/third_party/rust/rand/src/distributions/unit_sphere.rs +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2018 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , 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(&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); - } -} diff --git a/third_party/rust/rand/src/distributions/utils.rs b/third_party/rust/rand/src/distributions/utils.rs index 2d36b0226580..89da5fd7aad6 100644 --- a/third_party/rust/rand/src/distributions/utils.rs +++ b/third_party/rust/rand/src/distributions/utils.rs @@ -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 { +pub(crate) trait WideningMultiply { 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( - 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::() < pdf(x) { - return x; - } - } -} diff --git a/third_party/rust/rand/src/distributions/weibull.rs b/third_party/rust/rand/src/distributions/weibull.rs deleted file mode 100644 index ffbc93b01560..000000000000 --- a/third_party/rust/rand/src/distributions/weibull.rs +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2018 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , 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 for Weibull { - fn sample(&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.); - } - } -} diff --git a/third_party/rust/rand/src/distributions/weighted.rs b/third_party/rust/rand/src/distributions/weighted.rs new file mode 100644 index 000000000000..846b9df9c28b --- /dev/null +++ b/third_party/rust/rand/src/distributions/weighted.rs @@ -0,0 +1,47 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , 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 { + _phantom: PhantomData, + } + impl WeightedIndex { + pub fn new(_weights: Vec) -> Result { + 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,); +} diff --git a/third_party/rust/rand/src/distributions/weighted/alias_method.rs b/third_party/rust/rand/src/distributions/weighted/alias_method.rs deleted file mode 100644 index 7d42a35267b4..000000000000 --- a/third_party/rust/rand/src/distributions/weighted/alias_method.rs +++ /dev/null @@ -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`] distribution returns the index of a randomly -/// selected element from the vector used to create the [`WeightedIndex`]. -/// 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`], [`WeightedIndex`] 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`] with capacity `n`. -/// -/// Time complexity for the creation of a [`WeightedIndex`] is `O(n)`. -/// Sampling is `O(1)`, it makes a call to [`Uniform::sample`] and a call -/// to [`Uniform::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`]: crate::distributions::weighted::alias_method::WeightedIndex -/// [`Weight`]: crate::distributions::weighted::alias_method::Weight -/// [`Vec`]: Vec -/// [`Uniform::sample`]: Distribution::sample -/// [`Uniform::sample`]: Distribution::sample -pub struct WeightedIndex { - aliases: Vec, - no_alias_odds: Vec, - uniform_index: Uniform, - uniform_within_weight_sum: Uniform, -} - -impl WeightedIndex { - /// 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) -> Result { - 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, - 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 Distribution for WeightedIndex { - fn sample(&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 fmt::Debug for WeightedIndex -where - W: fmt::Debug, - Uniform: 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 Clone for WeightedIndex -where Uniform: 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 - + AddAssign - + Sub - + SubAssign - + Mul - + MulAssign - + Div - + 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; - - /// 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 { - 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(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 { - 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 f64>(w_to_f64: F) - where WeightedIndex: 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::(); - let expected_counts = weights - .iter() - .map(|&w| w_to_f64(w) / w_to_f64(weight_sum) * NUM_SAMPLES as f64) - .collect::>(); - 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::::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(weights: Vec, 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, - ]); - } -} diff --git a/third_party/rust/rand/src/distributions/weighted/mod.rs b/third_party/rust/rand/src/distributions/weighted_index.rs similarity index 81% rename from third_party/rust/rand/src/distributions/weighted/mod.rs rename to third_party/rust/rand/src/distributions/weighted_index.rs index 357e3a9f0243..8252b172f7f7 100644 --- a/third_party/rust/rand/src/distributions/weighted/mod.rs +++ b/third_party/rust/rand/src/distributions/weighted_index.rs @@ -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` contains a `Vec` and a [`Uniform`] 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`] doesn't allocate any memory. -/// -/// Time complexity of sampling from `WeightedIndex` is `O(log N)` where -/// `N` is the number of weights. +/// types, [`Uniform`] doesn't allocate any memory. /// /// Sampling from `WeightedIndex` will result in a single call to /// `Uniform::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::sample`. +/// exact number depends on the implementation of `Uniform::sample`. /// /// # Example /// @@ -79,9 +73,11 @@ use core::fmt; /// } /// ``` /// -/// [`Uniform`]: crate::distributions::uniform::Uniform +/// [`Uniform`]: 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 { cumulative_weights: Vec, total_weight: X, @@ -107,13 +103,15 @@ impl WeightedIndex { let mut total_weight: X = iter.next().ok_or(WeightedError::NoItem)?.borrow().clone(); let zero = ::default(); - if total_weight < zero { + if !(total_weight >= zero) { return Err(WeightedError::InvalidWeight); } let mut weights = Vec::::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 WeightedIndex { 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 WeightedIndex { 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 = + 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", + }) } } diff --git a/third_party/rust/rand/src/distributions/ziggurat_tables.rs b/third_party/rust/rand/src/distributions/ziggurat_tables.rs deleted file mode 100644 index f830a601bdd6..000000000000 --- a/third_party/rust/rand/src/distributions/ziggurat_tables.rs +++ /dev/null @@ -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 or the MIT license -// , 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]; diff --git a/third_party/rust/rand/src/lib.rs b/third_party/rust/rand/src/lib.rs index d42a79fb1242..6d847180111d 100644 --- a/third_party/rust/rand/src/lib.rs +++ b/third_party/rust/rand/src/lib.rs @@ -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(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(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(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(&mut self) -> T - where Standard: Distribution { - 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(&mut self, low: B1, high: B2) -> T - where - B1: SampleBorrow + Sized, - B2: SampleBorrow + 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::(Uniform::new(10, 15)); - /// ``` - fn sample>(&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 = 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::>()); - /// - /// // 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(self, distr: D) -> distributions::DistIter - where - D: Distribution, - 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(&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(&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 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 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`), 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` 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 where Standard: Distribution { @@ -557,8 +188,6 @@ where Standard: Distribution { #[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::(); - 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; - r.next_u32(); - r.gen::(); - 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> = 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); - } } diff --git a/third_party/rust/rand/src/prelude.rs b/third_party/rust/rand/src/prelude.rs index 98ae3bb4315d..51c457e3f9e0 100644 --- a/third_party/rust/rand/src/prelude.rs +++ b/third_party/rust/rand/src/prelude.rs @@ -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}; diff --git a/third_party/rust/rand/src/rng.rs b/third_party/rust/rand/src/rng.rs new file mode 100644 index 000000000000..79a9fbff46e0 --- /dev/null +++ b/third_party/rust/rand/src/rng.rs @@ -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 or the MIT license +// , 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(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(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(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(&mut self) -> T + where Standard: Distribution { + 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(&mut self, range: R) -> T + where + T: SampleUniform, + R: SampleRange + { + 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::(Uniform::new(10, 15)); + /// ``` + fn sample>(&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 = (&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::>()); + /// + /// // 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(self, distr: D) -> distributions::DistIter + where + D: Distribution, + 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(&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(&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 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(&mut self, rng: &mut R) -> Result<(), Error>; +} + +macro_rules! impl_fill_each { + () => {}; + ($t:ty) => { + impl Fill for [$t] { + fn try_fill(&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(&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(&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(&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 Fill for [T; N] +where [T]: Fill +{ + fn try_fill(&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 Fill for [T; $n] where [T]: Fill { + fn try_fill(&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::(); + 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; + r.next_u32(); + r.gen::(); + 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); + } +} diff --git a/third_party/rust/rand/src/rngs/adapter/mod.rs b/third_party/rust/rand/src/rngs/adapter/mod.rs index 45e56af72664..bd1d29432339 100644 --- a/third_party/rust/rand/src/rngs/adapter/mod.rs +++ b/third_party/rust/rand/src/rngs/adapter/mod.rs @@ -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; diff --git a/third_party/rust/rand/src/rngs/adapter/read.rs b/third_party/rust/rand/src/rngs/adapter/read.rs index 9a4b55d4e784..25a9ca7fca47 100644 --- a/third_party/rust/rand/src/rngs/adapter/read.rs +++ b/third_party/rust/rand/src/rngs/adapter/read.rs @@ -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::()); -/// ``` -/// /// [`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 { reader: R, } @@ -86,6 +78,7 @@ impl RngCore for ReadRng { /// `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] diff --git a/third_party/rust/rand/src/rngs/adapter/reseeding.rs b/third_party/rust/rand/src/rngs/adapter/reseeding.rs index 5460e3431f96..ae3fcbb2fc2b 100644 --- a/third_party/rust/rand/src/rngs/adapter/reseeding.rs +++ b/third_party/rust/rand/src/rngs/adapter/reseeding.rs @@ -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); diff --git a/third_party/rust/rand/src/rngs/entropy.rs b/third_party/rust/rand/src/rngs/entropy.rs deleted file mode 100644 index 9ad0d71e0cdd..000000000000 --- a/third_party/rust/rand/src/rngs/entropy.rs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2018 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , 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 - } -} diff --git a/third_party/rust/rand/src/rngs/mock.rs b/third_party/rust/rand/src/rngs/mock.rs index 9a47264a762c..a1745a490dd2 100644 --- a/third_party/rust/rand/src/rngs/mock.rs +++ b/third_party/rust/rand/src/rngs/mock.rs @@ -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); + + } +} diff --git a/third_party/rust/rand/src/rngs/mod.rs b/third_party/rust/rand/src/rngs/mod.rs index 111219602557..ac3c2c595da3 100644 --- a/third_party/rust/rand/src/rngs/mod.rs +++ b/third_party/rust/rand/src/rngs/mod.rs @@ -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; diff --git a/third_party/rust/rand/src/rngs/small.rs b/third_party/rust/rand/src/rngs/small.rs index d676898149c7..fb0e0d119b66 100644 --- a/third_party/rust/rand/src/rngs/small.rs +++ b/third_party/rust/rand/src/rngs/small.rs @@ -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 { diff --git a/third_party/rust/rand/src/rngs/std.rs b/third_party/rust/rand/src/rngs/std.rs index 8b07081a0484..cdae8fab01cb 100644 --- a/third_party/rust/rand/src/rngs/std.rs +++ b/third_party/rust/rand/src/rngs/std.rs @@ -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); diff --git a/third_party/rust/rand/src/rngs/thread.rs b/third_party/rust/rand/src/rngs/thread.rs index 91ed4c30a8ef..baebb1d99c7b 100644 --- a/third_party/rust/rand/src/rngs/thread.rs +++ b/third_party/rust/rand/src/rngs/thread.rs @@ -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>, + // Rc is explicitly !Send and !Sync + rng: Rc>>, } thread_local!( - static THREAD_RNG_KEY: UnsafeCell> = { + // We require Rc<..> to avoid premature freeing when thread_rng is used + // within thread-local destructors. See #968. + static THREAD_RNG_KEY: Rc>> = { 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::(); - assert_eq!(r.gen_range(0, 1), 0); + assert_eq!(r.gen_range(0..1), 0); } } diff --git a/third_party/rust/rand/src/rngs/xoshiro128plusplus.rs b/third_party/rust/rand/src/rngs/xoshiro128plusplus.rs new file mode 100644 index 000000000000..ece98fafd6ac --- /dev/null +++ b/third_party/rust/rand/src/rngs/xoshiro128plusplus.rs @@ -0,0 +1,118 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , 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); + } + } +} diff --git a/third_party/rust/rand/src/rngs/xoshiro256plusplus.rs b/third_party/rust/rand/src/rngs/xoshiro256plusplus.rs new file mode 100644 index 000000000000..8ffb18b80331 --- /dev/null +++ b/third_party/rust/rand/src/rngs/xoshiro256plusplus.rs @@ -0,0 +1,122 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , 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); + } + } +} diff --git a/third_party/rust/rand/src/seq/index.rs b/third_party/rust/rand/src/seq/index.rs index 551d409e71ca..b38e4649d1f0 100644 --- a/third_party/rust/rand/src/seq/index.rs +++ b/third_party/rust/rand/src/seq/index.rs @@ -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), @@ -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( + rng: &mut R, length: usize, weight: F, amount: usize, +) -> Result +where + R: Rng + ?Sized, + F: Fn(usize) -> X, + X: Into, +{ + 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( + rng: &mut R, length: N, weight: F, amount: N, +) -> Result +where + R: Rng + ?Sized, + F: Fn(usize) -> X, + X: Into, + N: UInt, + IndexVec: From>, +{ + 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 { + index: N, + key: f64, + } + impl PartialOrd for Element { + fn partial_cmp(&self, other: &Self) -> Option { + self.key.partial_cmp(&other.key) + } + } + impl Ord for Element { + 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 PartialEq for Element { + fn eq(&self, other: &Self) -> bool { + self.key == other.key + } + } + impl Eq for Element {} + + #[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::().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 = 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::().powf(1.0 / weight); + candidates.push(Element { index, key }); + + index += N::one(); + } + + let mut result: Vec = 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 = 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 + } } diff --git a/third_party/rust/rand/src/seq/mod.rs b/third_party/rust/rand/src/seq/mod.rs index dabf3292794d..069e9e6b19e6 100644 --- a/third_party/rust/rand/src/seq/mod.rs +++ b/third_party/rust/rand/src/seq/mod.rs @@ -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); -/// } +/// 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(&self, rng: &mut R, amount: usize) -> SliceChooseIter 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( &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( &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::>()); + /// ``` + /// [`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( + &self, rng: &mut R, amount: usize, weight: F, + ) -> Result, WeightedError> + where + R: Rng + ?Sized, + F: Fn(&Self::Item) -> X, + X: Into; + /// 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()); -/// } +/// 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(mut self, rng: &mut R) -> Option 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(mut self, rng: &mut R) -> Option + 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(mut self, rng: &mut R, amount: usize) -> Vec where R: Rng + ?Sized { let mut reservoir = Vec::with_capacity(amount); @@ -450,6 +560,29 @@ impl SliceRandom for [T] { Ok(&mut self[distr.sample(rng)]) } + #[cfg(feature = "std")] + fn choose_multiple_weighted( + &self, rng: &mut R, amount: usize, weight: F, + ) -> Result, WeightedError> + where + R: Rng + ?Sized, + F: Fn(&Self::Item) -> X, + X: Into, + { + 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(&mut self, rng: &mut R) where R: Rng + ?Sized { for i in (1..self.len()).rev() { @@ -487,6 +620,7 @@ impl 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 + ?Sized + 'a, T: 'a> ExactSizeIterator #[inline] fn gen_index(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::>(), + &['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 { 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 + 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::>().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 + 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::>().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>(iter: I) -> Option { + 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>(iter: I) -> Option { + 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>(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>(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::>(); + + 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::>(); + 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::>(); + + 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)); + } } diff --git a/third_party/rust/rand_chacha/.cargo-checksum.json b/third_party/rust/rand_chacha/.cargo-checksum.json index 0353160af164..a7100e9bcaf8 100644 --- a/third_party/rust/rand_chacha/.cargo-checksum.json +++ b/third_party/rust/rand_chacha/.cargo-checksum.json @@ -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"} \ No newline at end of file +{"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"} \ No newline at end of file diff --git a/third_party/rust/rand_chacha/CHANGELOG.md b/third_party/rust/rand_chacha/CHANGELOG.md index 1273895aff48..a598bb7ee6cf 100644 --- a/third_party/rust/rand_chacha/CHANGELOG.md +++ b/third_party/rust/rand_chacha/CHANGELOG.md @@ -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) diff --git a/third_party/rust/rand_chacha/Cargo.toml b/third_party/rust/rand_chacha/Cargo.toml index dea94e989cb5..c907ae97421b 100644 --- a/third_party/rust/rand_chacha/Cargo.toml +++ b/third_party/rust/rand_chacha/Cargo.toml @@ -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" diff --git a/third_party/rust/rand_chacha/README.md b/third_party/rust/rand_chacha/README.md index 69a0ce7cf2a5..edd754d791e2 100644 --- a/third_party/rust/rand_chacha/README.md +++ b/third_party/rust/rand_chacha/README.md @@ -1,12 +1,11 @@ # rand_chacha -[![Build Status](https://travis-ci.org/rust-random/rand.svg)](https://travis-ci.org/rust-random/rand) -[![Build Status](https://ci.appveyor.com/api/projects/status/github/rust-random/rand?svg=true)](https://ci.appveyor.com/project/rust-random/rand) +[![Test Status](https://github.com/rust-random/rand/workflows/Tests/badge.svg?event=push)](https://github.com/rust-random/rand/actions) [![Latest version](https://img.shields.io/crates/v/rand_chacha.svg)](https://crates.io/crates/rand_chacha) [![Book](https://img.shields.io/badge/book-master-yellow.svg)](https://rust-random.github.io/book/) [![API](https://img.shields.io/badge/api-master-yellow.svg)](https://rust-random.github.io/rand/rand_chacha) [![API](https://docs.rs/rand_chacha/badge.svg)](https://docs.rs/rand_chacha) -[![Minimum rustc version](https://img.shields.io/badge/rustc-1.32+-lightgray.svg)](https://github.com/rust-random/rand#rust-version-requirements) +[![Minimum rustc version](https://img.shields.io/badge/rustc-1.36+-lightgray.svg)](https://github.com/rust-random/rand#rust-version-requirements) A cryptographically secure random number generator that uses the ChaCha algorithm. diff --git a/third_party/rust/rand_chacha/src/chacha.rs b/third_party/rust/rand_chacha/src/chacha.rs index cf68c52c2aa8..50da81bfafe4 100644 --- a/third_party/rust/rand_chacha/src/chacha.rs +++ b/third_party/rust/rand_chacha/src/chacha.rs @@ -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; 64]); impl Default for Array64 where T: Default @@ -63,9 +68,9 @@ impl fmt::Debug for Array64 { } 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(&self, s: S) -> Result + where S: Serializer { + $abst::$ChaChaXRng::from(self).serialize(s) + } + } + #[cfg(feature = "serde1")] + impl<'de> Deserialize<'de> for $ChaChaXRng { + fn deserialize(d: D) -> Result where D: Deserializer<'de> { + $abst::$ChaChaXRng::deserialize(d).map(|x| Self::from(&x)) + } + } + + 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"); -chacha_impl!(ChaCha12Core, ChaCha12Rng, 6, "ChaCha with 12 rounds"); -chacha_impl!(ChaCha8Core, ChaCha8Rng, 4, "ChaCha with 8 rounds"); +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); + } } diff --git a/third_party/rust/rand_chacha/src/guts.rs b/third_party/rust/rand_chacha/src/guts.rs index 7561c1bcd116..cee8cf75d4c2 100644 --- a/third_party/rust/rand_chacha/src/guts.rs +++ b/third_party/rust/rand_chacha/src/guts.rs @@ -21,7 +21,10 @@ const BUFBLOCKS: u64 = 1 << LOG2_BUFBLOCKS; pub(crate) const BUFSZ64: u64 = BLOCK64 * BUFBLOCKS; pub(crate) const BUFSZ: usize = BUFSZ64 as usize; -#[derive(Clone)] +const STREAM_PARAM_NONCE: u32 = 1; +const STREAM_PARAM_BLOCK: u32 = 0; + +#[derive(Clone, PartialEq, Eq)] pub struct ChaCha { pub(crate) b: vec128_storage, pub(crate) c: vec128_storage, @@ -83,16 +86,32 @@ impl ChaCha { } #[inline(always)] - pub fn set_stream_param(&mut self, param: u32, value: u64) { - set_stream_param(self, param, value) + pub fn set_block_pos(&mut self, value: u64) { + set_stream_param(self, STREAM_PARAM_BLOCK, value) } #[inline(always)] - pub fn get_stream_param(&self, param: u32) -> u64 { - get_stream_param(self, param) + pub fn get_block_pos(&self) -> u64 { + get_stream_param(self, STREAM_PARAM_BLOCK) + } + + #[inline(always)] + pub fn set_nonce(&mut self, value: u64) { + set_stream_param(self, STREAM_PARAM_NONCE, value) + } + + #[inline(always)] + pub fn get_nonce(&self) -> u64 { + get_stream_param(self, STREAM_PARAM_NONCE) + } + + #[inline(always)] + pub fn get_seed(&self) -> [u8; 32] { + get_seed(self) } } +#[allow(clippy::many_single_char_names)] #[inline(always)] fn refill_wide_impl( m: Mach, state: &mut ChaCha, drounds: u32, out: &mut [u8; BUFSZ], @@ -100,11 +119,11 @@ fn refill_wide_impl( let k = m.vec([0x6170_7865, 0x3320_646e, 0x7962_2d32, 0x6b20_6574]); let mut pos = state.pos64(m); let d0: Mach::u32x4 = m.unpack(state.d); - pos += 1; + pos = pos.wrapping_add(1); let d1 = d0.insert((pos >> 32) as u32, 1).insert(pos as u32, 0); - pos += 1; + pos = pos.wrapping_add(1); let d2 = d0.insert((pos >> 32) as u32, 1).insert(pos as u32, 0); - pos += 1; + pos = pos.wrapping_add(1); let d3 = d0.insert((pos >> 32) as u32, 1).insert(pos as u32, 0); let b = m.unpack(state.b); @@ -121,13 +140,13 @@ fn refill_wide_impl( } let mut pos = state.pos64(m); let d0: Mach::u32x4 = m.unpack(state.d); - pos += 1; + pos = pos.wrapping_add(1); let d1 = d0.insert((pos >> 32) as u32, 1).insert(pos as u32, 0); - pos += 1; + pos = pos.wrapping_add(1); let d2 = d0.insert((pos >> 32) as u32, 1).insert(pos as u32, 0); - pos += 1; + pos = pos.wrapping_add(1); let d3 = d0.insert((pos >> 32) as u32, 1).insert(pos as u32, 0); - pos += 1; + pos = pos.wrapping_add(1); let d4 = d0.insert((pos >> 32) as u32, 1).insert(pos as u32, 0); let (a, b, c, d) = ( @@ -196,6 +215,17 @@ dispatch_light128!(m, Mach, { } }); +dispatch_light128!(m, Mach, { + fn get_seed(state: &ChaCha) -> [u8; 32] { + let b: Mach::u32x4 = m.unpack(state.b); + let c: Mach::u32x4 = m.unpack(state.c); + let mut key = [0u8; 32]; + b.write_le(&mut key[..16]); + c.write_le(&mut key[16..]); + key + } +}); + fn read_u32le(xs: &[u8]) -> u32 { assert_eq!(xs.len(), 4); u32::from(xs[0]) | (u32::from(xs[1]) << 8) | (u32::from(xs[2]) << 16) | (u32::from(xs[3]) << 24) diff --git a/third_party/rust/rand_core/.cargo-checksum.json b/third_party/rust/rand_core/.cargo-checksum.json index 3c6c0c61be11..26b1caec4263 100644 --- a/third_party/rust/rand_core/.cargo-checksum.json +++ b/third_party/rust/rand_core/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"CHANGELOG.md":"fe41510a0892dd4d79433ea093279d093de4b37601f672b480c06f8aaaf9f595","COPYRIGHT":"90eb64f0279b0d9432accfa6023ff803bc4965212383697eee27a0f426d5f8d5","Cargo.toml":"8f401d04ac2812f3861364f3eccc7a325a64e27beada85bf6f0beb0bad97534c","LICENSE-APACHE":"aaff376532ea30a0cd5330b9502ad4a4c8bf769c539c87ffe78819d188a18ebf","LICENSE-MIT":"209fbbe0ad52d9235e37badf9cadfe4dbdc87203179c0899e738b39ade42177b","README.md":"f39238c96e33b8a2d3545add73646fe7cd3d98c00f8524ef91b3ac31488e8d83","src/block.rs":"827e03e9b050175f1a9531323e203e576660a2582ac84490291a6e27e3d32412","src/error.rs":"bb7214f4db0ecdc66db711e688413e25b00ce4f5b583c516fe981063c16b26a6","src/impls.rs":"be460c286057857dd9dd7d925f36f98bea8ca336ef4663c1b06cfed7bb94a248","src/le.rs":"cb187f58f7514877918f7f47633397e08e20392dcf072bc245d62c9e5238198c","src/lib.rs":"225b6aa8ad2a0f5afeb6bc36226641c0dd2700d2686a7052c324537aec6d64f6","src/os.rs":"142db4cef4ceb3eb0232911f7472822d4aa824545e89f374b6714d7e09c6771a"},"package":"90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"} \ No newline at end of file +{"files":{"CHANGELOG.md":"25e64e1e95a61d0ba0eb476b3512cdacec6e64cbad44e560678efa16242ea291","COPYRIGHT":"90eb64f0279b0d9432accfa6023ff803bc4965212383697eee27a0f426d5f8d5","Cargo.toml":"262864cafee79bee4b22c53f4ba25bb938bab7e96495042241242e3472ba0262","LICENSE-APACHE":"aaff376532ea30a0cd5330b9502ad4a4c8bf769c539c87ffe78819d188a18ebf","LICENSE-MIT":"209fbbe0ad52d9235e37badf9cadfe4dbdc87203179c0899e738b39ade42177b","README.md":"bb3bd3831adc9eaabbcea108ab7f02f5837e9d2f81e872ffd7d340ad466df4de","src/block.rs":"724d13d7721396b46c18999231823c3ea9f6736492102c7c05ee057606372c39","src/error.rs":"0b6d5a188a256fa367dfa368e7dd846b58977a957489c03902307eb78ce4c9e8","src/impls.rs":"d6a97255d92c06bdd1a54590648bbe4cfb41111ac9e761496baf6b7eb5e92f6a","src/le.rs":"f302239d09cc8d915aa8d4fe46c32c8981900cb20d42b12eef9c34e2e820bc88","src/lib.rs":"8b17ae9af2eb43c28320a87893cb234c3889b4dd6246899bbc11e310ce142fa6","src/os.rs":"47849479e19c43dd01259eb14be7b4daf8474d23567dc32a1547c10b108b7069"},"package":"d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"} \ No newline at end of file diff --git a/third_party/rust/rand_core/CHANGELOG.md b/third_party/rust/rand_core/CHANGELOG.md index dfdd6928ef0a..82c830086cda 100644 --- a/third_party/rust/rand_core/CHANGELOG.md +++ b/third_party/rust/rand_core/CHANGELOG.md @@ -4,6 +4,37 @@ 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.6.3] - 2021-06-15 +### Changed +- Improved bound for `serde` impls on `BlockRng` (#1130) +- Minor doc additions (#1118) + +## [0.6.2] - 2021-02-12 +### Fixed +- Fixed assertions in `le::read_u32_into` and `le::read_u64_into` which could + have allowed buffers not to be fully populated (#1096) + +## [0.6.1] - 2021-01-03 +### Fixed +- Avoid panic when using `RngCore::seed_from_u64` with a seed which is not a + multiple of four (#1082) +### Other +- Enable all stable features in the playground (#1081) + +## [0.6.0] - 2020-12-08 +### Breaking changes +- Bump MSRV to 1.36, various code improvements (#1011) +- Update to getrandom v0.2 (#1041) +- Fix: `next_u32_via_fill` and `next_u64_via_fill` now use LE as documented (#1061) + +### Other +- Reduce usage of `unsafe` (#962, #963, #1011) +- Annotate feature-gates in documentation (#1019) +- Document available error codes (#1061) +- Various documentation tweaks +- Fix some clippy warnings (#1036) +- Apply rustfmt (#926) + ## [0.5.1] - 2019-08-28 - `OsRng` added to `rand_core` (#863) - `Error::INTERNAL_START` and `Error::CUSTOM_START` constants (#864) diff --git a/third_party/rust/rand_core/Cargo.toml b/third_party/rust/rand_core/Cargo.toml index 572276e5fba2..06ba1e85aa93 100644 --- a/third_party/rust/rand_core/Cargo.toml +++ b/third_party/rust/rand_core/Cargo.toml @@ -13,18 +13,24 @@ [package] edition = "2018" name = "rand_core" -version = "0.5.1" +version = "0.6.3" authors = ["The Rand Project Developers", "The Rust Project Developers"] description = "Core random number generator traits and tools for implementation.\n" -homepage = "https://crates.io/crates/rand_core" -documentation = "https://rust-random.github.io/rand/rand_core/" +homepage = "https://rust-random.github.io/book" +documentation = "https://docs.rs/rand_core" readme = "README.md" keywords = ["random", "rng"] categories = ["algorithms", "no-std"] license = "MIT OR Apache-2.0" repository = "https://github.com/rust-random/rand" +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "doc_cfg"] + +[package.metadata.playground] +all-features = true [dependencies.getrandom] -version = "0.1" +version = "0.2" optional = true [dependencies.serde] @@ -36,8 +42,3 @@ optional = true alloc = [] serde1 = ["serde"] std = ["alloc", "getrandom", "getrandom/std"] -[badges.appveyor] -repository = "rust-random/rand" - -[badges.travis-ci] -repository = "rust-random/rand" diff --git a/third_party/rust/rand_core/README.md b/third_party/rust/rand_core/README.md index 467e66f98b69..d32dd6853d04 100644 --- a/third_party/rust/rand_core/README.md +++ b/third_party/rust/rand_core/README.md @@ -1,12 +1,11 @@ # rand_core -[![Build Status](https://travis-ci.org/rust-random/rand.svg)](https://travis-ci.org/rust-random/rand) -[![Build Status](https://ci.appveyor.com/api/projects/status/github/rust-random/rand?svg=true)](https://ci.appveyor.com/project/rust-random/rand) +[![Test Status](https://github.com/rust-random/rand/workflows/Tests/badge.svg?event=push)](https://github.com/rust-random/rand/actions) [![Latest version](https://img.shields.io/crates/v/rand_core.svg)](https://crates.io/crates/rand_core) [![Book](https://img.shields.io/badge/book-master-yellow.svg)](https://rust-random.github.io/book/) [![API](https://img.shields.io/badge/api-master-yellow.svg)](https://rust-random.github.io/rand/rand_core) [![API](https://docs.rs/rand_core/badge.svg)](https://docs.rs/rand_core) -[![Minimum rustc version](https://img.shields.io/badge/rustc-1.32+-lightgray.svg)](https://github.com/rust-random/rand#rust-version-requirements) +[![Minimum rustc version](https://img.shields.io/badge/rustc-1.36+-lightgray.svg)](https://github.com/rust-random/rand#rust-version-requirements) Core traits and error types of the [rand] library, plus tools for implementing RNGs. @@ -44,7 +43,7 @@ The traits and error types are also available via `rand`. The current version is: ``` -rand_core = "0.5.0" +rand_core = "0.6.0" ``` Rand libs have inter-dependencies and make use of the diff --git a/third_party/rust/rand_core/src/block.rs b/third_party/rust/rand_core/src/block.rs index 0ab7458377f3..a54cadfed7d4 100644 --- a/third_party/rust/rand_core/src/block.rs +++ b/third_party/rust/rand_core/src/block.rs @@ -21,12 +21,14 @@ //! //! # Example //! -//! ```norun +//! ```no_run +//! use rand_core::{RngCore, SeedableRng}; //! use rand_core::block::{BlockRngCore, BlockRng}; //! //! struct MyRngCore; //! //! impl BlockRngCore for MyRngCore { +//! type Item = u32; //! type Results = [u32; 16]; //! //! fn generate(&mut self, results: &mut Self::Results) { @@ -35,7 +37,7 @@ //! } //! //! impl SeedableRng for MyRngCore { -//! type Seed = unimplemented!(); +//! type Seed = [u8; 32]; //! fn from_seed(seed: Self::Seed) -> Self { //! unimplemented!() //! } @@ -44,17 +46,19 @@ //! // optionally, also implement CryptoRng for MyRngCore //! //! // Final RNG. -//! type MyRng = BlockRng; +//! let mut rng = BlockRng::::seed_from_u64(0); +//! println!("First value: {}", rng.next_u32()); //! ``` //! //! [`BlockRngCore`]: crate::block::BlockRngCore //! [`fill_bytes`]: RngCore::fill_bytes -use core::convert::AsRef; -use core::{fmt, ptr}; -#[cfg(feature="serde1")] use serde::{Serialize, Deserialize}; -use crate::{RngCore, CryptoRng, SeedableRng, Error}; use crate::impls::{fill_via_u32_chunks, fill_via_u64_chunks}; +use crate::{CryptoRng, Error, RngCore, SeedableRng}; +use core::convert::AsRef; +use core::fmt; +#[cfg(feature = "serde1")] +use serde::{Deserialize, Serialize}; /// A trait for RNGs which do not generate random numbers individually, but in /// blocks (typically `[u32; N]`). This technique is commonly used by @@ -73,7 +77,6 @@ pub trait BlockRngCore { fn generate(&mut self, results: &mut Self::Results); } - /// A wrapper type implementing [`RngCore`] for some type implementing /// [`BlockRngCore`] with `u32` array buffer; i.e. this can be used to implement /// a full RNG from just a `generate` function. @@ -110,7 +113,13 @@ pub trait BlockRngCore { /// [`fill_bytes`]: RngCore::fill_bytes /// [`try_fill_bytes`]: RngCore::try_fill_bytes #[derive(Clone)] -#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] +#[cfg_attr( + feature = "serde1", + serde( + bound = "for<'x> R: Serialize + Deserialize<'x> + Sized, for<'x> R::Results: Serialize + Deserialize<'x>" + ) +)] pub struct BlockRng { results: R::Results, index: usize, @@ -122,10 +131,10 @@ pub struct BlockRng { impl fmt::Debug for BlockRng { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.debug_struct("BlockRng") - .field("core", &self.core) - .field("result_len", &self.results.as_ref().len()) - .field("index", &self.index) - .finish() + .field("core", &self.core) + .field("result_len", &self.results.as_ref().len()) + .field("index", &self.index) + .finish() } } @@ -133,7 +142,7 @@ impl BlockRng { /// Create a new `BlockRng` from an existing RNG implementing /// `BlockRngCore`. Results will be generated on first use. #[inline] - pub fn new(core: R) -> BlockRng{ + pub fn new(core: R) -> BlockRng { let results_empty = R::Results::default(); BlockRng { core, @@ -169,8 +178,9 @@ impl BlockRng { } } -impl> RngCore for BlockRng -where ::Results: AsRef<[u32]> + AsMut<[u32]> +impl> RngCore for BlockRng +where + ::Results: AsRef<[u32]> + AsMut<[u32]>, { #[inline] fn next_u32(&mut self) -> u32 { @@ -186,22 +196,14 @@ where ::Results: AsRef<[u32]> + AsMut<[u32]> #[inline] fn next_u64(&mut self) -> u64 { let read_u64 = |results: &[u32], index| { - if cfg!(any(target_endian = "little")) { - // requires little-endian CPU - #[allow(clippy::cast_ptr_alignment)] // false positive - let ptr: *const u64 = results[index..=index+1].as_ptr() as *const u64; - unsafe { ptr::read_unaligned(ptr) } - } else { - let x = u64::from(results[index]); - let y = u64::from(results[index + 1]); - (y << 32) | x - } + let data = &results[index..=index + 1]; + u64::from(data[1]) << 32 | u64::from(data[0]) }; let len = self.results.as_ref().len(); let index = self.index; - if index < len-1 { + if index < len - 1 { self.index += 2; // Read an u64 from the current index read_u64(self.results.as_ref(), index) @@ -209,7 +211,7 @@ where ::Results: AsRef<[u32]> + AsMut<[u32]> self.generate_and_set(2); read_u64(self.results.as_ref(), 0) } else { - let x = u64::from(self.results.as_ref()[len-1]); + let x = u64::from(self.results.as_ref()[len - 1]); self.generate_and_set(1); let y = u64::from(self.results.as_ref()[0]); (y << 32) | x @@ -224,8 +226,7 @@ where ::Results: AsRef<[u32]> + AsMut<[u32]> self.generate_and_set(0); } let (consumed_u32, filled_u8) = - fill_via_u32_chunks(&self.results.as_ref()[self.index..], - &mut dest[read_len..]); + fill_via_u32_chunks(&self.results.as_ref()[self.index..], &mut dest[read_len..]); self.index += consumed_u32; read_len += filled_u8; @@ -258,8 +259,6 @@ impl SeedableRng for BlockRng { } } - - /// A wrapper type implementing [`RngCore`] for some type implementing /// [`BlockRngCore`] with `u64` array buffer; i.e. this can be used to implement /// a full RNG from just a `generate` function. @@ -283,7 +282,7 @@ impl SeedableRng for BlockRng { /// [`fill_bytes`]: RngCore::fill_bytes /// [`try_fill_bytes`]: RngCore::try_fill_bytes #[derive(Clone)] -#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] pub struct BlockRng64 { results: R::Results, index: usize, @@ -296,11 +295,11 @@ pub struct BlockRng64 { impl fmt::Debug for BlockRng64 { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.debug_struct("BlockRng64") - .field("core", &self.core) - .field("result_len", &self.results.as_ref().len()) - .field("index", &self.index) - .field("half_used", &self.half_used) - .finish() + .field("core", &self.core) + .field("result_len", &self.results.as_ref().len()) + .field("index", &self.index) + .field("half_used", &self.half_used) + .finish() } } @@ -308,7 +307,7 @@ impl BlockRng64 { /// Create a new `BlockRng` from an existing RNG implementing /// `BlockRngCore`. Results will be generated on first use. #[inline] - pub fn new(core: R) -> BlockRng64{ + pub fn new(core: R) -> BlockRng64 { let results_empty = R::Results::default(); BlockRng64 { core, @@ -347,8 +346,9 @@ impl BlockRng64 { } } -impl> RngCore for BlockRng64 -where ::Results: AsRef<[u64]> + AsMut<[u64]> +impl> RngCore for BlockRng64 +where + ::Results: AsRef<[u64]> + AsMut<[u64]>, { #[inline] fn next_u32(&mut self) -> u32 { @@ -366,8 +366,7 @@ where ::Results: AsRef<[u64]> + AsMut<[u64]> // Index as if this is a u32 slice. unsafe { - let results = - &*(self.results.as_ref() as *const [u64] as *const [u32]); + let results = &*(self.results.as_ref() as *const [u64] as *const [u32]); if cfg!(target_endian = "little") { *results.get_unchecked(index) } else { @@ -399,9 +398,10 @@ where ::Results: AsRef<[u64]> + AsMut<[u64]> self.index = 0; } - let (consumed_u64, filled_u8) = - fill_via_u64_chunks(&self.results.as_ref()[self.index as usize..], - &mut dest[read_len..]); + let (consumed_u64, filled_u8) = fill_via_u64_chunks( + &self.results.as_ref()[self.index as usize..], + &mut dest[read_len..], + ); self.index += consumed_u64; read_len += filled_u8; diff --git a/third_party/rust/rand_core/src/error.rs b/third_party/rust/rand_core/src/error.rs index 30b095c3cffb..a64c430da8b6 100644 --- a/third_party/rust/rand_core/src/error.rs +++ b/third_party/rust/rand_core/src/error.rs @@ -11,6 +11,7 @@ use core::fmt; use core::num::NonZeroU32; +#[cfg(feature = "std")] use std::boxed::Box; /// Error type of random number generators /// @@ -18,54 +19,64 @@ use core::num::NonZeroU32; /// possible implementations: with `std` a boxed `Error` trait object is stored, /// while with `no_std` we merely store an error code. pub struct Error { - #[cfg(feature="std")] + #[cfg(feature = "std")] inner: Box, - #[cfg(not(feature="std"))] + #[cfg(not(feature = "std"))] code: NonZeroU32, } impl Error { + /// Codes at or above this point can be used by users to define their own + /// custom errors. + /// + /// This has a fixed value of `(1 << 31) + (1 << 30) = 0xC000_0000`, + /// therefore the number of values available for custom codes is `1 << 30`. + /// + /// This is identical to [`getrandom::Error::CUSTOM_START`](https://docs.rs/getrandom/latest/getrandom/struct.Error.html#associatedconstant.CUSTOM_START). + pub const CUSTOM_START: u32 = (1 << 31) + (1 << 30); + /// Codes below this point represent OS Errors (i.e. positive i32 values). + /// Codes at or above this point, but below [`Error::CUSTOM_START`] are + /// reserved for use by the `rand` and `getrandom` crates. + /// + /// This is identical to [`getrandom::Error::INTERNAL_START`](https://docs.rs/getrandom/latest/getrandom/struct.Error.html#associatedconstant.INTERNAL_START). + pub const INTERNAL_START: u32 = 1 << 31; + /// Construct from any type supporting `std::error::Error` - /// + /// /// Available only when configured with `std`. - /// + /// /// See also `From`, which is available with and without `std`. - #[cfg(feature="std")] + #[cfg(feature = "std")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "std")))] #[inline] pub fn new(err: E) -> Self - where E: Into> + where + E: Into>, { Error { inner: err.into() } } - + /// Reference the inner error (`std` only) - /// + /// /// When configured with `std`, this is a trivial operation and never /// panics. Without `std`, this method is simply unavailable. - #[cfg(feature="std")] + #[cfg(feature = "std")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "std")))] #[inline] pub fn inner(&self) -> &(dyn std::error::Error + Send + Sync + 'static) { &*self.inner } - + /// Unwrap the inner error (`std` only) - /// + /// /// When configured with `std`, this is a trivial operation and never /// panics. Without `std`, this method is simply unavailable. - #[cfg(feature="std")] + #[cfg(feature = "std")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "std")))] #[inline] pub fn take_inner(self) -> Box { self.inner } - - /// Codes below this point represent OS Errors (i.e. positive i32 values). - /// Codes at or above this point, but below [`Error::CUSTOM_START`] are - /// reserved for use by the `rand` and `getrandom` crates. - pub const INTERNAL_START: u32 = 1 << 31; - - /// Codes at or above this point can be used by users to define their own - /// custom errors. - pub const CUSTOM_START: u32 = (1 << 31) + (1 << 30); /// Extract the raw OS error code (if this error came from the OS) /// @@ -74,29 +85,31 @@ impl Error { /// error value can still be formatted via the `Diplay` implementation. #[inline] pub fn raw_os_error(&self) -> Option { - #[cfg(feature="std")] { + #[cfg(feature = "std")] + { if let Some(e) = self.inner.downcast_ref::() { return e.raw_os_error(); } } match self.code() { - Some(code) if u32::from(code) < Self::INTERNAL_START => - Some(u32::from(code) as i32), + Some(code) if u32::from(code) < Self::INTERNAL_START => Some(u32::from(code) as i32), _ => None, } } /// Retrieve the error code, if any. - /// + /// /// If this `Error` was constructed via `From`, then this method /// will return this `NonZeroU32` code (for `no_std` this is always the /// case). Otherwise, this method will return `None`. #[inline] pub fn code(&self) -> Option { - #[cfg(feature="std")] { + #[cfg(feature = "std")] + { self.inner.downcast_ref::().map(|c| c.0) } - #[cfg(not(feature="std"))] { + #[cfg(not(feature = "std"))] + { Some(self.code) } } @@ -104,13 +117,16 @@ impl Error { impl fmt::Debug for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - #[cfg(feature="std")] { + #[cfg(feature = "std")] + { write!(f, "Error {{ inner: {:?} }}", self.inner) } - #[cfg(all(feature="getrandom", not(feature="std")))] { + #[cfg(all(feature = "getrandom", not(feature = "std")))] + { getrandom::Error::from(self.code).fmt(f) } - #[cfg(not(feature="getrandom"))] { + #[cfg(not(feature = "getrandom"))] + { write!(f, "Error {{ code: {} }}", self.code) } } @@ -118,13 +134,16 @@ impl fmt::Debug for Error { impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - #[cfg(feature="std")] { + #[cfg(feature = "std")] + { write!(f, "{}", self.inner) } - #[cfg(all(feature="getrandom", not(feature="std")))] { + #[cfg(all(feature = "getrandom", not(feature = "std")))] + { getrandom::Error::from(self.code).fmt(f) } - #[cfg(not(feature="getrandom"))] { + #[cfg(not(feature = "getrandom"))] + { write!(f, "error code {}", self.code) } } @@ -133,29 +152,37 @@ impl fmt::Display for Error { impl From for Error { #[inline] fn from(code: NonZeroU32) -> Self { - #[cfg(feature="std")] { - Error { inner: Box::new(ErrorCode(code)) } + #[cfg(feature = "std")] + { + Error { + inner: Box::new(ErrorCode(code)), + } } - #[cfg(not(feature="std"))] { + #[cfg(not(feature = "std"))] + { Error { code } } } } -#[cfg(feature="getrandom")] +#[cfg(feature = "getrandom")] impl From for Error { #[inline] fn from(error: getrandom::Error) -> Self { - #[cfg(feature="std")] { - Error { inner: Box::new(error) } + #[cfg(feature = "std")] + { + Error { + inner: Box::new(error), + } } - #[cfg(not(feature="std"))] { + #[cfg(not(feature = "std"))] + { Error { code: error.code() } } } } -#[cfg(feature="std")] +#[cfg(feature = "std")] impl std::error::Error for Error { #[inline] fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { @@ -163,7 +190,7 @@ impl std::error::Error for Error { } } -#[cfg(feature="std")] +#[cfg(feature = "std")] impl From for std::io::Error { #[inline] fn from(error: Error) -> Self { @@ -175,16 +202,27 @@ impl From for std::io::Error { } } -#[cfg(feature="std")] +#[cfg(feature = "std")] #[derive(Debug, Copy, Clone)] struct ErrorCode(NonZeroU32); -#[cfg(feature="std")] +#[cfg(feature = "std")] impl fmt::Display for ErrorCode { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "error code {}", self.0) } } -#[cfg(feature="std")] +#[cfg(feature = "std")] impl std::error::Error for ErrorCode {} + +#[cfg(test)] +mod test { + #[cfg(feature = "getrandom")] + #[test] + fn test_error_codes() { + // Make sure the values are the same as in `getrandom`. + assert_eq!(super::Error::CUSTOM_START, getrandom::Error::CUSTOM_START); + assert_eq!(super::Error::INTERNAL_START, getrandom::Error::INTERNAL_START); + } +} diff --git a/third_party/rust/rand_core/src/impls.rs b/third_party/rust/rand_core/src/impls.rs index dee4ed11e6be..2588a72ea3f7 100644 --- a/third_party/rust/rand_core/src/impls.rs +++ b/third_party/rust/rand_core/src/impls.rs @@ -17,12 +17,8 @@ //! to/from byte sequences, and since its purpose is reproducibility, //! non-reproducible sources (e.g. `OsRng`) need not bother with it. -use core::ptr::copy_nonoverlapping; -use core::slice; -use core::cmp::min; -use core::mem::size_of; use crate::RngCore; - +use core::cmp::min; /// Implement `next_u64` via `next_u32`, little-endian order. pub fn next_u64_via_u32(rng: &mut R) -> u64 { @@ -41,7 +37,7 @@ pub fn next_u64_via_u32(rng: &mut R) -> u64 { pub fn fill_bytes_via_next(rng: &mut R, dest: &mut [u8]) { let mut left = dest; while left.len() >= 8 { - let (l, r) = {left}.split_at_mut(8); + let (l, r) = { left }.split_at_mut(8); left = r; let chunk: [u8; 8] = rng.next_u64().to_le_bytes(); l.copy_from_slice(&chunk); @@ -56,45 +52,36 @@ pub fn fill_bytes_via_next(rng: &mut R, dest: &mut [u8]) { } } -macro_rules! impl_uint_from_fill { - ($rng:expr, $ty:ty, $N:expr) => ({ - debug_assert!($N == size_of::<$ty>()); - - let mut int: $ty = 0; - unsafe { - let ptr = &mut int as *mut $ty as *mut u8; - let slice = slice::from_raw_parts_mut(ptr, $N); - $rng.fill_bytes(slice); - } - int - }); -} - macro_rules! fill_via_chunks { - ($src:expr, $dst:expr, $ty:ty, $size:expr) => ({ - let chunk_size_u8 = min($src.len() * $size, $dst.len()); - let chunk_size = (chunk_size_u8 + $size - 1) / $size; - if cfg!(target_endian="little") { + ($src:expr, $dst:expr, $ty:ty) => {{ + const SIZE: usize = core::mem::size_of::<$ty>(); + let chunk_size_u8 = min($src.len() * SIZE, $dst.len()); + let chunk_size = (chunk_size_u8 + SIZE - 1) / SIZE; + + // The following can be replaced with safe code, but unfortunately it's + // ca. 8% slower. + if cfg!(target_endian = "little") { unsafe { - copy_nonoverlapping( + core::ptr::copy_nonoverlapping( $src.as_ptr() as *const u8, $dst.as_mut_ptr(), chunk_size_u8); } } else { - for (&n, chunk) in $src.iter().zip($dst.chunks_mut($size)) { + for (&n, chunk) in $src.iter().zip($dst.chunks_mut(SIZE)) { let tmp = n.to_le(); let src_ptr = &tmp as *const $ty as *const u8; unsafe { - copy_nonoverlapping(src_ptr, - chunk.as_mut_ptr(), - chunk.len()); + core::ptr::copy_nonoverlapping( + src_ptr, + chunk.as_mut_ptr(), + chunk.len()); } } } (chunk_size, chunk_size_u8) - }); + }}; } /// Implement `fill_bytes` by reading chunks from the output buffer of a block @@ -128,7 +115,7 @@ macro_rules! fill_via_chunks { /// } /// ``` pub fn fill_via_u32_chunks(src: &[u32], dest: &mut [u8]) -> (usize, usize) { - fill_via_chunks!(src, dest, u32, 4) + fill_via_chunks!(src, dest, u32) } /// Implement `fill_bytes` by reading chunks from the output buffer of a block @@ -142,17 +129,56 @@ pub fn fill_via_u32_chunks(src: &[u32], dest: &mut [u8]) -> (usize, usize) { /// /// See `fill_via_u32_chunks` for an example. pub fn fill_via_u64_chunks(src: &[u64], dest: &mut [u8]) -> (usize, usize) { - fill_via_chunks!(src, dest, u64, 8) + fill_via_chunks!(src, dest, u64) } /// Implement `next_u32` via `fill_bytes`, little-endian order. pub fn next_u32_via_fill(rng: &mut R) -> u32 { - impl_uint_from_fill!(rng, u32, 4) + let mut buf = [0; 4]; + rng.fill_bytes(&mut buf); + u32::from_le_bytes(buf) } /// Implement `next_u64` via `fill_bytes`, little-endian order. pub fn next_u64_via_fill(rng: &mut R) -> u64 { - impl_uint_from_fill!(rng, u64, 8) + let mut buf = [0; 8]; + rng.fill_bytes(&mut buf); + u64::from_le_bytes(buf) } -// TODO: implement tests for the above +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_fill_via_u32_chunks() { + let src = [1, 2, 3]; + let mut dst = [0u8; 11]; + assert_eq!(fill_via_u32_chunks(&src, &mut dst), (3, 11)); + assert_eq!(dst, [1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0]); + + let mut dst = [0u8; 13]; + assert_eq!(fill_via_u32_chunks(&src, &mut dst), (3, 12)); + assert_eq!(dst, [1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0]); + + let mut dst = [0u8; 5]; + assert_eq!(fill_via_u32_chunks(&src, &mut dst), (2, 5)); + assert_eq!(dst, [1, 0, 0, 0, 2]); + } + + #[test] + fn test_fill_via_u64_chunks() { + let src = [1, 2]; + let mut dst = [0u8; 11]; + assert_eq!(fill_via_u64_chunks(&src, &mut dst), (2, 11)); + assert_eq!(dst, [1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0]); + + let mut dst = [0u8; 17]; + assert_eq!(fill_via_u64_chunks(&src, &mut dst), (2, 16)); + assert_eq!(dst, [1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0]); + + let mut dst = [0u8; 5]; + assert_eq!(fill_via_u64_chunks(&src, &mut dst), (1, 5)); + assert_eq!(dst, [1, 0, 0, 0, 0]); + } +} diff --git a/third_party/rust/rand_core/src/le.rs b/third_party/rust/rand_core/src/le.rs index 266651f10dc7..ed42e57f4786 100644 --- a/third_party/rust/rand_core/src/le.rs +++ b/third_party/rust/rand_core/src/le.rs @@ -7,61 +7,49 @@ // except according to those terms. //! Little-Endian utilities -//! +//! //! Little-Endian order has been chosen for internal usage; this makes some //! useful functions available. -use core::ptr; - -macro_rules! read_slice { - ($src:expr, $dst:expr, $size:expr, $which:ident) => {{ - assert_eq!($src.len(), $size * $dst.len()); - - unsafe { - ptr::copy_nonoverlapping( - $src.as_ptr(), - $dst.as_mut_ptr() as *mut u8, - $src.len()); - } - for v in $dst.iter_mut() { - *v = v.$which(); - } - }}; -} +use core::convert::TryInto; /// Reads unsigned 32 bit integers from `src` into `dst`. -/// Borrowed from the `byteorder` crate. #[inline] pub fn read_u32_into(src: &[u8], dst: &mut [u32]) { - read_slice!(src, dst, 4, to_le); + assert!(src.len() >= 4 * dst.len()); + for (out, chunk) in dst.iter_mut().zip(src.chunks_exact(4)) { + *out = u32::from_le_bytes(chunk.try_into().unwrap()); + } } /// Reads unsigned 64 bit integers from `src` into `dst`. -/// Borrowed from the `byteorder` crate. #[inline] pub fn read_u64_into(src: &[u8], dst: &mut [u64]) { - read_slice!(src, dst, 8, to_le); + assert!(src.len() >= 8 * dst.len()); + for (out, chunk) in dst.iter_mut().zip(src.chunks_exact(8)) { + *out = u64::from_le_bytes(chunk.try_into().unwrap()); + } } #[test] fn test_read() { let bytes = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; - + let mut buf = [0u32; 4]; read_u32_into(&bytes, &mut buf); assert_eq!(buf[0], 0x04030201); assert_eq!(buf[3], 0x100F0E0D); - + let mut buf = [0u32; 3]; - read_u32_into(&bytes[1..13], &mut buf); // unaligned + read_u32_into(&bytes[1..13], &mut buf); // unaligned assert_eq!(buf[0], 0x05040302); assert_eq!(buf[2], 0x0D0C0B0A); - + let mut buf = [0u64; 2]; read_u64_into(&bytes, &mut buf); assert_eq!(buf[0], 0x0807060504030201); assert_eq!(buf[1], 0x100F0E0D0C0B0A09); - + let mut buf = [0u64; 1]; read_u64_into(&bytes[7..15], &mut buf); // unaligned assert_eq!(buf[0], 0x0F0E0D0C0B0A0908); diff --git a/third_party/rust/rand_core/src/lib.rs b/third_party/rust/rand_core/src/lib.rs index d8e0189f223d..bc24270771b3 100644 --- a/third_party/rust/rand_core/src/lib.rs +++ b/third_party/rust/rand_core/src/lib.rs @@ -27,35 +27,33 @@ //! //! [`rand`]: https://docs.rs/rand -#![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/")] - +#![doc( + html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png", + html_favicon_url = "https://www.rust-lang.org/favicon.ico", + html_root_url = "https://rust-random.github.io/rand/" +)] #![deny(missing_docs)] #![deny(missing_debug_implementations)] #![doc(test(attr(allow(unused_variables), deny(warnings))))] +#![cfg_attr(doc_cfg, feature(doc_cfg))] +#![no_std] -#![allow(clippy::unreadable_literal)] - -#![cfg_attr(not(feature="std"), no_std)] - - -use core::default::Default; use core::convert::AsMut; -use core::ptr::copy_nonoverlapping; +use core::default::Default; -#[cfg(all(feature="alloc", not(feature="std")))] extern crate alloc; -#[cfg(all(feature="alloc", not(feature="std")))] use alloc::boxed::Box; +#[cfg(feature = "std")] extern crate std; +#[cfg(feature = "alloc")] extern crate alloc; +#[cfg(feature = "alloc")] use alloc::boxed::Box; pub use error::Error; -#[cfg(feature="getrandom")] pub use os::OsRng; +#[cfg(feature = "getrandom")] pub use os::OsRng; -mod error; pub mod block; +mod error; pub mod impls; pub mod le; -#[cfg(feature="getrandom")] mod os; +#[cfg(feature = "getrandom")] mod os; /// The core of a random number generator. @@ -69,19 +67,26 @@ pub mod le; /// optimal implementation of each is dependent on the type of generator. There /// is no required relationship between the output of each; e.g. many /// implementations of [`fill_bytes`] consume a whole number of `u32` or `u64` -/// values and drop any remaining unused bytes. +/// values and drop any remaining unused bytes. The same can happen with the +/// [`next_u32`] and [`next_u64`] methods, implementations may discard some +/// random bits for efficiency. /// /// The [`try_fill_bytes`] method is a variant of [`fill_bytes`] allowing error /// handling; it is not deemed sufficiently useful to add equivalents for /// [`next_u32`] or [`next_u64`] since the latter methods are almost always used /// with algorithmic generators (PRNGs), which are normally infallible. /// +/// Implementers should produce bits uniformly. Pathological RNGs (e.g. always +/// returning the same value, or never setting certain bits) can break rejection +/// sampling used by random distributions, and also break other RNGs when +/// seeding them via [`SeedableRng::from_rng`]. +/// /// Algorithmic generators implementing [`SeedableRng`] should normally have /// *portable, reproducible* output, i.e. fix Endianness when converting values /// to avoid platform differences, and avoid making any changes which affect /// output (except by communicating that the release has breaking changes). /// -/// Typically implementators will implement only one of the methods available +/// Typically an RNG will implement only one of the methods available /// in this trait directly, then use the helper functions from the /// [`impls`] module to implement the other methods. /// @@ -139,24 +144,22 @@ pub trait RngCore { /// /// RNGs must implement at least one method from this trait directly. In /// the case this method is not implemented directly, it can be implemented - /// using `self.next_u64() as u32` or via - /// [`fill_bytes`](impls::next_u32_via_fill). + /// using `self.next_u64() as u32` or via [`impls::next_u32_via_fill`]. fn next_u32(&mut self) -> u32; /// Return the next random `u64`. /// /// RNGs must implement at least one method from this trait directly. In /// the case this method is not implemented directly, it can be implemented - /// via [`next_u32`](impls::next_u64_via_u32) or via - /// [`fill_bytes`](impls::next_u64_via_fill). + /// via [`impls::next_u64_via_u32`] or via [`impls::next_u64_via_fill`]. fn next_u64(&mut self) -> u64; /// Fill `dest` with random data. /// /// RNGs must implement at least one method from this trait directly. In /// the case this method is not implemented directly, it can be implemented - /// via [`next_u*`](impls::fill_bytes_via_next) or - /// via [`try_fill_bytes`](RngCore::try_fill_bytes); if this generator can + /// via [`impls::fill_bytes_via_next`] or + /// via [`RngCore::try_fill_bytes`]; if this generator can /// fail the implementation must choose how best to handle errors here /// (e.g. panic with a descriptive message or log a warning and retry a few /// times). @@ -174,12 +177,10 @@ pub trait RngCore { /// by external (true) RNGs (e.g. `OsRng`) which can fail. It may be used /// directly to generate keys and to seed (infallible) PRNGs. /// - /// Other than error handling, this method is identical to [`fill_bytes`]; + /// Other than error handling, this method is identical to [`RngCore::fill_bytes`]; /// thus this may be implemented using `Ok(self.fill_bytes(dest))` or /// `fill_bytes` may be implemented with /// `self.try_fill_bytes(dest).unwrap()` or more specific error handling. - /// - /// [`fill_bytes`]: RngCore::fill_bytes fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error>; } @@ -304,24 +305,30 @@ pub trait SeedableRng: Sized { /// considered a value-breaking change. fn seed_from_u64(mut state: u64) -> Self { // We use PCG32 to generate a u32 sequence, and copy to the seed - const MUL: u64 = 6364136223846793005; - const INC: u64 = 11634580027462260723; + fn pcg32(state: &mut u64) -> [u8; 4] { + const MUL: u64 = 6364136223846793005; + const INC: u64 = 11634580027462260723; - let mut seed = Self::Seed::default(); - for chunk in seed.as_mut().chunks_mut(4) { // We advance the state first (to get away from the input value, // in case it has low Hamming Weight). - state = state.wrapping_mul(MUL).wrapping_add(INC); + *state = state.wrapping_mul(MUL).wrapping_add(INC); + let state = *state; // Use PCG output function with to_le to generate x: let xorshifted = (((state >> 18) ^ state) >> 27) as u32; let rot = (state >> 59) as u32; - let x = xorshifted.rotate_right(rot).to_le(); + let x = xorshifted.rotate_right(rot); + x.to_le_bytes() + } - unsafe { - let p = &x as *const u32 as *const u8; - copy_nonoverlapping(p, chunk.as_mut_ptr(), chunk.len()); - } + let mut seed = Self::Seed::default(); + let mut iter = seed.as_mut().chunks_exact_mut(4); + for chunk in &mut iter { + chunk.copy_from_slice(&pcg32(&mut state)); + } + let rem = iter.into_remainder(); + if !rem.is_empty() { + rem.copy_from_slice(&pcg32(&mut state)[..rem.len()]); } Self::from_seed(seed) @@ -351,7 +358,6 @@ pub trait SeedableRng: Sized { /// (in prior versions this was not required). /// /// [`rand`]: https://docs.rs/rand - /// [`rand_os`]: https://docs.rs/rand_os fn from_rng(mut rng: R) -> Result { let mut seed = Self::Seed::default(); rng.try_fill_bytes(seed.as_mut())?; @@ -372,7 +378,8 @@ pub trait SeedableRng: Sized { /// If [`getrandom`] is unable to provide secure entropy this method will panic. /// /// [`getrandom`]: https://docs.rs/getrandom - #[cfg(feature="getrandom")] + #[cfg(feature = "getrandom")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "getrandom")))] fn from_entropy() -> Self { let mut seed = Self::Seed::default(); if let Err(err) = getrandom::getrandom(seed.as_mut()) { @@ -410,7 +417,7 @@ impl<'a, R: RngCore + ?Sized> RngCore for &'a mut R { // Implement `RngCore` for boxed references to an `RngCore`. // Force inlining all functions, so that it is up to the `RngCore` // implementation and the optimizer to decide on inlining. -#[cfg(feature="alloc")] +#[cfg(feature = "alloc")] impl RngCore for Box { #[inline(always)] fn next_u32(&mut self) -> u32 { @@ -433,7 +440,7 @@ impl RngCore for Box { } } -#[cfg(feature="std")] +#[cfg(feature = "std")] impl std::io::Read for dyn RngCore { fn read(&mut self, buf: &mut [u8]) -> Result { self.try_fill_bytes(buf)?; @@ -445,7 +452,7 @@ impl std::io::Read for dyn RngCore { impl<'a, R: CryptoRng + ?Sized> CryptoRng for &'a mut R {} // Implement `CryptoRng` for boxed references to an `CryptoRng`. -#[cfg(feature="alloc")] +#[cfg(feature = "alloc")] impl CryptoRng for Box {} #[cfg(test)] @@ -457,6 +464,7 @@ mod test { struct SeedableNum(u64); impl SeedableRng for SeedableNum { type Seed = [u8; 8]; + fn from_seed(seed: Self::Seed) -> Self { let mut x = [0u64; 1]; le::read_u64_into(&seed, &mut x); @@ -477,10 +485,12 @@ mod test { // This is the binomial distribution B(64, 0.5), so chance of // weight < 20 is binocdf(19, 64, 0.5) = 7.8e-4, and same for // weight > 44. - assert!(weight >= 20 && weight <= 44); + assert!((20..=44).contains(&weight)); for (i2, r2) in results.iter().enumerate() { - if i1 == i2 { continue; } + if i1 == i2 { + continue; + } let diff_weight = (r1 ^ r2).count_ones(); assert!(diff_weight >= 20); } diff --git a/third_party/rust/rand_core/src/os.rs b/third_party/rust/rand_core/src/os.rs index fc23a57d960e..6cd1b9cf5dec 100644 --- a/third_party/rust/rand_core/src/os.rs +++ b/third_party/rust/rand_core/src/os.rs @@ -7,12 +7,11 @@ // except according to those terms. //! Interface to the random number generator of the operating system. -// Note: keep this code in sync with the rand_os crate! +use crate::{impls, CryptoRng, Error, RngCore}; use getrandom::getrandom; -use crate::{CryptoRng, RngCore, Error, impls}; -/// A random number generator that retrieves randomness from from the +/// A random number generator that retrieves randomness from the /// operating system. /// /// This is a zero-sized struct. It can be freely constructed with `OsRng`. @@ -44,6 +43,7 @@ use crate::{CryptoRng, RngCore, Error, impls}; /// ``` /// /// [getrandom]: https://crates.io/crates/getrandom +#[cfg_attr(doc_cfg, doc(cfg(feature = "getrandom")))] #[derive(Clone, Copy, Debug, Default)] pub struct OsRng; diff --git a/third_party/rust/rand_hc/.cargo-checksum.json b/third_party/rust/rand_hc/.cargo-checksum.json deleted file mode 100644 index 9c8919b9abb9..000000000000 --- a/third_party/rust/rand_hc/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"CHANGELOG.md":"011d4dd590882dd2e681c28f41bbfe089ab38587ca21336ca2332118cea0f662","COPYRIGHT":"90eb64f0279b0d9432accfa6023ff803bc4965212383697eee27a0f426d5f8d5","Cargo.toml":"7f51c625c5a4e1b9ca32192a914494d15a5568b8a7b7bbae72214c88d24d0a88","LICENSE-APACHE":"aaff376532ea30a0cd5330b9502ad4a4c8bf769c539c87ffe78819d188a18ebf","LICENSE-MIT":"a771e4354f6b3ad4c92da1a5c9a239b6c291527db869632ecea4f20e24ca1135","README.md":"18ac2dc683ade79e01d509870b82fe68c4f868a1afaeb951f9e75bd0dd965d7b","src/hc128.rs":"94ff3bb8a986c381102ddfde72bc9638dd19ebc2a7e16d7124ed32d95bd85fe3","src/lib.rs":"1e51045313d177cd609bedeee31acfa81a536da1fee93069f900b4fae51a79a0"},"package":"ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"} \ No newline at end of file diff --git a/third_party/rust/rand_hc/CHANGELOG.md b/third_party/rust/rand_hc/CHANGELOG.md deleted file mode 100644 index a629d7d8c72e..000000000000 --- a/third_party/rust/rand_hc/CHANGELOG.md +++ /dev/null @@ -1,16 +0,0 @@ -# Changelog -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - -## [0.2.0] - 2019-06-12 -- Bump minor crate version since rand_core bump is a breaking change -- Switch to Edition 2018 - -## [0.1.1] - 2019-06-06 - yanked -- Bump `rand_core` version -- Adjust usage of `#[inline]` - -## [0.1.0] - 2018-10-17 -- Pulled out of the Rand crate diff --git a/third_party/rust/rand_hc/COPYRIGHT b/third_party/rust/rand_hc/COPYRIGHT deleted file mode 100644 index 468d907caf99..000000000000 --- a/third_party/rust/rand_hc/COPYRIGHT +++ /dev/null @@ -1,12 +0,0 @@ -Copyrights in the Rand project are retained by their contributors. No -copyright assignment is required to contribute to the Rand project. - -For full authorship information, see the version control history. - -Except as otherwise noted (below and/or in individual files), Rand is -licensed under the Apache License, Version 2.0 or - or the MIT license - or , at your option. - -The Rand project includes code from the Rust project -published under these same licenses. diff --git a/third_party/rust/rand_hc/Cargo.toml b/third_party/rust/rand_hc/Cargo.toml deleted file mode 100644 index 29446cc195f0..000000000000 --- a/third_party/rust/rand_hc/Cargo.toml +++ /dev/null @@ -1,32 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# 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 -# -# 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) - -[package] -edition = "2018" -name = "rand_hc" -version = "0.2.0" -authors = ["The Rand Project Developers"] -description = "HC128 random number generator\n" -homepage = "https://crates.io/crates/rand_hc" -documentation = "https://rust-random.github.io/rand/rand_hc/" -readme = "README.md" -keywords = ["random", "rng", "hc128"] -categories = ["algorithms", "no-std"] -license = "MIT/Apache-2.0" -repository = "https://github.com/rust-random/rand" -[dependencies.rand_core] -version = "0.5" -[badges.appveyor] -repository = "rust-random/rand" - -[badges.travis-ci] -repository = "rust-random/rand" diff --git a/third_party/rust/rand_hc/LICENSE-APACHE b/third_party/rust/rand_hc/LICENSE-APACHE deleted file mode 100644 index 17d74680f8cf..000000000000 --- a/third_party/rust/rand_hc/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - https://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/third_party/rust/rand_hc/LICENSE-MIT b/third_party/rust/rand_hc/LICENSE-MIT deleted file mode 100644 index cf656074cbf6..000000000000 --- a/third_party/rust/rand_hc/LICENSE-MIT +++ /dev/null @@ -1,25 +0,0 @@ -Copyright 2018 Developers of the Rand project - -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/third_party/rust/rand_hc/README.md b/third_party/rust/rand_hc/README.md deleted file mode 100644 index 36449c0c826d..000000000000 --- a/third_party/rust/rand_hc/README.md +++ /dev/null @@ -1,45 +0,0 @@ -# rand_hc - -[![Build Status](https://travis-ci.org/rust-random/rand.svg)](https://travis-ci.org/rust-random/rand) -[![Build Status](https://ci.appveyor.com/api/projects/status/github/rust-random/rand?svg=true)](https://ci.appveyor.com/project/rust-random/rand) -[![Latest version](https://img.shields.io/crates/v/rand_hc.svg)](https://crates.io/crates/rand_hc) -[[![Book](https://img.shields.io/badge/book-master-yellow.svg)](https://rust-random.github.io/book/) -[![API](https://img.shields.io/badge/api-master-yellow.svg)](https://rust-random.github.io/rand/rand_hc) -[![API](https://docs.rs/rand_hc/badge.svg)](https://docs.rs/rand_hc) -[![Minimum rustc version](https://img.shields.io/badge/rustc-1.32+-lightgray.svg)](https://github.com/rust-random/rand#rust-version-requirements) - -A cryptographically secure random number generator that uses the HC-128 -algorithm. - -HC-128 is a stream cipher designed by Hongjun Wu[^1], that we use as an -RNG. It is selected as one of the "stream ciphers suitable for widespread -adoption" by eSTREAM[^2]. - -Links: - -- [API documentation (master)](https://rust-random.github.io/rand/rand_hc) -- [API documentation (docs.rs)](https://docs.rs/rand_hc) -- [Changelog](https://github.com/rust-random/rand/blob/master/rand_hc/CHANGELOG.md) - -[rand]: https://crates.io/crates/rand -[^1]: Hongjun Wu (2008). ["The Stream Cipher HC-128"]( - http://www.ecrypt.eu.org/stream/p3ciphers/hc/hc128_p3.pdf). - *The eSTREAM Finalists*, LNCS 4986, pp. 39–47, Springer-Verlag. - -[^2]: [eSTREAM: the ECRYPT Stream Cipher Project]( - http://www.ecrypt.eu.org/stream/) - - -## Crate Features - -`rand_hc` is `no_std` compatible. It does not require any functionality -outside of the `core` lib, thus there are no features to configure. - - -# License - -`rand_hc` is distributed under the terms of both the MIT license and the -Apache License (Version 2.0). - -See [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT), and -[COPYRIGHT](COPYRIGHT) for details. diff --git a/third_party/rust/rand_hc/src/hc128.rs b/third_party/rust/rand_hc/src/hc128.rs deleted file mode 100644 index a320f48f441f..000000000000 --- a/third_party/rust/rand_hc/src/hc128.rs +++ /dev/null @@ -1,464 +0,0 @@ -// Copyright 2018 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! The HC-128 random number generator. - -use core::fmt; -use rand_core::{CryptoRng, RngCore, SeedableRng, Error, le}; -use rand_core::block::{BlockRngCore, BlockRng}; - -const SEED_WORDS: usize = 8; // 128 bit key followed by 128 bit iv - -/// A cryptographically secure random number generator that uses the HC-128 -/// algorithm. -/// -/// HC-128 is a stream cipher designed by Hongjun Wu[^1], that we use as an -/// RNG. It is selected as one of the "stream ciphers suitable for widespread -/// adoption" by eSTREAM[^2]. -/// -/// HC-128 is an array based RNG. In this it is similar to RC-4 and ISAAC before -/// it, but those have never been proven cryptographically secure (or have even -/// been significantly compromised, as in the case of RC-4[^5]). -/// -/// Because HC-128 works with simple indexing into a large array and with a few -/// operations that parallelize well, it has very good performance. The size of -/// the array it needs, 4kb, can however be a disadvantage. -/// -/// This implementation is not based on the version of HC-128 submitted to the -/// eSTREAM contest, but on a later version by the author with a few small -/// improvements from December 15, 2009[^3]. -/// -/// HC-128 has no known weaknesses that are easier to exploit than doing a -/// brute-force search of 2128. A very comprehensive analysis of the -/// current state of known attacks / weaknesses of HC-128 is given in *Some -/// Results On Analysis And Implementation Of HC-128 Stream Cipher*[^4]. -/// -/// The average cycle length is expected to be -/// 21024*32+10-1 = 232777. -/// We support seeding with a 256-bit array, which matches the 128-bit key -/// concatenated with a 128-bit IV from the stream cipher. -/// -/// This implementation uses an output buffer of sixteen `u32` words, and uses -/// [`BlockRng`] to implement the [`RngCore`] methods. -/// -/// ## References -/// [^1]: Hongjun Wu (2008). ["The Stream Cipher HC-128"]( -/// http://www.ecrypt.eu.org/stream/p3ciphers/hc/hc128_p3.pdf). -/// *The eSTREAM Finalists*, LNCS 4986, pp. 39–47, Springer-Verlag. -/// -/// [^2]: [eSTREAM: the ECRYPT Stream Cipher Project]( -/// http://www.ecrypt.eu.org/stream/) -/// -/// [^3]: Hongjun Wu, [Stream Ciphers HC-128 and HC-256]( -/// https://www.ntu.edu.sg/home/wuhj/research/hc/index.html) -/// -/// [^4]: Shashwat Raizada (January 2015),["Some Results On Analysis And -/// Implementation Of HC-128 Stream Cipher"]( -/// http://library.isical.ac.in:8080/jspui/bitstream/123456789/6636/1/TH431.pdf). -/// -/// [^5]: Internet Engineering Task Force (February 2015), -/// ["Prohibiting RC4 Cipher Suites"](https://tools.ietf.org/html/rfc7465). -#[derive(Clone, Debug)] -pub struct Hc128Rng(BlockRng); - -impl RngCore for Hc128Rng { - #[inline] - fn next_u32(&mut self) -> u32 { - self.0.next_u32() - } - - #[inline] - fn next_u64(&mut self) -> u64 { - self.0.next_u64() - } - - #[inline] - fn fill_bytes(&mut self, dest: &mut [u8]) { - self.0.fill_bytes(dest) - } - - #[inline] - fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { - self.0.try_fill_bytes(dest) - } -} - -impl SeedableRng for Hc128Rng { - type Seed = ::Seed; - - #[inline] - fn from_seed(seed: Self::Seed) -> Self { - Hc128Rng(BlockRng::::from_seed(seed)) - } - - #[inline] - fn from_rng(rng: R) -> Result { - BlockRng::::from_rng(rng).map(Hc128Rng) - } -} - -impl CryptoRng for Hc128Rng {} - -/// The core of `Hc128Rng`, used with `BlockRng`. -#[derive(Clone)] -pub struct Hc128Core { - t: [u32; 1024], - counter1024: usize, -} - -// Custom Debug implementation that does not expose the internal state -impl fmt::Debug for Hc128Core { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Hc128Core {{}}") - } -} - -impl BlockRngCore for Hc128Core { - type Item = u32; - type Results = [u32; 16]; - - fn generate(&mut self, results: &mut Self::Results) { - assert!(self.counter1024 % 16 == 0); - - let cc = self.counter1024 % 512; - let dd = (cc + 16) % 512; - let ee = cc.wrapping_sub(16) % 512; - - if self.counter1024 & 512 == 0 { - // P block - results[0] = self.step_p(cc+0, cc+1, ee+13, ee+6, ee+4); - results[1] = self.step_p(cc+1, cc+2, ee+14, ee+7, ee+5); - results[2] = self.step_p(cc+2, cc+3, ee+15, ee+8, ee+6); - results[3] = self.step_p(cc+3, cc+4, cc+0, ee+9, ee+7); - results[4] = self.step_p(cc+4, cc+5, cc+1, ee+10, ee+8); - results[5] = self.step_p(cc+5, cc+6, cc+2, ee+11, ee+9); - results[6] = self.step_p(cc+6, cc+7, cc+3, ee+12, ee+10); - results[7] = self.step_p(cc+7, cc+8, cc+4, ee+13, ee+11); - results[8] = self.step_p(cc+8, cc+9, cc+5, ee+14, ee+12); - results[9] = self.step_p(cc+9, cc+10, cc+6, ee+15, ee+13); - results[10] = self.step_p(cc+10, cc+11, cc+7, cc+0, ee+14); - results[11] = self.step_p(cc+11, cc+12, cc+8, cc+1, ee+15); - results[12] = self.step_p(cc+12, cc+13, cc+9, cc+2, cc+0); - results[13] = self.step_p(cc+13, cc+14, cc+10, cc+3, cc+1); - results[14] = self.step_p(cc+14, cc+15, cc+11, cc+4, cc+2); - results[15] = self.step_p(cc+15, dd+0, cc+12, cc+5, cc+3); - } else { - // Q block - results[0] = self.step_q(cc+0, cc+1, ee+13, ee+6, ee+4); - results[1] = self.step_q(cc+1, cc+2, ee+14, ee+7, ee+5); - results[2] = self.step_q(cc+2, cc+3, ee+15, ee+8, ee+6); - results[3] = self.step_q(cc+3, cc+4, cc+0, ee+9, ee+7); - results[4] = self.step_q(cc+4, cc+5, cc+1, ee+10, ee+8); - results[5] = self.step_q(cc+5, cc+6, cc+2, ee+11, ee+9); - results[6] = self.step_q(cc+6, cc+7, cc+3, ee+12, ee+10); - results[7] = self.step_q(cc+7, cc+8, cc+4, ee+13, ee+11); - results[8] = self.step_q(cc+8, cc+9, cc+5, ee+14, ee+12); - results[9] = self.step_q(cc+9, cc+10, cc+6, ee+15, ee+13); - results[10] = self.step_q(cc+10, cc+11, cc+7, cc+0, ee+14); - results[11] = self.step_q(cc+11, cc+12, cc+8, cc+1, ee+15); - results[12] = self.step_q(cc+12, cc+13, cc+9, cc+2, cc+0); - results[13] = self.step_q(cc+13, cc+14, cc+10, cc+3, cc+1); - results[14] = self.step_q(cc+14, cc+15, cc+11, cc+4, cc+2); - results[15] = self.step_q(cc+15, dd+0, cc+12, cc+5, cc+3); - } - self.counter1024 = self.counter1024.wrapping_add(16); - } -} - -impl Hc128Core { - // One step of HC-128, update P and generate 32 bits keystream - #[inline(always)] - fn step_p(&mut self, i: usize, i511: usize, i3: usize, i10: usize, i12: usize) - -> u32 - { - let (p, q) = self.t.split_at_mut(512); - // FIXME: it would be great if we the bounds checks here could be - // optimized out, and we would not need unsafe. - // This improves performance by about 7%. - unsafe { - let temp0 = p.get_unchecked(i511).rotate_right(23); - let temp1 = p.get_unchecked(i3).rotate_right(10); - let temp2 = p.get_unchecked(i10).rotate_right(8); - *p.get_unchecked_mut(i) = p.get_unchecked(i) - .wrapping_add(temp2) - .wrapping_add(temp0 ^ temp1); - let temp3 = { - // The h1 function in HC-128 - let a = *p.get_unchecked(i12) as u8; - let c = (p.get_unchecked(i12) >> 16) as u8; - q[a as usize].wrapping_add(q[256 + c as usize]) - }; - temp3 ^ p.get_unchecked(i) - } - } - - // One step of HC-128, update Q and generate 32 bits keystream - // Similar to `step_p`, but `p` and `q` are swapped, and the rotates are to - // the left instead of to the right. - #[inline(always)] - fn step_q(&mut self, i: usize, i511: usize, i3: usize, i10: usize, i12: usize) - -> u32 - { - let (p, q) = self.t.split_at_mut(512); - unsafe { - let temp0 = q.get_unchecked(i511).rotate_left(23); - let temp1 = q.get_unchecked(i3).rotate_left(10); - let temp2 = q.get_unchecked(i10).rotate_left(8); - *q.get_unchecked_mut(i) = q.get_unchecked(i) - .wrapping_add(temp2) - .wrapping_add(temp0 ^ temp1); - let temp3 = { - // The h2 function in HC-128 - let a = *q.get_unchecked(i12) as u8; - let c = (q.get_unchecked(i12) >> 16) as u8; - p[a as usize].wrapping_add(p[256 + c as usize]) - }; - temp3 ^ q.get_unchecked(i) - } - } - - fn sixteen_steps(&mut self) { - assert!(self.counter1024 % 16 == 0); - - let cc = self.counter1024 % 512; - let dd = (cc + 16) % 512; - let ee = cc.wrapping_sub(16) % 512; - - if self.counter1024 < 512 { - // P block - self.t[cc+0] = self.step_p(cc+0, cc+1, ee+13, ee+6, ee+4); - self.t[cc+1] = self.step_p(cc+1, cc+2, ee+14, ee+7, ee+5); - self.t[cc+2] = self.step_p(cc+2, cc+3, ee+15, ee+8, ee+6); - self.t[cc+3] = self.step_p(cc+3, cc+4, cc+0, ee+9, ee+7); - self.t[cc+4] = self.step_p(cc+4, cc+5, cc+1, ee+10, ee+8); - self.t[cc+5] = self.step_p(cc+5, cc+6, cc+2, ee+11, ee+9); - self.t[cc+6] = self.step_p(cc+6, cc+7, cc+3, ee+12, ee+10); - self.t[cc+7] = self.step_p(cc+7, cc+8, cc+4, ee+13, ee+11); - self.t[cc+8] = self.step_p(cc+8, cc+9, cc+5, ee+14, ee+12); - self.t[cc+9] = self.step_p(cc+9, cc+10, cc+6, ee+15, ee+13); - self.t[cc+10] = self.step_p(cc+10, cc+11, cc+7, cc+0, ee+14); - self.t[cc+11] = self.step_p(cc+11, cc+12, cc+8, cc+1, ee+15); - self.t[cc+12] = self.step_p(cc+12, cc+13, cc+9, cc+2, cc+0); - self.t[cc+13] = self.step_p(cc+13, cc+14, cc+10, cc+3, cc+1); - self.t[cc+14] = self.step_p(cc+14, cc+15, cc+11, cc+4, cc+2); - self.t[cc+15] = self.step_p(cc+15, dd+0, cc+12, cc+5, cc+3); - } else { - // Q block - self.t[cc+512+0] = self.step_q(cc+0, cc+1, ee+13, ee+6, ee+4); - self.t[cc+512+1] = self.step_q(cc+1, cc+2, ee+14, ee+7, ee+5); - self.t[cc+512+2] = self.step_q(cc+2, cc+3, ee+15, ee+8, ee+6); - self.t[cc+512+3] = self.step_q(cc+3, cc+4, cc+0, ee+9, ee+7); - self.t[cc+512+4] = self.step_q(cc+4, cc+5, cc+1, ee+10, ee+8); - self.t[cc+512+5] = self.step_q(cc+5, cc+6, cc+2, ee+11, ee+9); - self.t[cc+512+6] = self.step_q(cc+6, cc+7, cc+3, ee+12, ee+10); - self.t[cc+512+7] = self.step_q(cc+7, cc+8, cc+4, ee+13, ee+11); - self.t[cc+512+8] = self.step_q(cc+8, cc+9, cc+5, ee+14, ee+12); - self.t[cc+512+9] = self.step_q(cc+9, cc+10, cc+6, ee+15, ee+13); - self.t[cc+512+10] = self.step_q(cc+10, cc+11, cc+7, cc+0, ee+14); - self.t[cc+512+11] = self.step_q(cc+11, cc+12, cc+8, cc+1, ee+15); - self.t[cc+512+12] = self.step_q(cc+12, cc+13, cc+9, cc+2, cc+0); - self.t[cc+512+13] = self.step_q(cc+13, cc+14, cc+10, cc+3, cc+1); - self.t[cc+512+14] = self.step_q(cc+14, cc+15, cc+11, cc+4, cc+2); - self.t[cc+512+15] = self.step_q(cc+15, dd+0, cc+12, cc+5, cc+3); - } - self.counter1024 += 16; - } - - // Initialize an HC-128 random number generator. The seed has to be - // 256 bits in length (`[u32; 8]`), matching the 128 bit `key` followed by - // 128 bit `iv` when HC-128 where to be used as a stream cipher. - #[inline(always)] // single use: SeedableRng::from_seed - fn init(seed: [u32; SEED_WORDS]) -> Self { - #[inline] - fn f1(x: u32) -> u32 { - x.rotate_right(7) ^ x.rotate_right(18) ^ (x >> 3) - } - - #[inline] - fn f2(x: u32) -> u32 { - x.rotate_right(17) ^ x.rotate_right(19) ^ (x >> 10) - } - - let mut t = [0u32; 1024]; - - // Expand the key and iv into P and Q - let (key, iv) = seed.split_at(4); - t[..4].copy_from_slice(key); - t[4..8].copy_from_slice(key); - t[8..12].copy_from_slice(iv); - t[12..16].copy_from_slice(iv); - - // Generate the 256 intermediate values W[16] ... W[256+16-1], and - // copy the last 16 generated values to the start op P. - for i in 16..256+16 { - t[i] = f2(t[i-2]).wrapping_add(t[i-7]).wrapping_add(f1(t[i-15])) - .wrapping_add(t[i-16]).wrapping_add(i as u32); - } - { - let (p1, p2) = t.split_at_mut(256); - p1[0..16].copy_from_slice(&p2[0..16]); - } - - // Generate both the P and Q tables - for i in 16..1024 { - t[i] = f2(t[i-2]).wrapping_add(t[i-7]).wrapping_add(f1(t[i-15])) - .wrapping_add(t[i-16]).wrapping_add(256 + i as u32); - } - - let mut core = Self { t, counter1024: 0 }; - - // run the cipher 1024 steps - for _ in 0..64 { core.sixteen_steps() }; - core.counter1024 = 0; - core - } -} - -impl SeedableRng for Hc128Core { - type Seed = [u8; SEED_WORDS*4]; - - /// Create an HC-128 random number generator with a seed. The seed has to be - /// 256 bits in length, matching the 128 bit `key` followed by 128 bit `iv` - /// when HC-128 where to be used as a stream cipher. - fn from_seed(seed: Self::Seed) -> Self { - let mut seed_u32 = [0u32; SEED_WORDS]; - le::read_u32_into(&seed, &mut seed_u32); - Self::init(seed_u32) - } -} - -impl CryptoRng for Hc128Core {} - -#[cfg(test)] -mod test { - use ::rand_core::{RngCore, SeedableRng}; - use super::Hc128Rng; - - #[test] - // Test vector 1 from the paper "The Stream Cipher HC-128" - fn test_hc128_true_values_a() { - let seed = [0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // key - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; // iv - let mut rng = Hc128Rng::from_seed(seed); - - let mut results = [0u32; 16]; - for i in results.iter_mut() { *i = rng.next_u32(); } - let expected = [0x73150082, 0x3bfd03a0, 0xfb2fd77f, 0xaa63af0e, - 0xde122fc6, 0xa7dc29b6, 0x62a68527, 0x8b75ec68, - 0x9036db1e, 0x81896005, 0x00ade078, 0x491fbf9a, - 0x1cdc3013, 0x6c3d6e24, 0x90f664b2, 0x9cd57102]; - assert_eq!(results, expected); - } - - #[test] - // Test vector 2 from the paper "The Stream Cipher HC-128" - fn test_hc128_true_values_b() { - let seed = [0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // key - 1,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; // iv - let mut rng = Hc128Rng::from_seed(seed); - - let mut results = [0u32; 16]; - for i in results.iter_mut() { *i = rng.next_u32(); } - let expected = [0xc01893d5, 0xb7dbe958, 0x8f65ec98, 0x64176604, - 0x36fc6724, 0xc82c6eec, 0x1b1c38a7, 0xc9b42a95, - 0x323ef123, 0x0a6a908b, 0xce757b68, 0x9f14f7bb, - 0xe4cde011, 0xaeb5173f, 0x89608c94, 0xb5cf46ca]; - assert_eq!(results, expected); - } - - #[test] - // Test vector 3 from the paper "The Stream Cipher HC-128" - fn test_hc128_true_values_c() { - let seed = [0x55,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // key - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; // iv - let mut rng = Hc128Rng::from_seed(seed); - - let mut results = [0u32; 16]; - for i in results.iter_mut() { *i = rng.next_u32(); } - let expected = [0x518251a4, 0x04b4930a, 0xb02af931, 0x0639f032, - 0xbcb4a47a, 0x5722480b, 0x2bf99f72, 0xcdc0e566, - 0x310f0c56, 0xd3cc83e8, 0x663db8ef, 0x62dfe07f, - 0x593e1790, 0xc5ceaa9c, 0xab03806f, 0xc9a6e5a0]; - assert_eq!(results, expected); - } - - #[test] - fn test_hc128_true_values_u64() { - let seed = [0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // key - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; // iv - let mut rng = Hc128Rng::from_seed(seed); - - let mut results = [0u64; 8]; - for i in results.iter_mut() { *i = rng.next_u64(); } - let expected = [0x3bfd03a073150082, 0xaa63af0efb2fd77f, - 0xa7dc29b6de122fc6, 0x8b75ec6862a68527, - 0x818960059036db1e, 0x491fbf9a00ade078, - 0x6c3d6e241cdc3013, 0x9cd5710290f664b2]; - assert_eq!(results, expected); - - // The RNG operates in a P block of 512 results and next a Q block. - // After skipping 2*800 u32 results we end up somewhere in the Q block - // of the second round - for _ in 0..800 { rng.next_u64(); } - - for i in results.iter_mut() { *i = rng.next_u64(); } - let expected = [0xd8c4d6ca84d0fc10, 0xf16a5d91dc66e8e7, - 0xd800de5bc37a8653, 0x7bae1f88c0dfbb4c, - 0x3bfe1f374e6d4d14, 0x424b55676be3fa06, - 0xe3a1e8758cbff579, 0x417f7198c5652bcd]; - assert_eq!(results, expected); - } - - #[test] - fn test_hc128_true_values_bytes() { - let seed = [0x55,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // key - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; // iv - let mut rng = Hc128Rng::from_seed(seed); - let expected = [0x31, 0xf9, 0x2a, 0xb0, 0x32, 0xf0, 0x39, 0x06, - 0x7a, 0xa4, 0xb4, 0xbc, 0x0b, 0x48, 0x22, 0x57, - 0x72, 0x9f, 0xf9, 0x2b, 0x66, 0xe5, 0xc0, 0xcd, - 0x56, 0x0c, 0x0f, 0x31, 0xe8, 0x83, 0xcc, 0xd3, - 0xef, 0xb8, 0x3d, 0x66, 0x7f, 0xe0, 0xdf, 0x62, - 0x90, 0x17, 0x3e, 0x59, 0x9c, 0xaa, 0xce, 0xc5, - 0x6f, 0x80, 0x03, 0xab, 0xa0, 0xe5, 0xa6, 0xc9, - 0x60, 0x95, 0x84, 0x7a, 0xa5, 0x68, 0x5a, 0x84, - 0xea, 0xd5, 0xf3, 0xea, 0x73, 0xa9, 0xad, 0x01, - 0x79, 0x7d, 0xbe, 0x9f, 0xea, 0xe3, 0xf9, 0x74, - 0x0e, 0xda, 0x2f, 0xa0, 0xe4, 0x7b, 0x4b, 0x1b, - 0xdd, 0x17, 0x69, 0x4a, 0xfe, 0x9f, 0x56, 0x95, - 0xad, 0x83, 0x6b, 0x9d, 0x60, 0xa1, 0x99, 0x96, - 0x90, 0x00, 0x66, 0x7f, 0xfa, 0x7e, 0x65, 0xe9, - 0xac, 0x8b, 0x92, 0x34, 0x77, 0xb4, 0x23, 0xd0, - 0xb9, 0xab, 0xb1, 0x47, 0x7d, 0x4a, 0x13, 0x0a]; - - // Pick a somewhat large buffer so we can test filling with the - // remainder from `state.results`, directly filling the buffer, and - // filling the remainder of the buffer. - let mut buffer = [0u8; 16*4*2]; - // Consume a value so that we have a remainder. - assert!(rng.next_u64() == 0x04b4930a518251a4); - rng.fill_bytes(&mut buffer); - - // [u8; 128] doesn't implement PartialEq - assert_eq!(buffer.len(), expected.len()); - for (b, e) in buffer.iter().zip(expected.iter()) { - assert_eq!(b, e); - } - } - - #[test] - fn test_hc128_clone() { - let seed = [0x55,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // key - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; // iv - let mut rng1 = Hc128Rng::from_seed(seed); - let mut rng2 = rng1.clone(); - for _ in 0..16 { - assert_eq!(rng1.next_u32(), rng2.next_u32()); - } - } -} diff --git a/third_party/rust/rand_hc/src/lib.rs b/third_party/rust/rand_hc/src/lib.rs deleted file mode 100644 index c1ae665147b3..000000000000 --- a/third_party/rust/rand_hc/src/lib.rs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2018 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! The HC128 random number generator. - -#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png", - html_favicon_url = "https://www.rust-lang.org/favicon.ico", - html_root_url = "https://rust-random.github.io/rand/")] - -#![deny(missing_docs)] -#![deny(missing_debug_implementations)] -#![doc(test(attr(allow(unused_variables), deny(warnings))))] - -#![no_std] - -mod hc128; - -pub use hc128::{Hc128Rng, Hc128Core}; diff --git a/third_party/rust/rand_pcg/.cargo-checksum.json b/third_party/rust/rand_pcg/.cargo-checksum.json deleted file mode 100644 index 434c84e8a1ff..000000000000 --- a/third_party/rust/rand_pcg/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"CHANGELOG.md":"292ca51a6202ad8a4f327d80f2049a63e9c49d06c6ff1c61fdcc299b5c77c279","COPYRIGHT":"90eb64f0279b0d9432accfa6023ff803bc4965212383697eee27a0f426d5f8d5","Cargo.toml":"e101de22750ddff758fc9a4115997b577f3670b2838ac65c4947cced09951ea1","LICENSE-APACHE":"aaff376532ea30a0cd5330b9502ad4a4c8bf769c539c87ffe78819d188a18ebf","LICENSE-MIT":"2234e3cefee876aeb686ad89e978bdb07bf118a1186ab1cf161bcdf69d4b4f57","README.md":"117266da3da7d9511e59800e3349fc8d899ace84c9c0f7624fd66392cd98a52a","src/lib.rs":"b64c8767ef4cbaa3dec51fc55354dfb1fcffd1ddcbc58ee1693bb1cc9b34bfb4","src/pcg128.rs":"8b8ee81f3774976f5f71a310b771535c0a37bc0051b096bfc9690d57fd2d9b7e","src/pcg64.rs":"748e59da6361d4255ae0a486ddeb63d665d15c3cef6a19a992f145317a1011e7","tests/lcg128xsl64.rs":"ab36c56f3e288b02a7d42540ac0968114af68e8cb838edc24701eaaaeb655542","tests/lcg64xsh32.rs":"0e1ab789d8918721d01871d3648d434747907ac1c6f3ffe9cf532b1196176b32","tests/mcg128xsl64.rs":"72cb8ef45e89eafcc01f261bfae7c3c7127a59a0d764434ceca32c17555af04c"},"package":"16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429"} \ No newline at end of file diff --git a/third_party/rust/rand_pcg/CHANGELOG.md b/third_party/rust/rand_pcg/CHANGELOG.md deleted file mode 100644 index 9f094bbacd2b..000000000000 --- a/third_party/rust/rand_pcg/CHANGELOG.md +++ /dev/null @@ -1,28 +0,0 @@ -# Changelog -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - -## [0.2.1] - 2019-10-22 -- Bump `bincode` version to 1.1.4 to fix minimal-dependency builds -- Removed unused `autocfg` build dependency. - -## [0.2.0] - 2019-06-12 -- Add `Lcg128Xsl64` aka `Pcg64` -- Bump minor crate version since rand_core bump is a breaking change -- Switch to Edition 2018 - -## [0.1.2] - 2019-02-23 -- require `bincode` 1.1.2 for i128 auto-detection -- make `bincode` a dev-dependency again #663 -- clean up tests and Serde support - -## [0.1.1] - 2018-10-04 -- make `bincode` an explicit dependency when using Serde - -## [0.1.0] - 2018-10-04 -Initial release, including: - -- `Lcg64Xsh32` aka `Pcg32` -- `Mcg128Xsl64` aka `Pcg64Mcg` diff --git a/third_party/rust/rand_pcg/COPYRIGHT b/third_party/rust/rand_pcg/COPYRIGHT deleted file mode 100644 index 468d907caf99..000000000000 --- a/third_party/rust/rand_pcg/COPYRIGHT +++ /dev/null @@ -1,12 +0,0 @@ -Copyrights in the Rand project are retained by their contributors. No -copyright assignment is required to contribute to the Rand project. - -For full authorship information, see the version control history. - -Except as otherwise noted (below and/or in individual files), Rand is -licensed under the Apache License, Version 2.0 or - or the MIT license - or , at your option. - -The Rand project includes code from the Rust project -published under these same licenses. diff --git a/third_party/rust/rand_pcg/Cargo.toml b/third_party/rust/rand_pcg/Cargo.toml deleted file mode 100644 index 2976bf3f0a63..000000000000 --- a/third_party/rust/rand_pcg/Cargo.toml +++ /dev/null @@ -1,42 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# 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 -# -# 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) - -[package] -edition = "2018" -name = "rand_pcg" -version = "0.2.1" -authors = ["The Rand Project Developers"] -description = "Selected PCG random number generators\n" -homepage = "https://crates.io/crates/rand_pcg" -documentation = "https://rust-random.github.io/rand/rand_pcg/" -readme = "README.md" -keywords = ["random", "rng", "pcg"] -categories = ["algorithms", "no-std"] -license = "MIT OR Apache-2.0" -repository = "https://github.com/rust-random/rand" -[dependencies.rand_core] -version = "0.5" - -[dependencies.serde] -version = "1" -features = ["derive"] -optional = true -[dev-dependencies.bincode] -version = "1.1.4" - -[features] -serde1 = ["serde"] -[badges.appveyor] -repository = "rust-random/rand" - -[badges.travis-ci] -repository = "rust-random/rand" diff --git a/third_party/rust/rand_pcg/LICENSE-APACHE b/third_party/rust/rand_pcg/LICENSE-APACHE deleted file mode 100644 index 17d74680f8cf..000000000000 --- a/third_party/rust/rand_pcg/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - https://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/third_party/rust/rand_pcg/LICENSE-MIT b/third_party/rust/rand_pcg/LICENSE-MIT deleted file mode 100644 index d46f058e98cc..000000000000 --- a/third_party/rust/rand_pcg/LICENSE-MIT +++ /dev/null @@ -1,26 +0,0 @@ -Copyright (c) 2014-2017 Melissa O'Neill and PCG Project contributors -Copyright 2018 Developers of the Rand project - -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/third_party/rust/rand_pcg/README.md b/third_party/rust/rand_pcg/README.md deleted file mode 100644 index fe47f2d41616..000000000000 --- a/third_party/rust/rand_pcg/README.md +++ /dev/null @@ -1,43 +0,0 @@ -# rand_pcg - -[![Build Status](https://travis-ci.org/rust-random/rand.svg?branch=master)](https://travis-ci.org/rust-random/rand) -[![Build Status](https://ci.appveyor.com/api/projects/status/github/rust-random/rand?svg=true)](https://ci.appveyor.com/project/rust-random/rand) -[![Latest version](https://img.shields.io/crates/v/rand_pcg.svg)](https://crates.io/crates/rand_pcg) -[[![Book](https://img.shields.io/badge/book-master-yellow.svg)](https://rust-random.github.io/book/) -[![API](https://img.shields.io/badge/api-master-yellow.svg)](https://rust-random.github.io/rand/rand_pcg) -[![API](https://docs.rs/rand_pcg/badge.svg)](https://docs.rs/rand_pcg) -[![Minimum rustc version](https://img.shields.io/badge/rustc-1.32+-lightgray.svg)](https://github.com/rust-random/rand#rust-version-requirements) - -Implements a selection of PCG random number generators. - -> PCG is a family of simple fast space-efficient statistically good algorithms -> for random number generation. [Melissa O'Neill, Harvey Mudd College, 2014]. - -The PCG algorithms are not suitable for cryptographic uses, but perform well -in statistical tests, use little memory and are fairly fast. -See the [pcg-random website](http://www.pcg-random.org/). - -This crate depends on [rand_core](https://crates.io/crates/rand_core) and is -part of the [Rand project](https://github.com/rust-random/rand). - -Links: - -- [API documentation (master)](https://rust-random.github.io/rand/rand_pcg) -- [API documentation (docs.rs)](https://docs.rs/rand_pcg) -- [Changelog](https://github.com/rust-random/rand/blob/master/rand_pcg/CHANGELOG.md) - - -## Crate Features - -`rand_pcg` is `no_std` compatible by default. - -The `serde1` feature includes implementations of `Serialize` and `Deserialize` -for the included RNGs. - -## License - -`rand_pcg` is distributed under the terms of both the MIT license and the -Apache License (Version 2.0). - -See [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT), and -[COPYRIGHT](COPYRIGHT) for details. diff --git a/third_party/rust/rand_pcg/src/lib.rs b/third_party/rust/rand_pcg/src/lib.rs deleted file mode 100644 index 22ba4a05d323..000000000000 --- a/third_party/rust/rand_pcg/src/lib.rs +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2018 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! The PCG random number generators. -//! -//! This is a native Rust implementation of a small selection of PCG generators. -//! The primary goal of this crate is simple, minimal, well-tested code; in -//! other words it is explicitly not a goal to re-implement all of PCG. -//! -//! This crate provides: -//! -//! - `Pcg32` aka `Lcg64Xsh32`, officially known as `pcg32`, a general -//! purpose RNG. This is a good choice on both 32-bit and 64-bit CPUs -//! (for 32-bit output). -//! - `Pcg64` aka `Lcg128Xsl64`, officially known as `pcg64`, a general -//! purpose RNG. This is a good choice on 64-bit CPUs. -//! - `Pcg64Mcg` aka `Mcg128Xsl64`, officially known as `pcg64_fast`, -//! a general purpose RNG using 128-bit multiplications. This has poor -//! performance on 32-bit CPUs but is a good choice on 64-bit CPUs for -//! both 32-bit and 64-bit output. -//! -//! Both of these use 16 bytes of state and 128-bit seeds, and are considered -//! value-stable (i.e. any change affecting the output given a fixed seed would -//! be considered a breaking change to the crate). - -#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png", - html_favicon_url = "https://www.rust-lang.org/favicon.ico", - html_root_url = "https://rust-random.github.io/rand/")] - -#![deny(missing_docs)] -#![deny(missing_debug_implementations)] - -#![allow(clippy::unreadable_literal)] - -#![no_std] - -mod pcg64; -#[cfg(not(target_os = "emscripten"))] mod pcg128; - -pub use self::pcg64::{Pcg32, Lcg64Xsh32}; -#[cfg(not(target_os = "emscripten"))] pub use self::pcg128::{ - Pcg64, Lcg128Xsl64, - Pcg64Mcg, Mcg128Xsl64, -}; diff --git a/third_party/rust/rand_pcg/src/pcg128.rs b/third_party/rust/rand_pcg/src/pcg128.rs deleted file mode 100644 index 311a41b29d8f..000000000000 --- a/third_party/rust/rand_pcg/src/pcg128.rs +++ /dev/null @@ -1,225 +0,0 @@ -// Copyright 2018 Developers of the Rand project. -// Copyright 2017 Paul Dicker. -// Copyright 2014-2017 Melissa O'Neill and PCG Project contributors -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! PCG random number generators - -// This is the default multiplier used by PCG for 64-bit state. -const MULTIPLIER: u128 = 0x2360_ED05_1FC6_5DA4_4385_DF64_9FCC_F645; - -use core::fmt; -use rand_core::{RngCore, SeedableRng, Error, le}; -#[cfg(feature="serde1")] use serde::{Serialize, Deserialize}; - -/// A PCG random number generator (XSL RR 128/64 (LCG) variant). -/// -/// Permuted Congruential Generator with 128-bit state, internal Linear -/// Congruential Generator, and 64-bit output via "xorshift low (bits), -/// random rotation" output function. -/// -/// This is a 128-bit LCG with explicitly chosen stream with the PCG-XSL-RR -/// output function. This combination is the standard `pcg64`. -/// -/// Despite the name, this implementation uses 32 bytes (256 bit) space -/// comprising 128 bits of state and 128 bits stream selector. These are both -/// set by `SeedableRng`, using a 256-bit seed. -#[derive(Clone)] -#[cfg_attr(feature="serde1", derive(Serialize,Deserialize))] -pub struct Lcg128Xsl64 { - state: u128, - increment: u128, -} - -/// `Lcg128Xsl64` is also officially known as `pcg64`. -pub type Pcg64 = Lcg128Xsl64; - -impl Lcg128Xsl64 { - /// Construct an instance compatible with PCG seed and stream. - /// - /// Note that PCG specifies default values for both parameters: - /// - /// - `state = 0xcafef00dd15ea5e5` - /// - `stream = 0xa02bdbf7bb3c0a7ac28fa16a64abf96` - pub fn new(state: u128, stream: u128) -> Self { - // The increment must be odd, hence we discard one bit: - let increment = (stream << 1) | 1; - Lcg128Xsl64::from_state_incr(state, increment) - } - - #[inline] - fn from_state_incr(state: u128, increment: u128) -> Self { - let mut pcg = Lcg128Xsl64 { state, increment }; - // Move away from inital value: - pcg.state = pcg.state.wrapping_add(pcg.increment); - pcg.step(); - pcg - } - - #[inline] - fn step(&mut self) { - // prepare the LCG for the next round - self.state = self.state - .wrapping_mul(MULTIPLIER) - .wrapping_add(self.increment); - } -} - -// Custom Debug implementation that does not expose the internal state -impl fmt::Debug for Lcg128Xsl64 { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Lcg128Xsl64 {{}}") - } -} - -/// We use a single 255-bit seed to initialise the state and select a stream. -/// One `seed` bit (lowest bit of `seed[8]`) is ignored. -impl SeedableRng for Lcg128Xsl64 { - type Seed = [u8; 32]; - - fn from_seed(seed: Self::Seed) -> Self { - let mut seed_u64 = [0u64; 4]; - le::read_u64_into(&seed, &mut seed_u64); - let state = u128::from(seed_u64[0]) | (u128::from(seed_u64[1]) << 64); - let incr = u128::from(seed_u64[2]) | (u128::from(seed_u64[3]) << 64); - - // The increment must be odd, hence we discard one bit: - Lcg128Xsl64::from_state_incr(state, incr | 1) - } -} - -impl RngCore for Lcg128Xsl64 { - #[inline] - fn next_u32(&mut self) -> u32 { - self.next_u64() as u32 - } - - #[inline] - fn next_u64(&mut self) -> u64 { - self.step(); - output_xsl_rr(self.state) - } - - #[inline] - fn fill_bytes(&mut self, dest: &mut [u8]) { - fill_bytes_impl(self, dest) - } - - #[inline] - fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { - self.fill_bytes(dest); - Ok(()) - } -} - - -/// A PCG random number generator (XSL 128/64 (MCG) variant). -/// -/// Permuted Congruential Generator with 128-bit state, internal Multiplicative -/// Congruential Generator, and 64-bit output via "xorshift low (bits), -/// random rotation" output function. -/// -/// This is a 128-bit MCG with the PCG-XSL-RR output function, also known as -/// `pcg64_fast`. -/// Note that compared to the standard `pcg64` (128-bit LCG with PCG-XSL-RR -/// output function), this RNG is faster, also has a long cycle, and still has -/// good performance on statistical tests. -#[derive(Clone)] -#[cfg_attr(feature="serde1", derive(Serialize,Deserialize))] -pub struct Mcg128Xsl64 { - state: u128, -} - -/// A friendly name for `Mcg128Xsl64` (also known as `pcg64_fast`). -pub type Pcg64Mcg = Mcg128Xsl64; - -impl Mcg128Xsl64 { - /// Construct an instance compatible with PCG seed. - /// - /// Note that PCG specifies a default value for the parameter: - /// - /// - `state = 0xcafef00dd15ea5e5` - pub fn new(state: u128) -> Self { - // Force low bit to 1, as in C version (C++ uses `state | 3` instead). - Mcg128Xsl64 { state: state | 1 } - } -} - -// Custom Debug implementation that does not expose the internal state -impl fmt::Debug for Mcg128Xsl64 { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Mcg128Xsl64 {{}}") - } -} - -/// We use a single 126-bit seed to initialise the state and select a stream. -/// Two `seed` bits (lowest order of last byte) are ignored. -impl SeedableRng for Mcg128Xsl64 { - type Seed = [u8; 16]; - - fn from_seed(seed: Self::Seed) -> Self { - // Read as if a little-endian u128 value: - let mut seed_u64 = [0u64; 2]; - le::read_u64_into(&seed, &mut seed_u64); - let state = u128::from(seed_u64[0]) | - u128::from(seed_u64[1]) << 64; - Mcg128Xsl64::new(state) - } -} - -impl RngCore for Mcg128Xsl64 { - #[inline] - fn next_u32(&mut self) -> u32 { - self.next_u64() as u32 - } - - #[inline] - fn next_u64(&mut self) -> u64 { - self.state = self.state.wrapping_mul(MULTIPLIER); - output_xsl_rr(self.state) - } - - #[inline] - fn fill_bytes(&mut self, dest: &mut [u8]) { - fill_bytes_impl(self, dest) - } - - #[inline] - fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { - self.fill_bytes(dest); - Ok(()) - } -} - -#[inline(always)] -fn output_xsl_rr(state: u128) -> u64 { - // Output function XSL RR ("xorshift low (bits), random rotation") - // Constants are for 128-bit state, 64-bit output - const XSHIFT: u32 = 64; // (128 - 64 + 64) / 2 - const ROTATE: u32 = 122; // 128 - 6 - - let rot = (state >> ROTATE) as u32; - let xsl = ((state >> XSHIFT) as u64) ^ (state as u64); - xsl.rotate_right(rot) -} - -#[inline(always)] -fn fill_bytes_impl(rng: &mut R, dest: &mut [u8]) { - let mut left = dest; - while left.len() >= 8 { - let (l, r) = {left}.split_at_mut(8); - left = r; - let chunk: [u8; 8] = rng.next_u64().to_le_bytes(); - l.copy_from_slice(&chunk); - } - let n = left.len(); - if n > 0 { - let chunk: [u8; 8] = rng.next_u64().to_le_bytes(); - left.copy_from_slice(&chunk[..n]); - } -} diff --git a/third_party/rust/rand_pcg/src/pcg64.rs b/third_party/rust/rand_pcg/src/pcg64.rs deleted file mode 100644 index fadc6dcdeeb5..000000000000 --- a/third_party/rust/rand_pcg/src/pcg64.rs +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright 2018 Developers of the Rand project. -// Copyright 2017 Paul Dicker. -// Copyright 2014-2017 Melissa O'Neill and PCG Project contributors -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! PCG random number generators - -use core::fmt; -use rand_core::{RngCore, SeedableRng, Error, le, impls}; -#[cfg(feature="serde1")] use serde::{Serialize, Deserialize}; - -// This is the default multiplier used by PCG for 64-bit state. -const MULTIPLIER: u64 = 6364136223846793005; - -/// A PCG random number generator (XSH RR 64/32 (LCG) variant). -/// -/// Permuted Congruential Generator with 64-bit state, internal Linear -/// Congruential Generator, and 32-bit output via "xorshift high (bits), -/// random rotation" output function. -/// -/// This is a 64-bit LCG with explicitly chosen stream with the PCG-XSH-RR -/// output function. This combination is the standard `pcg32`. -/// -/// Despite the name, this implementation uses 16 bytes (128 bit) space -/// comprising 64 bits of state and 64 bits stream selector. These are both set -/// by `SeedableRng`, using a 128-bit seed. -#[derive(Clone)] -#[cfg_attr(feature="serde1", derive(Serialize,Deserialize))] -pub struct Lcg64Xsh32 { - state: u64, - increment: u64, -} - -/// `Lcg64Xsh32` is also officially known as `pcg32`. -pub type Pcg32 = Lcg64Xsh32; - -impl Lcg64Xsh32 { - /// Construct an instance compatible with PCG seed and stream. - /// - /// Note that PCG specifies default values for both parameters: - /// - /// - `state = 0xcafef00dd15ea5e5` - /// - `stream = 0xa02bdbf7bb3c0a7` - // Note: stream is 1442695040888963407u64 >> 1 - pub fn new(state: u64, stream: u64) -> Self { - // The increment must be odd, hence we discard one bit: - let increment = (stream << 1) | 1; - Lcg64Xsh32::from_state_incr(state, increment) - } - - #[inline] - fn from_state_incr(state: u64, increment: u64) -> Self { - let mut pcg = Lcg64Xsh32 { state, increment }; - // Move away from inital value: - pcg.state = pcg.state.wrapping_add(pcg.increment); - pcg.step(); - pcg - } - - #[inline] - fn step(&mut self) { - // prepare the LCG for the next round - self.state = self.state - .wrapping_mul(MULTIPLIER) - .wrapping_add(self.increment); - } -} - -// Custom Debug implementation that does not expose the internal state -impl fmt::Debug for Lcg64Xsh32 { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Lcg64Xsh32 {{}}") - } -} - -/// We use a single 127-bit seed to initialise the state and select a stream. -/// One `seed` bit (lowest bit of `seed[8]`) is ignored. -impl SeedableRng for Lcg64Xsh32 { - type Seed = [u8; 16]; - - fn from_seed(seed: Self::Seed) -> Self { - let mut seed_u64 = [0u64; 2]; - le::read_u64_into(&seed, &mut seed_u64); - - // The increment must be odd, hence we discard one bit: - Lcg64Xsh32::from_state_incr(seed_u64[0], seed_u64[1] | 1) - } -} - -impl RngCore for Lcg64Xsh32 { - #[inline] - fn next_u32(&mut self) -> u32 { - let state = self.state; - self.step(); - - // Output function XSH RR: xorshift high (bits), followed by a random rotate - // Constants are for 64-bit state, 32-bit output - const ROTATE: u32 = 59; // 64 - 5 - const XSHIFT: u32 = 18; // (5 + 32) / 2 - const SPARE: u32 = 27; // 64 - 32 - 5 - - let rot = (state >> ROTATE) as u32; - let xsh = (((state >> XSHIFT) ^ state) >> SPARE) as u32; - xsh.rotate_right(rot) - } - - #[inline] - fn next_u64(&mut self) -> u64 { - impls::next_u64_via_u32(self) - } - - #[inline] - fn fill_bytes(&mut self, dest: &mut [u8]) { - impls::fill_bytes_via_next(self, dest) - } - - #[inline] - fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { - self.fill_bytes(dest); - Ok(()) - } -} diff --git a/third_party/rust/rand_pcg/tests/lcg128xsl64.rs b/third_party/rust/rand_pcg/tests/lcg128xsl64.rs deleted file mode 100644 index efc72fffd57f..000000000000 --- a/third_party/rust/rand_pcg/tests/lcg128xsl64.rs +++ /dev/null @@ -1,55 +0,0 @@ -use rand_core::{RngCore, SeedableRng}; -use rand_pcg::{Lcg128Xsl64, Pcg64}; - -#[test] -fn test_lcg128xsl64_construction() { - // Test that various construction techniques produce a working RNG. - let seed = [1,2,3,4, 5,6,7,8, 9,10,11,12, 13,14,15,16, - 17,18,19,20, 21,22,23,24, 25,26,27,28, 29,30,31,32]; - let mut rng1 = Lcg128Xsl64::from_seed(seed); - assert_eq!(rng1.next_u64(), 8740028313290271629); - - let mut rng2 = Lcg128Xsl64::from_rng(&mut rng1).unwrap(); - assert_eq!(rng2.next_u64(), 1922280315005786345); - - let mut rng3 = Lcg128Xsl64::seed_from_u64(0); - assert_eq!(rng3.next_u64(), 2354861276966075475); - - // This is the same as Lcg128Xsl64, so we only have a single test: - let mut rng4 = Pcg64::seed_from_u64(0); - assert_eq!(rng4.next_u64(), 2354861276966075475); -} - -#[test] -fn test_lcg128xsl64_true_values() { - // Numbers copied from official test suite (C version). - let mut rng = Lcg128Xsl64::new(42, 54); - - let mut results = [0u64; 6]; - for i in results.iter_mut() { *i = rng.next_u64(); } - let expected: [u64; 6] = [0x86b1da1d72062b68, 0x1304aa46c9853d39, - 0xa3670e9e0dd50358, 0xf9090e529a7dae00, 0xc85b9fd837996f2c, 0x606121f8e3919196]; - assert_eq!(results, expected); -} - -#[cfg(feature="serde1")] -#[test] -fn test_lcg128xsl64_serde() { - use bincode; - use std::io::{BufWriter, BufReader}; - - let mut rng = Lcg128Xsl64::seed_from_u64(0); - - let buf: Vec = Vec::new(); - let mut buf = BufWriter::new(buf); - bincode::serialize_into(&mut buf, &rng).expect("Could not serialize"); - - let buf = buf.into_inner().unwrap(); - let mut read = BufReader::new(&buf[..]); - let mut deserialized: Lcg128Xsl64 = bincode::deserialize_from(&mut read) - .expect("Could not deserialize"); - - for _ in 0..16 { - assert_eq!(rng.next_u64(), deserialized.next_u64()); - } -} diff --git a/third_party/rust/rand_pcg/tests/lcg64xsh32.rs b/third_party/rust/rand_pcg/tests/lcg64xsh32.rs deleted file mode 100644 index e05bcc1dfa3b..000000000000 --- a/third_party/rust/rand_pcg/tests/lcg64xsh32.rs +++ /dev/null @@ -1,54 +0,0 @@ -use rand_core::{RngCore, SeedableRng}; -use rand_pcg::{Lcg64Xsh32, Pcg32}; - -#[test] -fn test_lcg64xsh32_construction() { - // Test that various construction techniques produce a working RNG. - let seed = [1,2,3,4, 5,6,7,8, 9,10,11,12, 13,14,15,16]; - let mut rng1 = Lcg64Xsh32::from_seed(seed); - assert_eq!(rng1.next_u64(), 1204678643940597513); - - let mut rng2 = Lcg64Xsh32::from_rng(&mut rng1).unwrap(); - assert_eq!(rng2.next_u64(), 12384929573776311845); - - let mut rng3 = Lcg64Xsh32::seed_from_u64(0); - assert_eq!(rng3.next_u64(), 18195738587432868099); - - // This is the same as Lcg64Xsh32, so we only have a single test: - let mut rng4 = Pcg32::seed_from_u64(0); - assert_eq!(rng4.next_u64(), 18195738587432868099); -} - -#[test] -fn test_lcg64xsh32_true_values() { - // Numbers copied from official test suite. - let mut rng = Lcg64Xsh32::new(42, 54); - - let mut results = [0u32; 6]; - for i in results.iter_mut() { *i = rng.next_u32(); } - let expected: [u32; 6] = [0xa15c02b7, 0x7b47f409, 0xba1d3330, - 0x83d2f293, 0xbfa4784b, 0xcbed606e]; - assert_eq!(results, expected); -} - -#[cfg(feature="serde1")] -#[test] -fn test_lcg64xsh32_serde() { - use bincode; - use std::io::{BufWriter, BufReader}; - - let mut rng = Lcg64Xsh32::seed_from_u64(0); - - let buf: Vec = Vec::new(); - let mut buf = BufWriter::new(buf); - bincode::serialize_into(&mut buf, &rng).expect("Could not serialize"); - - let buf = buf.into_inner().unwrap(); - let mut read = BufReader::new(&buf[..]); - let mut deserialized: Lcg64Xsh32 = bincode::deserialize_from(&mut read) - .expect("Could not deserialize"); - - for _ in 0..16 { - assert_eq!(rng.next_u64(), deserialized.next_u64()); - } -} diff --git a/third_party/rust/rand_pcg/tests/mcg128xsl64.rs b/third_party/rust/rand_pcg/tests/mcg128xsl64.rs deleted file mode 100644 index d58fa7525998..000000000000 --- a/third_party/rust/rand_pcg/tests/mcg128xsl64.rs +++ /dev/null @@ -1,54 +0,0 @@ -use rand_core::{RngCore, SeedableRng}; -use rand_pcg::{Mcg128Xsl64, Pcg64Mcg}; - -#[test] -fn test_mcg128xsl64_construction() { - // Test that various construction techniques produce a working RNG. - let seed = [1,2,3,4, 5,6,7,8, 9,10,11,12, 13,14,15,16]; - let mut rng1 = Mcg128Xsl64::from_seed(seed); - assert_eq!(rng1.next_u64(), 7071994460355047496); - - let mut rng2 = Mcg128Xsl64::from_rng(&mut rng1).unwrap(); - assert_eq!(rng2.next_u64(), 12300796107712034932); - - let mut rng3 = Mcg128Xsl64::seed_from_u64(0); - assert_eq!(rng3.next_u64(), 6198063878555692194); - - // This is the same as Mcg128Xsl64, so we only have a single test: - let mut rng4 = Pcg64Mcg::seed_from_u64(0); - assert_eq!(rng4.next_u64(), 6198063878555692194); -} - -#[test] -fn test_mcg128xsl64_true_values() { - // Numbers copied from official test suite (C version). - let mut rng = Mcg128Xsl64::new(42); - - let mut results = [0u64; 6]; - for i in results.iter_mut() { *i = rng.next_u64(); } - let expected: [u64; 6] = [0x63b4a3a813ce700a, 0x382954200617ab24, - 0xa7fd85ae3fe950ce, 0xd715286aa2887737, 0x60c92fee2e59f32c, 0x84c4e96beff30017]; - assert_eq!(results, expected); -} - -#[cfg(feature="serde1")] -#[test] -fn test_mcg128xsl64_serde() { - use bincode; - use std::io::{BufWriter, BufReader}; - - let mut rng = Mcg128Xsl64::seed_from_u64(0); - - let buf: Vec = Vec::new(); - let mut buf = BufWriter::new(buf); - bincode::serialize_into(&mut buf, &rng).expect("Could not serialize"); - - let buf = buf.into_inner().unwrap(); - let mut read = BufReader::new(&buf[..]); - let mut deserialized: Mcg128Xsl64 = bincode::deserialize_from(&mut read) - .expect("Could not deserialize"); - - for _ in 0..16 { - assert_eq!(rng.next_u64(), deserialized.next_u64()); - } -} diff --git a/third_party/rust/wasi/.cargo-checksum.json b/third_party/rust/wasi/.cargo-checksum.json index 05c3a226971a..4c858cdd5726 100644 --- a/third_party/rust/wasi/.cargo-checksum.json +++ b/third_party/rust/wasi/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"CODE_OF_CONDUCT.md":"a13aaaf393818bd91207c618724d3fb74944ca5161201822a84af951bcf655ef","CONTRIBUTING.md":"2c908a3e263dc35dfed131c02ff907cd72fafb2c2096e4ba9b1e0cbb7a1b76df","Cargo.toml":"2ecba6e9e633226bc0a26ca5dd580c97c510be660fa348cea248125d90e85bf2","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-Apache-2.0_WITH_LLVM-exception":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","ORG_CODE_OF_CONDUCT.md":"a62b69bf86e605ee1bcbb2f0a12ba79e4cebb6983a7b6491949750aecc4f2178","README.md":"9412b3834687f28f0fae01a6e45b1309733ac92dcf04ef3ef36a823e76a6fed2","SECURITY.md":"4d75afb09dd28eb5982e3a1f768ee398d90204669ceef3240a16b31dcf04148a","old-bitflags.patch":"6a35cdbe866fbb51608195b74f0e6c0d37201ed933e473588cc2ab6211916b40","src/error.rs":"96818880fab83125079842e35aacb49333ac66699e223f896699e4fdb88b99e8","src/lib.rs":"7bfc4ffb02d1abfe25f3682affa3a50ca1e7b9d67a478a3d0f2e7788aeaab2b4","src/lib_generated.rs":"7983898c5fc69db19047cf5c3da5ed615b68859094cad8de9a3bc63d1a28de15"},"package":"cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"} \ No newline at end of file +{"files":{"CODE_OF_CONDUCT.md":"a13aaaf393818bd91207c618724d3fb74944ca5161201822a84af951bcf655ef","CONTRIBUTING.md":"2c908a3e263dc35dfed131c02ff907cd72fafb2c2096e4ba9b1e0cbb7a1b76df","Cargo.toml":"946b521f577983feb92abbad62bd85932fe4fe26b7a61dcaba4030d242667885","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-Apache-2.0_WITH_LLVM-exception":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","ORG_CODE_OF_CONDUCT.md":"a62b69bf86e605ee1bcbb2f0a12ba79e4cebb6983a7b6491949750aecc4f2178","README.md":"c021f687a5a61d9c308581401e7aa4454585a30c418abdd02e3a1ef71daa035f","SECURITY.md":"4d75afb09dd28eb5982e3a1f768ee398d90204669ceef3240a16b31dcf04148a","src/error.rs":"270ec14e103130ac5981997ddfa616851cb596fecd48ea7212a7a59dcb110c7f","src/lib.rs":"ce2e7ee6a6e4d5900f3835568b168afc70870d601b2bb94f1a6b9ddd2f046c3a","src/lib_generated.rs":"f92f8c522904454c5909843bc2db4c34af48ca2eae8634cc77dc51d89fa5eae2"},"package":"fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"} \ No newline at end of file diff --git a/third_party/rust/wasi/Cargo.toml b/third_party/rust/wasi/Cargo.toml index cd0dfb535118..23e3b2f6e8cc 100644 --- a/third_party/rust/wasi/Cargo.toml +++ b/third_party/rust/wasi/Cargo.toml @@ -13,7 +13,7 @@ [package] edition = "2018" name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" +version = "0.10.2+wasi-snapshot-preview1" authors = ["The Cranelift Project Developers"] description = "Experimental WASI API bindings for Rust" documentation = "https://docs.rs/wasi" diff --git a/third_party/rust/wasi/README.md b/third_party/rust/wasi/README.md index e92f50e3f5ca..801f56a4e023 100644 --- a/third_party/rust/wasi/README.md +++ b/third_party/rust/wasi/README.md @@ -64,6 +64,24 @@ $ cargo wasi run Hello, World! ``` +# Development + +The bulk of the `wasi` crate is generated by the `witx-bindgen` tool, which lives at +`crates/witx-bindgen` and is part of the cargo workspace. + +The `src/lib_generated.rs` file can be re-generated with the following +command: + +``` +cargo run -p witx-bindgen -- crates/witx-bindgen/WASI/phases/snapshot/witx/wasi_snapshot_preview1.witx > src/lib_generated.rs +``` + +Note that this uses the WASI standard repository as a submodule. If you do not +have this submodule present in your source tree, run: +``` +git submodule update --init +``` + # License This project is licensed under the Apache 2.0 license with the LLVM exception. diff --git a/third_party/rust/wasi/old-bitflags.patch b/third_party/rust/wasi/old-bitflags.patch deleted file mode 100644 index 7c874d495485..000000000000 --- a/third_party/rust/wasi/old-bitflags.patch +++ /dev/null @@ -1,570 +0,0 @@ -diff --git a/Cargo.toml b/Cargo.toml -index 47ecced..ec6e7c9 100644 ---- a/Cargo.toml -+++ b/Cargo.toml -@@ -12,6 +12,7 @@ readme = "README.md" - documentation = "https://docs.rs/wasi" - - [dependencies] -+bitflags = "1.1.0" - - [badges] - maintenance = { status = "experimental" } -diff --git a/src/lib.rs b/src/lib.rs -index 42e13ea..03d3d19 100644 ---- a/src/lib.rs -+++ b/src/lib.rs -@@ -13,4 +13,7 @@ - )] - #![no_std] - -+#[macro_use] -+extern crate bitflags; -+ - pub mod wasi_unstable; -diff --git a/src/wasi_unstable/mod.rs b/src/wasi_unstable/mod.rs -index 4703cc9..b3fd897 100644 ---- a/src/wasi_unstable/mod.rs -+++ b/src/wasi_unstable/mod.rs -@@ -19,27 +19,18 @@ pub type Clockid = __wasi_clockid_t; - pub type Device = __wasi_device_t; - pub type Dircookie = __wasi_dircookie_t; - pub type Errno = __wasi_errno_t; --pub type Eventrwflags = __wasi_eventrwflags_t; - pub type Eventtype = __wasi_eventtype_t; - pub type Exitcode = __wasi_exitcode_t; - pub type Fd = __wasi_fd_t; --pub type Fdflags = __wasi_fdflags_t; - pub type Filedelta = __wasi_filedelta_t; - pub type Filesize = __wasi_filesize_t; - pub type Filetype = __wasi_filetype_t; --pub type Fstflags = __wasi_fstflags_t; - pub type Inode = __wasi_inode_t; - pub type Linkcount = __wasi_linkcount_t; --pub type Lookupflags = __wasi_lookupflags_t; --pub type Oflags = __wasi_oflags_t; - pub type Preopentype = __wasi_preopentype_t; --pub type Riflags = __wasi_riflags_t; --pub type Rights = __wasi_rights_t; - pub type Roflags = __wasi_roflags_t; --pub type Sdflags = __wasi_sdflags_t; - pub type Siflags = __wasi_siflags_t; - pub type Signal = __wasi_signal_t; --pub type Subclockflags = __wasi_subclockflags_t; - pub type Timestamp = __wasi_timestamp_t; - pub type Userdata = __wasi_userdata_t; - pub type Whence = __wasi_whence_t; -@@ -52,189 +43,231 @@ pub type Subscription = __wasi_subscription_t; - pub type Event = __wasi_event_t; - pub type Prestat = __wasi_prestat_t; - --pub const ADVICE_NORMAL: u8 = __WASI_ADVICE_NORMAL; --pub const ADVICE_SEQUENTIAL: u8 = __WASI_ADVICE_SEQUENTIAL; --pub const ADVICE_RANDOM: u8 = __WASI_ADVICE_RANDOM; --pub const ADVICE_WILLNEED: u8 = __WASI_ADVICE_WILLNEED; --pub const ADVICE_DONTNEED: u8 = __WASI_ADVICE_DONTNEED; --pub const ADVICE_NOREUSE: u8 = __WASI_ADVICE_NOREUSE; --pub const CLOCK_REALTIME: u32 = __WASI_CLOCK_REALTIME; --pub const CLOCK_MONOTONIC: u32 = __WASI_CLOCK_MONOTONIC; --pub const CLOCK_PROCESS_CPUTIME_ID: u32 = __WASI_CLOCK_PROCESS_CPUTIME_ID; --pub const CLOCK_THREAD_CPUTIME_ID: u32 = __WASI_CLOCK_THREAD_CPUTIME_ID; --pub const DIRCOOKIE_START: u64 = __WASI_DIRCOOKIE_START; --pub const ESUCCESS: u16 = __WASI_ESUCCESS; --pub const E2BIG: u16 = __WASI_E2BIG; --pub const EACCES: u16 = __WASI_EACCES; --pub const EADDRINUSE: u16 = __WASI_EADDRINUSE; --pub const EADDRNOTAVAIL: u16 = __WASI_EADDRNOTAVAIL; --pub const EAFNOSUPPORT: u16 = __WASI_EAFNOSUPPORT; --pub const EAGAIN: u16 = __WASI_EAGAIN; --pub const EALREADY: u16 = __WASI_EALREADY; --pub const EBADF: u16 = __WASI_EBADF; --pub const EBADMSG: u16 = __WASI_EBADMSG; --pub const EBUSY: u16 = __WASI_EBUSY; --pub const ECANCELED: u16 = __WASI_ECANCELED; --pub const ECHILD: u16 = __WASI_ECHILD; --pub const ECONNABORTED: u16 = __WASI_ECONNABORTED; --pub const ECONNREFUSED: u16 = __WASI_ECONNREFUSED; --pub const ECONNRESET: u16 = __WASI_ECONNRESET; --pub const EDEADLK: u16 = __WASI_EDEADLK; --pub const EDESTADDRREQ: u16 = __WASI_EDESTADDRREQ; --pub const EDOM: u16 = __WASI_EDOM; --pub const EDQUOT: u16 = __WASI_EDQUOT; --pub const EEXIST: u16 = __WASI_EEXIST; --pub const EFAULT: u16 = __WASI_EFAULT; --pub const EFBIG: u16 = __WASI_EFBIG; --pub const EHOSTUNREACH: u16 = __WASI_EHOSTUNREACH; --pub const EIDRM: u16 = __WASI_EIDRM; --pub const EILSEQ: u16 = __WASI_EILSEQ; --pub const EINPROGRESS: u16 = __WASI_EINPROGRESS; --pub const EINTR: u16 = __WASI_EINTR; --pub const EINVAL: u16 = __WASI_EINVAL; --pub const EIO: u16 = __WASI_EIO; --pub const EISCONN: u16 = __WASI_EISCONN; --pub const EISDIR: u16 = __WASI_EISDIR; --pub const ELOOP: u16 = __WASI_ELOOP; --pub const EMFILE: u16 = __WASI_EMFILE; --pub const EMLINK: u16 = __WASI_EMLINK; --pub const EMSGSIZE: u16 = __WASI_EMSGSIZE; --pub const EMULTIHOP: u16 = __WASI_EMULTIHOP; --pub const ENAMETOOLONG: u16 = __WASI_ENAMETOOLONG; --pub const ENETDOWN: u16 = __WASI_ENETDOWN; --pub const ENETRESET: u16 = __WASI_ENETRESET; --pub const ENETUNREACH: u16 = __WASI_ENETUNREACH; --pub const ENFILE: u16 = __WASI_ENFILE; --pub const ENOBUFS: u16 = __WASI_ENOBUFS; --pub const ENODEV: u16 = __WASI_ENODEV; --pub const ENOENT: u16 = __WASI_ENOENT; --pub const ENOEXEC: u16 = __WASI_ENOEXEC; --pub const ENOLCK: u16 = __WASI_ENOLCK; --pub const ENOLINK: u16 = __WASI_ENOLINK; --pub const ENOMEM: u16 = __WASI_ENOMEM; --pub const ENOMSG: u16 = __WASI_ENOMSG; --pub const ENOPROTOOPT: u16 = __WASI_ENOPROTOOPT; --pub const ENOSPC: u16 = __WASI_ENOSPC; --pub const ENOSYS: u16 = __WASI_ENOSYS; --pub const ENOTCONN: u16 = __WASI_ENOTCONN; --pub const ENOTDIR: u16 = __WASI_ENOTDIR; --pub const ENOTEMPTY: u16 = __WASI_ENOTEMPTY; --pub const ENOTRECOVERABLE: u16 = __WASI_ENOTRECOVERABLE; --pub const ENOTSOCK: u16 = __WASI_ENOTSOCK; --pub const ENOTSUP: u16 = __WASI_ENOTSUP; --pub const ENOTTY: u16 = __WASI_ENOTTY; --pub const ENXIO: u16 = __WASI_ENXIO; --pub const EOVERFLOW: u16 = __WASI_EOVERFLOW; --pub const EOWNERDEAD: u16 = __WASI_EOWNERDEAD; --pub const EPERM: u16 = __WASI_EPERM; --pub const EPIPE: u16 = __WASI_EPIPE; --pub const EPROTO: u16 = __WASI_EPROTO; --pub const EPROTONOSUPPORT: u16 = __WASI_EPROTONOSUPPORT; --pub const EPROTOTYPE: u16 = __WASI_EPROTOTYPE; --pub const ERANGE: u16 = __WASI_ERANGE; --pub const EROFS: u16 = __WASI_EROFS; --pub const ESPIPE: u16 = __WASI_ESPIPE; --pub const ESRCH: u16 = __WASI_ESRCH; --pub const ESTALE: u16 = __WASI_ESTALE; --pub const ETIMEDOUT: u16 = __WASI_ETIMEDOUT; --pub const ETXTBSY: u16 = __WASI_ETXTBSY; --pub const EXDEV: u16 = __WASI_EXDEV; --pub const ENOTCAPABLE: u16 = __WASI_ENOTCAPABLE; --pub const EVENT_FD_READWRITE_HANGUP: u16 = __WASI_EVENT_FD_READWRITE_HANGUP; --pub const EVENTTYPE_CLOCK: u8 = __WASI_EVENTTYPE_CLOCK; --pub const EVENTTYPE_FD_READ: u8 = __WASI_EVENTTYPE_FD_READ; --pub const EVENTTYPE_FD_WRITE: u8 = __WASI_EVENTTYPE_FD_WRITE; --pub const FDFLAG_APPEND: u16 = __WASI_FDFLAG_APPEND; --pub const FDFLAG_DSYNC: u16 = __WASI_FDFLAG_DSYNC; --pub const FDFLAG_NONBLOCK: u16 = __WASI_FDFLAG_NONBLOCK; --pub const FDFLAG_RSYNC: u16 = __WASI_FDFLAG_RSYNC; --pub const FDFLAG_SYNC: u16 = __WASI_FDFLAG_SYNC; --pub const FILETYPE_UNKNOWN: u8 = __WASI_FILETYPE_UNKNOWN; --pub const FILETYPE_BLOCK_DEVICE: u8 = __WASI_FILETYPE_BLOCK_DEVICE; --pub const FILETYPE_CHARACTER_DEVICE: u8 = __WASI_FILETYPE_CHARACTER_DEVICE; --pub const FILETYPE_DIRECTORY: u8 = __WASI_FILETYPE_DIRECTORY; --pub const FILETYPE_REGULAR_FILE: u8 = __WASI_FILETYPE_REGULAR_FILE; --pub const FILETYPE_SOCKET_DGRAM: u8 = __WASI_FILETYPE_SOCKET_DGRAM; --pub const FILETYPE_SOCKET_STREAM: u8 = __WASI_FILETYPE_SOCKET_STREAM; --pub const FILETYPE_SYMBOLIC_LINK: u8 = __WASI_FILETYPE_SYMBOLIC_LINK; --pub const FILESTAT_SET_ATIM: u16 = __WASI_FILESTAT_SET_ATIM; --pub const FILESTAT_SET_ATIM_NOW: u16 = __WASI_FILESTAT_SET_ATIM_NOW; --pub const FILESTAT_SET_MTIM: u16 = __WASI_FILESTAT_SET_MTIM; --pub const FILESTAT_SET_MTIM_NOW: u16 = __WASI_FILESTAT_SET_MTIM_NOW; --pub const LOOKUP_SYMLINK_FOLLOW: u32 = __WASI_LOOKUP_SYMLINK_FOLLOW; --pub const O_CREAT: u16 = __WASI_O_CREAT; --pub const O_DIRECTORY: u16 = __WASI_O_DIRECTORY; --pub const O_EXCL: u16 = __WASI_O_EXCL; --pub const O_TRUNC: u16 = __WASI_O_TRUNC; --pub const PREOPENTYPE_DIR: u8 = __WASI_PREOPENTYPE_DIR; --pub const SOCK_RECV_PEEK: u16 = __WASI_SOCK_RECV_PEEK; --pub const SOCK_RECV_WAITALL: u16 = __WASI_SOCK_RECV_WAITALL; --pub const RIGHT_FD_DATASYNC: u64 = __WASI_RIGHT_FD_DATASYNC; --pub const RIGHT_FD_READ: u64 = __WASI_RIGHT_FD_READ; --pub const RIGHT_FD_SEEK: u64 = __WASI_RIGHT_FD_SEEK; --pub const RIGHT_FD_FDSTAT_SET_FLAGS: u64 = __WASI_RIGHT_FD_FDSTAT_SET_FLAGS; --pub const RIGHT_FD_SYNC: u64 = __WASI_RIGHT_FD_SYNC; --pub const RIGHT_FD_TELL: u64 = __WASI_RIGHT_FD_TELL; --pub const RIGHT_FD_WRITE: u64 = __WASI_RIGHT_FD_WRITE; --pub const RIGHT_FD_ADVISE: u64 = __WASI_RIGHT_FD_ADVISE; --pub const RIGHT_FD_ALLOCATE: u64 = __WASI_RIGHT_FD_ALLOCATE; --pub const RIGHT_PATH_CREATE_DIRECTORY: u64 = __WASI_RIGHT_PATH_CREATE_DIRECTORY; --pub const RIGHT_PATH_CREATE_FILE: u64 = __WASI_RIGHT_PATH_CREATE_FILE; --pub const RIGHT_PATH_LINK_SOURCE: u64 = __WASI_RIGHT_PATH_LINK_SOURCE; --pub const RIGHT_PATH_LINK_TARGET: u64 = __WASI_RIGHT_PATH_LINK_TARGET; --pub const RIGHT_PATH_OPEN: u64 = __WASI_RIGHT_PATH_OPEN; --pub const RIGHT_FD_READDIR: u64 = __WASI_RIGHT_FD_READDIR; --pub const RIGHT_PATH_READLINK: u64 = __WASI_RIGHT_PATH_READLINK; --pub const RIGHT_PATH_RENAME_SOURCE: u64 = __WASI_RIGHT_PATH_RENAME_SOURCE; --pub const RIGHT_PATH_RENAME_TARGET: u64 = __WASI_RIGHT_PATH_RENAME_TARGET; --pub const RIGHT_PATH_FILESTAT_GET: u64 = __WASI_RIGHT_PATH_FILESTAT_GET; --pub const RIGHT_PATH_FILESTAT_SET_SIZE: u64 = __WASI_RIGHT_PATH_FILESTAT_SET_SIZE; --pub const RIGHT_PATH_FILESTAT_SET_TIMES: u64 = __WASI_RIGHT_PATH_FILESTAT_SET_TIMES; --pub const RIGHT_FD_FILESTAT_GET: u64 = __WASI_RIGHT_FD_FILESTAT_GET; --pub const RIGHT_FD_FILESTAT_SET_SIZE: u64 = __WASI_RIGHT_FD_FILESTAT_SET_SIZE; --pub const RIGHT_FD_FILESTAT_SET_TIMES: u64 = __WASI_RIGHT_FD_FILESTAT_SET_TIMES; --pub const RIGHT_PATH_SYMLINK: u64 = __WASI_RIGHT_PATH_SYMLINK; --pub const RIGHT_PATH_REMOVE_DIRECTORY: u64 = __WASI_RIGHT_PATH_REMOVE_DIRECTORY; --pub const RIGHT_PATH_UNLINK_FILE: u64 = __WASI_RIGHT_PATH_UNLINK_FILE; --pub const RIGHT_POLL_FD_READWRITE: u64 = __WASI_RIGHT_POLL_FD_READWRITE; --pub const RIGHT_SOCK_SHUTDOWN: u64 = __WASI_RIGHT_SOCK_SHUTDOWN; --pub const SOCK_RECV_DATA_TRUNCATED: u16 = __WASI_SOCK_RECV_DATA_TRUNCATED; --pub const SHUT_RD: u8 = __WASI_SHUT_RD; --pub const SHUT_WR: u8 = __WASI_SHUT_WR; --pub const SIGHUP: u8 = __WASI_SIGHUP; --pub const SIGINT: u8 = __WASI_SIGINT; --pub const SIGQUIT: u8 = __WASI_SIGQUIT; --pub const SIGILL: u8 = __WASI_SIGILL; --pub const SIGTRAP: u8 = __WASI_SIGTRAP; --pub const SIGABRT: u8 = __WASI_SIGABRT; --pub const SIGBUS: u8 = __WASI_SIGBUS; --pub const SIGFPE: u8 = __WASI_SIGFPE; --pub const SIGKILL: u8 = __WASI_SIGKILL; --pub const SIGUSR1: u8 = __WASI_SIGUSR1; --pub const SIGSEGV: u8 = __WASI_SIGSEGV; --pub const SIGUSR2: u8 = __WASI_SIGUSR2; --pub const SIGPIPE: u8 = __WASI_SIGPIPE; --pub const SIGALRM: u8 = __WASI_SIGALRM; --pub const SIGTERM: u8 = __WASI_SIGTERM; --pub const SIGCHLD: u8 = __WASI_SIGCHLD; --pub const SIGCONT: u8 = __WASI_SIGCONT; --pub const SIGSTOP: u8 = __WASI_SIGSTOP; --pub const SIGTSTP: u8 = __WASI_SIGTSTP; --pub const SIGTTIN: u8 = __WASI_SIGTTIN; --pub const SIGTTOU: u8 = __WASI_SIGTTOU; --pub const SIGURG: u8 = __WASI_SIGURG; --pub const SIGXCPU: u8 = __WASI_SIGXCPU; --pub const SIGXFSZ: u8 = __WASI_SIGXFSZ; --pub const SIGVTALRM: u8 = __WASI_SIGVTALRM; --pub const SIGPROF: u8 = __WASI_SIGPROF; --pub const SIGWINCH: u8 = __WASI_SIGWINCH; --pub const SIGPOLL: u8 = __WASI_SIGPOLL; --pub const SIGPWR: u8 = __WASI_SIGPWR; --pub const SIGSYS: u8 = __WASI_SIGSYS; --pub const SUBSCRIPTION_CLOCK_ABSTIME: u16 = __WASI_SUBSCRIPTION_CLOCK_ABSTIME; --pub const WHENCE_CUR: u8 = __WASI_WHENCE_CUR; --pub const WHENCE_END: u8 = __WASI_WHENCE_END; --pub const WHENCE_SET: u8 = __WASI_WHENCE_SET; -+pub const ADVICE_NORMAL: Advice = __WASI_ADVICE_NORMAL; -+pub const ADVICE_SEQUENTIAL: Advice = __WASI_ADVICE_SEQUENTIAL; -+pub const ADVICE_RANDOM: Advice = __WASI_ADVICE_RANDOM; -+pub const ADVICE_WILLNEED: Advice = __WASI_ADVICE_WILLNEED; -+pub const ADVICE_DONTNEED: Advice = __WASI_ADVICE_DONTNEED; -+pub const ADVICE_NOREUSE: Advice = __WASI_ADVICE_NOREUSE; -+pub const CLOCK_REALTIME: Clockid = __WASI_CLOCK_REALTIME; -+pub const CLOCK_MONOTONIC: Clockid = __WASI_CLOCK_MONOTONIC; -+pub const CLOCK_PROCESS_CPUTIME_ID: Clockid = __WASI_CLOCK_PROCESS_CPUTIME_ID; -+pub const CLOCK_THREAD_CPUTIME_ID: Clockid = __WASI_CLOCK_THREAD_CPUTIME_ID; -+pub const DIRCOOKIE_START: Dircookie = __WASI_DIRCOOKIE_START; -+pub const ESUCCESS: Errno = __WASI_ESUCCESS; -+pub const E2BIG: Errno = __WASI_E2BIG; -+pub const EACCES: Errno = __WASI_EACCES; -+pub const EADDRINUSE: Errno = __WASI_EADDRINUSE; -+pub const EADDRNOTAVAIL: Errno = __WASI_EADDRNOTAVAIL; -+pub const EAFNOSUPPORT: Errno = __WASI_EAFNOSUPPORT; -+pub const EAGAIN: Errno = __WASI_EAGAIN; -+pub const EALREADY: Errno = __WASI_EALREADY; -+pub const EBADF: Errno = __WASI_EBADF; -+pub const EBADMSG: Errno = __WASI_EBADMSG; -+pub const EBUSY: Errno = __WASI_EBUSY; -+pub const ECANCELED: Errno = __WASI_ECANCELED; -+pub const ECHILD: Errno = __WASI_ECHILD; -+pub const ECONNABORTED: Errno = __WASI_ECONNABORTED; -+pub const ECONNREFUSED: Errno = __WASI_ECONNREFUSED; -+pub const ECONNRESET: Errno = __WASI_ECONNRESET; -+pub const EDEADLK: Errno = __WASI_EDEADLK; -+pub const EDESTADDRREQ: Errno = __WASI_EDESTADDRREQ; -+pub const EDOM: Errno = __WASI_EDOM; -+pub const EDQUOT: Errno = __WASI_EDQUOT; -+pub const EEXIST: Errno = __WASI_EEXIST; -+pub const EFAULT: Errno = __WASI_EFAULT; -+pub const EFBIG: Errno = __WASI_EFBIG; -+pub const EHOSTUNREACH: Errno = __WASI_EHOSTUNREACH; -+pub const EIDRM: Errno = __WASI_EIDRM; -+pub const EILSEQ: Errno = __WASI_EILSEQ; -+pub const EINPROGRESS: Errno = __WASI_EINPROGRESS; -+pub const EINTR: Errno = __WASI_EINTR; -+pub const EINVAL: Errno = __WASI_EINVAL; -+pub const EIO: Errno = __WASI_EIO; -+pub const EISCONN: Errno = __WASI_EISCONN; -+pub const EISDIR: Errno = __WASI_EISDIR; -+pub const ELOOP: Errno = __WASI_ELOOP; -+pub const EMFILE: Errno = __WASI_EMFILE; -+pub const EMLINK: Errno = __WASI_EMLINK; -+pub const EMSGSIZE: Errno = __WASI_EMSGSIZE; -+pub const EMULTIHOP: Errno = __WASI_EMULTIHOP; -+pub const ENAMETOOLONG: Errno = __WASI_ENAMETOOLONG; -+pub const ENETDOWN: Errno = __WASI_ENETDOWN; -+pub const ENETRESET: Errno = __WASI_ENETRESET; -+pub const ENETUNREACH: Errno = __WASI_ENETUNREACH; -+pub const ENFILE: Errno = __WASI_ENFILE; -+pub const ENOBUFS: Errno = __WASI_ENOBUFS; -+pub const ENODEV: Errno = __WASI_ENODEV; -+pub const ENOENT: Errno = __WASI_ENOENT; -+pub const ENOEXEC: Errno = __WASI_ENOEXEC; -+pub const ENOLCK: Errno = __WASI_ENOLCK; -+pub const ENOLINK: Errno = __WASI_ENOLINK; -+pub const ENOMEM: Errno = __WASI_ENOMEM; -+pub const ENOMSG: Errno = __WASI_ENOMSG; -+pub const ENOPROTOOPT: Errno = __WASI_ENOPROTOOPT; -+pub const ENOSPC: Errno = __WASI_ENOSPC; -+pub const ENOSYS: Errno = __WASI_ENOSYS; -+pub const ENOTCONN: Errno = __WASI_ENOTCONN; -+pub const ENOTDIR: Errno = __WASI_ENOTDIR; -+pub const ENOTEMPTY: Errno = __WASI_ENOTEMPTY; -+pub const ENOTRECOVERABLE: Errno = __WASI_ENOTRECOVERABLE; -+pub const ENOTSOCK: Errno = __WASI_ENOTSOCK; -+pub const ENOTSUP: Errno = __WASI_ENOTSUP; -+pub const ENOTTY: Errno = __WASI_ENOTTY; -+pub const ENXIO: Errno = __WASI_ENXIO; -+pub const EOVERFLOW: Errno = __WASI_EOVERFLOW; -+pub const EOWNERDEAD: Errno = __WASI_EOWNERDEAD; -+pub const EPERM: Errno = __WASI_EPERM; -+pub const EPIPE: Errno = __WASI_EPIPE; -+pub const EPROTO: Errno = __WASI_EPROTO; -+pub const EPROTONOSUPPORT: Errno = __WASI_EPROTONOSUPPORT; -+pub const EPROTOTYPE: Errno = __WASI_EPROTOTYPE; -+pub const ERANGE: Errno = __WASI_ERANGE; -+pub const EROFS: Errno = __WASI_EROFS; -+pub const ESPIPE: Errno = __WASI_ESPIPE; -+pub const ESRCH: Errno = __WASI_ESRCH; -+pub const ESTALE: Errno = __WASI_ESTALE; -+pub const ETIMEDOUT: Errno = __WASI_ETIMEDOUT; -+pub const ETXTBSY: Errno = __WASI_ETXTBSY; -+pub const EXDEV: Errno = __WASI_EXDEV; -+pub const ENOTCAPABLE: Errno = __WASI_ENOTCAPABLE; -+pub const EVENTTYPE_CLOCK: Eventtype = __WASI_EVENTTYPE_CLOCK; -+pub const EVENTTYPE_FD_READ: Eventtype = __WASI_EVENTTYPE_FD_READ; -+pub const EVENTTYPE_FD_WRITE: Eventtype = __WASI_EVENTTYPE_FD_WRITE; -+pub const FILETYPE_UNKNOWN: Filetype = __WASI_FILETYPE_UNKNOWN; -+pub const FILETYPE_BLOCK_DEVICE: Filetype = __WASI_FILETYPE_BLOCK_DEVICE; -+pub const FILETYPE_CHARACTER_DEVICE: Filetype = __WASI_FILETYPE_CHARACTER_DEVICE; -+pub const FILETYPE_DIRECTORY: Filetype = __WASI_FILETYPE_DIRECTORY; -+pub const FILETYPE_REGULAR_FILE: Filetype = __WASI_FILETYPE_REGULAR_FILE; -+pub const FILETYPE_SOCKET_DGRAM: Filetype = __WASI_FILETYPE_SOCKET_DGRAM; -+pub const FILETYPE_SOCKET_STREAM: Filetype = __WASI_FILETYPE_SOCKET_STREAM; -+pub const FILETYPE_SYMBOLIC_LINK: Filetype = __WASI_FILETYPE_SYMBOLIC_LINK; -+pub const PREOPENTYPE_DIR: Preopentype = __WASI_PREOPENTYPE_DIR; -+pub const SIGHUP: Signal = __WASI_SIGHUP; -+pub const SIGINT: Signal = __WASI_SIGINT; -+pub const SIGQUIT: Signal = __WASI_SIGQUIT; -+pub const SIGILL: Signal = __WASI_SIGILL; -+pub const SIGTRAP: Signal = __WASI_SIGTRAP; -+pub const SIGABRT: Signal = __WASI_SIGABRT; -+pub const SIGBUS: Signal = __WASI_SIGBUS; -+pub const SIGFPE: Signal = __WASI_SIGFPE; -+pub const SIGKILL: Signal = __WASI_SIGKILL; -+pub const SIGUSR1: Signal = __WASI_SIGUSR1; -+pub const SIGSEGV: Signal = __WASI_SIGSEGV; -+pub const SIGUSR2: Signal = __WASI_SIGUSR2; -+pub const SIGPIPE: Signal = __WASI_SIGPIPE; -+pub const SIGALRM: Signal = __WASI_SIGALRM; -+pub const SIGTERM: Signal = __WASI_SIGTERM; -+pub const SIGCHLD: Signal = __WASI_SIGCHLD; -+pub const SIGCONT: Signal = __WASI_SIGCONT; -+pub const SIGSTOP: Signal = __WASI_SIGSTOP; -+pub const SIGTSTP: Signal = __WASI_SIGTSTP; -+pub const SIGTTIN: Signal = __WASI_SIGTTIN; -+pub const SIGTTOU: Signal = __WASI_SIGTTOU; -+pub const SIGURG: Signal = __WASI_SIGURG; -+pub const SIGXCPU: Signal = __WASI_SIGXCPU; -+pub const SIGXFSZ: Signal = __WASI_SIGXFSZ; -+pub const SIGVTALRM: Signal = __WASI_SIGVTALRM; -+pub const SIGPROF: Signal = __WASI_SIGPROF; -+pub const SIGWINCH: Signal = __WASI_SIGWINCH; -+pub const SIGPOLL: Signal = __WASI_SIGPOLL; -+pub const SIGPWR: Signal = __WASI_SIGPWR; -+pub const SIGSYS: Signal = __WASI_SIGSYS; -+pub const SOCK_RECV_DATA_TRUNCATED: Roflags = __WASI_SOCK_RECV_DATA_TRUNCATED; -+ -+bitflags! { -+ pub struct Sdflags: __wasi_sdflags_t { -+ const SHUT_RD = __WASI_SHUT_RD; -+ const SHUT_WR = __WASI_SHUT_WR; -+ } -+} -+ -+bitflags! { -+ pub struct Riflags: __wasi_riflags_t { -+ const PEEK = __WASI_SOCK_RECV_PEEK; -+ const WAITALL = __WASI_SOCK_RECV_WAITALL; -+ } -+} -+ -+bitflags! { -+ pub struct Eventrwflags: __wasi_eventrwflags_t { -+ const FD_READWRITE_HANGUP = __WASI_EVENT_FD_READWRITE_HANGUP; -+ } -+} -+ -+bitflags! { -+ pub struct Subclockflags: __wasi_subclockflags_t { -+ const SUBSCRIPTION_CLOCK_ABSTIME = __WASI_SUBSCRIPTION_CLOCK_ABSTIME; -+ } -+} -+ -+bitflags! { -+ pub struct Oflags: __wasi_oflags_t { -+ const CREAT = __WASI_O_CREAT; -+ const DIRECTORY = __WASI_O_DIRECTORY; -+ const EXCL = __WASI_O_EXCL; -+ const TRUNC = __WASI_O_TRUNC; -+ } -+} -+ -+bitflags! { -+ pub struct Fdflags: __wasi_fdflags_t { -+ const APPEND = __WASI_FDFLAG_APPEND; -+ const DSYNC = __WASI_FDFLAG_DSYNC; -+ const NONBLOCK = __WASI_FDFLAG_NONBLOCK; -+ const RSYNC = __WASI_FDFLAG_RSYNC; -+ const SYNC = __WASI_FDFLAG_SYNC; -+ } -+} -+ -+bitflags! { -+ pub struct Lookupflags: __wasi_lookupflags_t { -+ const SYMLINK_FOLLOW = __WASI_LOOKUP_SYMLINK_FOLLOW; -+ } -+} -+ -+bitflags! { -+ pub struct Rights: __wasi_rights_t { -+ const FD_DATASYNC = __WASI_RIGHT_FD_DATASYNC; -+ const FD_READ = __WASI_RIGHT_FD_READ; -+ const FD_SEEK = __WASI_RIGHT_FD_SEEK; -+ const FD_FDSTAT_SET_FLAGS = __WASI_RIGHT_FD_FDSTAT_SET_FLAGS; -+ const FD_SYNC = __WASI_RIGHT_FD_SYNC; -+ const FD_TELL = __WASI_RIGHT_FD_TELL; -+ const FD_WRITE = __WASI_RIGHT_FD_WRITE; -+ const FD_ADVISE = __WASI_RIGHT_FD_ADVISE; -+ const FD_ALLOCATE = __WASI_RIGHT_FD_ALLOCATE; -+ const PATH_CREATE_DIRECTORY = __WASI_RIGHT_PATH_CREATE_DIRECTORY; -+ const PATH_CREATE_FILE = __WASI_RIGHT_PATH_CREATE_FILE; -+ const PATH_LINK_SOURCE = __WASI_RIGHT_PATH_LINK_SOURCE; -+ const PATH_LINK_TARGET = __WASI_RIGHT_PATH_LINK_TARGET; -+ const PATH_OPEN = __WASI_RIGHT_PATH_OPEN; -+ const FD_READDIR = __WASI_RIGHT_FD_READDIR; -+ const PATH_READLINK = __WASI_RIGHT_PATH_READLINK; -+ const PATH_RENAME_SOURCE = __WASI_RIGHT_PATH_RENAME_SOURCE; -+ const PATH_RENAME_TARGET = __WASI_RIGHT_PATH_RENAME_TARGET; -+ const PATH_FILESTAT_GET = __WASI_RIGHT_PATH_FILESTAT_GET; -+ const PATH_FILESTAT_SET_SIZE = __WASI_RIGHT_PATH_FILESTAT_SET_SIZE; -+ const PATH_FILESTAT_SET_TIMES = __WASI_RIGHT_PATH_FILESTAT_SET_TIMES; -+ const FD_FILESTAT_GET = __WASI_RIGHT_FD_FILESTAT_GET; -+ const FD_FILESTAT_SET_SIZE = __WASI_RIGHT_FD_FILESTAT_SET_SIZE; -+ const FD_FILESTAT_SET_TIMES = __WASI_RIGHT_FD_FILESTAT_SET_TIMES; -+ const PATH_SYMLINK = __WASI_RIGHT_PATH_SYMLINK; -+ const PATH_REMOVE_DIRECTORY = __WASI_RIGHT_PATH_REMOVE_DIRECTORY; -+ const PATH_UNLINK_FILE = __WASI_RIGHT_PATH_UNLINK_FILE; -+ const POLL_FD_READWRITE = __WASI_RIGHT_POLL_FD_READWRITE; -+ const SOCK_SHUTDOWN = __WASI_RIGHT_SOCK_SHUTDOWN; -+ } -+} -+ -+bitflags! { -+ pub struct Fstflags: __wasi_fstflags_t { -+ const SET_ATIM = __WASI_FILESTAT_SET_ATIM; -+ const SET_ATIM_NOW = __WASI_FILESTAT_SET_ATIM_NOW; -+ const SET_MTIM = __WASI_FILESTAT_SET_MTIM; -+ const SET_MTIM_NOW = __WASI_FILESTAT_SET_MTIM_NOW; -+ } -+} - - pub fn clock_res_get(clock_id: Clockid) -> (Errno, Timestamp) { - let mut resolution = MaybeUninit::::uninit(); -@@ -333,11 +366,11 @@ pub fn fd_fdstat_get(fd: Fd) -> (Errno, Fdstat) { - } - - pub fn fd_fdstat_set_flags(fd: Fd, flags: Fdflags) -> Errno { -- unsafe { __wasi_fd_fdstat_set_flags(fd, flags) } -+ unsafe { __wasi_fd_fdstat_set_flags(fd, flags.bits()) } - } - - pub fn fd_fdstat_set_rights(fd: Fd, fs_rights_base: Rights, fs_rights_inheriting: Rights) -> Errno { -- unsafe { __wasi_fd_fdstat_set_rights(fd, fs_rights_base, fs_rights_inheriting) } -+ unsafe { __wasi_fd_fdstat_set_rights(fd, fs_rights_base.bits(), fs_rights_inheriting.bits()) } - } - - pub fn fd_sync(fd: Fd) -> Errno { -@@ -376,7 +409,7 @@ pub fn path_link( - unsafe { - __wasi_path_link( - old_fd, -- old_flags, -+ old_flags.bits(), - old_path.as_ptr(), - old_path.len(), - new_fd, -@@ -400,13 +433,13 @@ pub fn path_open( - ( - __wasi_path_open( - dirfd, -- dirflags, -+ dirflags.bits(), - path.as_ptr(), - path.len(), -- oflags, -- fs_rights_base, -- fs_rights_inheriting, -- fs_flags, -+ oflags.bits(), -+ fs_rights_base.bits(), -+ fs_rights_inheriting.bits(), -+ fs_flags.bits(), - fd.as_mut_ptr(), - ), - fd.assume_init(), -@@ -476,7 +509,7 @@ pub fn fd_filestat_set_times( - st_mtim: Timestamp, - fstflags: Fstflags, - ) -> Errno { -- unsafe { __wasi_fd_filestat_set_times(fd, st_atim, st_mtim, fstflags) } -+ unsafe { __wasi_fd_filestat_set_times(fd, st_atim, st_mtim, fstflags.bits()) } - } - - pub fn fd_filestat_set_size(fd: Fd, st_size: Filesize) -> Errno { -@@ -487,7 +520,13 @@ pub fn path_filestat_get(fd: Fd, flags: Lookupflags, path: &[u8]) -> (Errno, Fil - let mut buf = MaybeUninit::::uninit(); - unsafe { - ( -- __wasi_path_filestat_get(fd, flags, path.as_ptr(), path.len(), buf.as_mut_ptr()), -+ __wasi_path_filestat_get( -+ fd, -+ flags.bits(), -+ path.as_ptr(), -+ path.len(), -+ buf.as_mut_ptr(), -+ ), - buf.assume_init(), - ) - } -@@ -504,12 +543,12 @@ pub fn path_filestat_set_times( - unsafe { - __wasi_path_filestat_set_times( - fd, -- flags, -+ flags.bits(), - path.as_ptr(), - path.len(), - st_atim, - st_mtim, -- fstflags, -+ fstflags.bits(), - ) - } - } -@@ -567,7 +606,7 @@ pub fn sock_recv(sock: Fd, ri_data: &[Iovec], ri_flags: Riflags) -> (Errno, usiz - sock, - ri_data.as_ptr(), - ri_data.len(), -- ri_flags, -+ ri_flags.bits(), - ro_datalen.as_mut_ptr(), - ro_flags.as_mut_ptr(), - ), -@@ -594,7 +633,7 @@ pub fn sock_send(sock: Fd, si_data: &[Ciovec], si_flags: Siflags) -> (Errno, usi - } - - pub fn sock_shutdown(sock: Fd, how: Sdflags) -> Errno { -- unsafe { __wasi_sock_shutdown(sock, how) } -+ unsafe { __wasi_sock_shutdown(sock, how.bits()) } - } - - pub fn sched_yield() -> Errno { diff --git a/third_party/rust/wasi/src/error.rs b/third_party/rust/wasi/src/error.rs index 2f2aaf4b90dd..fb8b443894a1 100644 --- a/third_party/rust/wasi/src/error.rs +++ b/third_party/rust/wasi/src/error.rs @@ -29,7 +29,7 @@ impl fmt::Display for Error { write!( f, "{} (error {})", - super::strerror(self.code.get()), + super::errno_name(self.code.get()), self.code )?; Ok(()) @@ -40,7 +40,8 @@ impl fmt::Debug for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Error") .field("code", &self.code) - .field("message", &super::strerror(self.code.get())) + .field("name", &super::errno_name(self.code.get())) + .field("message", &super::errno_docs(self.code.get())) .finish() } } diff --git a/third_party/rust/wasi/src/lib.rs b/third_party/rust/wasi/src/lib.rs index 45c24692771c..51f488907f82 100644 --- a/third_party/rust/wasi/src/lib.rs +++ b/third_party/rust/wasi/src/lib.rs @@ -34,3 +34,15 @@ mod error; mod lib_generated; pub use lib_generated::*; + +/// Special `Dircookie` value indicating the start of a directory. +pub const DIRCOOKIE_START: Dircookie = 0; + +/// The "standard input" descriptor number. +pub const FD_STDIN: Fd = 0; + +/// The "standard output" descriptor number. +pub const FD_STDOUT: Fd = 1; + +/// The "standard error" descriptor number. +pub const FD_STDERR: Fd = 2; diff --git a/third_party/rust/wasi/src/lib_generated.rs b/third_party/rust/wasi/src/lib_generated.rs index 8adf4664707e..09d58c2b3701 100644 --- a/third_party/rust/wasi/src/lib_generated.rs +++ b/third_party/rust/wasi/src/lib_generated.rs @@ -1,6 +1,6 @@ // This file is automatically generated, DO NOT EDIT // -// To regenerate this file run the `crates/generate-raw` command +// To regenerate this file run the `crates/witx-bindgen` command use core::mem::MaybeUninit; @@ -177,7 +177,89 @@ pub const ERRNO_TXTBSY: Errno = 74; pub const ERRNO_XDEV: Errno = 75; /// Extension: Capabilities insufficient. pub const ERRNO_NOTCAPABLE: Errno = 76; -pub(crate) fn strerror(code: u16) -> &'static str { +pub fn errno_name(code: u16) -> &'static str { + match code { + ERRNO_SUCCESS => "SUCCESS", + ERRNO_2BIG => "2BIG", + ERRNO_ACCES => "ACCES", + ERRNO_ADDRINUSE => "ADDRINUSE", + ERRNO_ADDRNOTAVAIL => "ADDRNOTAVAIL", + ERRNO_AFNOSUPPORT => "AFNOSUPPORT", + ERRNO_AGAIN => "AGAIN", + ERRNO_ALREADY => "ALREADY", + ERRNO_BADF => "BADF", + ERRNO_BADMSG => "BADMSG", + ERRNO_BUSY => "BUSY", + ERRNO_CANCELED => "CANCELED", + ERRNO_CHILD => "CHILD", + ERRNO_CONNABORTED => "CONNABORTED", + ERRNO_CONNREFUSED => "CONNREFUSED", + ERRNO_CONNRESET => "CONNRESET", + ERRNO_DEADLK => "DEADLK", + ERRNO_DESTADDRREQ => "DESTADDRREQ", + ERRNO_DOM => "DOM", + ERRNO_DQUOT => "DQUOT", + ERRNO_EXIST => "EXIST", + ERRNO_FAULT => "FAULT", + ERRNO_FBIG => "FBIG", + ERRNO_HOSTUNREACH => "HOSTUNREACH", + ERRNO_IDRM => "IDRM", + ERRNO_ILSEQ => "ILSEQ", + ERRNO_INPROGRESS => "INPROGRESS", + ERRNO_INTR => "INTR", + ERRNO_INVAL => "INVAL", + ERRNO_IO => "IO", + ERRNO_ISCONN => "ISCONN", + ERRNO_ISDIR => "ISDIR", + ERRNO_LOOP => "LOOP", + ERRNO_MFILE => "MFILE", + ERRNO_MLINK => "MLINK", + ERRNO_MSGSIZE => "MSGSIZE", + ERRNO_MULTIHOP => "MULTIHOP", + ERRNO_NAMETOOLONG => "NAMETOOLONG", + ERRNO_NETDOWN => "NETDOWN", + ERRNO_NETRESET => "NETRESET", + ERRNO_NETUNREACH => "NETUNREACH", + ERRNO_NFILE => "NFILE", + ERRNO_NOBUFS => "NOBUFS", + ERRNO_NODEV => "NODEV", + ERRNO_NOENT => "NOENT", + ERRNO_NOEXEC => "NOEXEC", + ERRNO_NOLCK => "NOLCK", + ERRNO_NOLINK => "NOLINK", + ERRNO_NOMEM => "NOMEM", + ERRNO_NOMSG => "NOMSG", + ERRNO_NOPROTOOPT => "NOPROTOOPT", + ERRNO_NOSPC => "NOSPC", + ERRNO_NOSYS => "NOSYS", + ERRNO_NOTCONN => "NOTCONN", + ERRNO_NOTDIR => "NOTDIR", + ERRNO_NOTEMPTY => "NOTEMPTY", + ERRNO_NOTRECOVERABLE => "NOTRECOVERABLE", + ERRNO_NOTSOCK => "NOTSOCK", + ERRNO_NOTSUP => "NOTSUP", + ERRNO_NOTTY => "NOTTY", + ERRNO_NXIO => "NXIO", + ERRNO_OVERFLOW => "OVERFLOW", + ERRNO_OWNERDEAD => "OWNERDEAD", + ERRNO_PERM => "PERM", + ERRNO_PIPE => "PIPE", + ERRNO_PROTO => "PROTO", + ERRNO_PROTONOSUPPORT => "PROTONOSUPPORT", + ERRNO_PROTOTYPE => "PROTOTYPE", + ERRNO_RANGE => "RANGE", + ERRNO_ROFS => "ROFS", + ERRNO_SPIPE => "SPIPE", + ERRNO_SRCH => "SRCH", + ERRNO_STALE => "STALE", + ERRNO_TIMEDOUT => "TIMEDOUT", + ERRNO_TXTBSY => "TXTBSY", + ERRNO_XDEV => "XDEV", + ERRNO_NOTCAPABLE => "NOTCAPABLE", + _ => "Unknown error.", + } +} +pub fn errno_docs(code: u16) -> &'static str { match code { ERRNO_SUCCESS => "No error occurred. System call completed successfully.", ERRNO_2BIG => "Argument list too long.", @@ -262,7 +344,7 @@ pub(crate) fn strerror(code: u16) -> &'static str { pub type Rights = u64; /// The right to invoke `fd_datasync`. /// If `path_open` is set, includes the right to invoke -/// `path_open` with `fdflag::dsync`. +/// `path_open` with `fdflags::dsync`. pub const RIGHTS_FD_DATASYNC: Rights = 0x1; /// The right to invoke `fd_read` and `sock_recv`. /// If `rights::fd_seek` is set, includes the right to invoke `fd_pread`. @@ -273,10 +355,10 @@ pub const RIGHTS_FD_SEEK: Rights = 0x4; pub const RIGHTS_FD_FDSTAT_SET_FLAGS: Rights = 0x8; /// The right to invoke `fd_sync`. /// If `path_open` is set, includes the right to invoke -/// `path_open` with `fdflag::rsync` and `fdflag::dsync`. +/// `path_open` with `fdflags::rsync` and `fdflags::dsync`. pub const RIGHTS_FD_SYNC: Rights = 0x10; /// The right to invoke `fd_seek` in such a way that the file offset -/// remains unaltered (i.e., `WHENCE_CUR` with offset zero), or to +/// remains unaltered (i.e., `whence::cur` with offset zero), or to /// invoke `fd_tell`. pub const RIGHTS_FD_TELL: Rights = 0x20; /// The right to invoke `fd_write` and `sock_send`. @@ -332,7 +414,7 @@ pub const RIGHTS_POLL_FD_READWRITE: Rights = 0x8000000; pub const RIGHTS_SOCK_SHUTDOWN: Rights = 0x10000000; pub type Fd = u32; #[repr(C)] -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub struct Iovec { /// The address of the buffer to be filled. pub buf: *mut u8, @@ -340,7 +422,7 @@ pub struct Iovec { pub buf_len: Size, } #[repr(C)] -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub struct Ciovec { /// The address of the buffer to be written. pub buf: *const u8, @@ -378,7 +460,7 @@ pub const FILETYPE_SOCKET_STREAM: Filetype = 6; /// The file refers to a symbolic link inode. pub const FILETYPE_SYMBOLIC_LINK: Filetype = 7; #[repr(C)] -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub struct Dirent { /// The offset of the next directory entry stored in this directory. pub d_next: Dircookie, @@ -416,7 +498,7 @@ pub const FDFLAGS_RSYNC: Fdflags = 0x8; /// may also synchronously update the file's metadata. pub const FDFLAGS_SYNC: Fdflags = 0x10; #[repr(C)] -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub struct Fdstat { /// File type. pub fs_filetype: Filetype, @@ -430,13 +512,13 @@ pub struct Fdstat { } pub type Device = u64; pub type Fstflags = u16; -/// Adjust the last data access timestamp to the value stored in `filestat::st_atim`. +/// Adjust the last data access timestamp to the value stored in `filestat::atim`. pub const FSTFLAGS_ATIM: Fstflags = 0x1; -/// Adjust the last data access timestamp to the time of clock `clock::realtime`. +/// Adjust the last data access timestamp to the time of clock `clockid::realtime`. pub const FSTFLAGS_ATIM_NOW: Fstflags = 0x2; -/// Adjust the last data modification timestamp to the value stored in `filestat::st_mtim`. +/// Adjust the last data modification timestamp to the value stored in `filestat::mtim`. pub const FSTFLAGS_MTIM: Fstflags = 0x4; -/// Adjust the last data modification timestamp to the time of clock `clock::realtime`. +/// Adjust the last data modification timestamp to the time of clock `clockid::realtime`. pub const FSTFLAGS_MTIM_NOW: Fstflags = 0x8; pub type Lookupflags = u32; /// As long as the resolved path corresponds to a symbolic link, it is expanded. @@ -452,7 +534,7 @@ pub const OFLAGS_EXCL: Oflags = 0x4; pub const OFLAGS_TRUNC: Oflags = 0x8; pub type Linkcount = u64; #[repr(C)] -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub struct Filestat { /// Device ID of device containing the file. pub dev: Device, @@ -473,20 +555,20 @@ pub struct Filestat { } pub type Userdata = u64; pub type Eventtype = u8; -/// The time value of clock `subscription::u.clock.clock_id` has -/// reached timestamp `subscription::u.clock.timeout`. +/// The time value of clock `subscription_clock::id` has +/// reached timestamp `subscription_clock::timeout`. pub const EVENTTYPE_CLOCK: Eventtype = 0; -/// File descriptor `subscription::u.fd_readwrite.fd` has data +/// File descriptor `subscription_fd_readwrite::file_descriptor` has data /// available for reading. This event always triggers for regular files. pub const EVENTTYPE_FD_READ: Eventtype = 1; -/// File descriptor `subscription::u.fd_readwrite.fd` has capacity +/// File descriptor `subscription_fd_readwrite::file_descriptor` has capacity /// available for writing. This event always triggers for regular files. pub const EVENTTYPE_FD_WRITE: Eventtype = 2; pub type Eventrwflags = u16; /// The peer of this socket has closed or disconnected. pub const EVENTRWFLAGS_FD_READWRITE_HANGUP: Eventrwflags = 0x1; #[repr(C)] -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub struct EventFdReadwrite { /// The number of bytes available for reading or writing. pub nbytes: Filesize, @@ -494,32 +576,27 @@ pub struct EventFdReadwrite { pub flags: Eventrwflags, } #[repr(C)] -#[derive(Copy, Clone)] -pub union EventU { - /// When type is `eventtype::fd_read` or `eventtype::fd_write`: - pub fd_readwrite: EventFdReadwrite, -} -#[repr(C)] -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub struct Event { /// User-provided value that got attached to `subscription::userdata`. pub userdata: Userdata, /// If non-zero, an error that occurred while processing the subscription request. pub error: Errno, - /// The type of the event that occurred. + /// The type of event that occured pub r#type: Eventtype, - /// The contents of the event. - pub u: EventU, + /// The contents of the event, if it is an `eventtype::fd_read` or + /// `eventtype::fd_write`. `eventtype::clock` events ignore this field. + pub fd_readwrite: EventFdReadwrite, } pub type Subclockflags = u16; /// If set, treat the timestamp provided in -/// `subscription::u.clock.timeout` as an absolute timestamp of clock -/// `subscription::u.clock.clock_id.` If clear, treat the timestamp -/// provided in `subscription::u.clock.timeout` relative to the -/// current time value of clock `subscription::u.clock.clock_id.` +/// `subscription_clock::timeout` as an absolute timestamp of clock +/// `subscription_clock::id`. If clear, treat the timestamp +/// provided in `subscription_clock::timeout` relative to the +/// current time value of clock `subscription_clock::id`. pub const SUBCLOCKFLAGS_SUBSCRIPTION_CLOCK_ABSTIME: Subclockflags = 0x1; #[repr(C)] -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub struct SubscriptionClock { /// The clock against which to compare the timestamp. pub id: Clockid, @@ -532,28 +609,32 @@ pub struct SubscriptionClock { pub flags: Subclockflags, } #[repr(C)] -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub struct SubscriptionFdReadwrite { /// The file descriptor on which to wait for it to become ready for reading or writing. pub file_descriptor: Fd, } #[repr(C)] #[derive(Copy, Clone)] -pub union SubscriptionU { - /// When type is `eventtype::clock`: +pub union SubscriptionUU { pub clock: SubscriptionClock, - /// When type is `eventtype::fd_read` or `eventtype::fd_write`: - pub fd_readwrite: SubscriptionFdReadwrite, + pub fd_read: SubscriptionFdReadwrite, + pub fd_write: SubscriptionFdReadwrite, } +#[repr(C)] +#[derive(Copy, Clone)] +pub struct SubscriptionU { + pub tag: Eventtype, + pub u: SubscriptionUU, +} + #[repr(C)] #[derive(Copy, Clone)] pub struct Subscription { /// User-provided value that is attached to the subscription in the /// implementation and returned through `event::userdata`. pub userdata: Userdata, - /// The type of the event to which to subscribe. - pub r#type: Eventtype, - /// The contents of the subscription. + /// The type of the event to which to subscribe, and its contents pub u: SubscriptionU, } pub type Exitcode = u32; @@ -669,7 +750,7 @@ pub type Preopentype = u8; /// A pre-opened directory. pub const PREOPENTYPE_DIR: Preopentype = 0; #[repr(C)] -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub struct PrestatDir { /// The length of the directory name for use with `fd_prestat_dir_name`. pub pr_name_len: Size, @@ -677,19 +758,17 @@ pub struct PrestatDir { #[repr(C)] #[derive(Copy, Clone)] pub union PrestatU { - /// When type is `preopentype::dir`: pub dir: PrestatDir, } #[repr(C)] #[derive(Copy, Clone)] pub struct Prestat { - /// The type of the pre-opened capability. - pub pr_type: Preopentype, - /// The contents of the information. + pub tag: Preopentype, pub u: PrestatU, } + /// Read command-line argument data. -/// The size of the array should match that returned by `wasi_args_sizes_get()` +/// The size of the array should match that returned by `args_sizes_get` pub unsafe fn args_get(argv: *mut *mut u8, argv_buf: *mut u8) -> Result<()> { let rc = wasi_snapshot_preview1::args_get(argv, argv_buf); if let Some(err) = Error::from_raw_error(rc) { @@ -717,7 +796,7 @@ pub unsafe fn args_sizes_get() -> Result<(Size, Size)> { } /// Read environment variable data. -/// The sizes of the buffers should match that returned by `environ.sizes_get()`. +/// The sizes of the buffers should match that returned by `environ_sizes_get`. pub unsafe fn environ_get(environ: *mut *mut u8, environ_buf: *mut u8) -> Result<()> { let rc = wasi_snapshot_preview1::environ_get(environ, environ_buf); if let Some(err) = Error::from_raw_error(rc) { @@ -727,26 +806,29 @@ pub unsafe fn environ_get(environ: *mut *mut u8, environ_buf: *mut u8) -> Result } } -/// Return command-line argument data sizes. +/// Return environment variable data sizes. /// /// ## Return /// -/// * `argc` - The number of arguments. -/// * `argv_buf_size` - The size of the argument string data. +/// * `environc` - The number of environment variable arguments. +/// * `environ_buf_size` - The size of the environment variable data. pub unsafe fn environ_sizes_get() -> Result<(Size, Size)> { - let mut argc = MaybeUninit::uninit(); - let mut argv_buf_size = MaybeUninit::uninit(); - let rc = - wasi_snapshot_preview1::environ_sizes_get(argc.as_mut_ptr(), argv_buf_size.as_mut_ptr()); + let mut environc = MaybeUninit::uninit(); + let mut environ_buf_size = MaybeUninit::uninit(); + let rc = wasi_snapshot_preview1::environ_sizes_get( + environc.as_mut_ptr(), + environ_buf_size.as_mut_ptr(), + ); if let Some(err) = Error::from_raw_error(rc) { Err(err) } else { - Ok((argc.assume_init(), argv_buf_size.assume_init())) + Ok((environc.assume_init(), environ_buf_size.assume_init())) } } /// Return the resolution of a clock. -/// Implementations are required to provide a non-zero value for supported clocks. For unsupported clocks, return `WASI_EINVAL` +/// Implementations are required to provide a non-zero value for supported clocks. For unsupported clocks, +/// return `errno::inval`. /// Note: This is similar to `clock_getres` in POSIX. /// /// ## Parameters @@ -874,7 +956,7 @@ pub unsafe fn fd_fdstat_set_flags(fd: Fd, flags: Fdflags) -> Result<()> { } /// Adjust the rights associated with a file descriptor. -/// This can only be used to remove rights, and returns `ENOTCAPABLE` if called in a way that would attempt to add rights +/// This can only be used to remove rights, and returns `errno::notcapable` if called in a way that would attempt to add rights /// /// ## Parameters /// @@ -955,7 +1037,7 @@ pub unsafe fn fd_filestat_set_times( /// ## Return /// /// * `nread` - The number of bytes read. -pub unsafe fn fd_pread(fd: Fd, iovs: IovecArray, offset: Filesize) -> Result { +pub unsafe fn fd_pread(fd: Fd, iovs: IovecArray<'_>, offset: Filesize) -> Result { let mut nread = MaybeUninit::uninit(); let rc = wasi_snapshot_preview1::fd_pread(fd, iovs.as_ptr(), iovs.len(), offset, nread.as_mut_ptr()); @@ -1006,7 +1088,7 @@ pub unsafe fn fd_prestat_dir_name(fd: Fd, path: *mut u8, path_len: Size) -> Resu /// ## Return /// /// * `nwritten` - The number of bytes written. -pub unsafe fn fd_pwrite(fd: Fd, iovs: CiovecArray, offset: Filesize) -> Result { +pub unsafe fn fd_pwrite(fd: Fd, iovs: CiovecArray<'_>, offset: Filesize) -> Result { let mut nwritten = MaybeUninit::uninit(); let rc = wasi_snapshot_preview1::fd_pwrite( fd, @@ -1032,7 +1114,7 @@ pub unsafe fn fd_pwrite(fd: Fd, iovs: CiovecArray, offset: Filesize) -> Result Result { +pub unsafe fn fd_read(fd: Fd, iovs: IovecArray<'_>) -> Result { let mut nread = MaybeUninit::uninit(); let rc = wasi_snapshot_preview1::fd_read(fd, iovs.as_ptr(), iovs.len(), nread.as_mut_ptr()); if let Some(err) = Error::from_raw_error(rc) { @@ -1044,8 +1126,8 @@ pub unsafe fn fd_read(fd: Fd, iovs: IovecArray) -> Result { /// Read directory entries from a directory. /// When successful, the contents of the output buffer consist of a sequence of -/// directory entries. Each directory entry consists of a dirent_t object, -/// followed by dirent_t::d_namlen bytes holding the name of the directory +/// directory entries. Each directory entry consists of a `dirent` object, +/// followed by `dirent::d_namlen` bytes holding the name of the directory /// entry. /// This function fills the output buffer as much as possible, potentially /// truncating the last directory entry. This allows the caller to grow its @@ -1149,7 +1231,7 @@ pub unsafe fn fd_tell(fd: Fd) -> Result { /// ## Return /// /// * `nwritten` - The number of bytes written. -pub unsafe fn fd_write(fd: Fd, iovs: CiovecArray) -> Result { +pub unsafe fn fd_write(fd: Fd, iovs: CiovecArray<'_>) -> Result { let mut nwritten = MaybeUninit::uninit(); let rc = wasi_snapshot_preview1::fd_write(fd, iovs.as_ptr(), iovs.len(), nwritten.as_mut_ptr()); if let Some(err) = Error::from_raw_error(rc) { @@ -1279,7 +1361,7 @@ pub unsafe fn path_link( /// /// * `dirflags` - Flags determining the method of how the path is resolved. /// * `path` - The relative path of the file or directory to open, relative to the -/// `dirfd` directory. +/// `path_open::fd` directory. /// * `oflags` - The method by which to open the file. /// * `fs_rights_base` - The initial rights of the newly created file descriptor. The /// implementation is allowed to return a file descriptor with fewer rights @@ -1298,7 +1380,7 @@ pub unsafe fn path_open( path: &str, oflags: Oflags, fs_rights_base: Rights, - fs_rights_inherting: Rights, + fs_rights_inheriting: Rights, fdflags: Fdflags, ) -> Result { let mut opened_fd = MaybeUninit::uninit(); @@ -1309,7 +1391,7 @@ pub unsafe fn path_open( path.len(), oflags, fs_rights_base, - fs_rights_inherting, + fs_rights_inheriting, fdflags, opened_fd.as_mut_ptr(), ); @@ -1349,7 +1431,7 @@ pub unsafe fn path_readlink(fd: Fd, path: &str, buf: *mut u8, buf_len: Size) -> } /// Remove a directory. -/// Return `ENOTEMPTY` if the directory is not empty. +/// Return `errno::notempty` if the directory is not empty. /// Note: This is similar to `unlinkat(fd, path, AT_REMOVEDIR)` in POSIX. /// /// ## Parameters @@ -1411,7 +1493,7 @@ pub unsafe fn path_symlink(old_path: &str, fd: Fd, new_path: &str) -> Result<()> } /// Unlink a file. -/// Return `EISDIR` if the path refers to a directory. +/// Return `errno::isdir` if the path refers to a directory. /// Note: This is similar to `unlinkat(fd, path, 0)` in POSIX. /// /// ## Parameters @@ -1520,7 +1602,11 @@ pub unsafe fn random_get(buf: *mut u8, buf_len: Size) -> Result<()> { /// /// * `ro_datalen` - Number of bytes stored in ri_data. /// * `ro_flags` - Message flags. -pub unsafe fn sock_recv(fd: Fd, ri_data: IovecArray, ri_flags: Riflags) -> Result<(Size, Roflags)> { +pub unsafe fn sock_recv( + fd: Fd, + ri_data: IovecArray<'_>, + ri_flags: Riflags, +) -> Result<(Size, Roflags)> { let mut ro_datalen = MaybeUninit::uninit(); let mut ro_flags = MaybeUninit::uninit(); let rc = wasi_snapshot_preview1::sock_recv( @@ -1550,7 +1636,7 @@ pub unsafe fn sock_recv(fd: Fd, ri_data: IovecArray, ri_flags: Riflags) -> Resul /// ## Return /// /// * `so_datalen` - Number of bytes transmitted. -pub unsafe fn sock_send(fd: Fd, si_data: CiovecArray, si_flags: Siflags) -> Result { +pub unsafe fn sock_send(fd: Fd, si_data: CiovecArray<'_>, si_flags: Siflags) -> Result { let mut so_datalen = MaybeUninit::uninit(); let rc = wasi_snapshot_preview1::sock_send( fd, @@ -1586,17 +1672,18 @@ pub mod wasi_snapshot_preview1 { #[link(wasm_import_module = "wasi_snapshot_preview1")] extern "C" { /// Read command-line argument data. - /// The size of the array should match that returned by `wasi_args_sizes_get()` + /// The size of the array should match that returned by `args_sizes_get` pub fn args_get(argv: *mut *mut u8, argv_buf: *mut u8) -> Errno; /// Return command-line argument data sizes. pub fn args_sizes_get(argc: *mut Size, argv_buf_size: *mut Size) -> Errno; /// Read environment variable data. - /// The sizes of the buffers should match that returned by `environ.sizes_get()`. + /// The sizes of the buffers should match that returned by `environ_sizes_get`. pub fn environ_get(environ: *mut *mut u8, environ_buf: *mut u8) -> Errno; - /// Return command-line argument data sizes. - pub fn environ_sizes_get(argc: *mut Size, argv_buf_size: *mut Size) -> Errno; + /// Return environment variable data sizes. + pub fn environ_sizes_get(environc: *mut Size, environ_buf_size: *mut Size) -> Errno; /// Return the resolution of a clock. - /// Implementations are required to provide a non-zero value for supported clocks. For unsupported clocks, return `WASI_EINVAL` + /// Implementations are required to provide a non-zero value for supported clocks. For unsupported clocks, + /// return `errno::inval`. /// Note: This is similar to `clock_getres` in POSIX. pub fn clock_res_get(id: Clockid, resolution: *mut Timestamp) -> Errno; /// Return the time value of a clock. @@ -1621,7 +1708,7 @@ pub mod wasi_snapshot_preview1 { /// Note: This is similar to `fcntl(fd, F_SETFL, flags)` in POSIX. pub fn fd_fdstat_set_flags(fd: Fd, flags: Fdflags) -> Errno; /// Adjust the rights associated with a file descriptor. - /// This can only be used to remove rights, and returns `ENOTCAPABLE` if called in a way that would attempt to add rights + /// This can only be used to remove rights, and returns `errno::notcapable` if called in a way that would attempt to add rights pub fn fd_fdstat_set_rights( fd: Fd, fs_rights_base: Rights, @@ -1667,8 +1754,8 @@ pub mod wasi_snapshot_preview1 { pub fn fd_read(fd: Fd, iovs_ptr: *const Iovec, iovs_len: usize, nread: *mut Size) -> Errno; /// Read directory entries from a directory. /// When successful, the contents of the output buffer consist of a sequence of - /// directory entries. Each directory entry consists of a dirent_t object, - /// followed by dirent_t::d_namlen bytes holding the name of the directory + /// directory entries. Each directory entry consists of a `dirent` object, + /// followed by `dirent::d_namlen` bytes holding the name of the directory /// entry. /// This function fills the output buffer as much as possible, potentially /// truncating the last directory entry. This allows the caller to grow its @@ -1760,7 +1847,7 @@ pub mod wasi_snapshot_preview1 { path_len: usize, oflags: Oflags, fs_rights_base: Rights, - fs_rights_inherting: Rights, + fs_rights_inheriting: Rights, fdflags: Fdflags, opened_fd: *mut Fd, ) -> Errno; @@ -1775,7 +1862,7 @@ pub mod wasi_snapshot_preview1 { bufused: *mut Size, ) -> Errno; /// Remove a directory. - /// Return `ENOTEMPTY` if the directory is not empty. + /// Return `errno::notempty` if the directory is not empty. /// Note: This is similar to `unlinkat(fd, path, AT_REMOVEDIR)` in POSIX. pub fn path_remove_directory(fd: Fd, path_ptr: *const u8, path_len: usize) -> Errno; /// Rename a file or directory. @@ -1798,7 +1885,7 @@ pub mod wasi_snapshot_preview1 { new_path_len: usize, ) -> Errno; /// Unlink a file. - /// Return `EISDIR` if the path refers to a directory. + /// Return `errno::isdir` if the path refers to a directory. /// Note: This is similar to `unlinkat(fd, path, 0)` in POSIX. pub fn path_unlink_file(fd: Fd, path_ptr: *const u8, path_len: usize) -> Errno; /// Concurrently poll for the occurrence of a set of events.