1use std::sync::OnceLock;
4use std::time::Instant;
5
6static TIMER_START: OnceLock<Instant> = OnceLock::new();
9
10pub fn timer_init() -> Result<(), &'static str> {
16 TIMER_START
17 .set(Instant::now())
18 .map_err(|_| "Timer already initialized")
19}
20
21#[inline(always)]
26pub fn elapsed_ns() -> u64 {
27 let start = TIMER_START
28 .get()
29 .expect("Timer not initialized. Call timer_init() first.");
30 Instant::now().duration_since(*start).as_nanos() as u64
31}
32
33const VIBE_MULT_A: u64 = 0x9e3779b97f4a7c15;
35const VIBE_MULT_B: u64 = 0xc6a4a7935bd1e995;
36const VIBE_MULT_C: u64 = 0xe7037ed1a0b428db;
37
38#[derive(Clone, Copy, Debug)]
40pub struct VibeRng {
41 state_a: u64,
42 state_b: u64,
43 counter: u64,
44}
45
46#[derive(Clone, Copy, Debug)]
49pub enum BiasStrategy {
50 None,
51 Exponential,
52 Weighted,
53 Power(f64),
54 Stepped,
55}
56
57impl VibeRng {
58 #[inline(always)]
60 pub fn new(seed: u64) -> Self {
61 let mut z = seed.wrapping_add(VIBE_MULT_A);
62
63 z = (z ^ (z >> 30)).wrapping_mul(VIBE_MULT_B);
64 z = (z ^ (z >> 27)).wrapping_mul(VIBE_MULT_C);
65 z = z ^ (z >> 31);
66 let state_a = z;
67
68 z = state_a.wrapping_add(VIBE_MULT_A);
69 z = (z ^ (z >> 29)).wrapping_mul(VIBE_MULT_C);
70 z = (z ^ (z >> 26)).wrapping_mul(VIBE_MULT_B);
71 z = z ^ (z >> 30);
72 let state_b = z;
73
74 z = state_b.wrapping_add(VIBE_MULT_A);
75 z = (z ^ (z >> 28)).wrapping_mul(VIBE_MULT_B);
76 let counter = z ^ (z >> 32);
77
78 Self {
79 state_a,
80 state_b,
81 counter,
82 }
83 }
84
85 #[inline(always)]
87 pub fn range(&mut self, min: u64, max: u64) -> u64 {
88 if min >= max {
89 return min;
90 }
91
92 let range = max - min + 1;
93 let result = match range {
94 1 => 0,
95 2..=256 if range.is_power_of_two() => vibe_range_pow2(self, range),
96 2..=256 => vibe_range_small(self, range),
97 _ => vibe_range_unbiased(self, range),
98 };
99 min + result
100 }
101
102 #[inline(always)]
104 pub fn range_biased(&mut self, min: u64, max: u64, bias: BiasStrategy) -> u64 {
105 if min >= max {
106 return min;
107 }
108
109 match bias {
110 BiasStrategy::None => self.range(min, max),
111 _ => self.range_biased_impl(min, max, bias),
112 }
113 }
114
115 #[inline(always)]
117 pub fn next_raw(&mut self) -> u64 {
118 let s0 = self.state_a;
119 let mut s1 = self.state_b;
120
121 s1 ^= s0;
122 self.state_a = s0.rotate_left(26) ^ s1 ^ (s1 << 9);
123 self.state_b = s1.rotate_left(13);
124
125 let result = s0.wrapping_add(s1);
126 let result = result ^ (result >> 31);
127 let result = result.wrapping_mul(VIBE_MULT_B);
128 let result = result ^ (result >> 29);
129
130 self.counter = self.counter.wrapping_add(1);
131 result
132 }
133
134 #[inline(always)]
136 fn next_f64_fast(&mut self) -> f64 {
137 const SCALE: f64 = 1.0 / (1u32 << 24) as f64;
138 ((self.next_raw() >> 40) as u32 as f64) * SCALE
139 }
140
141 #[inline(always)]
143 pub fn next_f64(&mut self) -> f64 {
144 const SCALE: f64 = 1.0 / (1u64 << 53) as f64;
145 ((self.next_raw() >> 11) as f64) * SCALE
146 }
147
148 #[inline(always)]
150 fn range_biased_impl(&mut self, min: u64, max: u64, bias: BiasStrategy) -> u64 {
151 let full_range = max - min + 1;
152 let quarter_size = full_range / 4;
153 let quarter_end = min + quarter_size.saturating_sub(1);
154
155 match bias {
156 BiasStrategy::Weighted => {
157 if self.next_raw() % 100 < 60 {
158 self.range(min, quarter_end.min(max))
159 } else {
160 let rest_start = (min + quarter_size).min(max);
161 if rest_start > max {
162 min
163 } else {
164 self.range(rest_start, max)
165 }
166 }
167 }
168
169 BiasStrategy::Exponential => {
170 let u = self.next_f64_fast();
171 let biased_u = (-u * 3.0).exp();
172 let offset = (biased_u * full_range as f64) as u64;
173 min + offset.min(full_range - 1)
174 }
175
176 BiasStrategy::Power(power) => {
177 let u = self.next_f64_fast();
178 let biased_u = if power < 1.0 {
179 1.0 - (1.0 - u).powf(1.0 / power)
180 } else {
181 u.powf(power)
182 };
183 let offset = (biased_u * full_range as f64) as u64;
184 min + offset.min(full_range - 1)
185 }
186
187 BiasStrategy::Stepped => {
188 if (self.next_raw() & 3) < 3 {
189 self.range(min, quarter_end.min(max))
190 } else {
191 self.range(min, max)
192 }
193 }
194
195 BiasStrategy::None => unreachable!(),
196 }
197 }
198}
199
200#[inline(always)]
202fn vibe_range_unbiased(rng: &mut VibeRng, range: u64) -> u64 {
203 if range <= 1 {
204 return 0;
205 }
206
207 let mut random = rng.next_raw();
208 let mut multiresult = (random as u128) * (range as u128);
209 let mut leftover = multiresult as u64;
210
211 if leftover < range {
212 let threshold = (0u64.wrapping_sub(range)) % range;
213 while leftover < threshold {
214 random = rng.next_raw();
215 multiresult = (random as u128) * (range as u128);
216 leftover = multiresult as u64;
217 }
218 }
219 (multiresult >> 64) as u64
220}
221
222#[inline(always)]
224fn vibe_range_pow2(rng: &mut VibeRng, range: u64) -> u64 {
225 debug_assert!(range.is_power_of_two());
226 rng.next_raw() & (range - 1)
227}
228
229#[inline(always)]
231fn vibe_range_small(rng: &mut VibeRng, range: u64) -> u64 {
232 if range.is_power_of_two() {
233 return vibe_range_pow2(rng, range);
234 }
235
236 let mask = range.next_power_of_two() - 1;
237 loop {
238 let candidate = rng.next_raw() & mask;
239 if candidate < range {
240 return candidate;
241 }
242 }
243}