diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-05-11 05:07:52 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-05-11 05:07:52 +0000 |
commit | 474a8e9cd65ef42e89b04ec5f15907494dc9b1c5 (patch) | |
tree | 369e273affe8fedc061e4b74319fcf9b418aa961 | |
parent | e488058ff72271a0aeacfa339e81787d6a818005 (diff) | |
parent | 76b2d3b02842d754c8f35d32c2e5bef690796a19 (diff) | |
download | rand-android13-mainline-scheduling-release.tar.gz |
Snap for 8570526 from 76b2d3b02842d754c8f35d32c2e5bef690796a19 to mainline-scheduling-releaseaml_sch_331113000aml_sch_331111000android13-mainline-scheduling-release
Change-Id: I1be94b17aa931f4857d24e386f4d88fe42d4abdf
33 files changed, 843 insertions, 558 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json index c17e718..681c31d 100644 --- a/.cargo_vcs_info.json +++ b/.cargo_vcs_info.json @@ -1,5 +1,6 @@ { "git": { - "sha1": "6ecbe2626b2cc6110a25c97b1702b347574febc7" - } -} + "sha1": "937320cbfeebd4352a23086d9c6e68f067f74644" + }, + "path_in_vcs": "" +}
\ No newline at end of file @@ -1,8 +1,6 @@ -// This file is generated by cargo2android.py --device --run --dependencies --patch=patches/Android.bp.patch. +// This file is generated by cargo2android.py --config cargo2android.json. // Do not modify this file as changes will be overridden on upgrade. - - package { default_applicable_licenses: ["external_rust_crates_rand_license"], } @@ -44,6 +42,8 @@ rust_library { name: "librand", host_supported: true, crate_name: "rand", + cargo_env_compat: true, + cargo_pkg_version: "0.8.5", srcs: ["src/lib.rs"], edition: "2018", features: [ @@ -52,7 +52,7 @@ rust_library { "getrandom", "libc", "rand_chacha", - "rand_hc", + "small_rng", "std", "std_rng", ], @@ -61,13 +61,8 @@ rust_library { "librand_chacha", "librand_core", ], + apex_available: [ + "//apex_available:platform", + "com.android.virt", + ], } - -// dependent_library ["feature_list"] -// cfg-if-1.0.0 -// getrandom-0.2.2 "std" -// libc-0.2.93 -// ppv-lite86-0.2.10 "simd,std" -// rand_chacha-0.3.0 "std" -// rand_core-0.6.2 "alloc,getrandom,std" -// rand_hc-0.3.0 diff --git a/CHANGELOG.md b/CHANGELOG.md index 536c510..b0872af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,38 @@ 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) @@ -664,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 @@ -1,28 +1,17 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "bincode" -version = "1.3.1" +version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30d3a39baa26f9651f17b375061f3233dde33424a8b72b0dbe93a68a0bc896d" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" dependencies = [ - "byteorder", "serde", ] [[package]] -name = "byteorder" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b" - -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - -[[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -30,20 +19,20 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "getrandom" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" +checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "wasi", ] [[package]] name = "libc" -version = "0.2.82" +version = "0.2.112" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89203f3fba0a3795506acaad8ebce3c80c0af93f994d5a1d7a0b1eeb23271929" +checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125" [[package]] name = "libm" @@ -53,50 +42,50 @@ checksum = "7fc7aa29613bd6a620df431842069224d8bc9011086b1db4c0e0cd47fa03ec9a" [[package]] name = "log" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcf3805d4480bb5b86070dcfeb9e2cb2ebc148adb753c5cca5f884d1d65a42b2" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" dependencies = [ - "cfg-if 0.1.10", + "cfg-if", ] [[package]] name = "packed_simd_2" -version = "0.3.4" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3278e0492f961fd4ae70909f56b2723a7e8d01a228427294e19cdfdebda89a17" +checksum = "defdcfef86dcc44ad208f71d9ff4ce28df6537a4e0d6b0e8e845cb8ca10059a6" dependencies = [ - "cfg-if 0.1.10", + "cfg-if", "libm", ] [[package]] name = "ppv-lite86" -version = "0.2.10" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" +checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" [[package]] name = "proc-macro2" -version = "1.0.24" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" dependencies = [ "unicode-xid", ] [[package]] name = "quote" -version = "1.0.8" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df" +checksum = "47aa80447ce4daf1717500037052af176af5d38cc3e571d9ec1c7353fc10c87d" dependencies = [ "proc-macro2", ] [[package]] name = "rand" -version = "0.8.3" +version = "0.8.5" dependencies = [ "bincode", "libc", @@ -104,16 +93,15 @@ dependencies = [ "packed_simd_2", "rand_chacha", "rand_core", - "rand_hc", "rand_pcg", "serde", ] [[package]] name = "rand_chacha" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", "rand_core", @@ -121,45 +109,37 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.6.1" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c026d7df8b298d90ccbbc5190bd04d85e159eaf5576caeacf8741da93ccbd2e5" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" dependencies = [ "getrandom", -] - -[[package]] -name = "rand_hc" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" -dependencies = [ - "rand_core", + "serde", ] [[package]] name = "rand_pcg" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7de198537002b913568a3847e53535ace266f93526caf5c360ec41d72c5787f0" +checksum = "59cad018caf63deb318e5a4586d99a24424a364f40f1e5778c29aca23f4fc73e" dependencies = [ "rand_core", ] [[package]] name = "serde" -version = "1.0.120" +version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "166b2349061381baf54a58e4b13c89369feb0ef2eaa57198899e2312aac30aab" +checksum = "97565067517b60e2d1ea8b268e59ce036de907ac523ad83a0475da04e818989a" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.120" +version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ca2a8cb5805ce9e3b95435e3765b7b553cecc762d938d409434338386cb5775" +checksum = "ed201699328568d8d08208fdd080e3ff594e6c422e438b6705905da01005d537" dependencies = [ "proc-macro2", "quote", @@ -168,9 +148,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.59" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07cb8b1b4ebf86a89ee88cbd201b022b94138c623644d035185c84d3f41b7e66" +checksum = "a684ac3dcd8913827e18cd09a68384ee66c1de24157e3c556c9ab16d85695fb7" dependencies = [ "proc-macro2", "quote", @@ -179,12 +159,12 @@ dependencies = [ [[package]] name = "unicode-xid" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" [[package]] name = "wasi" -version = "0.10.1+wasi-snapshot-preview1" +version = "0.10.2+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93c6c3420963c5c64bca373b25e77acb562081b9bb4dd5bb864187742186cea9" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" @@ -3,17 +3,16 @@ # 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.8.3" +version = "0.8.5" authors = ["The Rand Project Developers", "The Rust Project Developers"] include = ["src/", "LICENSE-*", "README.md", "CHANGELOG.md", "COPYRIGHT"] autobenches = true @@ -36,11 +35,16 @@ version = "0.4.4" optional = true [dependencies.packed_simd] -version = "0.3.4" +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.6.0" @@ -51,9 +55,6 @@ optional = true [dev-dependencies.bincode] version = "1.2.1" -[dev-dependencies.rand_hc] -version = "0.3.0" - [dev-dependencies.rand_pcg] version = "0.3.0" @@ -61,19 +62,13 @@ version = "0.3.0" alloc = ["rand_core/alloc"] default = ["std", "std_rng"] getrandom = ["rand_core/getrandom"] +min_const_gen = [] nightly = [] -serde1 = ["serde"] +serde1 = ["serde", "rand_core/serde1"] simd_support = ["packed_simd"] small_rng = [] std = ["rand_core/std", "rand_chacha/std", "alloc", "getrandom", "libc"] -std_rng = ["rand_chacha", "rand_hc"] -[target."cfg(not(target_os = \"emscripten\"))".dependencies.rand_chacha] -version = "0.3.0" -optional = true -default-features = false -[target."cfg(target_os = \"emscripten\")".dependencies.rand_hc] -version = "0.3.0" -optional = true +std_rng = ["rand_chacha"] [target."cfg(unix)".dependencies.libc] version = "0.2.22" optional = true diff --git a/Cargo.toml.orig b/Cargo.toml.orig index afd1339..98ba373 100644 --- a/Cargo.toml.orig +++ b/Cargo.toml.orig @@ -1,6 +1,6 @@ [package] name = "rand" -version = "0.8.3" +version = "0.8.5" authors = ["The Rand Project Developers", "The Rust Project Developers"] license = "MIT OR Apache-2.0" readme = "README.md" @@ -16,11 +16,20 @@ autobenches = true edition = "2018" include = ["src/", "LICENSE-*", "README.md", "CHANGELOG.md", "COPYRIGHT"] +[package.metadata.docs.rs] +# To build locally: +# RUSTDOCFLAGS="--cfg doc_cfg" cargo +nightly doc --all-features --no-deps --open +all-features = true +rustdoc-args = ["--cfg", "doc_cfg"] + +[package.metadata.playground] +features = ["small_rng", "serde1"] + [features] # Meta-features: default = ["std", "std_rng"] nightly = [] # enables performance optimizations requiring nightly rust -serde1 = ["serde"] +serde1 = ["serde", "rand_core/serde1"] # Option (enabled by default): without "std" rand uses libcore; this option # enables functionality expected to be available on a standard platform. @@ -36,17 +45,20 @@ getrandom = ["rand_core/getrandom"] simd_support = ["packed_simd"] # Option (enabled by default): enable StdRng -std_rng = ["rand_chacha", "rand_hc"] +std_rng = ["rand_chacha"] # Option: enable SmallRng small_rng = [] +# Option: for rustc ≥ 1.51, enable generating random arrays of any size +# using min-const-generics +min_const_gen = [] + [workspace] members = [ "rand_core", "rand_distr", "rand_chacha", - "rand_hc", "rand_pcg", ] @@ -54,11 +66,12 @@ members = [ rand_core = { path = "rand_core", version = "0.6.0" } log = { version = "0.4.4", optional = true } serde = { version = "1.0.103", features = ["derive"], optional = true } +rand_chacha = { path = "rand_chacha", version = "0.3.0", default-features = false, optional = true } [dependencies.packed_simd] # NOTE: so far no version works reliably due to dependence on unstable features package = "packed_simd_2" -version = "0.3.4" +version = "0.3.7" optional = true features = ["into_bits"] @@ -66,25 +79,7 @@ features = ["into_bits"] # Used for fork protection (reseeding.rs) libc = { version = "0.2.22", optional = true, default-features = false } -# Emscripten does not support 128-bit integers, which are used by ChaCha code. -# We work around this by using a different RNG. -[target.'cfg(not(target_os = "emscripten"))'.dependencies] -rand_chacha = { path = "rand_chacha", version = "0.3.0", default-features = false, optional = true } -[target.'cfg(target_os = "emscripten")'.dependencies] -rand_hc = { path = "rand_hc", version = "0.3.0", optional = true } - [dev-dependencies] rand_pcg = { path = "rand_pcg", version = "0.3.0" } -# Only for benches: -rand_hc = { path = "rand_hc", version = "0.3.0" } # Only to test serde1 bincode = "1.2.1" - -[package.metadata.docs.rs] -# To build locally: -# RUSTDOCFLAGS="--cfg doc_cfg" cargo +nightly doc --all-features --no-deps --open -all-features = true -rustdoc-args = ["--cfg", "doc_cfg"] - -[package.metadata.playground] -features = ["small_rng", "serde1"] diff --git a/LICENSE-APACHE b/LICENSE-APACHE index 17d7468..494ad3b 100644 --- a/LICENSE-APACHE +++ b/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. @@ -7,13 +7,13 @@ third_party { } url { type: ARCHIVE - value: "https://static.crates.io/crates/rand/rand-0.8.3.crate" + value: "https://static.crates.io/crates/rand/rand-0.8.5.crate" } - version: "0.8.3" + version: "0.8.5" license_type: NOTICE last_upgrade_date { - year: 2021 - month: 4 + year: 2022 + month: 3 day: 1 } } @@ -51,7 +51,7 @@ Add this to your `Cargo.toml`: ```toml [dependencies] -rand = "0.8.0" +rand = "0.8.4" ``` To get started using Rand, see [The Book](https://rust-random.github.io/book). @@ -120,7 +120,7 @@ Rand is built with these features enabled by default: Optionally, the following dependencies can be enabled: -- `log` enables logging via the `log` crate` crate +- `log` enables logging via the `log` crate Additionally, these features configure Rand: @@ -128,6 +128,8 @@ Additionally, these features configure Rand: - `nightly` enables some optimizations requiring nightly Rust - `simd_support` (experimental) enables sampling of SIMD values (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 @@ -139,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/TEST_MAPPING b/TEST_MAPPING index c152478..ff12af6 100644 --- a/TEST_MAPPING +++ b/TEST_MAPPING @@ -1,134 +1,93 @@ // Generated by update_crate_tests.py for tests that depend on this crate. { - "presubmit": [ - { - "name": "crossbeam-epoch_device_test_src_lib" - }, - { - "name": "crossbeam-epoch_device_test_tests_loom" - }, - { - "name": "crossbeam-utils_device_test_src_lib" - }, - { - "name": "crossbeam-utils_device_test_tests_atomic_cell" - }, - { - "name": "crossbeam-utils_device_test_tests_cache_padded" - }, - { - "name": "crossbeam-utils_device_test_tests_parker" - }, - { - "name": "crossbeam-utils_device_test_tests_sharded_lock" - }, + "imports": [ { - "name": "crossbeam-utils_device_test_tests_thread" - }, - { - "name": "crossbeam-utils_device_test_tests_wait_group" - }, - { - "name": "keystore2_test" + "path": "external/rust/crates/base64" }, { - "name": "tokio_device_test_tests_buffered" + "path": "external/rust/crates/cast" }, { - "name": "tokio_device_test_tests_io_async_read" + "path": "external/rust/crates/crc32fast" }, { - "name": "tokio_device_test_tests_io_copy_bidirectional" + "path": "external/rust/crates/crossbeam-deque" }, { - "name": "tokio_device_test_tests_io_lines" + "path": "external/rust/crates/crossbeam-epoch" }, { - "name": "tokio_device_test_tests_io_mem_stream" + "path": "external/rust/crates/crossbeam-queue" }, { - "name": "tokio_device_test_tests_io_read" + "path": "external/rust/crates/crossbeam-utils" }, { - "name": "tokio_device_test_tests_io_read_buf" + "path": "external/rust/crates/mio" }, { - "name": "tokio_device_test_tests_io_read_to_end" + "path": "external/rust/crates/quickcheck" }, { - "name": "tokio_device_test_tests_io_take" + "path": "external/rust/crates/regex" }, { - "name": "tokio_device_test_tests_io_write" + "path": "external/rust/crates/ryu" }, { - "name": "tokio_device_test_tests_io_write_all" - }, - { - "name": "tokio_device_test_tests_io_write_buf" - }, - { - "name": "tokio_device_test_tests_io_write_int" - }, - { - "name": "tokio_device_test_tests_macros_join" - }, - { - "name": "tokio_device_test_tests_no_rt" - }, - { - "name": "tokio_device_test_tests_rt_basic" - }, - { - "name": "tokio_device_test_tests_rt_threaded" - }, + "path": "external/rust/crates/tokio" + } + ], + "presubmit": [ { - "name": "tokio_device_test_tests_sync_barrier" + "name": "ZipFuseTest" }, { - "name": "tokio_device_test_tests_sync_broadcast" + "name": "apkdmverity.test" }, { - "name": "tokio_device_test_tests_sync_errors" + "name": "authfs_device_test_src_lib" }, { - "name": "tokio_device_test_tests_sync_mpsc" + "name": "keystore2_test" }, { - "name": "tokio_device_test_tests_sync_mutex_owned" + "name": "keystore2_test_utils_test" }, { - "name": "tokio_device_test_tests_sync_rwlock" + "name": "legacykeystore_test" }, { - "name": "tokio_device_test_tests_sync_watch" + "name": "microdroid_manager_test" }, { - "name": "tokio_device_test_tests_task_local" - }, + "name": "virtualizationservice_device_test" + } + ], + "presubmit-rust": [ { - "name": "tokio_device_test_tests_task_local_set" + "name": "ZipFuseTest" }, { - "name": "tokio_device_test_tests_tcp_accept" + "name": "apkdmverity.test" }, { - "name": "tokio_device_test_tests_tcp_echo" + "name": "authfs_device_test_src_lib" }, { - "name": "tokio_device_test_tests_tcp_into_std" + "name": "keystore2_test" }, { - "name": "tokio_device_test_tests_tcp_shutdown" + "name": "keystore2_test_utils_test" }, { - "name": "tokio_device_test_tests_time_rt" + "name": "legacykeystore_test" }, { - "name": "tokio_device_test_tests_uds_split" + "name": "microdroid_manager_test" }, { - "name": "vpnprofilestore_test" + "name": "virtualizationservice_device_test" } ] } diff --git a/cargo2android.json b/cargo2android.json new file mode 100644 index 0000000..cdb5c0d --- /dev/null +++ b/cargo2android.json @@ -0,0 +1,10 @@ +{ + "apex-available": [ + "//apex_available:platform", + "com.android.virt" + ], + "dependencies": true, + "device": true, + "features": "default,small_rng", + "run": true +}
\ No newline at end of file diff --git a/patches/Android.bp.patch b/patches/Android.bp.patch deleted file mode 100644 index 59579a5..0000000 --- a/patches/Android.bp.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff --git a/Android.bp b/Android.bp -index 49626bd..5c40f99 100644 ---- a/Android.bp -+++ b/Android.bp -@@ -23,7 +23,6 @@ rust_library { - "liblibc", - "librand_chacha", - "librand_core", -- "librand_hc", - ], - } - diff --git a/src/distributions/bernoulli.rs b/src/distributions/bernoulli.rs index b968ca0..226db79 100644 --- a/src/distributions/bernoulli.rs +++ b/src/distributions/bernoulli.rs @@ -33,7 +33,7 @@ use serde::{Serialize, Deserialize}; /// This `Bernoulli` distribution uses 64 bits from the RNG (a `u64`), /// so only probabilities that are multiples of 2<sup>-64</sup> can be /// represented. -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, PartialEq)] #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] pub struct Bernoulli { /// Probability of success, relative to the maximal integer. @@ -49,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 @@ -96,7 +96,7 @@ impl Bernoulli { /// 2<sup>-64</sup> in `[0, 1]` can be represented as a `f64`.) #[inline] pub fn new(p: f64) -> Result<Bernoulli, BernoulliError> { - if !(p >= 0.0 && p < 1.0) { + if !(0.0..1.0).contains(&p) { if p == 1.0 { return Ok(Bernoulli { p_int: ALWAYS_TRUE }); } @@ -157,6 +157,9 @@ mod test { #[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(); @@ -208,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/src/distributions/distribution.rs b/src/distributions/distribution.rs new file mode 100644 index 0000000..c5cf6a6 --- /dev/null +++ b/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 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Distribution trait and associates + +use crate::Rng; +use core::iter; +#[cfg(feature = "alloc")] +use alloc::string::String; + +/// Types (distributions) that can be used to create a random instance of `T`. +/// +/// It is possible to sample from a distribution through both the +/// `Distribution` and [`Rng`] traits, via `distr.sample(&mut rng)` and +/// `rng.sample(distr)`. They also both offer the [`sample_iter`] method, which +/// produces an iterator that samples from the distribution. +/// +/// All implementations are expected to be immutable; this has the significant +/// advantage of not needing to consider thread safety, and for most +/// distributions efficient state-less sampling algorithms are available. +/// +/// Implementations are typically expected to be portable with reproducible +/// results when used with a PRNG with fixed seed; see the +/// [portability chapter](https://rust-random.github.io/book/portability.html) +/// of The Rust Rand Book. In some cases this does not apply, e.g. the `usize` +/// type requires different sampling on 32-bit and 64-bit machines. +/// +/// [`sample_iter`]: Distribution::sample_iter +pub trait Distribution<T> { + /// Generate a random value of `T`, using `rng` as the source of randomness. + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> T; + + /// Create an iterator that generates random values of `T`, using `rng` as + /// the source of randomness. + /// + /// Note that this function takes `self` by value. This works since + /// `Distribution<T>` is impl'd for `&D` where `D: Distribution<T>`, + /// however borrowing is not automatic hence `distr.sample_iter(...)` may + /// need to be replaced with `(&distr).sample_iter(...)` to borrow or + /// `(&*distr).sample_iter(...)` to reborrow an existing reference. + /// + /// # Example + /// + /// ``` + /// use rand::thread_rng; + /// use rand::distributions::{Distribution, Alphanumeric, Uniform, Standard}; + /// + /// let mut rng = thread_rng(); + /// + /// // Vec of 16 x f32: + /// let v: Vec<f32> = Standard.sample_iter(&mut rng).take(16).collect(); + /// + /// // String: + /// let s: String = Alphanumeric + /// .sample_iter(&mut rng) + /// .take(7) + /// .map(char::from) + /// .collect(); + /// + /// // Dice-rolling: + /// let die_range = Uniform::new_inclusive(1, 6); + /// let mut roll_die = die_range.sample_iter(&mut rng); + /// while roll_die.next().unwrap() != 6 { + /// println!("Not a 6; rolling again!"); + /// } + /// ``` + fn sample_iter<R>(self, rng: R) -> DistIter<Self, R, T> + where + R: Rng, + Self: Sized, + { + DistIter { + distr: self, + rng, + phantom: ::core::marker::PhantomData, + } + } + + /// Create a distribution of values of 'S' by mapping the output of `Self` + /// through the closure `F` + /// + /// # Example + /// + /// ``` + /// use rand::thread_rng; + /// use rand::distributions::{Distribution, Uniform}; + /// + /// let mut rng = thread_rng(); + /// + /// let die = Uniform::new_inclusive(1, 6); + /// let even_number = die.map(|num| num % 2 == 0); + /// while !even_number.sample(&mut rng) { + /// println!("Still odd; rolling again!"); + /// } + /// ``` + fn map<F, S>(self, func: F) -> DistMap<Self, F, T, S> + where + F: Fn(T) -> S, + Self: Sized, + { + DistMap { + distr: self, + func, + phantom: ::core::marker::PhantomData, + } + } +} + +impl<'a, T, D: Distribution<T>> Distribution<T> for &'a D { + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> T { + (*self).sample(rng) + } +} + +/// An iterator that generates random values of `T` with distribution `D`, +/// using `R` as the source of randomness. +/// +/// This `struct` is created by the [`sample_iter`] method on [`Distribution`]. +/// See its documentation for more. +/// +/// [`sample_iter`]: Distribution::sample_iter +#[derive(Debug)] +pub struct DistIter<D, R, T> { + distr: D, + rng: R, + phantom: ::core::marker::PhantomData<T>, +} + +impl<D, R, T> Iterator for DistIter<D, R, T> +where + D: Distribution<T>, + R: Rng, +{ + type Item = T; + + #[inline(always)] + fn next(&mut self) -> Option<T> { + // Here, self.rng may be a reference, but we must take &mut anyway. + // Even if sample could take an R: Rng by value, we would need to do this + // since Rng is not copyable and we cannot enforce that this is "reborrowable". + Some(self.distr.sample(&mut self.rng)) + } + + fn size_hint(&self) -> (usize, Option<usize>) { + (usize::max_value(), None) + } +} + +impl<D, R, T> iter::FusedIterator for DistIter<D, R, T> +where + D: Distribution<T>, + R: Rng, +{ +} + +#[cfg(features = "nightly")] +impl<D, R, T> iter::TrustedLen for DistIter<D, R, T> +where + D: Distribution<T>, + R: Rng, +{ +} + +/// A distribution of values of type `S` derived from the distribution `D` +/// by mapping its output of type `T` through the closure `F`. +/// +/// This `struct` is created by the [`Distribution::map`] method. +/// See its documentation for more. +#[derive(Debug)] +pub struct DistMap<D, F, T, S> { + distr: D, + func: F, + phantom: ::core::marker::PhantomData<fn(T) -> S>, +} + +impl<D, F, T, S> Distribution<S> for DistMap<D, F, T, S> +where + D: Distribution<T>, + F: Fn(T) -> S, +{ + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> S { + (self.func)(self.distr.sample(rng)) + } +} + +/// `String` sampler +/// +/// Sampling a `String` of random characters is not quite the same as collecting +/// a sequence of chars. This trait contains some helpers. +#[cfg(feature = "alloc")] +pub trait DistString { + /// Append `len` random chars to `string` + fn append_string<R: Rng + ?Sized>(&self, rng: &mut R, string: &mut String, len: usize); + + /// Generate a `String` of `len` random chars + #[inline] + fn sample_string<R: Rng + ?Sized>(&self, rng: &mut R, len: usize) -> String { + let mut s = String::new(); + self.append_string(rng, &mut s, len); + s + } +} + +#[cfg(test)] +mod tests { + use crate::distributions::{Distribution, Uniform}; + use crate::Rng; + + #[test] + fn test_distributions_iter() { + use crate::distributions::Open01; + let mut rng = crate::test::rng(210); + let distr = Open01; + let mut iter = Distribution::<f32>::sample_iter(distr, &mut rng); + let mut sum: f32 = 0.; + for _ in 0..100 { + sum += iter.next().unwrap(); + } + assert!(0. < sum && sum < 100.); + } + + #[test] + fn test_distributions_map() { + let dist = Uniform::new_inclusive(0, 5).map(|val| val + 15); + + let mut rng = crate::test::rng(212); + let val = dist.sample(&mut rng); + assert!((15..=20).contains(&val)); + } + + #[test] + fn test_make_an_iter() { + fn ten_dice_rolls_other_than_five<R: Rng>( + rng: &mut R, + ) -> impl Iterator<Item = i32> + '_ { + Uniform::new_inclusive(1, 6) + .sample_iter(rng) + .filter(|x| *x != 5) + .take(10) + } + + let mut rng = crate::test::rng(211); + let mut count = 0; + for val in ten_dice_rolls_other_than_five(&mut rng) { + assert!((1..=6).contains(&val) && val != 5); + count += 1; + } + assert_eq!(count, 10); + } + + #[test] + #[cfg(feature = "alloc")] + fn test_dist_string() { + use core::str; + use crate::distributions::{Alphanumeric, DistString, Standard}; + let mut rng = crate::test::rng(213); + + let s1 = Alphanumeric.sample_string(&mut rng, 20); + assert_eq!(s1.len(), 20); + assert_eq!(str::from_utf8(s1.as_bytes()), Ok(s1.as_str())); + + let s2 = Standard.sample_string(&mut rng, 20); + assert_eq!(s2.chars().count(), 20); + assert_eq!(str::from_utf8(s2.as_bytes()), Ok(s2.as_str())); + } +} diff --git a/src/distributions/float.rs b/src/distributions/float.rs index 733a403..ce5946f 100644 --- a/src/distributions/float.rs +++ b/src/distributions/float.rs @@ -78,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/src/distributions/integer.rs b/src/distributions/integer.rs index 8a2ce4c..19ce715 100644 --- a/src/distributions/integer.rs +++ b/src/distributions/integer.rs @@ -14,8 +14,8 @@ use crate::Rng; use core::arch::x86::{__m128i, __m256i}; #[cfg(all(target_arch = "x86_64", feature = "simd_support"))] use core::arch::x86_64::{__m128i, __m256i}; -#[cfg(not(target_os = "emscripten"))] use core::num::NonZeroU128; -use core::num::{NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize}; +use core::num::{NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize, + NonZeroU128}; #[cfg(feature = "simd_support")] use packed_simd::*; impl Distribution<u8> for Standard { @@ -46,7 +46,6 @@ impl Distribution<u64> for Standard { } } -#[cfg(not(target_os = "emscripten"))] impl Distribution<u128> for Standard { #[inline] fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u128 { @@ -86,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 } @@ -108,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); @@ -173,7 +170,6 @@ mod tests { rng.sample::<i16, _>(Standard); rng.sample::<i32, _>(Standard); rng.sample::<i64, _>(Standard); - #[cfg(not(target_os = "emscripten"))] rng.sample::<i128, _>(Standard); rng.sample::<usize, _>(Standard); @@ -181,7 +177,6 @@ mod tests { rng.sample::<u16, _>(Standard); rng.sample::<u32, _>(Standard); rng.sample::<u64, _>(Standard); - #[cfg(not(target_os = "emscripten"))] rng.sample::<u128, _>(Standard); } diff --git a/src/distributions/mod.rs b/src/distributions/mod.rs index 652f52a..05ca806 100644 --- a/src/distributions/mod.rs +++ b/src/distributions/mod.rs @@ -93,163 +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_index::{WeightedError, WeightedIndex}; - mod bernoulli; -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; -#[cfg(feature = "alloc")] mod weighted_index; - -#[cfg(feature = "serde1")] -use serde::{Serialize, Deserialize}; - +mod distribution; mod float; -#[doc(hidden)] -pub mod hidden_export { - pub use super::float::IntoFloat; // used by rand_distr -} mod integer; mod other; +mod slice; mod utils; +#[cfg(feature = "alloc")] +mod weighted_index; -/// Types (distributions) that can be used to create a random instance of `T`. -/// -/// It is possible to sample from a distribution through both the -/// `Distribution` and [`Rng`] traits, via `distr.sample(&mut rng)` and -/// `rng.sample(distr)`. They also both offer the [`sample_iter`] method, which -/// produces an iterator that samples from the distribution. -/// -/// All implementations are expected to be immutable; this has the significant -/// advantage of not needing to consider thread safety, and for most -/// distributions efficient state-less sampling algorithms are available. -/// -/// Implementations are typically expected to be portable with reproducible -/// results when used with a PRNG with fixed seed; see the -/// [portability chapter](https://rust-random.github.io/book/portability.html) -/// of The Rust Rand Book. In some cases this does not apply, e.g. the `usize` -/// type requires different sampling on 32-bit and 64-bit machines. -/// -/// [`sample_iter`]: Distribution::method.sample_iter -pub trait Distribution<T> { - /// Generate a random value of `T`, using `rng` as the source of randomness. - fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> T; - - /// Create an iterator that generates random values of `T`, using `rng` as - /// the source of randomness. - /// - /// Note that this function takes `self` by value. This works since - /// `Distribution<T>` is impl'd for `&D` where `D: Distribution<T>`, - /// however borrowing is not automatic hence `distr.sample_iter(...)` may - /// need to be replaced with `(&distr).sample_iter(...)` to borrow or - /// `(&*distr).sample_iter(...)` to reborrow an existing reference. - /// - /// # Example - /// - /// ``` - /// use rand::thread_rng; - /// use rand::distributions::{Distribution, Alphanumeric, Uniform, Standard}; - /// - /// let mut rng = thread_rng(); - /// - /// // Vec of 16 x f32: - /// let v: Vec<f32> = Standard.sample_iter(&mut rng).take(16).collect(); - /// - /// // String: - /// let s: String = Alphanumeric - /// .sample_iter(&mut rng) - /// .take(7) - /// .map(char::from) - /// .collect(); - /// - /// // Dice-rolling: - /// let die_range = Uniform::new_inclusive(1, 6); - /// let mut roll_die = die_range.sample_iter(&mut rng); - /// while roll_die.next().unwrap() != 6 { - /// println!("Not a 6; rolling again!"); - /// } - /// ``` - fn sample_iter<R>(self, rng: R) -> DistIter<Self, R, T> - where - R: Rng, - Self: Sized, - { - DistIter { - distr: self, - rng, - phantom: ::core::marker::PhantomData, - } - } -} - -impl<'a, T, D: Distribution<T>> Distribution<T> for &'a D { - fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> T { - (*self).sample(rng) - } -} - - -/// An iterator that generates random values of `T` with distribution `D`, -/// using `R` as the source of randomness. -/// -/// This `struct` is created by the [`sample_iter`] method on [`Distribution`]. -/// See its documentation for more. -/// -/// [`sample_iter`]: Distribution::sample_iter -#[derive(Debug)] -pub struct DistIter<D, R, T> { - distr: D, - rng: R, - phantom: ::core::marker::PhantomData<T>, -} - -impl<D, R, T> Iterator for DistIter<D, R, T> -where - D: Distribution<T>, - R: Rng, -{ - type Item = T; - - #[inline(always)] - fn next(&mut self) -> Option<T> { - // Here, self.rng may be a reference, but we must take &mut anyway. - // Even if sample could take an R: Rng by value, we would need to do this - // since Rng is not copyable and we cannot enforce that this is "reborrowable". - Some(self.distr.sample(&mut self.rng)) - } - - fn size_hint(&self) -> (usize, Option<usize>) { - (usize::max_value(), None) - } -} - -impl<D, R, T> iter::FusedIterator for DistIter<D, R, T> -where - D: Distribution<T>, - R: Rng, -{ +#[doc(hidden)] +pub mod hidden_export { + pub use super::float::IntoFloat; // used by rand_distr } +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; -#[cfg(features = "nightly")] -impl<D, R, T> iter::TrustedLen for DistIter<D, R, T> -where - D: Distribution<T>, - R: Rng, -{ -} +pub use self::bernoulli::{Bernoulli, BernoulliError}; +pub use self::distribution::{Distribution, DistIter, DistMap}; +#[cfg(feature = "alloc")] +pub use self::distribution::DistString; +pub use self::float::{Open01, OpenClosed01}; +pub use self::other::Alphanumeric; +pub use self::slice::Slice; +#[doc(inline)] +pub use self::uniform::Uniform; +#[cfg(feature = "alloc")] +pub use self::weighted_index::{WeightedError, WeightedIndex}; +#[allow(unused)] +use crate::Rng; /// A generic random value distribution, implemented for many primitive types. /// Usually generates values with a numerically uniform distribution, and with a @@ -278,7 +158,13 @@ where /// * Tuples (up to 12 elements): each element is generated sequentially. /// * Arrays (up to 32 elements): each element is generated sequentially; /// see also [`Rng::fill`] which supports arbitrary array length for integer -/// types and tends to be faster for `u32` and smaller types. +/// and float types and tends to be faster for `u32` and smaller types. +/// When using `rustc` ≥ 1.51, enable the `min_const_gen` feature to support +/// arrays larger than 32 elements. +/// Note that [`Rng::fill`] and `Standard`'s array support are *not* equivalent: +/// the former is optimised for integer types (using fewer RNG calls for +/// element types smaller than the RNG word size), while the latter supports +/// any element type supported by `Standard`. /// * `Option<T>` first generates a `bool`, and if true generates and returns /// `Some(value)` where `value: T`, otherwise returning `None`. /// @@ -328,45 +214,5 @@ where /// /// [`Uniform`]: uniform::Uniform #[derive(Clone, Copy, Debug)] -#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))] pub struct Standard; - - -#[cfg(test)] -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 mut iter = Distribution::<f32>::sample_iter(distr, &mut rng); - let mut sum: f32 = 0.; - for _ in 0..100 { - sum += iter.next().unwrap(); - } - assert!(0. < sum && sum < 100.); - } - - #[test] - fn test_make_an_iter() { - fn ten_dice_rolls_other_than_five<'a, R: Rng>( - rng: &'a mut R, - ) -> impl Iterator<Item = i32> + 'a { - Uniform::new_inclusive(1, 6) - .sample_iter(rng) - .filter(|x| *x != 5) - .take(10) - } - - let mut rng = crate::test::rng(211); - let mut count = 0; - for val in ten_dice_rolls_other_than_five(&mut rng) { - assert!(val >= 1 && val <= 6 && val != 5); - count += 1; - } - assert_eq!(count, 10); - } -} diff --git a/src/distributions/other.rs b/src/distributions/other.rs index f62fe59..03802a7 100644 --- a/src/distributions/other.rs +++ b/src/distributions/other.rs @@ -10,12 +10,19 @@ 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 ----- @@ -25,19 +32,22 @@ use serde::{Serialize, Deserialize}; /// # 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)) -/// .map(char::from) -/// .take(7) -/// .collect(); +/// let chars: String = (0..7).map(|_| rng.sample(Alphanumeric) as char).collect(); /// println!("Random chars: {}", chars); /// ``` /// +/// 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 @@ -54,7 +64,7 @@ use serde::{Serialize, Deserialize}; /// /// - [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)] +#[derive(Debug, Clone, Copy)] #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] pub struct Alphanumeric; @@ -82,6 +92,19 @@ impl Distribution<char> for Standard { } } +/// Note: the `String` is potentially left with excess capacity; optionally the +/// user may call `string.shrink_to_fit()` afterwards. +#[cfg(feature = "alloc")] +impl DistString for Standard { + fn append_string<R: Rng + ?Sized>(&self, rng: &mut R, s: &mut String, len: usize) { + // A char is encoded with at most four bytes, thus this reservation is + // guaranteed to be sufficient. We do not shrink_to_fit afterwards so + // that repeated usage on the same `String` buffer does not reallocate. + s.reserve(4 * len); + s.extend(Distribution::<char>::sample_iter(self, rng).take(len)); + } +} + impl Distribution<u8> for Alphanumeric { fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u8 { const RANGE: u32 = 26 + 26 + 10; @@ -101,6 +124,16 @@ impl Distribution<u8> for Alphanumeric { } } +#[cfg(feature = "alloc")] +impl DistString for Alphanumeric { + fn append_string<R: Rng + ?Sized>(&self, rng: &mut R, string: &mut String, len: usize) { + unsafe { + let v = string.as_mut_vec(); + v.extend(self.sample_iter(rng).take(len)); + } + } +} + impl Distribution<bool> for Standard { #[inline] fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> bool { @@ -156,6 +189,24 @@ tuple_impl! {A, B, C, D, E, F, G, H, I, J} tuple_impl! {A, B, C, D, E, F, G, H, I, J, K} tuple_impl! {A, B, C, D, E, F, G, H, I, J, K, L} +#[cfg(feature = "min_const_gen")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "min_const_gen")))] +impl<T, const N: usize> Distribution<[T; N]> for Standard +where Standard: Distribution<T> +{ + #[inline] + fn sample<R: Rng + ?Sized>(&self, _rng: &mut R) -> [T; N] { + let mut buff: [MaybeUninit<T>; N] = unsafe { MaybeUninit::uninit().assume_init() }; + + for elem in &mut buff { + *elem = MaybeUninit::new(_rng.gen()); + } + + unsafe { mem::transmute_copy::<_, _>(&buff) } + } +} + +#[cfg(not(feature = "min_const_gen"))] macro_rules! array_impl { // recursive, given at least one type parameter: {$n:expr, $t:ident, $($ts:ident,)*} => { @@ -176,6 +227,7 @@ macro_rules! array_impl { }; } +#[cfg(not(feature = "min_const_gen"))] array_impl! {32, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,} impl<T> Distribution<Option<T>> for Standard @@ -228,7 +280,7 @@ mod tests { .map(|()| rng.gen::<char>()) .take(1000) .collect(); - assert!(word.len() != 0); + assert!(!word.is_empty()); } #[test] @@ -240,11 +292,11 @@ mod tests { let mut incorrect = false; for _ in 0..100 { let c: char = rng.sample(Alphanumeric).into(); - incorrect |= !((c >= '0' && c <= '9') || - (c >= 'A' && c <= 'Z') || - (c >= 'a' && c <= 'z') ); + incorrect |= !(('0'..='9').contains(&c) || + ('A'..='Z').contains(&c) || + ('a'..='z').contains(&c) ); } - assert!(incorrect == false); + assert!(!incorrect); } #[test] diff --git a/src/distributions/slice.rs b/src/distributions/slice.rs new file mode 100644 index 0000000..3302deb --- /dev/null +++ b/src/distributions/slice.rs @@ -0,0 +1,117 @@ +// Copyright 2021 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use crate::distributions::{Distribution, Uniform}; + +/// A distribution to sample items uniformly from a slice. +/// +/// [`Slice::new`] constructs a distribution referencing a slice and uniformly +/// samples references from the items in the slice. It may do extra work up +/// front to make sampling of multiple values faster; if only one sample from +/// the slice is required, [`SliceRandom::choose`] can be more efficient. +/// +/// Steps are taken to avoid bias which might be present in naive +/// implementations; for example `slice[rng.gen() % slice.len()]` samples from +/// the slice, but may be more likely to select numbers in the low range than +/// other values. +/// +/// This distribution samples with replacement; each sample is independent. +/// Sampling without replacement requires state to be retained, and therefore +/// cannot be handled by a distribution; you should instead consider methods +/// on [`SliceRandom`], such as [`SliceRandom::choose_multiple`]. +/// +/// # Example +/// +/// ``` +/// use rand::Rng; +/// use rand::distributions::Slice; +/// +/// let vowels = ['a', 'e', 'i', 'o', 'u']; +/// let vowels_dist = Slice::new(&vowels).unwrap(); +/// let rng = rand::thread_rng(); +/// +/// // build a string of 10 vowels +/// let vowel_string: String = rng +/// .sample_iter(&vowels_dist) +/// .take(10) +/// .collect(); +/// +/// println!("{}", vowel_string); +/// assert_eq!(vowel_string.len(), 10); +/// assert!(vowel_string.chars().all(|c| vowels.contains(&c))); +/// ``` +/// +/// For a single sample, [`SliceRandom::choose`][crate::seq::SliceRandom::choose] +/// may be preferred: +/// +/// ``` +/// use rand::seq::SliceRandom; +/// +/// let vowels = ['a', 'e', 'i', 'o', 'u']; +/// let mut rng = rand::thread_rng(); +/// +/// println!("{}", vowels.choose(&mut rng).unwrap()) +/// ``` +/// +/// [`SliceRandom`]: crate::seq::SliceRandom +/// [`SliceRandom::choose`]: crate::seq::SliceRandom::choose +/// [`SliceRandom::choose_multiple`]: crate::seq::SliceRandom::choose_multiple +#[derive(Debug, Clone, Copy)] +pub struct Slice<'a, T> { + slice: &'a [T], + range: Uniform<usize>, +} + +impl<'a, T> Slice<'a, T> { + /// Create a new `Slice` instance which samples uniformly from the slice. + /// Returns `Err` if the slice is empty. + pub fn new(slice: &'a [T]) -> Result<Self, EmptySlice> { + match slice.len() { + 0 => Err(EmptySlice), + len => Ok(Self { + slice, + range: Uniform::new(0, len), + }), + } + } +} + +impl<'a, T> Distribution<&'a T> for Slice<'a, T> { + fn sample<R: crate::Rng + ?Sized>(&self, rng: &mut R) -> &'a T { + let idx = self.range.sample(rng); + + debug_assert!( + idx < self.slice.len(), + "Uniform::new(0, {}) somehow returned {}", + self.slice.len(), + idx + ); + + // Safety: at construction time, it was ensured that the slice was + // non-empty, and that the `Uniform` range produces values in range + // for the slice + unsafe { self.slice.get_unchecked(idx) } + } +} + +/// Error type indicating that a [`Slice`] distribution was improperly +/// constructed with an empty slice. +#[derive(Debug, Clone, Copy)] +pub struct EmptySlice; + +impl core::fmt::Display for EmptySlice { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!( + f, + "Tried to create a `distributions::Slice` with an empty slice" + ) + } +} + +#[cfg(feature = "std")] +impl std::error::Error for EmptySlice {} diff --git a/src/distributions/uniform.rs b/src/distributions/uniform.rs index e4a6407..261357b 100644 --- a/src/distributions/uniform.rs +++ b/src/distributions/uniform.rs @@ -80,7 +80,10 @@ //! where B1: SampleBorrow<Self::X> + Sized, //! B2: SampleBorrow<Self::X> + Sized //! { -//! UniformSampler::new(low, high) +//! UniformMyF32(UniformFloat::<f32>::new_inclusive( +//! low.borrow().0, +//! high.borrow().0, +//! )) //! } //! fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X { //! MyF32(self.0.sample(rng)) @@ -103,8 +106,7 @@ //! [`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; @@ -158,7 +160,7 @@ use serde::{Serialize, Deserialize}; /// println!("{}", sum); /// ``` /// -/// For a single sample, [`Rng::gen_range`] may be prefered: +/// For a single sample, [`Rng::gen_range`] may be preferred: /// /// ``` /// use rand::Rng; @@ -170,8 +172,10 @@ use serde::{Serialize, Deserialize}; /// [`new`]: Uniform::new /// [`new_inclusive`]: Uniform::new_inclusive /// [`Rng::gen_range`]: Rng::gen_range -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, PartialEq)] #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serde1", serde(bound(serialize = "X::Sampler: Serialize")))] +#[cfg_attr(feature = "serde1", serde(bound(deserialize = "X::Sampler: Deserialize<'de>")))] pub struct Uniform<X: SampleUniform>(X::Sampler); impl<X: SampleUniform> Uniform<X> { @@ -414,7 +418,7 @@ impl<T: SampleUniform + PartialOrd> SampleRange<T> for RangeInclusive<T> { /// An alternative to using a modulus is widening multiply: After a widening /// multiply by `range`, the result is in the high word. Then comparing the low /// word against `zone` makes sure our distribution is uniform. -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, PartialEq)] #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] pub struct UniformInt<X> { low: X, @@ -556,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 } @@ -564,7 +567,6 @@ 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(feature = "simd_support")] @@ -804,7 +806,7 @@ impl UniformSampler for UniformChar { /// [`new`]: UniformSampler::new /// [`new_inclusive`]: UniformSampler::new_inclusive /// [`Standard`]: crate::distributions::Standard -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, PartialEq)] #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] pub struct UniformFloat<X> { low: X, @@ -827,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); @@ -858,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); @@ -909,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) @@ -1134,7 +1155,7 @@ mod tests { #[test] #[cfg(feature = "serde1")] fn test_serialization_uniform_duration() { - let distr = UniformDuration::new(std::time::Duration::from_secs(10), std::time::Duration::from_secs(60)); + 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 @@ -1205,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}; @@ -1273,9 +1294,7 @@ 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(feature = "simd_support")] { @@ -1297,7 +1316,7 @@ mod tests { let mut max = core::char::from_u32(0).unwrap(); for _ in 0..100 { let c = rng.gen_range('A'..='Z'); - assert!('A' <= c && c <= 'Z'); + assert!(('A'..='Z').contains(&c)); max = max.max(c); } assert_eq!(max, 'Z'); @@ -1328,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() { @@ -1413,6 +1428,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", not(target_arch = "wasm32"), @@ -1477,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 = &[ @@ -1622,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/src/distributions/utils.rs b/src/distributions/utils.rs index e3bceb8..89da5fd 100644 --- a/src/distributions/utils.rs +++ b/src/distributions/utils.rs @@ -56,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 @@ -120,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 { @@ -138,6 +134,8 @@ 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")] @@ -235,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; diff --git a/src/distributions/weighted.rs b/src/distributions/weighted.rs index 6dd9273..846b9df 100644 --- a/src/distributions/weighted.rs +++ b/src/distributions/weighted.rs @@ -43,6 +43,5 @@ pub mod alias_method { impl_weight!(f64, f32,); impl_weight!(u8, u16, u32, u64, usize,); impl_weight!(i8, i16, i32, i64, isize,); - #[cfg(not(target_os = "emscripten"))] impl_weight!(u128, i128,); } diff --git a/src/distributions/weighted_index.rs b/src/distributions/weighted_index.rs index 07ba53e..8252b17 100644 --- a/src/distributions/weighted_index.rs +++ b/src/distributions/weighted_index.rs @@ -75,7 +75,7 @@ use serde::{Serialize, Deserialize}; /// /// [`Uniform<X>`]: crate::distributions::Uniform /// [`RngCore`]: crate::RngCore -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] pub struct WeightedIndex<X: SampleUniform + PartialOrd> { @@ -418,6 +418,11 @@ 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`. @@ -439,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", + }) } } @@ -50,7 +50,6 @@ #![doc(test(attr(allow(unused_variables), deny(warnings))))] #![no_std] #![cfg_attr(feature = "simd_support", feature(stdsimd))] -#![cfg_attr(feature = "nightly", feature(slice_partition_at_index))] #![cfg_attr(doc_cfg, feature(doc_cfg))] #![allow( clippy::float_cmp, @@ -201,10 +200,10 @@ mod test { #[test] #[cfg(all(feature = "std", feature = "std_rng"))] fn test_random() { - // not sure how to test this aside from just getting some values let _n: usize = random(); let _f: f32 = random(); let _o: Option<Option<i8>> = random(); + #[allow(clippy::type_complexity)] let _many: ( (), (usize, isize, Option<(u32, (bool,))>), @@ -28,7 +28,7 @@ use core::{mem, slice}; /// - 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 +/// type-erased references; i.e. `foo(r)` where `r: &mut dyn RngCore`. Without /// this it would be necessary to write `foo(&mut r)`. /// /// An alternative pattern is possible: `fn foo<R: Rng>(rng: R)`. This has some @@ -71,6 +71,8 @@ pub trait Rng: RngCore { /// 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`]. @@ -387,13 +389,20 @@ macro_rules! impl_fill { } } -impl_fill!(u16, u32, u64, usize,); -#[cfg(not(target_os = "emscripten"))] -impl_fill!(u128); -impl_fill!(i8, i16, i32, i64, isize,); -#[cfg(not(target_os = "emscripten"))] -impl_fill!(i128); +impl_fill!(u16, u32, u64, usize, u128,); +impl_fill!(i8, i16, i32, i64, isize, i128,); +#[cfg_attr(doc_cfg, doc(cfg(feature = "min_const_gen")))] +#[cfg(feature = "min_const_gen")] +impl<T, const N: usize> Fill for [T; N] +where [T]: Fill +{ + fn try_fill<R: Rng + ?Sized>(&mut self, rng: &mut R) -> Result<(), Error> { + self[..].try_fill(rng) + } +} + +#[cfg(not(feature = "min_const_gen"))] macro_rules! impl_fill_arrays { ($n:expr,) => {}; ($n:expr, $N:ident) => { @@ -413,8 +422,10 @@ macro_rules! impl_fill_arrays { 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)] @@ -487,15 +498,15 @@ mod test { 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); + 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!(a >= 10u16 && a < 99u16); - let a = r.gen_range(-100i32..2000); - assert!(a >= -100i32 && a < 2000i32); + 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!(a >= 12u32 && a <= 24u32); + assert!((12..=24).contains(&a)); assert_eq!(r.gen_range(0u32..1), 0u32); assert_eq!(r.gen_range(-12i64..-11), -12i64); @@ -508,9 +519,9 @@ mod test { let mut r = rng(101); for _ in 0..1000 { let a = r.gen_range(-4.5..1.7); - assert!(a >= -4.5 && a < 1.7); + assert!((-4.5..1.7).contains(&a)); let a = r.gen_range(-1.1..=-0.3); - assert!(a >= -1.1 && a <= -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.); @@ -521,6 +532,7 @@ mod test { #[test] #[should_panic] fn test_gen_range_panic_int() { + #![allow(clippy::reversed_empty_ranges)] let mut r = rng(102); r.gen_range(5..-2); } @@ -528,12 +540,15 @@ mod test { #[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); diff --git a/src/rngs/adapter/mod.rs b/src/rngs/adapter/mod.rs index 22b7158..bd1d294 100644 --- a/src/rngs/adapter/mod.rs +++ b/src/rngs/adapter/mod.rs @@ -11,5 +11,6 @@ mod read; mod reseeding; +#[allow(deprecated)] pub use self::read::{ReadError, ReadRng}; pub use self::reseeding::ReseedingRng; diff --git a/src/rngs/adapter/read.rs b/src/rngs/adapter/read.rs index 63b0dd0..25a9ca7 100644 --- a/src/rngs/adapter/read.rs +++ b/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::<u32>()); -/// ``` -/// /// [`OsRng`]: crate::rngs::OsRng /// [`try_fill_bytes`]: RngCore::try_fill_bytes #[derive(Debug)] +#[deprecated(since="0.8.4", note="removal due to lack of usage")] pub struct ReadRng<R> { reader: R, } @@ -86,6 +78,7 @@ impl<R: Read> RngCore for ReadRng<R> { /// `ReadRng` error type #[derive(Debug)] +#[deprecated(since="0.8.4")] pub struct ReadError(std::io::Error); impl fmt::Display for ReadError { diff --git a/src/rngs/adapter/reseeding.rs b/src/rngs/adapter/reseeding.rs index 1977cb3..ae3fcbb 100644 --- a/src/rngs/adapter/reseeding.rs +++ b/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 @@ -310,8 +316,16 @@ 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); + } }); } } @@ -355,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/src/rngs/std.rs b/src/rngs/std.rs index 80f8433..cdae8fa 100644 --- a/src/rngs/std.rs +++ b/src/rngs/std.rs @@ -10,13 +10,9 @@ use crate::{CryptoRng, Error, RngCore, SeedableRng}; -#[cfg(all(any(test, feature = "std"), not(target_os = "emscripten")))] pub(crate) use rand_chacha::ChaCha12Core as Core; -#[cfg(all(any(test, feature = "std"), target_os = "emscripten"))] -pub(crate) use rand_hc::Hc128Core as Core; -#[cfg(not(target_os = "emscripten"))] use rand_chacha::ChaCha12Rng 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 diff --git a/src/rngs/thread.rs b/src/rngs/thread.rs index 552851f..baebb1d 100644 --- a/src/rngs/thread.rs +++ b/src/rngs/thread.rs @@ -33,15 +33,16 @@ 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; /// A reference to the thread-local generator /// /// An instance can be obtained via [`thread_rng`] or via `ThreadRng::default()`. -/// This handle is safe to use everywhere (including thread-local destructors) -/// but cannot be passed between threads (is not `Send` or `Sync`). +/// 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`]. @@ -59,7 +60,7 @@ const THREAD_RNG_RESEED_THRESHOLD: u64 = 1024 * 64; #[cfg_attr(doc_cfg, doc(cfg(all(feature = "std", feature = "std_rng"))))] #[derive(Clone, Debug)] pub struct ThreadRng { - // Rc is explictly !Send and !Sync + // Rc is explicitly !Send and !Sync rng: Rc<UnsafeCell<ReseedingRng<Core, OsRng>>>, } diff --git a/src/rngs/xoshiro256plusplus.rs b/src/rngs/xoshiro256plusplus.rs index cd373c3..8ffb18b 100644 --- a/src/rngs/xoshiro256plusplus.rs +++ b/src/rngs/xoshiro256plusplus.rs @@ -11,9 +11,9 @@ 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. +/// A xoshiro256++ random number generator. /// -/// The xoshiro256** algorithm is not suitable for cryptographic purposes, but +/// 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` diff --git a/src/seq/index.rs b/src/seq/index.rs index 8b155e1..b38e464 100644 --- a/src/seq/index.rs +++ b/src/seq/index.rs @@ -16,11 +16,11 @@ use alloc::collections::BTreeSet; #[cfg(feature = "std")] use std::collections::HashSet; -#[cfg(feature = "alloc")] -use crate::distributions::{uniform::SampleUniform, Distribution, Uniform}; #[cfg(feature = "std")] use crate::distributions::WeightedError; -use crate::Rng; + +#[cfg(feature = "alloc")] +use crate::{Rng, distributions::{uniform::SampleUniform, Distribution, Uniform}}; #[cfg(feature = "serde1")] use serde::{Serialize, Deserialize}; @@ -380,7 +380,7 @@ where #[cfg(not(feature = "nightly"))] { - use std::collections::BinaryHeap; + use alloc::collections::BinaryHeap; // Partially sort the array such that the `amount` elements with the largest // keys are first using a binary max heap. @@ -630,7 +630,7 @@ mod test { match v { IndexVec::U32(mut indices) => { assert_eq!(indices.len(), amount); - indices.sort(); + indices.sort_unstable(); indices.dedup(); assert_eq!(indices.len(), amount); for &i in &indices { @@ -668,10 +668,10 @@ mod test { 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(1000_000, 8, &[ + do_test(1_000_000, 8, &[ 103717, 963485, 826422, 509101, 736394, 807035, 5327, 632573, ]); // floyd - do_test(1000_000, 180, &[ + do_test(1_000_000, 180, &[ 103718, 963490, 826426, 509103, 736396, 807036, 5327, 632573, ]); // rejection } diff --git a/src/seq/mod.rs b/src/seq/mod.rs index 4375fa1..069e9e6 100644 --- a/src/seq/mod.rs +++ b/src/seq/mod.rs @@ -991,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; } @@ -1252,11 +1252,10 @@ mod test { // Case 2: All of the weights are 0 let choices = [('a', 0), ('b', 0), ('c', 0)]; - let result = choices + + assert_eq!(choices .choose_multiple_weighted(&mut rng, 2, |item| item.1) - .unwrap() - .collect::<Vec<_>>(); - assert_eq!(result.len(), 2); + .unwrap().count(), 2); // Case 3: Negative weights let choices = [('a', -1), ('b', 1), ('c', 1)]; @@ -1269,11 +1268,9 @@ mod test { // Case 4: Empty list let choices = []; - let result = choices + assert_eq!(choices .choose_multiple_weighted(&mut rng, 0, |_: &()| 0) - .unwrap() - .collect::<Vec<_>>(); - assert_eq!(result.len(), 0); + .unwrap().count(), 0); // Case 5: NaN weights let choices = [('a', core::f64::NAN), ('b', 1.0), ('c', 1.0)]; |