use super::{Emulation, EmulationOS, EmulationOption};
use std::cell::Cell;
use std::collections::hash_map::RandomState;
use std::hash::{BuildHasher, Hasher};
use std::num::Wrapping;
use strum::VariantArray;
fn fast_random() -> u64 {
thread_local! {
static RNG: Cell<Wrapping<u64>> = Cell::new(Wrapping(seed()));
}
#[inline]
fn seed() -> u64 {
let seed = RandomState::new();
let mut out = 0;
let mut cnt = 0;
while out == 0 {
cnt += 1;
let mut hasher = seed.build_hasher();
hasher.write_usize(cnt);
out = hasher.finish();
}
out
}
RNG.with(|rng| {
let mut n = rng.get();
debug_assert_ne!(n.0, 0);
n ^= n >> 12;
n ^= n << 25;
n ^= n >> 27;
rng.set(n);
n.0.wrapping_mul(0x2545_f491_4f6c_dd1d)
})
}
impl Emulation {
#[inline]
pub fn random() -> EmulationOption {
let emulation = Emulation::VARIANTS;
let emulation_os = EmulationOS::VARIANTS;
let rand = fast_random() as usize;
EmulationOption::builder()
.emulation(emulation[rand % emulation.len()])
.emulation_os(emulation_os[rand % emulation_os.len()])
.build()
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::sync::{Arc, Mutex};
use std::thread;
#[test]
fn test_concurrent_get_random_emulation() {
const THREAD_COUNT: usize = 10;
const ITERATIONS: usize = 100;
let results = Arc::new(Mutex::new(Vec::new()));
let mut handles = vec![];
for _ in 0..THREAD_COUNT {
let results = Arc::clone(&results);
let handle = thread::spawn(move || {
for _ in 0..ITERATIONS {
let emulation = Emulation::random();
let mut results = results.lock().unwrap();
results.push(emulation);
}
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
let results = results.lock().unwrap();
println!("Total results: {}", results.len());
}
}