use core::char;
use core::num::Wrapping;
use crate::distributions::{Distribution, Standard, Uniform};
use crate::Rng;
#[cfg(feature = "serde1")]
use serde::{Serialize, Deserialize};
#[derive(Debug)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct Alphanumeric;
impl Distribution<char> for Standard {
#[inline]
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> char {
const GAP_SIZE: u32 = 0xDFFF - 0xD800 + 1;
let range = Uniform::new(GAP_SIZE, 0x11_0000);
let mut n = range.sample(rng);
if n <= 0xDFFF {
n -= GAP_SIZE;
}
unsafe { char::from_u32_unchecked(n) }
}
}
impl Distribution<u8> for Alphanumeric {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u8 {
const RANGE: u32 = 26 + 26 + 10;
const GEN_ASCII_STR_CHARSET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
abcdefghijklmnopqrstuvwxyz\
0123456789";
loop {
let var = rng.next_u32() >> (32 - 6);
if var < RANGE {
return GEN_ASCII_STR_CHARSET[var as usize];
}
}
}
}
impl Distribution<bool> for Standard {
#[inline]
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> bool {
(rng.next_u32() as i32) < 0
}
}
macro_rules! tuple_impl {
($($tyvar:ident),* ) => {
impl< $( $tyvar ),* >
Distribution<( $( $tyvar ),* , )>
for Standard
where $( Standard: Distribution<$tyvar> ),*
{
#[inline]
fn sample<R: Rng + ?Sized>(&self, _rng: &mut R) -> ( $( $tyvar ),* , ) {
(
$(
_rng.gen::<$tyvar>()
),*
,
)
}
}
}
}
impl Distribution<()> for Standard {
#[allow(clippy::unused_unit)]
#[inline]
fn sample<R: Rng + ?Sized>(&self, _: &mut R) -> () {
()
}
}
tuple_impl! {A}
tuple_impl! {A, B}
tuple_impl! {A, B, C}
tuple_impl! {A, B, C, D}
tuple_impl! {A, B, C, D, E}
tuple_impl! {A, B, C, D, E, F}
tuple_impl! {A, B, C, D, E, F, G}
tuple_impl! {A, B, C, D, E, F, G, H}
tuple_impl! {A, B, C, D, E, F, G, H, I}
tuple_impl! {A, B, C, D, E, F, G, H, I, J}
tuple_impl! {A, B, C, D, E, F, G, H, I, J, K}
tuple_impl! {A, B, C, D, E, F, G, H, I, J, K, L}
macro_rules! array_impl {
{$n:expr, $t:ident, $($ts:ident,)*} => {
array_impl!{($n - 1), $($ts,)*}
impl<T> Distribution<[T; $n]> for Standard where Standard: Distribution<T> {
#[inline]
fn sample<R: Rng + ?Sized>(&self, _rng: &mut R) -> [T; $n] {
[_rng.gen::<$t>(), $(_rng.gen::<$ts>()),*]
}
}
};
{$n:expr,} => {
impl<T> Distribution<[T; $n]> for Standard {
fn sample<R: Rng + ?Sized>(&self, _rng: &mut R) -> [T; $n] { [] }
}
};
}
array_impl! {32, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,}
impl<T> Distribution<Option<T>> for Standard
where Standard: Distribution<T>
{
#[inline]
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Option<T> {
if rng.gen::<bool>() {
Some(rng.gen())
} else {
None
}
}
}
impl<T> Distribution<Wrapping<T>> for Standard
where Standard: Distribution<T>
{
#[inline]
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Wrapping<T> {
Wrapping(rng.gen())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::RngCore;
#[cfg(feature = "alloc")] use alloc::string::String;
#[test]
fn test_misc() {
let rng: &mut dyn RngCore = &mut crate::test::rng(820);
rng.sample::<char, _>(Standard);
rng.sample::<bool, _>(Standard);
}
#[cfg(feature = "alloc")]
#[test]
fn test_chars() {
use core::iter;
let mut rng = crate::test::rng(805);
let word: String = iter::repeat(())
.map(|()| rng.gen::<char>())
.take(1000)
.collect();
assert!(word.len() != 0);
}
#[test]
fn test_alphanumeric() {
let mut rng = crate::test::rng(806);
let mut incorrect = false;
for _ in 0..100 {
let c: char = rng.sample(Alphanumeric).into();
incorrect |= !((c >= '0' && c <= '9') ||
(c >= 'A' && c <= 'Z') ||
(c >= 'a' && c <= 'z') );
}
assert!(incorrect == false);
}
#[test]
fn value_stability() {
fn test_samples<T: Copy + core::fmt::Debug + PartialEq, D: Distribution<T>>(
distr: &D, zero: T, expected: &[T],
) {
let mut rng = crate::test::rng(807);
let mut buf = [zero; 5];
for x in &mut buf {
*x = rng.sample(&distr);
}
assert_eq!(&buf, expected);
}
test_samples(&Standard, 'a', &[
'\u{8cdac}',
'\u{a346a}',
'\u{80120}',
'\u{ed692}',
'\u{35888}',
]);
test_samples(&Alphanumeric, 0, &[104, 109, 101, 51, 77]);
test_samples(&Standard, false, &[true, true, false, true, false]);
test_samples(&Standard, None as Option<bool>, &[
Some(true),
None,
Some(false),
None,
Some(false),
]);
test_samples(&Standard, Wrapping(0i32), &[
Wrapping(-2074640887),
Wrapping(-1719949321),
Wrapping(2018088303),
Wrapping(-547181756),
Wrapping(838957336),
]);
test_samples(&Standard, (), &[(), (), (), (), ()]);
test_samples(&Standard, (false,), &[
(true,),
(true,),
(false,),
(true,),
(false,),
]);
test_samples(&Standard, (false, false), &[
(true, true),
(false, true),
(false, false),
(true, false),
(false, false),
]);
test_samples(&Standard, [0u8; 0], &[[], [], [], [], []]);
test_samples(&Standard, [0u8; 3], &[
[9, 247, 111],
[68, 24, 13],
[174, 19, 194],
[172, 69, 213],
[149, 207, 29],
]);
}
}