diff --git a/.travis.yml b/.travis.yml index 99b369bfbe..5bcf70a559 100644 --- a/.travis.yml +++ b/.travis.yml @@ -112,7 +112,11 @@ matrix: - cargo build --manifest-path futures/Cargo.toml --target thumbv6m-none-eabi --no-default-features - --features unstable,alloc,cfg-target-has-atomic + --features unstable,cfg-target-has-atomic,alloc + - cargo build --manifest-path futures/Cargo.toml + --target thumbv6m-none-eabi + --no-default-features + --features unstable,cfg-target-has-atomic,async-await - name: cargo build --target=thumbv7m-none-eabi rust: nightly @@ -127,6 +131,10 @@ matrix: --target thumbv7m-none-eabi --no-default-features --features alloc + - cargo build --manifest-path futures/Cargo.toml + --target thumbv7m-none-eabi + --no-default-features + --features async-await - name: cargo check (futures-util) rust: nightly diff --git a/futures-select-macro/src/lib.rs b/futures-select-macro/src/lib.rs index 84d035011a..ffb4776f2f 100644 --- a/futures-select-macro/src/lib.rs +++ b/futures-select-macro/src/lib.rs @@ -149,7 +149,6 @@ pub fn select(input: TokenStream) -> TokenStream { let parsed = syn::parse_macro_input!(input as Select); let futures_crate: syn::Path = parsed.futures_crate_path.unwrap_or_else(|| parse_quote!(::futures_util)); - let rand_crate: syn::Path = parse_quote!(#futures_crate::rand_reexport); // should be def_site, but that's unstable let span = Span::call_site(); @@ -265,10 +264,7 @@ pub fn select(input: TokenStream) -> TokenStream { #( #poll_functions )* let mut __select_arr = [#( #variant_names ),*]; - <[_] as #rand_crate::SliceRandom>::shuffle( - &mut __select_arr, - &mut #rand_crate::thread_rng(), - ); + #futures_crate::async_await::shuffle(&mut __select_arr); for poller in &mut __select_arr { let poller: &mut &mut dyn FnMut( &mut #futures_crate::task::Context<'_> diff --git a/futures-util/Cargo.toml b/futures-util/Cargo.toml index 360dd3ec3f..33f0428c50 100644 --- a/futures-util/Cargo.toml +++ b/futures-util/Cargo.toml @@ -25,7 +25,7 @@ sink = ["futures-sink-preview"] io = ["std", "futures-io-preview", "memchr"] channel = ["std", "futures-channel-preview"] join-macro = ["async-await", "futures-join-macro-preview", "proc-macro-hack", "proc-macro-nested"] -select-macro = ["async-await", "futures-select-macro-preview", "proc-macro-hack", "proc-macro-nested", "rand"] +select-macro = ["async-await", "futures-select-macro-preview", "proc-macro-hack", "proc-macro-nested"] # Unstable features # These features are outside of the normal semver guarantees and require the @@ -43,7 +43,6 @@ futures-join-macro-preview = { path = "../futures-join-macro", version = "=0.3.0 futures-select-macro-preview = { path = "../futures-select-macro", version = "=0.3.0-alpha.18", default-features = false, optional = true } proc-macro-hack = { version = "0.5.9", optional = true } proc-macro-nested = { version = "0.1.2", optional = true } -rand = { version = "0.7.0", optional = true } slab = { version = "0.4", optional = true } memchr = { version = "2.2", optional = true } futures_01 = { version = "0.1.25", optional = true, package = "futures" } diff --git a/futures-util/src/async_await/mod.rs b/futures-util/src/async_await/mod.rs index ef5052f757..0a68dba695 100644 --- a/futures-util/src/async_await/mod.rs +++ b/futures-util/src/async_await/mod.rs @@ -31,6 +31,11 @@ mod select_mod; #[cfg(feature = "select-macro")] pub use self::select_mod::*; +#[cfg(feature = "select-macro")] +mod random; +#[cfg(feature = "select-macro")] +pub use self::random::*; + #[doc(hidden)] #[inline(always)] pub fn assert_unpin(_: &T) {} diff --git a/futures-util/src/async_await/random.rs b/futures-util/src/async_await/random.rs new file mode 100644 index 0000000000..4f8c7254b4 --- /dev/null +++ b/futures-util/src/async_await/random.rs @@ -0,0 +1,54 @@ +use std::{ + cell::Cell, + collections::hash_map::DefaultHasher, + hash::Hasher, + num::Wrapping, + sync::atomic::{AtomicUsize, Ordering}, +}; + +// Based on [Fisher–Yates shuffle]. +// +// [Fisher–Yates shuffle]: https://en.wikipedia.org/wiki/Fisher–Yates_shuffle +#[doc(hidden)] +pub fn shuffle(slice: &mut [T]) { + for i in (1..slice.len()).rev() { + slice.swap(i, gen_index(i + 1)); + } +} + +/// Return a value from `0..n`. +fn gen_index(n: usize) -> usize { + (random() % n as u64) as usize +} + +/// Pseudorandom number generator based on [xorshift*]. +/// +/// [xorshift*]: https://en.wikipedia.org/wiki/Xorshift#xorshift* +fn random() -> u64 { + thread_local! { + static RNG: Cell> = Cell::new(Wrapping(prng_seed())); + } + + fn prng_seed() -> u64 { + static COUNTER: AtomicUsize = AtomicUsize::new(0); + + // Any non-zero seed will do + let mut seed = 0; + while seed == 0 { + let mut hasher = DefaultHasher::new(); + hasher.write_usize(COUNTER.fetch_add(1, Ordering::Relaxed)); + seed = hasher.finish(); + } + seed + } + + RNG.with(|rng| { + let mut x = rng.get(); + debug_assert_ne!(x.0, 0); + x ^= x >> 12; + x ^= x << 25; + x ^= x >> 27; + rng.set(x); + x.0.wrapping_mul(0x2545_f491_4f6c_dd1d) + }) +} diff --git a/futures-util/src/lib.rs b/futures-util/src/lib.rs index 1216768851..4446c1476d 100644 --- a/futures-util/src/lib.rs +++ b/futures-util/src/lib.rs @@ -39,14 +39,6 @@ pub mod async_await; #[doc(hidden)] pub use self::async_await::*; -#[cfg(feature = "std")] -#[cfg(feature = "select-macro")] -#[doc(hidden)] -pub mod rand_reexport { // used by select! - #[doc(hidden)] - pub use rand::{prelude::SliceRandom, thread_rng}; -} - #[doc(hidden)] pub use futures_core::core_reexport; diff --git a/futures/src/lib.rs b/futures/src/lib.rs index 747ffd59b6..33f6e79a0a 100644 --- a/futures/src/lib.rs +++ b/futures/src/lib.rs @@ -527,7 +527,7 @@ pub mod never { #[cfg(feature = "std")] #[cfg(feature = "async-await")] #[doc(hidden)] -pub use futures_util::rand_reexport; +pub use futures_util::async_await; #[cfg(feature = "std")] #[cfg(feature = "async-await")]