Auto merge of #104658 - thomcc:rand-update-and-usable-no_std, r=Mark-Simulacrum
Update `rand` in the stdlib tests, and remove the `getrandom` feature from it. The main goal is actually removing `getrandom`, so that eventually we can allow running the stdlib test suite on tier3 targets which don't have `getrandom` support. Currently those targets can only run the subset of stdlib tests that exist in uitests, and (generally speaking), we prefer not to test libstd functionality in uitests, which came up recently in https://github.com/rust-lang/rust/pull/104095 and https://github.com/rust-lang/rust/pull/104185. Additionally, the fact that we can't update `rand`/`getrandom` means we're stuck with the old set of tier3 targets, so can't test new ones. ~~Anyway, I haven't checked that this actually does allow use on tier3 targets (I think it does not, as some work is needed in stdlib submodules) but it moves us slightly closer to this, and seems to allow at least finally updating our `rand` dep, which definitely improves the status quo.~~ Checked and works now. For the most part, our tests and benchmarks are fine using hard-coded seeds. A couple tests seem to fail with this (stuff manipulating the environment expecting no collisions, for example), or become pointless (all inputs to a function become equivalent). In these cases I've done a (gross) dance (ab)using `RandomState` and `Location::caller()` for some extra "entropy". Trying to share that code seems *way* more painful than it's worth given that the duplication is a 7-line function, even if the lines are quite gross. (Keeping in mind that sharing it would require adding `rand` as a non-dev dep to std, and exposing a type from it publicly, all of which sounds truly awful, even if done behind a perma-unstable feature). See also some previous attempts: - https://github.com/rust-lang/rust/pull/86963 (in particular https://github.com/rust-lang/rust/pull/86963#issuecomment-885438936 which explains why this is non-trivial) - https://github.com/rust-lang/rust/pull/89131 - https://github.com/rust-lang/rust/pull/96626#issuecomment-1114562857 (I tried in that PR at the same time, but settled for just removing the usage of `thread_rng()` from the benchmarks, since that was the main goal). - https://github.com/rust-lang/rust/pull/104185 - Probably more. It's very tempting of a thing to "just update". r? `@Mark-Simulacrum`
This commit is contained in:
commit
2afe58571e
125
Cargo.lock
125
Cargo.lock
@ -30,7 +30,7 @@ version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43bb833f0bf979d8475d38fbf09ed3b8a55e1885fe93ad3f93239fc6a4f17b98"
|
||||
dependencies = [
|
||||
"getrandom 0.2.8",
|
||||
"getrandom",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
]
|
||||
@ -50,7 +50,7 @@ version = "0.0.0"
|
||||
dependencies = [
|
||||
"compiler_builtins",
|
||||
"core",
|
||||
"rand 0.7.3",
|
||||
"rand",
|
||||
"rand_xorshift",
|
||||
]
|
||||
|
||||
@ -951,7 +951,7 @@ checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
|
||||
name = "core"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"rand 0.7.3",
|
||||
"rand",
|
||||
"rand_xorshift",
|
||||
]
|
||||
|
||||
@ -1055,7 +1055,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"rand_core 0.6.4",
|
||||
"rand_core",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
@ -1314,7 +1314,7 @@ version = "2.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a3d382e8464107391c8706b4c14b087808ecb909f6c15c34114bc42e53a9e4c"
|
||||
dependencies = [
|
||||
"getrandom 0.2.8",
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1351,7 +1351,7 @@ dependencies = [
|
||||
"hkdf",
|
||||
"pem-rfc7468",
|
||||
"pkcs8",
|
||||
"rand_core 0.6.4",
|
||||
"rand_core",
|
||||
"sec1",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
@ -1482,7 +1482,7 @@ version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160"
|
||||
dependencies = [
|
||||
"rand_core 0.6.4",
|
||||
"rand_core",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
@ -1749,17 +1749,6 @@ dependencies = [
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.1.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi 0.9.0+wasi-snapshot-preview1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.8"
|
||||
@ -1769,7 +1758,7 @@ dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
"libc",
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
"wasi",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
@ -1840,7 +1829,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7"
|
||||
dependencies = [
|
||||
"ff",
|
||||
"rand_core 0.6.4",
|
||||
"rand_core",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
@ -2115,7 +2104,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af1955a75fa080c677d3972822ec4bad316169ab1cfc6c257a942c2265dbe5fe"
|
||||
dependencies = [
|
||||
"bitmaps",
|
||||
"rand_core 0.6.4",
|
||||
"rand_core",
|
||||
"rand_xoshiro",
|
||||
"sized-chunks",
|
||||
"typenum",
|
||||
@ -2660,14 +2649,14 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"colored",
|
||||
"env_logger 0.9.0",
|
||||
"getrandom 0.2.8",
|
||||
"getrandom",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"libffi",
|
||||
"libloading",
|
||||
"log",
|
||||
"measureme",
|
||||
"rand 0.8.5",
|
||||
"rand",
|
||||
"regex",
|
||||
"rustc-workspace-hack",
|
||||
"rustc_version",
|
||||
@ -2970,10 +2959,10 @@ checksum = "ed20c4c21d893414f42e0cbfebe8a8036b5ae9b0264611fb6504e395eda6ceec"
|
||||
dependencies = [
|
||||
"ct-codecs",
|
||||
"ed25519-compact",
|
||||
"getrandom 0.2.8",
|
||||
"getrandom",
|
||||
"orion",
|
||||
"p384",
|
||||
"rand_core 0.6.4",
|
||||
"rand_core",
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@ -3093,7 +3082,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6"
|
||||
dependencies = [
|
||||
"phf_shared",
|
||||
"rand 0.8.5",
|
||||
"rand",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3298,19 +3287,6 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
|
||||
dependencies = [
|
||||
"getrandom 0.1.16",
|
||||
"libc",
|
||||
"rand_chacha 0.2.2",
|
||||
"rand_core 0.5.1",
|
||||
"rand_hc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.5"
|
||||
@ -3318,18 +3294,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha 0.3.0",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core 0.5.1",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3339,16 +3305,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
|
||||
dependencies = [
|
||||
"getrandom 0.1.16",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3357,25 +3314,16 @@ version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"getrandom 0.2.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_hc"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
|
||||
dependencies = [
|
||||
"rand_core 0.5.1",
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_xorshift"
|
||||
version = "0.2.0"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77d416b86801d23dde1aa643023b775c3a462efc0ed96443add11546cdf1dca8"
|
||||
checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f"
|
||||
dependencies = [
|
||||
"rand_core 0.5.1",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3384,7 +3332,7 @@ version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa"
|
||||
dependencies = [
|
||||
"rand_core 0.6.4",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3426,7 +3374,7 @@ version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64"
|
||||
dependencies = [
|
||||
"getrandom 0.2.8",
|
||||
"getrandom",
|
||||
"redox_syscall",
|
||||
]
|
||||
|
||||
@ -3640,10 +3588,10 @@ version = "1.0.0"
|
||||
dependencies = [
|
||||
"bstr 0.2.17",
|
||||
"clap 3.2.20",
|
||||
"getrandom 0.2.8",
|
||||
"getrandom",
|
||||
"libc",
|
||||
"libz-sys",
|
||||
"rand 0.8.5",
|
||||
"rand",
|
||||
"regex",
|
||||
"serde_json",
|
||||
"syn",
|
||||
@ -3656,7 +3604,7 @@ name = "rustc_abi"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"rand 0.8.5",
|
||||
"rand",
|
||||
"rand_xoshiro",
|
||||
"rustc_data_structures",
|
||||
"rustc_index",
|
||||
@ -4162,7 +4110,7 @@ dependencies = [
|
||||
name = "rustc_incremental"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"rand 0.8.5",
|
||||
"rand",
|
||||
"rustc_ast",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
@ -5185,7 +5133,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c"
|
||||
dependencies = [
|
||||
"digest",
|
||||
"rand_core 0.6.4",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -5345,11 +5293,12 @@ dependencies = [
|
||||
"panic_abort",
|
||||
"panic_unwind",
|
||||
"profiler_builtins",
|
||||
"rand 0.7.3",
|
||||
"rand",
|
||||
"rand_xorshift",
|
||||
"rustc-demangle",
|
||||
"std_detect",
|
||||
"unwind",
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -5821,7 +5770,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"rand 0.8.5",
|
||||
"rand",
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
@ -6104,7 +6053,7 @@ version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
|
||||
dependencies = [
|
||||
"getrandom 0.2.8",
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -6145,12 +6094,6 @@ dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.9.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
|
@ -13,8 +13,8 @@ core = { path = "../core" }
|
||||
compiler_builtins = { version = "0.1.40", features = ['rustc-dep-of-std'] }
|
||||
|
||||
[dev-dependencies]
|
||||
rand = "0.7"
|
||||
rand_xorshift = "0.2"
|
||||
rand = { version = "0.8.5", default-features = false, features = ["alloc"] }
|
||||
rand_xorshift = "0.3.0"
|
||||
|
||||
[[test]]
|
||||
name = "collectionstests"
|
||||
|
@ -1,6 +1,6 @@
|
||||
use std::{mem, ptr};
|
||||
|
||||
use rand::distributions::{Alphanumeric, Standard};
|
||||
use rand::distributions::{Alphanumeric, DistString, Standard};
|
||||
use rand::Rng;
|
||||
use test::{black_box, Bencher};
|
||||
|
||||
@ -218,7 +218,7 @@ fn gen_strings(len: usize) -> Vec<String> {
|
||||
let mut v = vec![];
|
||||
for _ in 0..len {
|
||||
let n = rng.gen::<usize>() % 20 + 1;
|
||||
v.push((&mut rng).sample_iter(&Alphanumeric).take(n).collect());
|
||||
v.push(Alphanumeric.sample_string(&mut rng, n));
|
||||
}
|
||||
v
|
||||
}
|
||||
|
@ -465,7 +465,7 @@ fn test_retain() {
|
||||
#[test]
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
fn panic_safe() {
|
||||
use rand::{seq::SliceRandom, thread_rng};
|
||||
use rand::seq::SliceRandom;
|
||||
use std::cmp;
|
||||
use std::panic::{self, AssertUnwindSafe};
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
@ -490,7 +490,7 @@ fn panic_safe() {
|
||||
self.0.partial_cmp(&other.0)
|
||||
}
|
||||
}
|
||||
let mut rng = thread_rng();
|
||||
let mut rng = crate::test_helpers::test_rng();
|
||||
const DATASZ: usize = 32;
|
||||
// Miri is too slow
|
||||
let ntest = if cfg!(miri) { 1 } else { 10 };
|
||||
|
@ -5,7 +5,7 @@ use crate::vec::Vec;
|
||||
use std::panic::{catch_unwind, AssertUnwindSafe};
|
||||
use std::thread;
|
||||
|
||||
use rand::{thread_rng, RngCore};
|
||||
use rand::RngCore;
|
||||
|
||||
#[test]
|
||||
fn test_basic() {
|
||||
@ -481,12 +481,12 @@ fn test_split_off_2() {
|
||||
}
|
||||
}
|
||||
|
||||
fn fuzz_test(sz: i32) {
|
||||
fn fuzz_test(sz: i32, rng: &mut impl RngCore) {
|
||||
let mut m: LinkedList<_> = LinkedList::new();
|
||||
let mut v = vec![];
|
||||
for i in 0..sz {
|
||||
check_links(&m);
|
||||
let r: u8 = thread_rng().next_u32() as u8;
|
||||
let r: u8 = rng.next_u32() as u8;
|
||||
match r % 6 {
|
||||
0 => {
|
||||
m.pop_back();
|
||||
@ -521,11 +521,12 @@ fn fuzz_test(sz: i32) {
|
||||
|
||||
#[test]
|
||||
fn test_fuzz() {
|
||||
let mut rng = crate::test_helpers::test_rng();
|
||||
for _ in 0..25 {
|
||||
fuzz_test(3);
|
||||
fuzz_test(16);
|
||||
fuzz_test(3, &mut rng);
|
||||
fuzz_test(16, &mut rng);
|
||||
#[cfg(not(miri))] // Miri is too slow
|
||||
fuzz_test(189);
|
||||
fuzz_test(189, &mut rng);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -192,6 +192,7 @@
|
||||
#![feature(unsized_fn_params)]
|
||||
#![feature(c_unwind)]
|
||||
#![feature(with_negative_coherence)]
|
||||
#![cfg_attr(test, feature(panic_update_hook))]
|
||||
//
|
||||
// Rustdoc features:
|
||||
#![feature(doc_cfg)]
|
||||
@ -255,3 +256,20 @@ pub mod vec;
|
||||
pub mod __export {
|
||||
pub use core::format_args;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(dead_code)] // Not used in all configurations
|
||||
pub(crate) mod test_helpers {
|
||||
/// Copied from `std::test_helpers::test_rng`, since these tests rely on the
|
||||
/// seed not being the same for every RNG invocation too.
|
||||
pub(crate) fn test_rng() -> rand_xorshift::XorShiftRng {
|
||||
use std::hash::{BuildHasher, Hash, Hasher};
|
||||
let mut hasher = std::collections::hash_map::RandomState::new().build_hasher();
|
||||
std::panic::Location::caller().hash(&mut hasher);
|
||||
let hc64 = hasher.finish();
|
||||
let seed_vec =
|
||||
hc64.to_le_bytes().into_iter().chain(0u8..8).collect::<crate::vec::Vec<u8>>();
|
||||
let seed: [u8; 16] = seed_vec.as_slice().try_into().unwrap();
|
||||
rand::SeedableRng::from_seed(seed)
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,9 @@ use crate::borrow::ToOwned;
|
||||
use crate::boxed::Box;
|
||||
use crate::vec::Vec;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
#[unstable(feature = "slice_range", issue = "76393")]
|
||||
pub use core::slice::range;
|
||||
#[unstable(feature = "array_chunks", issue = "74985")]
|
||||
|
359
library/alloc/src/slice/tests.rs
Normal file
359
library/alloc/src/slice/tests.rs
Normal file
@ -0,0 +1,359 @@
|
||||
use crate::borrow::ToOwned;
|
||||
use crate::rc::Rc;
|
||||
use crate::string::ToString;
|
||||
use crate::test_helpers::test_rng;
|
||||
use crate::vec::Vec;
|
||||
|
||||
use core::cell::Cell;
|
||||
use core::cmp::Ordering::{self, Equal, Greater, Less};
|
||||
use core::convert::identity;
|
||||
use core::fmt;
|
||||
use core::mem;
|
||||
use core::sync::atomic::{AtomicUsize, Ordering::Relaxed};
|
||||
use rand::{distributions::Standard, prelude::*, Rng, RngCore};
|
||||
use std::panic;
|
||||
|
||||
macro_rules! do_test {
|
||||
($input:ident, $func:ident) => {
|
||||
let len = $input.len();
|
||||
|
||||
// Work out the total number of comparisons required to sort
|
||||
// this array...
|
||||
let mut count = 0usize;
|
||||
$input.to_owned().$func(|a, b| {
|
||||
count += 1;
|
||||
a.cmp(b)
|
||||
});
|
||||
|
||||
// ... and then panic on each and every single one.
|
||||
for panic_countdown in 0..count {
|
||||
// Refresh the counters.
|
||||
VERSIONS.store(0, Relaxed);
|
||||
for i in 0..len {
|
||||
DROP_COUNTS[i].store(0, Relaxed);
|
||||
}
|
||||
|
||||
let v = $input.to_owned();
|
||||
let _ = std::panic::catch_unwind(move || {
|
||||
let mut v = v;
|
||||
let mut panic_countdown = panic_countdown;
|
||||
v.$func(|a, b| {
|
||||
if panic_countdown == 0 {
|
||||
SILENCE_PANIC.with(|s| s.set(true));
|
||||
panic!();
|
||||
}
|
||||
panic_countdown -= 1;
|
||||
a.cmp(b)
|
||||
})
|
||||
});
|
||||
|
||||
// Check that the number of things dropped is exactly
|
||||
// what we expect (i.e., the contents of `v`).
|
||||
for (i, c) in DROP_COUNTS.iter().enumerate().take(len) {
|
||||
let count = c.load(Relaxed);
|
||||
assert!(count == 1, "found drop count == {} for i == {}, len == {}", count, i, len);
|
||||
}
|
||||
|
||||
// Check that the most recent versions of values were dropped.
|
||||
assert_eq!(VERSIONS.load(Relaxed), 0);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const MAX_LEN: usize = 80;
|
||||
|
||||
static DROP_COUNTS: [AtomicUsize; MAX_LEN] = [
|
||||
// FIXME(RFC 1109): AtomicUsize is not Copy.
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
];
|
||||
|
||||
static VERSIONS: AtomicUsize = AtomicUsize::new(0);
|
||||
|
||||
#[derive(Clone, Eq)]
|
||||
struct DropCounter {
|
||||
x: u32,
|
||||
id: usize,
|
||||
version: Cell<usize>,
|
||||
}
|
||||
|
||||
impl PartialEq for DropCounter {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.partial_cmp(other) == Some(Ordering::Equal)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for DropCounter {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
self.version.set(self.version.get() + 1);
|
||||
other.version.set(other.version.get() + 1);
|
||||
VERSIONS.fetch_add(2, Relaxed);
|
||||
self.x.partial_cmp(&other.x)
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for DropCounter {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
self.partial_cmp(other).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for DropCounter {
|
||||
fn drop(&mut self) {
|
||||
DROP_COUNTS[self.id].fetch_add(1, Relaxed);
|
||||
VERSIONS.fetch_sub(self.version.get(), Relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
std::thread_local!(static SILENCE_PANIC: Cell<bool> = Cell::new(false));
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(target_os = "emscripten", ignore)] // no threads
|
||||
fn panic_safe() {
|
||||
panic::update_hook(move |prev, info| {
|
||||
if !SILENCE_PANIC.with(|s| s.get()) {
|
||||
prev(info);
|
||||
}
|
||||
});
|
||||
|
||||
let mut rng = test_rng();
|
||||
|
||||
// Miri is too slow (but still need to `chain` to make the types match)
|
||||
let lens = if cfg!(miri) { (1..10).chain(0..0) } else { (1..20).chain(70..MAX_LEN) };
|
||||
let moduli: &[u32] = if cfg!(miri) { &[5] } else { &[5, 20, 50] };
|
||||
|
||||
for len in lens {
|
||||
for &modulus in moduli {
|
||||
for &has_runs in &[false, true] {
|
||||
let mut input = (0..len)
|
||||
.map(|id| DropCounter {
|
||||
x: rng.next_u32() % modulus,
|
||||
id: id,
|
||||
version: Cell::new(0),
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if has_runs {
|
||||
for c in &mut input {
|
||||
c.x = c.id as u32;
|
||||
}
|
||||
|
||||
for _ in 0..5 {
|
||||
let a = rng.gen::<usize>() % len;
|
||||
let b = rng.gen::<usize>() % len;
|
||||
if a < b {
|
||||
input[a..b].reverse();
|
||||
} else {
|
||||
input.swap(a, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
do_test!(input, sort_by);
|
||||
do_test!(input, sort_unstable_by);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set default panic hook again.
|
||||
drop(panic::take_hook());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(miri, ignore)] // Miri is too slow
|
||||
fn test_sort() {
|
||||
let mut rng = test_rng();
|
||||
|
||||
for len in (2..25).chain(500..510) {
|
||||
for &modulus in &[5, 10, 100, 1000] {
|
||||
for _ in 0..10 {
|
||||
let orig: Vec<_> = (&mut rng)
|
||||
.sample_iter::<i32, _>(&Standard)
|
||||
.map(|x| x % modulus)
|
||||
.take(len)
|
||||
.collect();
|
||||
|
||||
// Sort in default order.
|
||||
let mut v = orig.clone();
|
||||
v.sort();
|
||||
assert!(v.windows(2).all(|w| w[0] <= w[1]));
|
||||
|
||||
// Sort in ascending order.
|
||||
let mut v = orig.clone();
|
||||
v.sort_by(|a, b| a.cmp(b));
|
||||
assert!(v.windows(2).all(|w| w[0] <= w[1]));
|
||||
|
||||
// Sort in descending order.
|
||||
let mut v = orig.clone();
|
||||
v.sort_by(|a, b| b.cmp(a));
|
||||
assert!(v.windows(2).all(|w| w[0] >= w[1]));
|
||||
|
||||
// Sort in lexicographic order.
|
||||
let mut v1 = orig.clone();
|
||||
let mut v2 = orig.clone();
|
||||
v1.sort_by_key(|x| x.to_string());
|
||||
v2.sort_by_cached_key(|x| x.to_string());
|
||||
assert!(v1.windows(2).all(|w| w[0].to_string() <= w[1].to_string()));
|
||||
assert!(v1 == v2);
|
||||
|
||||
// Sort with many pre-sorted runs.
|
||||
let mut v = orig.clone();
|
||||
v.sort();
|
||||
v.reverse();
|
||||
for _ in 0..5 {
|
||||
let a = rng.gen::<usize>() % len;
|
||||
let b = rng.gen::<usize>() % len;
|
||||
if a < b {
|
||||
v[a..b].reverse();
|
||||
} else {
|
||||
v.swap(a, b);
|
||||
}
|
||||
}
|
||||
v.sort();
|
||||
assert!(v.windows(2).all(|w| w[0] <= w[1]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sort using a completely random comparison function.
|
||||
// This will reorder the elements *somehow*, but won't panic.
|
||||
let mut v = [0; 500];
|
||||
for i in 0..v.len() {
|
||||
v[i] = i as i32;
|
||||
}
|
||||
v.sort_by(|_, _| *[Less, Equal, Greater].choose(&mut rng).unwrap());
|
||||
v.sort();
|
||||
for i in 0..v.len() {
|
||||
assert_eq!(v[i], i as i32);
|
||||
}
|
||||
|
||||
// Should not panic.
|
||||
[0i32; 0].sort();
|
||||
[(); 10].sort();
|
||||
[(); 100].sort();
|
||||
|
||||
let mut v = [0xDEADBEEFu64];
|
||||
v.sort();
|
||||
assert!(v == [0xDEADBEEF]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sort_stability() {
|
||||
// Miri is too slow
|
||||
let large_range = if cfg!(miri) { 0..0 } else { 500..510 };
|
||||
let rounds = if cfg!(miri) { 1 } else { 10 };
|
||||
|
||||
let mut rng = test_rng();
|
||||
for len in (2..25).chain(large_range) {
|
||||
for _ in 0..rounds {
|
||||
let mut counts = [0; 10];
|
||||
|
||||
// create a vector like [(6, 1), (5, 1), (6, 2), ...],
|
||||
// where the first item of each tuple is random, but
|
||||
// the second item represents which occurrence of that
|
||||
// number this element is, i.e., the second elements
|
||||
// will occur in sorted order.
|
||||
let orig: Vec<_> = (0..len)
|
||||
.map(|_| {
|
||||
let n = rng.gen::<usize>() % 10;
|
||||
counts[n] += 1;
|
||||
(n, counts[n])
|
||||
})
|
||||
.collect();
|
||||
|
||||
let mut v = orig.clone();
|
||||
// Only sort on the first element, so an unstable sort
|
||||
// may mix up the counts.
|
||||
v.sort_by(|&(a, _), &(b, _)| a.cmp(&b));
|
||||
|
||||
// This comparison includes the count (the second item
|
||||
// of the tuple), so elements with equal first items
|
||||
// will need to be ordered with increasing
|
||||
// counts... i.e., exactly asserting that this sort is
|
||||
// stable.
|
||||
assert!(v.windows(2).all(|w| w[0] <= w[1]));
|
||||
|
||||
let mut v = orig.clone();
|
||||
v.sort_by_cached_key(|&(x, _)| x);
|
||||
assert!(v.windows(2).all(|w| w[0] <= w[1]));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,15 +1,9 @@
|
||||
use std::cell::Cell;
|
||||
use std::cmp::Ordering::{self, Equal, Greater, Less};
|
||||
use std::cmp::Ordering::{Equal, Greater, Less};
|
||||
use std::convert::identity;
|
||||
use std::fmt;
|
||||
use std::mem;
|
||||
use std::panic;
|
||||
use std::rc::Rc;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering::Relaxed};
|
||||
|
||||
use rand::distributions::Standard;
|
||||
use rand::seq::SliceRandom;
|
||||
use rand::{thread_rng, Rng, RngCore};
|
||||
|
||||
fn square(n: usize) -> usize {
|
||||
n * n
|
||||
@ -388,123 +382,6 @@ fn test_reverse() {
|
||||
assert_eq!(v, (-50..51i16).rev().collect::<Vec<_>>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(miri, ignore)] // Miri is too slow
|
||||
fn test_sort() {
|
||||
let mut rng = thread_rng();
|
||||
|
||||
for len in (2..25).chain(500..510) {
|
||||
for &modulus in &[5, 10, 100, 1000] {
|
||||
for _ in 0..10 {
|
||||
let orig: Vec<_> =
|
||||
rng.sample_iter::<i32, _>(&Standard).map(|x| x % modulus).take(len).collect();
|
||||
|
||||
// Sort in default order.
|
||||
let mut v = orig.clone();
|
||||
v.sort();
|
||||
assert!(v.windows(2).all(|w| w[0] <= w[1]));
|
||||
|
||||
// Sort in ascending order.
|
||||
let mut v = orig.clone();
|
||||
v.sort_by(|a, b| a.cmp(b));
|
||||
assert!(v.windows(2).all(|w| w[0] <= w[1]));
|
||||
|
||||
// Sort in descending order.
|
||||
let mut v = orig.clone();
|
||||
v.sort_by(|a, b| b.cmp(a));
|
||||
assert!(v.windows(2).all(|w| w[0] >= w[1]));
|
||||
|
||||
// Sort in lexicographic order.
|
||||
let mut v1 = orig.clone();
|
||||
let mut v2 = orig.clone();
|
||||
v1.sort_by_key(|x| x.to_string());
|
||||
v2.sort_by_cached_key(|x| x.to_string());
|
||||
assert!(v1.windows(2).all(|w| w[0].to_string() <= w[1].to_string()));
|
||||
assert!(v1 == v2);
|
||||
|
||||
// Sort with many pre-sorted runs.
|
||||
let mut v = orig.clone();
|
||||
v.sort();
|
||||
v.reverse();
|
||||
for _ in 0..5 {
|
||||
let a = rng.gen::<usize>() % len;
|
||||
let b = rng.gen::<usize>() % len;
|
||||
if a < b {
|
||||
v[a..b].reverse();
|
||||
} else {
|
||||
v.swap(a, b);
|
||||
}
|
||||
}
|
||||
v.sort();
|
||||
assert!(v.windows(2).all(|w| w[0] <= w[1]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sort using a completely random comparison function.
|
||||
// This will reorder the elements *somehow*, but won't panic.
|
||||
let mut v = [0; 500];
|
||||
for i in 0..v.len() {
|
||||
v[i] = i as i32;
|
||||
}
|
||||
v.sort_by(|_, _| *[Less, Equal, Greater].choose(&mut rng).unwrap());
|
||||
v.sort();
|
||||
for i in 0..v.len() {
|
||||
assert_eq!(v[i], i as i32);
|
||||
}
|
||||
|
||||
// Should not panic.
|
||||
[0i32; 0].sort();
|
||||
[(); 10].sort();
|
||||
[(); 100].sort();
|
||||
|
||||
let mut v = [0xDEADBEEFu64];
|
||||
v.sort();
|
||||
assert!(v == [0xDEADBEEF]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sort_stability() {
|
||||
// Miri is too slow
|
||||
let large_range = if cfg!(miri) { 0..0 } else { 500..510 };
|
||||
let rounds = if cfg!(miri) { 1 } else { 10 };
|
||||
|
||||
for len in (2..25).chain(large_range) {
|
||||
for _ in 0..rounds {
|
||||
let mut counts = [0; 10];
|
||||
|
||||
// create a vector like [(6, 1), (5, 1), (6, 2), ...],
|
||||
// where the first item of each tuple is random, but
|
||||
// the second item represents which occurrence of that
|
||||
// number this element is, i.e., the second elements
|
||||
// will occur in sorted order.
|
||||
let orig: Vec<_> = (0..len)
|
||||
.map(|_| {
|
||||
let n = thread_rng().gen::<usize>() % 10;
|
||||
counts[n] += 1;
|
||||
(n, counts[n])
|
||||
})
|
||||
.collect();
|
||||
|
||||
let mut v = orig.clone();
|
||||
// Only sort on the first element, so an unstable sort
|
||||
// may mix up the counts.
|
||||
v.sort_by(|&(a, _), &(b, _)| a.cmp(&b));
|
||||
|
||||
// This comparison includes the count (the second item
|
||||
// of the tuple), so elements with equal first items
|
||||
// will need to be ordered with increasing
|
||||
// counts... i.e., exactly asserting that this sort is
|
||||
// stable.
|
||||
assert!(v.windows(2).all(|w| w[0] <= w[1]));
|
||||
|
||||
let mut v = orig.clone();
|
||||
v.sort_by_cached_key(|&(x, _)| x);
|
||||
assert!(v.windows(2).all(|w| w[0] <= w[1]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rotate_left() {
|
||||
let expected: Vec<_> = (0..13).collect();
|
||||
@ -1608,230 +1485,6 @@ fn test_copy_from_slice_dst_shorter() {
|
||||
dst.copy_from_slice(&src);
|
||||
}
|
||||
|
||||
const MAX_LEN: usize = 80;
|
||||
|
||||
static DROP_COUNTS: [AtomicUsize; MAX_LEN] = [
|
||||
// FIXME(RFC 1109): AtomicUsize is not Copy.
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
AtomicUsize::new(0),
|
||||
];
|
||||
|
||||
static VERSIONS: AtomicUsize = AtomicUsize::new(0);
|
||||
|
||||
#[derive(Clone, Eq)]
|
||||
struct DropCounter {
|
||||
x: u32,
|
||||
id: usize,
|
||||
version: Cell<usize>,
|
||||
}
|
||||
|
||||
impl PartialEq for DropCounter {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.partial_cmp(other) == Some(Ordering::Equal)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for DropCounter {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
self.version.set(self.version.get() + 1);
|
||||
other.version.set(other.version.get() + 1);
|
||||
VERSIONS.fetch_add(2, Relaxed);
|
||||
self.x.partial_cmp(&other.x)
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for DropCounter {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
self.partial_cmp(other).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for DropCounter {
|
||||
fn drop(&mut self) {
|
||||
DROP_COUNTS[self.id].fetch_add(1, Relaxed);
|
||||
VERSIONS.fetch_sub(self.version.get(), Relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! test {
|
||||
($input:ident, $func:ident) => {
|
||||
let len = $input.len();
|
||||
|
||||
// Work out the total number of comparisons required to sort
|
||||
// this array...
|
||||
let mut count = 0usize;
|
||||
$input.to_owned().$func(|a, b| {
|
||||
count += 1;
|
||||
a.cmp(b)
|
||||
});
|
||||
|
||||
// ... and then panic on each and every single one.
|
||||
for panic_countdown in 0..count {
|
||||
// Refresh the counters.
|
||||
VERSIONS.store(0, Relaxed);
|
||||
for i in 0..len {
|
||||
DROP_COUNTS[i].store(0, Relaxed);
|
||||
}
|
||||
|
||||
let v = $input.to_owned();
|
||||
let _ = std::panic::catch_unwind(move || {
|
||||
let mut v = v;
|
||||
let mut panic_countdown = panic_countdown;
|
||||
v.$func(|a, b| {
|
||||
if panic_countdown == 0 {
|
||||
SILENCE_PANIC.with(|s| s.set(true));
|
||||
panic!();
|
||||
}
|
||||
panic_countdown -= 1;
|
||||
a.cmp(b)
|
||||
})
|
||||
});
|
||||
|
||||
// Check that the number of things dropped is exactly
|
||||
// what we expect (i.e., the contents of `v`).
|
||||
for (i, c) in DROP_COUNTS.iter().enumerate().take(len) {
|
||||
let count = c.load(Relaxed);
|
||||
assert!(count == 1, "found drop count == {} for i == {}, len == {}", count, i, len);
|
||||
}
|
||||
|
||||
// Check that the most recent versions of values were dropped.
|
||||
assert_eq!(VERSIONS.load(Relaxed), 0);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
thread_local!(static SILENCE_PANIC: Cell<bool> = Cell::new(false));
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(target_os = "emscripten", ignore)] // no threads
|
||||
fn panic_safe() {
|
||||
panic::update_hook(move |prev, info| {
|
||||
if !SILENCE_PANIC.with(|s| s.get()) {
|
||||
prev(info);
|
||||
}
|
||||
});
|
||||
|
||||
let mut rng = thread_rng();
|
||||
|
||||
// Miri is too slow (but still need to `chain` to make the types match)
|
||||
let lens = if cfg!(miri) { (1..10).chain(0..0) } else { (1..20).chain(70..MAX_LEN) };
|
||||
let moduli: &[u32] = if cfg!(miri) { &[5] } else { &[5, 20, 50] };
|
||||
|
||||
for len in lens {
|
||||
for &modulus in moduli {
|
||||
for &has_runs in &[false, true] {
|
||||
let mut input = (0..len)
|
||||
.map(|id| DropCounter {
|
||||
x: rng.next_u32() % modulus,
|
||||
id: id,
|
||||
version: Cell::new(0),
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if has_runs {
|
||||
for c in &mut input {
|
||||
c.x = c.id as u32;
|
||||
}
|
||||
|
||||
for _ in 0..5 {
|
||||
let a = rng.gen::<usize>() % len;
|
||||
let b = rng.gen::<usize>() % len;
|
||||
if a < b {
|
||||
input[a..b].reverse();
|
||||
} else {
|
||||
input.swap(a, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test!(input, sort_by);
|
||||
test!(input, sort_unstable_by);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set default panic hook again.
|
||||
drop(panic::take_hook());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn repeat_generic_slice() {
|
||||
assert_eq!([1, 2].repeat(2), vec![1, 2, 1, 2]);
|
||||
|
@ -24,8 +24,8 @@ path = "benches/lib.rs"
|
||||
test = true
|
||||
|
||||
[dev-dependencies]
|
||||
rand = "0.7"
|
||||
rand_xorshift = "0.2"
|
||||
rand = { version = "0.8.5", default-features = false }
|
||||
rand_xorshift = { version = "0.3.0", default-features = false }
|
||||
|
||||
[features]
|
||||
# Make panics and failed asserts immediately abort without formatting any message
|
||||
|
@ -21,7 +21,7 @@ macro_rules! int_log_bench {
|
||||
/* Exponentially distributed random numbers from the whole range of the type. */
|
||||
let numbers: Vec<$t> = (0..256)
|
||||
.map(|_| {
|
||||
let x = rng.gen::<$t>() >> rng.gen_range(0, <$t>::BITS);
|
||||
let x = rng.gen::<$t>() >> rng.gen_range(0..<$t>::BITS);
|
||||
if x != 0 { x } else { 1 }
|
||||
})
|
||||
.collect();
|
||||
@ -38,7 +38,7 @@ macro_rules! int_log_bench {
|
||||
/* Exponentially distributed random numbers from the range 0..256. */
|
||||
let numbers: Vec<$t> = (0..256)
|
||||
.map(|_| {
|
||||
let x = (rng.gen::<u8>() >> rng.gen_range(0, u8::BITS)) as $t;
|
||||
let x = (rng.gen::<u8>() >> rng.gen_range(0..u8::BITS)) as $t;
|
||||
if x != 0 { x } else { 1 }
|
||||
})
|
||||
.collect();
|
||||
|
@ -155,3 +155,16 @@ mod time;
|
||||
mod tuple;
|
||||
mod unicode;
|
||||
mod waker;
|
||||
|
||||
/// Copied from `std::test_helpers::test_rng`, see that function for rationale.
|
||||
#[track_caller]
|
||||
#[allow(dead_code)] // Not used in all configurations.
|
||||
pub(crate) fn test_rng() -> rand_xorshift::XorShiftRng {
|
||||
use core::hash::{BuildHasher, Hash, Hasher};
|
||||
let mut hasher = std::collections::hash_map::RandomState::new().build_hasher();
|
||||
core::panic::Location::caller().hash(&mut hasher);
|
||||
let hc64 = hasher.finish();
|
||||
let seed_vec = hc64.to_le_bytes().into_iter().chain(0u8..8).collect::<Vec<u8>>();
|
||||
let seed: [u8; 16] = seed_vec.as_slice().try_into().unwrap();
|
||||
rand::SeedableRng::from_seed(seed)
|
||||
}
|
||||
|
@ -9,8 +9,6 @@ use core::num::flt2dec::MAX_SIG_DIGITS;
|
||||
use core::num::flt2dec::{decode, DecodableFloat, Decoded, FullDecoded};
|
||||
|
||||
use rand::distributions::{Distribution, Uniform};
|
||||
use rand::rngs::StdRng;
|
||||
use rand::SeedableRng;
|
||||
|
||||
pub fn decode_finite<T: DecodableFloat>(v: T) -> Decoded {
|
||||
match decode(v).1 {
|
||||
@ -92,7 +90,7 @@ where
|
||||
if cfg!(target_os = "emscripten") {
|
||||
return; // using rng pulls in i128 support, which doesn't work
|
||||
}
|
||||
let mut rng = StdRng::from_entropy();
|
||||
let mut rng = crate::test_rng();
|
||||
let f32_range = Uniform::new(0x0000_0001u32, 0x7f80_0000);
|
||||
iterate("f32_random_equivalence_test", k, n, f, g, |_| {
|
||||
let x = f32::from_bits(f32_range.sample(&mut rng));
|
||||
@ -108,7 +106,7 @@ where
|
||||
if cfg!(target_os = "emscripten") {
|
||||
return; // using rng pulls in i128 support, which doesn't work
|
||||
}
|
||||
let mut rng = StdRng::from_entropy();
|
||||
let mut rng = crate::test_rng();
|
||||
let f64_range = Uniform::new(0x0000_0000_0000_0001u64, 0x7ff0_0000_0000_0000);
|
||||
iterate("f64_random_equivalence_test", k, n, f, g, |_| {
|
||||
let x = f64::from_bits(f64_range.sample(&mut rng));
|
||||
|
@ -1805,7 +1805,7 @@ fn brute_force_rotate_test_1() {
|
||||
fn sort_unstable() {
|
||||
use core::cmp::Ordering::{Equal, Greater, Less};
|
||||
use core::slice::heapsort;
|
||||
use rand::{rngs::StdRng, seq::SliceRandom, Rng, SeedableRng};
|
||||
use rand::{seq::SliceRandom, Rng};
|
||||
|
||||
// Miri is too slow (but still need to `chain` to make the types match)
|
||||
let lens = if cfg!(miri) { (2..20).chain(0..0) } else { (2..25).chain(500..510) };
|
||||
@ -1813,7 +1813,7 @@ fn sort_unstable() {
|
||||
|
||||
let mut v = [0; 600];
|
||||
let mut tmp = [0; 600];
|
||||
let mut rng = StdRng::from_entropy();
|
||||
let mut rng = crate::test_rng();
|
||||
|
||||
for len in lens {
|
||||
let v = &mut v[0..len];
|
||||
@ -1879,11 +1879,10 @@ fn sort_unstable() {
|
||||
#[cfg_attr(miri, ignore)] // Miri is too slow
|
||||
fn select_nth_unstable() {
|
||||
use core::cmp::Ordering::{Equal, Greater, Less};
|
||||
use rand::rngs::StdRng;
|
||||
use rand::seq::SliceRandom;
|
||||
use rand::{Rng, SeedableRng};
|
||||
use rand::Rng;
|
||||
|
||||
let mut rng = StdRng::from_entropy();
|
||||
let mut rng = crate::test_rng();
|
||||
|
||||
for len in (2..21).chain(500..501) {
|
||||
let mut orig = vec![0; len];
|
||||
|
@ -33,7 +33,8 @@ default-features = false
|
||||
features = ['read_core', 'elf', 'macho', 'pe', 'unaligned', 'archive']
|
||||
|
||||
[dev-dependencies]
|
||||
rand = "0.7"
|
||||
rand = { version = "0.8.5", default-features = false, features = ["alloc"] }
|
||||
rand_xorshift = "0.3.0"
|
||||
|
||||
[target.'cfg(any(all(target_family = "wasm", not(target_os = "emscripten")), all(target_vendor = "fortanix", target_env = "sgx")))'.dependencies]
|
||||
dlmalloc = { version = "0.2.3", features = ['rustc-dep-of-std'] }
|
||||
|
@ -3,7 +3,8 @@ use super::HashMap;
|
||||
use super::RandomState;
|
||||
use crate::assert_matches::assert_matches;
|
||||
use crate::cell::RefCell;
|
||||
use rand::{thread_rng, Rng};
|
||||
use crate::test_helpers::test_rng;
|
||||
use rand::Rng;
|
||||
use realstd::collections::TryReserveErrorKind::*;
|
||||
|
||||
// https://github.com/rust-lang/rust/issues/62301
|
||||
@ -710,16 +711,16 @@ fn test_entry_take_doesnt_corrupt() {
|
||||
}
|
||||
|
||||
let mut m = HashMap::new();
|
||||
let mut rng = thread_rng();
|
||||
let mut rng = test_rng();
|
||||
|
||||
// Populate the map with some items.
|
||||
for _ in 0..50 {
|
||||
let x = rng.gen_range(-10, 10);
|
||||
let x = rng.gen_range(-10..10);
|
||||
m.insert(x, ());
|
||||
}
|
||||
|
||||
for _ in 0..1000 {
|
||||
let x = rng.gen_range(-10, 10);
|
||||
let x = rng.gen_range(-10..10);
|
||||
match m.entry(x) {
|
||||
Vacant(_) => {}
|
||||
Occupied(e) => {
|
||||
|
@ -10,7 +10,7 @@ use crate::sys_common::io::test::{tmpdir, TempDir};
|
||||
use crate::thread;
|
||||
use crate::time::{Duration, Instant};
|
||||
|
||||
use rand::{rngs::StdRng, RngCore, SeedableRng};
|
||||
use rand::RngCore;
|
||||
|
||||
#[cfg(unix)]
|
||||
use crate::os::unix::fs::symlink as symlink_dir;
|
||||
@ -1181,7 +1181,7 @@ fn _assert_send_sync() {
|
||||
#[test]
|
||||
fn binary_file() {
|
||||
let mut bytes = [0; 1024];
|
||||
StdRng::from_entropy().fill_bytes(&mut bytes);
|
||||
crate::test_helpers::test_rng().fill_bytes(&mut bytes);
|
||||
|
||||
let tmpdir = tmpdir();
|
||||
|
||||
@ -1194,7 +1194,7 @@ fn binary_file() {
|
||||
#[test]
|
||||
fn write_then_read() {
|
||||
let mut bytes = [0; 1024];
|
||||
StdRng::from_entropy().fill_bytes(&mut bytes);
|
||||
crate::test_helpers::test_rng().fill_bytes(&mut bytes);
|
||||
|
||||
let tmpdir = tmpdir();
|
||||
|
||||
|
@ -652,3 +652,30 @@ mod sealed {
|
||||
#[unstable(feature = "sealed", issue = "none")]
|
||||
pub trait Sealed {}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(dead_code)] // Not used in all configurations.
|
||||
pub(crate) mod test_helpers {
|
||||
/// Test-only replacement for `rand::thread_rng()`, which is unusable for
|
||||
/// us, as we want to allow running stdlib tests on tier-3 targets which may
|
||||
/// not have `getrandom` support.
|
||||
///
|
||||
/// Does a bit of a song and dance to ensure that the seed is different on
|
||||
/// each call (as some tests sadly rely on this), but doesn't try that hard.
|
||||
///
|
||||
/// This is duplicated in the `core`, `alloc` test suites (as well as
|
||||
/// `std`'s integration tests), but figuring out a mechanism to share these
|
||||
/// seems far more painful than copy-pasting a 7 line function a couple
|
||||
/// times, given that even under a perma-unstable feature, I don't think we
|
||||
/// want to expose types from `rand` from `std`.
|
||||
#[track_caller]
|
||||
pub(crate) fn test_rng() -> rand_xorshift::XorShiftRng {
|
||||
use core::hash::{BuildHasher, Hash, Hasher};
|
||||
let mut hasher = crate::collections::hash_map::RandomState::new().build_hasher();
|
||||
core::panic::Location::caller().hash(&mut hasher);
|
||||
let hc64 = hasher.finish();
|
||||
let seed_vec = hc64.to_le_bytes().into_iter().chain(0u8..8).collect::<Vec<u8>>();
|
||||
let seed: [u8; 16] = seed_vec.as_slice().try_into().unwrap();
|
||||
rand::SeedableRng::from_seed(seed)
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ use crate::sync::atomic::{AtomicUsize, Ordering};
|
||||
use crate::sync::mpsc::channel;
|
||||
use crate::sync::{Arc, RwLock, RwLockReadGuard, TryLockError};
|
||||
use crate::thread;
|
||||
use rand::{self, Rng};
|
||||
use rand::Rng;
|
||||
|
||||
#[derive(Eq, PartialEq, Debug)]
|
||||
struct NonCopy(i32);
|
||||
@ -28,7 +28,7 @@ fn frob() {
|
||||
let tx = tx.clone();
|
||||
let r = r.clone();
|
||||
thread::spawn(move || {
|
||||
let mut rng = rand::thread_rng();
|
||||
let mut rng = crate::test_helpers::test_rng();
|
||||
for _ in 0..M {
|
||||
if rng.gen_bool(1.0 / (N as f64)) {
|
||||
drop(r.write().unwrap());
|
||||
|
@ -39,9 +39,10 @@ pub mod test {
|
||||
}
|
||||
}
|
||||
|
||||
#[track_caller] // for `test_rng`
|
||||
pub fn tmpdir() -> TempDir {
|
||||
let p = env::temp_dir();
|
||||
let mut r = rand::thread_rng();
|
||||
let mut r = crate::test_helpers::test_rng();
|
||||
let ret = p.join(&format!("rust-{}", r.next_u32()));
|
||||
fs::create_dir(&ret).unwrap();
|
||||
TempDir(ret)
|
||||
|
@ -1,12 +1,24 @@
|
||||
use std::env::*;
|
||||
use std::ffi::{OsStr, OsString};
|
||||
|
||||
use rand::distributions::Alphanumeric;
|
||||
use rand::{thread_rng, Rng};
|
||||
use rand::distributions::{Alphanumeric, DistString};
|
||||
|
||||
/// Copied from `std::test_helpers::test_rng`, since these tests rely on the
|
||||
/// seed not being the same for every RNG invocation too.
|
||||
#[track_caller]
|
||||
pub(crate) fn test_rng() -> rand_xorshift::XorShiftRng {
|
||||
use core::hash::{BuildHasher, Hash, Hasher};
|
||||
let mut hasher = std::collections::hash_map::RandomState::new().build_hasher();
|
||||
core::panic::Location::caller().hash(&mut hasher);
|
||||
let hc64 = hasher.finish();
|
||||
let seed_vec = hc64.to_le_bytes().into_iter().chain(0u8..8).collect::<Vec<u8>>();
|
||||
let seed: [u8; 16] = seed_vec.as_slice().try_into().unwrap();
|
||||
rand::SeedableRng::from_seed(seed)
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn make_rand_name() -> OsString {
|
||||
let rng = thread_rng();
|
||||
let n = format!("TEST{}", rng.sample_iter(&Alphanumeric).take(10).collect::<String>());
|
||||
let n = format!("TEST{}", Alphanumeric.sample_string(&mut test_rng(), 10));
|
||||
let n = OsString::from(n);
|
||||
assert!(var_os(&n).is_none());
|
||||
n
|
||||
|
@ -195,7 +195,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
|
||||
"rand",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
"rand_hc",
|
||||
"rand_xorshift",
|
||||
"rand_xoshiro",
|
||||
"redox_syscall",
|
||||
|
Loading…
x
Reference in New Issue
Block a user