aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoel Galenson <jgalenson@google.com>2021-06-21 13:51:31 -0700
committerJoel Galenson <jgalenson@google.com>2021-06-21 13:51:31 -0700
commite03dd303df24abd093696211bb78e6dd0868d27c (patch)
tree34072b805e4d90c05ed0065f67fee4234d50b3ff
parente4c6db4ae93ad5e7fc4378ddeb3b5e83379746cf (diff)
downloadrand-e03dd303df24abd093696211bb78e6dd0868d27c.tar.gz
Upgrade rust/crates/rand to 0.8.4
Test: make Change-Id: Ia6bad5e9cf67375ae1d6a84413ff9b6195829482
-rw-r--r--.cargo_vcs_info.json2
-rw-r--r--Android.bp6
-rw-r--r--CHANGELOG.md14
-rw-r--r--Cargo.lock61
-rw-r--r--Cargo.toml7
-rw-r--r--Cargo.toml.orig10
-rw-r--r--METADATA8
-rw-r--r--README.md8
-rw-r--r--TEST_MAPPING99
-rw-r--r--src/distributions/bernoulli.rs5
-rw-r--r--src/distributions/distribution.rs272
-rw-r--r--src/distributions/mod.rs224
-rw-r--r--src/distributions/other.rs60
-rw-r--r--src/distributions/slice.rs117
-rw-r--r--src/distributions/uniform.rs58
-rw-r--r--src/distributions/utils.rs2
-rw-r--r--src/distributions/weighted_index.rs14
-rw-r--r--src/lib.rs2
-rw-r--r--src/rng.rs38
-rw-r--r--src/rngs/adapter/mod.rs1
-rw-r--r--src/rngs/adapter/read.rs15
-rw-r--r--src/rngs/adapter/reseeding.rs2
-rw-r--r--src/rngs/xoshiro256plusplus.rs4
-rw-r--r--src/seq/index.rs6
-rw-r--r--src/seq/mod.rs4
25 files changed, 748 insertions, 291 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"
}
}
diff --git a/Android.bp b/Android.bp
index 75212d3..8118506 100644
--- a/Android.bp
+++ b/Android.bp
@@ -64,7 +64,7 @@ rust_library {
// dependent_library ["feature_list"]
// cfg-if-1.0.0
// getrandom-0.2.3 "std"
-// libc-0.2.95
+// libc-0.2.97
// ppv-lite86-0.2.10 "simd,std"
-// rand_chacha-0.3.0 "std"
-// rand_core-0.6.2 "alloc,getrandom,std"
+// rand_chacha-0.3.1 "std"
+// rand_core-0.6.3 "alloc,getrandom,std"
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)
diff --git a/Cargo.lock b/Cargo.lock
index 01304e6..d9cea07 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -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"
diff --git a/Cargo.toml b/Cargo.toml
index 1086335..b109e37 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -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"]
diff --git a/METADATA b/METADATA
index 7ad83fc..5d320d8 100644
--- a/METADATA
+++ b/METADATA
@@ -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
}
}
diff --git a/README.md b/README.md
index aaf6df1..355e53b 100644
--- a/README.md
+++ b/README.md
@@ -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..2441f5b 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -32,15 +32,33 @@
"name": "keystore2_test"
},
{
+ "name": "tokio_device_test_tests__require_full"
+ },
+ {
"name": "tokio_device_test_tests_buffered"
},
{
+ "name": "tokio_device_test_tests_io_async_fd"
+ },
+ {
"name": "tokio_device_test_tests_io_async_read"
},
{
+ "name": "tokio_device_test_tests_io_chain"
+ },
+ {
+ "name": "tokio_device_test_tests_io_copy"
+ },
+ {
"name": "tokio_device_test_tests_io_copy_bidirectional"
},
{
+ "name": "tokio_device_test_tests_io_driver"
+ },
+ {
+ "name": "tokio_device_test_tests_io_driver_drop"
+ },
+ {
"name": "tokio_device_test_tests_io_lines"
},
{
@@ -53,9 +71,24 @@
"name": "tokio_device_test_tests_io_read_buf"
},
{
+ "name": "tokio_device_test_tests_io_read_exact"
+ },
+ {
+ "name": "tokio_device_test_tests_io_read_line"
+ },
+ {
"name": "tokio_device_test_tests_io_read_to_end"
},
{
+ "name": "tokio_device_test_tests_io_read_to_string"
+ },
+ {
+ "name": "tokio_device_test_tests_io_read_until"
+ },
+ {
+ "name": "tokio_device_test_tests_io_split"
+ },
+ {
"name": "tokio_device_test_tests_io_take"
},
{
@@ -74,12 +107,36 @@
"name": "tokio_device_test_tests_macros_join"
},
{
+ "name": "tokio_device_test_tests_macros_pin"
+ },
+ {
+ "name": "tokio_device_test_tests_macros_select"
+ },
+ {
+ "name": "tokio_device_test_tests_macros_test"
+ },
+ {
+ "name": "tokio_device_test_tests_macros_try_join"
+ },
+ {
+ "name": "tokio_device_test_tests_net_bind_resource"
+ },
+ {
+ "name": "tokio_device_test_tests_net_lookup_host"
+ },
+ {
"name": "tokio_device_test_tests_no_rt"
},
{
+ "name": "tokio_device_test_tests_process_kill_on_drop"
+ },
+ {
"name": "tokio_device_test_tests_rt_basic"
},
{
+ "name": "tokio_device_test_tests_rt_common"
+ },
+ {
"name": "tokio_device_test_tests_rt_threaded"
},
{
@@ -95,15 +152,36 @@
"name": "tokio_device_test_tests_sync_mpsc"
},
{
+ "name": "tokio_device_test_tests_sync_mutex"
+ },
+ {
"name": "tokio_device_test_tests_sync_mutex_owned"
},
{
+ "name": "tokio_device_test_tests_sync_notify"
+ },
+ {
+ "name": "tokio_device_test_tests_sync_oneshot"
+ },
+ {
"name": "tokio_device_test_tests_sync_rwlock"
},
{
+ "name": "tokio_device_test_tests_sync_semaphore"
+ },
+ {
+ "name": "tokio_device_test_tests_sync_semaphore_owned"
+ },
+ {
"name": "tokio_device_test_tests_sync_watch"
},
{
+ "name": "tokio_device_test_tests_task_abort"
+ },
+ {
+ "name": "tokio_device_test_tests_task_blocking"
+ },
+ {
"name": "tokio_device_test_tests_task_local"
},
{
@@ -113,18 +191,39 @@
"name": "tokio_device_test_tests_tcp_accept"
},
{
+ "name": "tokio_device_test_tests_tcp_connect"
+ },
+ {
"name": "tokio_device_test_tests_tcp_echo"
},
{
+ "name": "tokio_device_test_tests_tcp_into_split"
+ },
+ {
"name": "tokio_device_test_tests_tcp_into_std"
},
{
+ "name": "tokio_device_test_tests_tcp_peek"
+ },
+ {
"name": "tokio_device_test_tests_tcp_shutdown"
},
{
+ "name": "tokio_device_test_tests_tcp_socket"
+ },
+ {
+ "name": "tokio_device_test_tests_tcp_split"
+ },
+ {
"name": "tokio_device_test_tests_time_rt"
},
{
+ "name": "tokio_device_test_tests_udp"
+ },
+ {
+ "name": "tokio_device_test_tests_uds_cred"
+ },
+ {
"name": "tokio_device_test_tests_uds_split"
},
{
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",
+ })
}
}
diff --git a/src/lib.rs b/src/lib.rs
index 8bf7a9d..6f8665a 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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,))>),
diff --git a/src/rng.rs b/src/rng.rs
index bb977a5..07643c5 100644
--- a/src/rng.rs
+++ b/src/rng.rs
@@ -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;
}