futures_util/async_await/
random.rs

1use std::{
2    cell::Cell,
3    collections::hash_map::DefaultHasher,
4    hash::Hasher,
5    num::Wrapping,
6    sync::atomic::{AtomicUsize, Ordering},
7};
8
9// Based on [Fisher–Yates shuffle].
10//
11// [Fisher–Yates shuffle]: https://en.wikipedia.org/wiki/Fisher–Yates_shuffle
12#[doc(hidden)]
13pub fn shuffle<T>(slice: &mut [T]) {
14    for i in (1..slice.len()).rev() {
15        slice.swap(i, gen_index(i + 1));
16    }
17}
18
19/// Return a value from `0..n`.
20fn gen_index(n: usize) -> usize {
21    (random() % n as u64) as usize
22}
23
24/// Pseudorandom number generator based on [xorshift*].
25///
26/// [xorshift*]: https://en.wikipedia.org/wiki/Xorshift#xorshift*
27fn random() -> u64 {
28    thread_local! {
29        static RNG: Cell<Wrapping<u64>> = Cell::new(Wrapping(prng_seed()));
30    }
31
32    fn prng_seed() -> u64 {
33        static COUNTER: AtomicUsize = AtomicUsize::new(0);
34
35        // Any non-zero seed will do
36        let mut seed = 0;
37        while seed == 0 {
38            let mut hasher = DefaultHasher::new();
39            hasher.write_usize(COUNTER.fetch_add(1, Ordering::Relaxed));
40            seed = hasher.finish();
41        }
42        seed
43    }
44
45    RNG.with(|rng| {
46        let mut x = rng.get();
47        debug_assert_ne!(x.0, 0);
48        x ^= x >> 12;
49        x ^= x << 25;
50        x ^= x >> 27;
51        rng.set(x);
52        x.0.wrapping_mul(0x2545_f491_4f6c_dd1d)
53    })
54}