Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove rand dependency by using our own PRNG #1837

Merged
merged 1 commit into from Aug 30, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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]) {
taiki-e marked this conversation as resolved.
Show resolved Hide resolved
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();
}
Nemo157 marked this conversation as resolved.
Show resolved Hide resolved
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