use std::collections::hash_map::RandomState;
use std::hash::BuildHasher;
use std::hash::Hasher;
pub fn fill_bytes<F>(buffer: &mut [u8], mut rng: F)
where
F: FnMut() -> u64,
{
if buffer.is_empty() {
return; }
for chunk in buffer.chunks_mut(8) {
let random_bytes = rng().to_le_bytes();
chunk.copy_from_slice(&random_bytes[..chunk.len()]);
}
}
pub fn fill_numbers<T, F>(buffer: &mut [T], mut rng: F)
where
F: FnMut() -> T,
T: Copy, {
for item in buffer.iter_mut() {
*item = rng();
}
}
pub fn fast_u64() -> u64 {
let s = RandomState::new();
let hasher = s.build_hasher();
hasher.finish()
}
pub fn fast_u32() -> u32 {
let s = RandomState::new();
let hasher = s.build_hasher();
(hasher.finish() & 0xFFFFFFFF) as u32
}
pub fn fast_f32() -> f32 {
let s = RandomState::new();
let hasher = s.build_hasher();
(hasher.finish() as f32) / (u64::MAX as f32)
}
pub fn fast_f64() -> f64 {
let s = RandomState::new();
let hasher = s.build_hasher();
(hasher.finish() as f64) / (u64::MAX as f64)
}
pub fn random_f64() -> f64 {
(random_u64() as f64) / (u64::MAX as f64)
}
pub fn random_f32() -> f32 {
(random_u64() as f32) / (u64::MAX as f32)
}
pub fn random_u64() -> u64 {
let handle = std::thread::spawn(|| fast_u64());
match handle.join() {
Ok(randomness) => randomness, Err(_) => {
fast_u64()
}
}
}
pub fn random_u32() -> u32 {
(random_u64() & 0xFFFFFFFF) as u32
}
use std::convert::TryFrom;
use std::ops::{Bound, RangeBounds};
#[track_caller]
pub fn gen_range<R, F, T>(range: R, mut rng: F) -> T
where
R: RangeBounds<u64>,
F: FnMut() -> u64,
T: TryFrom<u64> + 'static, {
#[track_caller]
fn convert_to_t<T>(final_result: u64) -> T
where
T: TryFrom<u64> + 'static,
{
match T::try_from(final_result) {
Ok(value) => value,
Err(_) => panic!(
"Conversion failed: Cannot convert {} into target type {}",
final_result,
std::any::type_name::<T>()
),
}
}
let start = match range.start_bound() {
Bound::Included(s) => *s,
_ => panic!("Invalid range: Start must be included."),
};
let (end, is_inclusive) = match range.end_bound() {
Bound::Included(e) => (*e, true),
Bound::Excluded(e) => (*e, false),
_ => panic!("Invalid range: End must be bounded."),
};
if end < start {
panic!("Invalid range: End must be greater than or equal to start.");
}
let range_size = if is_inclusive {
if end == u64::MAX {
if start == 0 {
u64::MAX
} else {
u64::MAX - start + 1
}
} else {
end - start + 1
}
} else {
end - start
};
if range_size == 0 {
panic!("Invalid range: Cannot generate a number from an empty range.");
}
let raw_random = rng();
let mapped_to_zero_based_range = raw_random % range_size;
let final_result = start + mapped_to_zero_based_range;
convert_to_t(final_result)
}
#[cfg(test)]
mod basic_tests;
#[cfg(test)]
mod generator_tests;
#[cfg(test)]
mod overflow_tests;