use core::{array, char, num};
use super::*;
#[derive(Copy, Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct StandardUniform;
macro_rules! impl_standard_dist {
($ty:ty, $rand:ident => $e:expr) => {
impl Distribution<$ty> for StandardUniform {
#[inline]
fn sample<R: Rng + ?Sized>(&self, $rand: &mut Random<R>) -> $ty { $e }
}
};
}
impl_standard_dist! { bool, rand => (rand.next_u32() as i32) < 0 }
impl_standard_dist! { i8, rand => rand.next_u32() as i8 }
impl_standard_dist! { u8, rand => rand.next_u32() as u8 }
impl_standard_dist! { i16, rand => rand.next_u32() as i16 }
impl_standard_dist! { u16, rand => rand.next_u32() as u16 }
impl_standard_dist! { i32, rand => rand.next_u32() as i32 }
impl_standard_dist! { u32, rand => rand.next_u32() as u32 }
impl_standard_dist! { i64, rand => rand.next_u64() as i64 }
impl_standard_dist! { u64, rand => rand.next_u64() as u64 }
impl_standard_dist! { i128, rand => { let low = rand.next_u64() as i128; let high = rand.next_u64() as i128; low | high << 64 } }
impl_standard_dist! { u128, rand => { let low = rand.next_u64() as u128; let high = rand.next_u64() as u128; low | high << 64 } }
#[cfg(target_pointer_width = "32")]
impl_standard_dist! { isize, rand => rand.next_u32() as isize }
#[cfg(target_pointer_width = "32")]
impl_standard_dist! { usize, rand => rand.next_u32() as usize }
#[cfg(target_pointer_width = "64")]
impl_standard_dist! { isize, rand => rand.next_u64() as isize }
#[cfg(target_pointer_width = "64")]
impl_standard_dist! { usize, rand => rand.next_u64() as usize }
impl_standard_dist! { f32, rand => rand.next_f32() }
impl_standard_dist! { f64, rand => rand.next_f64() }
impl Distribution<char> for StandardUniform {
#[inline]
fn sample<R: Rng + ?Sized>(&self, rand: &mut Random<R>) -> char {
const GAP_SIZE: u32 = 0xE000 - 0xD800;
let range = Uniform::new(GAP_SIZE, 0x11_0000);
let mut n = range.sample(rand);
if n < 0xE000 {
n -= GAP_SIZE;
}
#[cfg(debug_assertions)]
return char::from_u32(n).unwrap();
#[cfg(not(debug_assertions))]
#[allow(unsafe_code)]
return unsafe { char::from_u32_unchecked(n) };
}
}
impl<T> Distribution<num::Wrapping<T>> for num::Wrapping<T> where StandardUniform: Distribution<T> {
#[inline]
fn sample<R: Rng + ?Sized>(&self, rand: &mut Random<R>) -> num::Wrapping<T> {
num::Wrapping(StandardUniform.sample(rand))
}
}
macro_rules! impl_nzint {
($name:ident) => {
impl Distribution<num::$name> for StandardUniform {
#[inline]
fn sample<R: Rng + ?Sized>(&self, rand: &mut Random<R>) -> num::$name {
loop {
if let Some(nz) = num::$name::new(rand.next()) {
break nz;
}
}
}
}
};
}
impl_nzint!(NonZeroU8);
impl_nzint!(NonZeroU16);
impl_nzint!(NonZeroU32);
impl_nzint!(NonZeroU64);
impl_nzint!(NonZeroU128);
impl_nzint!(NonZeroUsize);
macro_rules! impl_standard_dist_tuple {
($($T:ident),*) => {
impl<$($T),*> Distribution<($($T,)*)> for StandardUniform where $(StandardUniform: Distribution<$T>),* {
#[inline]
fn sample<R: Rng + ?Sized>(&self, _rng: &mut Random<R>) -> ($($T,)*) {
($(<StandardUniform as Distribution<$T>>::sample(&StandardUniform, _rng),)*)
}
}
};
}
impl_standard_dist_tuple!();
impl_standard_dist_tuple!(A);
impl_standard_dist_tuple!(A, B);
impl_standard_dist_tuple!(A, B, C);
impl_standard_dist_tuple!(A, B, C, D);
impl_standard_dist_tuple!(A, B, C, D, E);
impl_standard_dist_tuple!(A, B, C, D, E, F);
impl_standard_dist_tuple!(A, B, C, D, E, F, G);
impl_standard_dist_tuple!(A, B, C, D, E, F, G, H);
impl_standard_dist_tuple!(A, B, C, D, E, F, G, H, I);
impl_standard_dist_tuple!(A, B, C, D, E, F, G, H, I, J);
impl_standard_dist_tuple!(A, B, C, D, E, F, G, H, I, J, K);
impl_standard_dist_tuple!(A, B, C, D, E, F, G, H, I, J, K, L);
impl<T, const N: usize> Distribution<[T; N]> for StandardUniform where StandardUniform: Distribution<T> {
#[inline]
fn sample<R: Rng + ?Sized>(&self, rand: &mut Random<R>) -> [T; N] {
array::from_fn(move |_| <StandardUniform as Distribution<T>>::sample(&StandardUniform, rand))
}
}
#[test]
fn test_arrays() {
let mut rand = crate::new();
let _: [i8; 0] = rand.sample(&StandardUniform);
let _: [u8; 1] = rand.sample(&StandardUniform);
let _: [i16; 13] = rand.sample(&StandardUniform);
let _: [u16; 14] = rand.sample(&StandardUniform);
let _: [i32; 20] = rand.sample(&StandardUniform);
let _: [u32; 21] = rand.sample(&StandardUniform);
let _: [u64; 31] = rand.sample(&StandardUniform);
let _: [i64; 78] = rand.sample(&StandardUniform);
let _: [isize; 8] = rand.sample(&StandardUniform);
let _: [usize; 9] = rand.sample(&StandardUniform);
}
#[test]
fn test_nzint() {
let mut rand = crate::new();
for _ in 0..9000 {
let _: num::NonZeroU32 = rand.sample(&StandardUniform);
}
}
#[test]
fn test_char() {
let mut rand = crate::new();
for _ in 0..9000 {
let _: char = rand.sample(&StandardUniform);
}
}
#[test]
fn test_bool() {
let mut rand = crate::new();
const N: usize = 10000;
let mut results = [0i32; 2];
for _ in 0..N {
results[rand.coin_flip() as usize] += 1;
}
let [tails, heads] = results;
assert!((tails - heads).abs() < 1000, "Unbalanced coin flips!! heads = {heads}, tails = {tails} out of {N} trails ");
}