use std::mem::transmute;
use std::sync::{Arc, Mutex};
use std::thread::Builder;
use crate::cmn;
#[derive(Debug, Clone)]
pub struct ThreadRandom {
state: Arc<Mutex<[u32; 4]>>,
}
impl ThreadRandom {
fn randomise(input: [u32; 4]) -> [u32; 4] {
let mut out = input;
let tmp = out[3];
out[3] = out[2];
out[2] = out[1];
out[1] = out[0];
out[0] ^= out[0] << 13;
out[0] ^= out[0] >> 7;
out[0] ^= out[0] << 17;
let i = (out[0] >> 4) & 1;
let j = (out[0] >> 7) & 1;
let k = (out[0] >> 11) & 1;
let l = (out[0] >> 25) & 1;
out[0] = tmp ^ (out[0] >> 1) ^ ((i ^ j ^ k ^ l) << 31);
return out;
}
fn from_seed(v: [u32; 4]) -> Option<Self> {
let s = Arc::new(Mutex::new(v));
let s1 = Arc::clone(&s);
let _ = Builder::new()
.name("multirand".into())
.stack_size(1024 * 32) .spawn(move || {
loop {
let mut num = s1.lock().unwrap();
*num = Self::randomise(*num);
}
})
.ok()?;
Some(Self { state: s })
}
pub fn os() -> Option<Self> {
let mut buf = [0u8; 16];
getrandom::fill(&mut buf).ok()?;
Self::from_seed(unsafe { transmute::<[u8; 16], [u32; 4]>(buf) })
}
pub fn new(seed: u128) -> Option<Self> {
Self::from_seed(unsafe { transmute::<u128, [u32; 4]>(seed) })
}
pub fn random<T: cmn::CreateFrom>(&self) -> Option<T> {
let mut s = (self.state).lock().ok()?;
*s = Self::randomise(*s);
Some(T::create(*s))
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::HashSet;
use std::vec::Vec;
#[test]
fn distinct_from_last() {
let rand = ThreadRandom::os().unwrap();
let mut last = 0;
for _ in 0..10 {
let i = rand.random::<u64>().unwrap();
dbg!(&rand, i);
assert!(i != last);
last = i;
}
}
#[test]
fn purely_unique() {
let rand = ThreadRandom::os().unwrap();
let mut v = Vec::<u128>::new();
for _ in 0..100 {
let i = rand.random::<u128>().unwrap();
dbg!(&rand, i);
v.push(i);
}
let h = v.clone().into_iter().collect::<HashSet<u128>>();
assert!(h.len() == v.len());
}
#[test]
fn conversions() {
let rand = ThreadRandom::os().unwrap();
let boolean = rand.random::<bool>();
dbg!(&rand, boolean);
assert!(boolean.is_some());
let character = rand.random::<char>();
dbg!(&rand, character);
assert!(character.is_some());
let unsigned_8 = rand.random::<u8>();
dbg!(&rand, unsigned_8);
assert!(unsigned_8.is_some());
let unsigned_16 = rand.random::<u16>();
dbg!(&rand, unsigned_16);
assert!(unsigned_16.is_some());
let unsigned_32 = rand.random::<u32>();
dbg!(&rand, unsigned_32);
assert!(unsigned_32.is_some());
let unsigned_64 = rand.random::<u64>();
dbg!(&rand, unsigned_64);
assert!(unsigned_64.is_some());
let unsigned_128 = rand.random::<u128>();
dbg!(&rand, unsigned_128);
assert!(unsigned_128.is_some());
let unsigned_size = rand.random::<usize>();
dbg!(&rand, unsigned_size);
assert!(unsigned_size.is_some());
let signed_8 = rand.random::<i8>();
dbg!(&rand, signed_8);
assert!(signed_8.is_some());
let signed_16 = rand.random::<i16>();
dbg!(&rand, signed_16);
assert!(signed_16.is_some());
let signed_32 = rand.random::<i32>();
dbg!(&rand, signed_32);
assert!(signed_32.is_some());
let signed_64 = rand.random::<i64>();
dbg!(&rand, signed_64);
assert!(signed_64.is_some());
let signed_128 = rand.random::<i128>();
dbg!(&rand, signed_128);
assert!(signed_128.is_some());
let signed_size = rand.random::<isize>();
dbg!(&rand, signed_size);
assert!(signed_size.is_some());
let float_32 = rand.random::<f32>();
dbg!(&rand, float_32);
assert!(float_32.is_some());
let float_64 = rand.random::<f64>();
dbg!(&rand, float_64);
assert!(float_64.is_some());
}
}