use rand::{
Rng,
SeedableRng,
distributions::{Distribution, Standard},
rngs::StdRng,
};
use rand_xorshift::XorShiftRng;
pub trait Uniform: Sized {
fn rand<R: Rng + ?Sized>(rng: &mut R) -> Self;
}
impl<T> Uniform for T
where
Standard: Distribution<T>,
{
#[inline]
fn rand<R: Rng + ?Sized>(rng: &mut R) -> Self {
rng.sample(Standard)
}
}
pub struct TestRng(XorShiftRng);
impl Default for TestRng {
fn default() -> Self {
let seed = StdRng::from_entropy().gen();
Self::fixed(seed)
}
}
impl TestRng {
pub fn fixed(seed: u64) -> Self {
println!("\nInitializing 'TestRng' with seed '{seed}'\n");
Self::from_seed(seed)
}
pub fn from_seed(seed: u64) -> Self {
Self(XorShiftRng::seed_from_u64(seed))
}
pub fn next_string(&mut self, max_bytes: u32, is_fixed_size: bool) -> String {
fn adjust_unsafe_char(ch: char) -> char {
let code = ch as u32;
if code < 9
|| code == 11
|| code == 12
|| (14..=31).contains(&code)
|| code == 127
|| (0x202a..=0x202e).contains(&code)
|| (0x2066..=0x2069).contains(&code)
{
'0'
} else {
ch
}
}
fn adjust_backslash_and_doublequote(ch: char) -> char {
if ch == '\\' || ch == '\"' { '0' } else { ch }
}
let range = match is_fixed_size {
true => 0..max_bytes,
false => 0..self.gen_range(0..max_bytes),
};
range.map(|_| self.gen::<char>()).map(adjust_unsafe_char).map(adjust_backslash_and_doublequote).collect()
}
}
impl rand::RngCore for TestRng {
fn next_u32(&mut self) -> u32 {
self.0.next_u32()
}
fn next_u64(&mut self) -> u64 {
self.0.next_u64()
}
fn fill_bytes(&mut self, dest: &mut [u8]) {
self.0.fill_bytes(dest)
}
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand::Error> {
self.0.try_fill_bytes(dest)
}
}
impl rand::CryptoRng for TestRng {}