diff --git a/futures-util/src/async_await/mod.rs b/futures-util/src/async_await/mod.rs index 09152f94c..f2cd9fc62 100644 --- a/futures-util/src/async_await/mod.rs +++ b/futures-util/src/async_await/mod.rs @@ -34,10 +34,8 @@ mod stream_select_mod; #[cfg(feature = "async-await-macro")] pub use self::stream_select_mod::*; -#[cfg(feature = "std")] #[cfg(feature = "async-await-macro")] mod random; -#[cfg(feature = "std")] #[cfg(feature = "async-await-macro")] pub use self::random::*; diff --git a/futures-util/src/async_await/random.rs b/futures-util/src/async_await/random.rs index 2ac2f78a8..e8d53e604 100644 --- a/futures-util/src/async_await/random.rs +++ b/futures-util/src/async_await/random.rs @@ -1,10 +1,4 @@ -use std::{ - cell::Cell, - collections::hash_map::DefaultHasher, - hash::Hasher, - num::Wrapping, - sync::atomic::{AtomicUsize, Ordering}, -}; +use core::num::Wrapping; // Based on [Fisher–Yates shuffle]. // @@ -24,7 +18,15 @@ fn gen_index(n: usize) -> usize { /// Pseudorandom number generator based on [xorshift*]. /// /// [xorshift*]: https://en.wikipedia.org/wiki/Xorshift#xorshift* +#[cfg(feature = "std")] fn random() -> u64 { + use std::{ + cell::Cell, + collections::hash_map::DefaultHasher, + hash::Hasher, + sync::atomic::{AtomicUsize, Ordering}, + }; + std::thread_local! { static RNG: Cell> = Cell::new(Wrapping(prng_seed())); } @@ -43,12 +45,52 @@ fn random() -> u64 { } 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) + let x = rng.get(); + let (next, result) = xorshift64star(x); + rng.set(next); + result }) } + +#[cfg(not(feature = "std"))] +fn random() -> u64 { + use core::sync::atomic::{AtomicUsize, Ordering}; + + static RNG: AtomicUsize = AtomicUsize::new(1); + + let x = RNG.load(Ordering::Relaxed); + + if core::mem::size_of::() == 4 { + let next = xorshift32(x as u32); + RNG.store(next as usize, Ordering::Relaxed); + next as u64 + } else if core::mem::size_of::() == 8 { + let (next, result) = xorshift64star(Wrapping(x as u64)); + RNG.store(next.0 as usize, Ordering::Relaxed); + result + } else { + panic!("random() function is not supported on this platform"); + } +} + +/// Xorshift64* algorithm. +/// Returns the next state and the random number; `(next_state, random_number)`. +#[inline] +fn xorshift64star(mut x: Wrapping) -> (Wrapping, u64) { + debug_assert_ne!(x.0, 0); + x ^= x >> 12; + x ^= x << 25; + x ^= x >> 27; + (x, x.0.wrapping_mul(0x2545_f491_4f6c_dd1d)) +} + +/// Xorshift32 algorithm. +#[cfg(not(feature = "std"))] +#[inline] +fn xorshift32(mut x: u32) -> u32 { + debug_assert_ne!(x, 0); + x ^= x << 13; + x ^= x >> 17; + x ^= x << 5; + x +} diff --git a/futures-util/src/async_await/select_mod.rs b/futures-util/src/async_await/select_mod.rs index 638a92eb1..de801e1ad 100644 --- a/futures-util/src/async_await/select_mod.rs +++ b/futures-util/src/async_await/select_mod.rs @@ -305,7 +305,6 @@ macro_rules! document_select_macro { }; } -#[cfg(feature = "std")] #[doc(hidden)] pub use futures_macro::select_internal; @@ -313,7 +312,6 @@ pub use futures_macro::select_internal; pub use futures_macro::select_biased_internal; document_select_macro! { - #[cfg(feature = "std")] #[macro_export] macro_rules! select { ($($tokens:tt)*) => {{ diff --git a/futures/src/lib.rs b/futures/src/lib.rs index 839a0a1f0..fececa498 100644 --- a/futures/src/lib.rs +++ b/futures/src/lib.rs @@ -120,7 +120,6 @@ pub use futures_util::{AsyncBufReadExt, AsyncReadExt, AsyncSeekExt, AsyncWriteEx // Macro reexports pub use futures_core::ready; // Readiness propagation pub use futures_util::pin_mut; -#[cfg(feature = "std")] #[cfg(feature = "async-await")] pub use futures_util::select; #[cfg(feature = "async-await")]