wreq_util/emulation/
rand.rs1use super::{Emulation, EmulationOS, EmulationOption};
2use std::cell::Cell;
3use std::collections::hash_map::RandomState;
4use std::hash::{BuildHasher, Hasher};
5use std::num::Wrapping;
6use strum::VariantArray;
7
8fn fast_random() -> u64 {
10 thread_local! {
11 static RNG: Cell<Wrapping<u64>> = Cell::new(Wrapping(seed()));
12 }
13
14 #[inline]
15 fn seed() -> u64 {
16 let seed = RandomState::new();
17
18 let mut out = 0;
19 let mut cnt = 0;
20 while out == 0 {
21 cnt += 1;
22 let mut hasher = seed.build_hasher();
23 hasher.write_usize(cnt);
24 out = hasher.finish();
25 }
26 out
27 }
28
29 RNG.with(|rng| {
30 let mut n = rng.get();
31 debug_assert_ne!(n.0, 0);
32 n ^= n >> 12;
33 n ^= n << 25;
34 n ^= n >> 27;
35 rng.set(n);
36 n.0.wrapping_mul(0x2545_f491_4f6c_dd1d)
37 })
38}
39
40impl Emulation {
41 #[inline]
61 pub fn random() -> EmulationOption {
62 let emulation = Emulation::VARIANTS;
63 let emulation_os = EmulationOS::VARIANTS;
64 let rand = fast_random() as usize;
65 EmulationOption::builder()
66 .emulation(emulation[rand % emulation.len()])
67 .emulation_os(emulation_os[rand % emulation_os.len()])
68 .build()
69 }
70}
71
72#[cfg(test)]
73mod tests {
74 use super::*;
75 use std::sync::{Arc, Mutex};
76 use std::thread;
77
78 #[test]
79 fn test_concurrent_get_random_emulation() {
80 const THREAD_COUNT: usize = 10;
81 const ITERATIONS: usize = 100;
82
83 let results = Arc::new(Mutex::new(Vec::new()));
84
85 let mut handles = vec![];
86
87 for _ in 0..THREAD_COUNT {
88 let results = Arc::clone(&results);
89 let handle = thread::spawn(move || {
90 for _ in 0..ITERATIONS {
91 let emulation = Emulation::random();
92 let mut results = results.lock().unwrap();
93 results.push(emulation);
94 }
95 });
96 handles.push(handle);
97 }
98
99 for handle in handles {
100 handle.join().unwrap();
101 }
102
103 let results = results.lock().unwrap();
104 println!("Total results: {}", results.len());
105 }
106}