diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-02-17 03:34:09 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-02-17 03:34:09 +0000 |
commit | 4dabd850288094946be4feb9890e2f00382f9500 (patch) | |
tree | 858bd5e42515f6d5833d6e17d6245863c49477ee | |
parent | d9485ccfbc37a8736dfc085f2f6ceafa3e31696a (diff) | |
parent | 271eede053420cdcea5f348bb0eed9f41a0c006f (diff) | |
download | rand-4dabd850288094946be4feb9890e2f00382f9500.tar.gz |
Snap for 8191477 from 271eede053420cdcea5f348bb0eed9f41a0c006f to tm-frc-resolv-release
Change-Id: Ib11cb0847776a5e5d64713ffdba810efbe484368
-rw-r--r-- | .cargo_vcs_info.json | 2 | ||||
-rw-r--r-- | Android.bp | 20 | ||||
-rw-r--r-- | CHANGELOG.md | 14 | ||||
-rw-r--r-- | Cargo.lock | 61 | ||||
-rw-r--r-- | Cargo.toml | 7 | ||||
-rw-r--r-- | Cargo.toml.orig | 10 | ||||
-rw-r--r-- | METADATA | 8 | ||||
-rw-r--r-- | README.md | 8 | ||||
-rw-r--r-- | TEST_MAPPING | 111 | ||||
-rw-r--r-- | cargo2android.json | 10 | ||||
-rw-r--r-- | patches/Android.bp.patch | 12 | ||||
-rw-r--r-- | src/distributions/bernoulli.rs | 5 | ||||
-rw-r--r-- | src/distributions/distribution.rs | 272 | ||||
-rw-r--r-- | src/distributions/mod.rs | 224 | ||||
-rw-r--r-- | src/distributions/other.rs | 60 | ||||
-rw-r--r-- | src/distributions/slice.rs | 117 | ||||
-rw-r--r-- | src/distributions/uniform.rs | 58 | ||||
-rw-r--r-- | src/distributions/utils.rs | 2 | ||||
-rw-r--r-- | src/distributions/weighted_index.rs | 14 | ||||
-rw-r--r-- | src/lib.rs | 2 | ||||
-rw-r--r-- | src/rng.rs | 38 | ||||
-rw-r--r-- | src/rngs/adapter/mod.rs | 1 | ||||
-rw-r--r-- | src/rngs/adapter/read.rs | 15 | ||||
-rw-r--r-- | src/rngs/adapter/reseeding.rs | 2 | ||||
-rw-r--r-- | src/rngs/xoshiro256plusplus.rs | 4 | ||||
-rw-r--r-- | src/seq/index.rs | 6 | ||||
-rw-r--r-- | src/seq/mod.rs | 4 |
27 files changed, 699 insertions, 388 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json index c17e718..7f98fc0 100644 --- a/.cargo_vcs_info.json +++ b/.cargo_vcs_info.json @@ -1,5 +1,5 @@ { "git": { - "sha1": "6ecbe2626b2cc6110a25c97b1702b347574febc7" + "sha1": "8792268dfe57e49bb4518190bf4fe66176759a44" } } @@ -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.4", srcs: ["src/lib.rs"], edition: "2018", features: [ @@ -53,6 +53,7 @@ rust_library { "libc", "rand_chacha", "rand_hc", + "small_rng", "std", "std_rng", ], @@ -61,13 +62,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..2c7387a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,20 @@ 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.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) @@ -2,9 +2,9 @@ # It is not intended for manual editing. [[package]] name = "bincode" -version = "1.3.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30d3a39baa26f9651f17b375061f3233dde33424a8b72b0dbe93a68a0bc896d" +checksum = "d175dfa69e619905c4c3cdb7c3c203fa3bdd5d51184e3afdb2742c0280493772" dependencies = [ "byteorder", "serde", @@ -12,9 +12,9 @@ dependencies = [ [[package]] name = "byteorder" -version = "1.4.2" +version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b" +checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" [[package]] name = "cfg-if" @@ -41,9 +41,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.82" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89203f3fba0a3795506acaad8ebce3c80c0af93f994d5a1d7a0b1eeb23271929" +checksum = "8916b1f6ca17130ec6568feccee27c156ad12037880833a3b842a823236502e7" [[package]] name = "libm" @@ -53,18 +53,18 @@ 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 1.0.0", ] [[package]] name = "packed_simd_2" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3278e0492f961fd4ae70909f56b2723a7e8d01a228427294e19cdfdebda89a17" +checksum = "0e64858a2d3733fdd61adfdd6da89aa202f7ff0e741d2fc7ed1e452ba9dc99d7" dependencies = [ "cfg-if 0.1.10", "libm", @@ -87,16 +87,16 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" dependencies = [ "proc-macro2", ] [[package]] name = "rand" -version = "0.8.3" +version = "0.8.4" dependencies = [ "bincode", "libc", @@ -111,9 +111,9 @@ dependencies = [ [[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 +121,46 @@ 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", + "serde", ] [[package]] name = "rand_hc" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" +checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" dependencies = [ "rand_core", ] [[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.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "166b2349061381baf54a58e4b13c89369feb0ef2eaa57198899e2312aac30aab" +checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.120" +version = "1.0.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ca2a8cb5805ce9e3b95435e3765b7b553cecc762d938d409434338386cb5775" +checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d" dependencies = [ "proc-macro2", "quote", @@ -168,9 +169,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.59" +version = "1.0.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07cb8b1b4ebf86a89ee88cbd201b022b94138c623644d035185c84d3f41b7e66" +checksum = "6498a9efc342871f91cc2d0d694c674368b4ceb40f62b65a7a08c3792935e702" dependencies = [ "proc-macro2", "quote", @@ -185,6 +186,6 @@ checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" [[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" @@ -13,7 +13,7 @@ [package] edition = "2018" name = "rand" -version = "0.8.3" +version = "0.8.4" authors = ["The Rand Project Developers", "The Rust Project Developers"] include = ["src/", "LICENSE-*", "README.md", "CHANGELOG.md", "COPYRIGHT"] autobenches = true @@ -36,7 +36,7 @@ version = "0.4.4" optional = true [dependencies.packed_simd] -version = "0.3.4" +version = "0.3.5" features = ["into_bits"] optional = true package = "packed_simd_2" @@ -61,8 +61,9 @@ 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"] diff --git a/Cargo.toml.orig b/Cargo.toml.orig index afd1339..5ce3123 100644 --- a/Cargo.toml.orig +++ b/Cargo.toml.orig @@ -1,6 +1,6 @@ [package] name = "rand" -version = "0.8.3" +version = "0.8.4" authors = ["The Rand Project Developers", "The Rust Project Developers"] license = "MIT OR Apache-2.0" readme = "README.md" @@ -20,7 +20,7 @@ include = ["src/", "LICENSE-*", "README.md", "CHANGELOG.md", "COPYRIGHT"] # 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. @@ -41,6 +41,10 @@ std_rng = ["rand_chacha", "rand_hc"] # 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", @@ -58,7 +62,7 @@ serde = { version = "1.0.103", features = ["derive"], 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.5" optional = true features = ["into_bits"] @@ -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.4.crate" } - version: "0.8.3" + version: "0.8.4" license_type: NOTICE last_upgrade_date { year: 2021 - month: 4 - day: 1 + month: 6 + day: 21 } } @@ -139,6 +139,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 dependancy 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..d54d599 100644 --- a/src/distributions/bernoulli.rs +++ b/src/distributions/bernoulli.rs @@ -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(); diff --git a/src/distributions/distribution.rs b/src/distributions/distribution.rs new file mode 100644 index 0000000..e7f7677 --- /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::{Alphanumeric, Distribution, Standard, 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!(val >= 15 && val <= 20); + } + + #[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::DistString; + 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/mod.rs b/src/distributions/mod.rs index 652f52a..e308668 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 @@ -279,6 +159,12 @@ where /// * 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. +/// 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..71fb267 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 std::mem::{self, MaybeUninit}; + // ----- Sampling distributions ----- @@ -54,7 +61,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 +89,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 +121,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 +186,23 @@ 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")] +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 +223,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 +276,7 @@ mod tests { .map(|()| rng.gen::<char>()) .take(1000) .collect(); - assert!(word.len() != 0); + assert!(!word.is_empty()); } #[test] @@ -240,11 +288,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..fb89837 100644 --- a/src/distributions/uniform.rs +++ b/src/distributions/uniform.rs @@ -827,16 +827,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 +863,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 +919,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) @@ -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() { + 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"), diff --git a/src/distributions/utils.rs b/src/distributions/utils.rs index e3bceb8..b11f602 100644 --- a/src/distributions/utils.rs +++ b/src/distributions/utils.rs @@ -235,6 +235,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_index.rs b/src/distributions/weighted_index.rs index 07ba53e..32da37f 100644 --- a/src/distributions/weighted_index.rs +++ b/src/distributions/weighted_index.rs @@ -439,15 +439,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", + }) } } @@ -201,10 +201,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`]. @@ -394,6 +396,16 @@ impl_fill!(i8, i16, i32, i64, isize,); #[cfg(not(target_os = "emscripten"))] impl_fill!(i128); +#[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 +425,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 +501,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 +522,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 +535,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 +543,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..70b0b82 100644 --- a/src/rngs/adapter/reseeding.rs +++ b/src/rngs/adapter/reseeding.rs @@ -355,6 +355,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/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..ae36c32 100644 --- a/src/seq/index.rs +++ b/src/seq/index.rs @@ -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..9eeb777 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; } |