presentar_terminal/
seed.rs1use std::sync::OnceLock;
22
23pub const DEFAULT_TEST_SEED: u64 = 42;
25
26pub const DEFAULT_PROPTEST_SEED: u64 = 0xdeadbeef;
28
29pub const DEFAULT_BENCH_SEED: u64 = 12345;
31
32static TEST_SEED: OnceLock<u64> = OnceLock::new();
33static BENCH_SEED: OnceLock<u64> = OnceLock::new();
34
35pub fn get_test_seed() -> u64 {
37 *TEST_SEED.get_or_init(|| {
38 std::env::var("PRESENTAR_TEST_SEED")
39 .ok()
40 .and_then(|s| s.parse().ok())
41 .unwrap_or(DEFAULT_TEST_SEED)
42 })
43}
44
45pub fn get_bench_seed() -> u64 {
47 *BENCH_SEED.get_or_init(|| {
48 std::env::var("PRESENTAR_BENCH_SEED")
49 .ok()
50 .and_then(|s| s.parse().ok())
51 .unwrap_or(DEFAULT_BENCH_SEED)
52 })
53}
54
55#[derive(Clone, Debug)]
58pub struct DeterministicRng {
59 state: u64,
60}
61
62impl DeterministicRng {
63 pub fn new(seed: u64) -> Self {
65 Self { state: seed }
66 }
67
68 pub fn from_test_seed() -> Self {
70 Self::new(get_test_seed())
71 }
72
73 pub fn from_bench_seed() -> Self {
75 Self::new(get_bench_seed())
76 }
77
78 pub fn next_u64(&mut self) -> u64 {
80 self.state ^= self.state << 13;
82 self.state ^= self.state >> 7;
83 self.state ^= self.state << 17;
84 self.state
85 }
86
87 pub fn next_f64(&mut self) -> f64 {
89 (self.next_u64() as f64) / (u64::MAX as f64)
90 }
91
92 pub fn next_f64_range(&mut self, min: f64, max: f64) -> f64 {
94 min + self.next_f64() * (max - min)
95 }
96
97 pub fn reset(&mut self, seed: u64) {
99 self.state = seed;
100 }
101}
102
103pub fn deterministic_rng() -> DeterministicRng {
105 DeterministicRng::from_test_seed()
106}
107
108#[cfg(test)]
109mod tests {
110 use super::*;
111
112 #[test]
113 fn test_deterministic_rng_reproducible() {
114 let mut rng1 = DeterministicRng::new(42);
115 let mut rng2 = DeterministicRng::new(42);
116
117 for _ in 0..100 {
118 assert_eq!(rng1.next_u64(), rng2.next_u64());
119 }
120 }
121
122 #[test]
123 fn test_f64_range() {
124 let mut rng = DeterministicRng::new(42);
125
126 for _ in 0..100 {
127 let v = rng.next_f64_range(0.0, 100.0);
128 assert!((0.0..100.0).contains(&v));
129 }
130 }
131
132 #[test]
133 fn test_seed_from_env() {
134 let seed = get_test_seed();
136 assert_eq!(seed, DEFAULT_TEST_SEED);
137 }
138
139 #[test]
141 fn test_default_constants() {
142 assert_eq!(DEFAULT_TEST_SEED, 42);
143 assert_eq!(DEFAULT_PROPTEST_SEED, 0xdeadbeef);
144 assert_eq!(DEFAULT_BENCH_SEED, 12345);
145 }
146
147 #[test]
148 fn test_get_bench_seed() {
149 let seed = get_bench_seed();
150 assert_eq!(seed, DEFAULT_BENCH_SEED);
151 }
152
153 #[test]
154 fn test_deterministic_rng_from_test_seed() {
155 let mut rng = DeterministicRng::from_test_seed();
156 let val1 = rng.next_u64();
157 rng.reset(get_test_seed());
159 let val2 = rng.next_u64();
160 assert_eq!(val1, val2);
161 }
162
163 #[test]
164 fn test_deterministic_rng_from_bench_seed() {
165 let mut rng = DeterministicRng::from_bench_seed();
166 let _val = rng.next_u64();
167 }
169
170 #[test]
171 fn test_next_f64() {
172 let mut rng = DeterministicRng::new(12345);
173 for _ in 0..100 {
174 let val = rng.next_f64();
175 assert!((0.0..1.0).contains(&val));
176 }
177 }
178
179 #[test]
180 fn test_next_f64_range_negative() {
181 let mut rng = DeterministicRng::new(42);
182 for _ in 0..100 {
183 let val = rng.next_f64_range(-50.0, 50.0);
184 assert!((-50.0..50.0).contains(&val));
185 }
186 }
187
188 #[test]
189 fn test_reset() {
190 let mut rng = DeterministicRng::new(42);
191 let val1 = rng.next_u64();
192 let val2 = rng.next_u64();
193
194 rng.reset(42);
195 let val3 = rng.next_u64();
196 let val4 = rng.next_u64();
197
198 assert_eq!(val1, val3);
199 assert_eq!(val2, val4);
200 }
201
202 #[test]
203 fn test_deterministic_rng_debug() {
204 let rng = DeterministicRng::new(42);
205 let debug = format!("{:?}", rng);
206 assert!(debug.contains("DeterministicRng"));
207 }
208
209 #[test]
210 fn test_deterministic_rng_clone() {
211 let mut rng1 = DeterministicRng::new(42);
212 let _ = rng1.next_u64();
213 let mut rng2 = rng1.clone();
214
215 assert_eq!(rng1.next_u64(), rng2.next_u64());
217 }
218
219 #[test]
220 fn test_deterministic_rng_different_seeds() {
221 let mut rng1 = DeterministicRng::new(1);
222 let mut rng2 = DeterministicRng::new(2);
223
224 assert_ne!(rng1.next_u64(), rng2.next_u64());
226 }
227
228 #[test]
229 fn test_deterministic_rng_function() {
230 let mut rng = deterministic_rng();
231 let _val = rng.next_u64();
232 }
234
235 #[test]
236 fn test_next_u64_not_zero() {
237 let mut rng = DeterministicRng::new(42);
238 for _ in 0..10 {
240 rng.next_u64();
241 }
242 assert_ne!(rng.next_u64(), 0);
243 }
244
245 #[test]
246 fn test_deterministic_rng_zero_seed() {
247 let mut rng = DeterministicRng::new(0);
249 let val = rng.next_u64();
251 assert_eq!(val, 0);
252 }
253
254 #[test]
255 fn test_deterministic_rng_max_seed() {
256 let mut rng = DeterministicRng::new(u64::MAX);
258 let _val = rng.next_u64();
259 }
261}