Skip to content

Commit

Permalink
Remove rand dependency by using our own PRNG
Browse files Browse the repository at this point in the history
  • Loading branch information
taiki-e authored and cramertj committed Aug 30, 2019
1 parent 62894c6 commit 8019d99
Show file tree
Hide file tree
Showing 7 changed files with 71 additions and 17 deletions.
10 changes: 9 additions & 1 deletion .travis.yml
Expand Up @@ -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
Expand All @@ -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
Expand Down
6 changes: 1 addition & 5 deletions futures-select-macro/src/lib.rs
Expand Up @@ -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();
Expand Down Expand Up @@ -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<'_>
Expand Down
3 changes: 1 addition & 2 deletions futures-util/Cargo.toml
Expand Up @@ -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
Expand All @@ -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" }
Expand Down
5 changes: 5 additions & 0 deletions futures-util/src/async_await/mod.rs
Expand Up @@ -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: Unpin>(_: &T) {}
Expand Down
54 changes: 54 additions & 0 deletions 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<T>(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<Wrapping<u64>> = 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)
})
}
8 changes: 0 additions & 8 deletions futures-util/src/lib.rs
Expand Up @@ -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;

Expand Down
2 changes: 1 addition & 1 deletion futures/src/lib.rs
Expand Up @@ -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")]
Expand Down

0 comments on commit 8019d99

Please sign in to comment.