1use crate::inf_iterator::InfIterator;
2use std::marker::PhantomData;
3use std::ops::Range;
4use std::time::{Duration, SystemTime};
5
6pub trait Rand64 {
8 fn next_u64(&mut self) -> u64;
10
11 #[inline]
20 fn gen_bool(&mut self, p: Probability) -> bool {
21 let cutoff = (p.0 * u64::MAX as f64) as u64;
22 let mut next = self.next_u64();
23 if next == u64::MAX {
24 next = u64::MAX - 1;
26 }
27 #[cfg(test)]
28 dbg!((cutoff, next));
29 next < cutoff
30 }
31}
32
33#[derive(Clone, Copy)]
35pub struct Probability(f64);
36
37impl Probability {
38 pub fn new(p: f64) -> Self {
50 assert!(p >= 0f64, "p ({p}) cannot be less than 0");
51 assert!(p <= 1f64, "p ({p}) cannot be greater than 1");
52 Self(p)
53 }
54}
55
56impl From<Probability> for f64 {
57 fn from(p: Probability) -> Self {
58 p.0
59 }
60}
61
62impl From<f64> for Probability {
63 fn from(p: f64) -> Self {
64 Probability::new(p)
65 }
66}
67
68pub trait Seeded {
70 type Rng: Rand64;
71
72 fn seed(seed: u64) -> Self::Rng;
74}
75
76pub trait RandDuration {
78 fn gen_range(&mut self, range: Range<Duration>) -> Duration;
79}
80
81impl<R: Rand64> RandDuration for R {
82 #[inline(always)]
83 fn gen_range(&mut self, range: Range<Duration>) -> Duration {
84 if range.is_empty() {
85 return range.start;
86 }
87 let span = (range.end - range.start).as_nanos();
88 if span <= u64::MAX as u128 {
89 let span = span as u64;
90 let random = span.gen(self);
91 range.start + Duration::from_nanos(random)
92 } else {
93 let random = span.gen(self);
94 range.start + duration_from_nanos(random)
95 }
96 }
97}
98
99trait GenSpan {
100 fn gen(&self, rng: &mut impl Rand64) -> Self;
101}
102
103impl GenSpan for u64 {
104 #[inline(always)]
105 fn gen(&self, rng: &mut impl Rand64) -> Self {
106 rng.next_u64() % self
107 }
108}
109
110impl GenSpan for u128 {
111 #[inline(always)]
112 fn gen(&self, rng: &mut impl Rand64) -> Self {
113 let random = (rng.next_u64() as u128) << 64 | (rng.next_u64() as u128);
114 random % self
115 }
116}
117
118#[inline(always)]
122pub const fn duration_from_nanos(nanos: u128) -> Duration {
123 const NANOS_PER_SEC: u128 = 1_000_000_000;
124 let secs = (nanos / NANOS_PER_SEC) as u64;
125 let nanos = (nanos % NANOS_PER_SEC) as u32;
126 Duration::new(secs, nanos)
127}
128
129pub struct FixedDuration;
130
131pub const FIXED_DURATION: FixedDuration = FixedDuration;
132
133impl Default for FixedDuration {
134 #[inline(always)]
135 fn default() -> Self {
136 Self
137 }
138}
139
140impl RandDuration for FixedDuration {
141 #[inline(always)]
142 fn gen_range(&mut self, range: Range<Duration>) -> Duration {
143 const NANOSECOND: Duration = Duration::new(0, 1);
144 if range.is_empty() {
145 range.end
146 } else {
147 range.end - NANOSECOND
148 }
149 }
150}
151
152pub struct Xorshift {
154 seed: u64,
155}
156
157impl Default for Xorshift {
158 fn default() -> Self {
159 Self::seed(1)
160 }
161}
162
163impl Rand64 for Xorshift {
164 fn next_u64(&mut self) -> u64 {
165 let mut s = self.seed;
166 s ^= s << 13;
167 s ^= s >> 7;
168 s ^= s << 17;
169 self.seed = s;
170 s
171 }
172}
173
174impl Seeded for Xorshift {
175 type Rng = Xorshift;
176
177 #[inline]
178 fn seed(seed: u64) -> Self::Rng {
179 Self { seed: if seed == 0 { u64::MAX >> 1 } else { seed } }
181 }
182}
183
184#[derive(Debug)]
185pub struct CyclicSeed(u64);
186
187impl CyclicSeed {
188 #[inline]
189 pub fn new(seed: u64) -> Self {
190 Self(seed)
191 }
192}
193
194impl Default for CyclicSeed {
195 #[inline]
196 fn default() -> Self {
197 Self(0)
198 }
199}
200
201impl InfIterator for CyclicSeed {
202 type Item = u64;
203
204 #[inline]
205 fn next(&mut self) -> Self::Item {
206 let current = self.0;
207 self.0 = if current == u64::MAX { 0 } else { current + 1 };
208 current
209 }
210}
211
212pub struct LazyRand64<S: Seeded, F: FnOnce() -> u64> {
213 state: Option<InitState<S::Rng, F>>,
214 __phantom_data: PhantomData<S>,
215}
216
217impl<S: Seeded, F: FnOnce() -> u64> LazyRand64<S, F> {
218 pub fn lazy(f: F) -> Self {
219 Self {
220 state: Some(InitState::Uninit(f)),
221 __phantom_data: PhantomData::default(),
222 }
223 }
224
225 pub fn eager(rng: S::Rng) -> Self {
226 Self {
227 state: Some(InitState::Ready(rng)),
228 __phantom_data: PhantomData::default(),
229 }
230 }
231}
232
233enum InitState<R: Rand64, F: FnOnce() -> u64> {
234 Uninit(F),
235 Ready(R),
236}
237
238impl<S: Seeded, F: FnOnce() -> u64> Rand64 for LazyRand64<S, F> {
239 fn next_u64(&mut self) -> u64 {
240 match self.state.take() {
241 Some(InitState::Uninit(f)) => {
242 let seed = f();
243 let mut rng = S::seed(seed);
244 let next = rng.next_u64();
245 self.state = Some(InitState::<S::Rng, F>::Ready(rng));
246 next
247 }
248 Some(InitState::Ready(mut rng)) => {
249 let next = rng.next_u64();
250 self.state = Some(InitState::Ready(rng));
251 next
252 }
253 None => unreachable!(),
254 }
255 }
256}
257
258pub fn clock_seed() -> u64 {
261 let time = SystemTime::now()
262 .duration_since(SystemTime::UNIX_EPOCH)
263 .unwrap()
264 .as_nanos();
265 let folded = (time >> 64) ^ time;
266 folded as u64
267}
268
269#[cfg(test)]
270mod tests;