1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
use alloc::sync::Arc;
use core::{
    future::Future,
    pin::Pin,
    task::{Context, Poll},
};
use parking_lot::Mutex;
use pin_project::pin_project;
use rand::{distributions, prelude::*};
use rand_xoshiro::Xoshiro256PlusPlus;

crate::scope::define!(scope, Scope);

pub fn fill_bytes(bytes: &mut [u8]) {
    scope::borrow_mut_with(|scope| scope.fill_bytes(bytes))
}

pub fn fill<T>(values: &mut [T])
where
    [T]: rand::Fill,
{
    scope::borrow_mut_with(|scope| scope.fill(values))
}

pub fn gen<T>() -> T
where
    distributions::Standard: Distribution<T>,
{
    scope::borrow_mut_with(|scope| scope.gen())
}

pub fn gen_range<B, T>(range: B) -> T
where
    B: distributions::uniform::SampleRange<T>,
    T: distributions::uniform::SampleUniform + PartialOrd,
{
    scope::borrow_mut_with(|scope| scope.gen_range(range))
}

pub fn shuffle<T>(items: &mut [T]) {
    scope::borrow_mut_with(|scope| items.shuffle(scope))
}

pub fn swap<T>(items: &mut [T]) {
    swap_count(items, 1)
}

pub fn swap_count<T>(items: &mut [T], count: usize) {
    scope::borrow_mut_with(|r| {
        let mut r = r.rng.lock();
        for _ in 0..count {
            let a = r.gen_range(0..items.len());
            let b = r.gen_range(0..items.len());
            items.swap(a, b)
        }
    })
}

pub fn one_of<T>(items: &[T]) -> &T {
    let index = gen_range(0..items.len());
    &items[index]
}

#[derive(Clone)]
pub struct Scope {
    rng: Arc<Mutex<Xoshiro256PlusPlus>>,
}

impl Scope {
    pub fn new(seed: u64) -> Self {
        let rng = Xoshiro256PlusPlus::seed_from_u64(seed);
        let rng = Arc::new(Mutex::new(rng));
        Self { rng }
    }

    pub fn enter<F: FnOnce() -> O, O>(&self, f: F) -> O {
        scope::with(self.clone(), f)
    }
}

impl RngCore for Scope {
    fn next_u32(&mut self) -> u32 {
        self.rng.lock().next_u32()
    }

    fn next_u64(&mut self) -> u64 {
        self.rng.lock().next_u64()
    }

    fn fill_bytes(&mut self, bytes: &mut [u8]) {
        self.rng.lock().fill_bytes(bytes)
    }

    fn try_fill_bytes(&mut self, bytes: &mut [u8]) -> Result<(), rand::Error> {
        self.rng.lock().try_fill_bytes(bytes)
    }
}

#[pin_project]
pub struct Task<F> {
    #[pin]
    inner: F,
    scope: Scope,
}

impl<F> Task<F> {
    pub fn new(inner: F, scope: Scope) -> Self {
        Self { inner, scope }
    }
}

impl<F: Future> Future for Task<F> {
    type Output = F::Output;

    fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
        let this = self.project();
        let inner = this.inner;
        this.scope.enter(move || Future::poll(inner, cx))
    }
}