#[cfg(feature = "alloc")]
use alloc::string::String;
use core::array;
use core::char;
use core::num::Wrapping;
use crate::Rng;
#[cfg(feature = "alloc")]
use crate::distr::SampleString;
use crate::distr::{Distribution, StandardUniform, Uniform};
#[cfg(feature = "simd_support")]
use core::simd::prelude::*;
#[cfg(feature = "simd_support")]
use core::simd::{LaneCount, MaskElement, SupportedLaneCount};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, Default)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Alphanumeric;
#[derive(Debug, Clone, Copy, Default)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Alphabetic;
impl Distribution<char> for StandardUniform {
#[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).unwrap();
let mut n = range.sample(rng);
if n <= 0xDFFF {
n -= GAP_SIZE;
}
unsafe { char::from_u32_unchecked(n) }
}
}
#[cfg(feature = "alloc")]
impl SampleString for StandardUniform {
fn append_string<R: Rng + ?Sized>(&self, rng: &mut R, s: &mut String, len: usize) {
s.reserve(4 * len);
s.extend(Distribution::<char>::sample_iter(self, rng).take(len));
}
}
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<u8> for Alphabetic {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u8 {
const RANGE: u8 = 26 + 26;
let offset = rng.random_range(0..RANGE) + b'A';
offset + (offset > b'Z') as u8 * (b'a' - b'Z' - 1)
}
}
#[cfg(feature = "alloc")]
impl SampleString for Alphanumeric {
fn append_string<R: Rng + ?Sized>(&self, rng: &mut R, string: &mut String, len: usize) {
unsafe {
let v = string.as_mut_vec();
v.extend(
self.sample_iter(rng)
.take(len)
.inspect(|b| debug_assert!(b.is_ascii_alphanumeric())),
);
}
}
}
#[cfg(feature = "alloc")]
impl SampleString for Alphabetic {
fn append_string<R: Rng + ?Sized>(&self, rng: &mut R, string: &mut String, len: usize) {
unsafe {
let v = string.as_mut_vec();
v.reserve_exact(len);
v.extend(self.sample_iter(rng).take(len));
}
}
}
impl Distribution<bool> for StandardUniform {
#[inline]
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> bool {
(rng.next_u32() as i32) < 0
}
}
#[cfg(feature = "simd_support")]
impl<T, const LANES: usize> Distribution<Mask<T, LANES>> for StandardUniform
where
T: MaskElement + Default,
LaneCount<LANES>: SupportedLaneCount,
StandardUniform: Distribution<Simd<T, LANES>>,
Simd<T, LANES>: SimdPartialOrd<Mask = Mask<T, LANES>>,
{
#[inline]
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Mask<T, LANES> {
let var = rng.random::<Simd<T, LANES>>();
var.simd_lt(Simd::default())
}
}
macro_rules! tuple_impl {
($($tyvar:ident)*) => {
impl< $($tyvar,)* > Distribution<($($tyvar,)*)> for StandardUniform
where $(
StandardUniform: Distribution< $tyvar >,
)*
{
#[inline]
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> ( $($tyvar,)* ) {
let out = ($(
rng.random::<$tyvar>()
,)*);
let _rng = rng;
out
}
}
}
}
macro_rules! tuple_impls {
($($tyvar:ident)*) => {tuple_impls!{[] $($tyvar)*}};
([$($prefix:ident)*] $head:ident $($tail:ident)*) => {
tuple_impl!{$($prefix)*}
tuple_impls!{[$($prefix)* $head] $($tail)*}
};
([$($prefix:ident)*]) => {
tuple_impl!{$($prefix)*}
};
}
tuple_impls! {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, rng: &mut R) -> [T; N] {
array::from_fn(|_| rng.random())
}
}
impl<T> Distribution<Wrapping<T>> for StandardUniform
where
StandardUniform: Distribution<T>,
{
#[inline]
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Wrapping<T> {
Wrapping(rng.random())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::RngCore;
#[test]
fn test_misc() {
let rng: &mut dyn RngCore = &mut crate::test::rng(820);
rng.sample::<char, _>(StandardUniform);
rng.sample::<bool, _>(StandardUniform);
}
#[cfg(feature = "alloc")]
#[test]
fn test_chars() {
use core::iter;
let mut rng = crate::test::rng(805);
let word: String = iter::repeat(())
.map(|()| rng.random::<char>())
.take(1000)
.collect();
assert!(!word.is_empty());
}
#[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.is_ascii_alphanumeric();
}
assert!(!incorrect);
}
#[test]
fn test_alphabetic() {
let mut rng = crate::test::rng(806);
let mut incorrect = false;
for _ in 0..100 {
let c: char = rng.sample(Alphabetic).into();
incorrect |= !c.is_ascii_alphabetic();
}
assert!(!incorrect);
}
#[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(
&StandardUniform,
'a',
&[
'\u{8cdac}',
'\u{a346a}',
'\u{80120}',
'\u{ed692}',
'\u{35888}',
],
);
test_samples(&Alphanumeric, 0, &[104, 109, 101, 51, 77]);
test_samples(&Alphabetic, 0, &[97, 102, 89, 116, 75]);
test_samples(&StandardUniform, false, &[true, true, false, true, false]);
test_samples(
&StandardUniform,
Wrapping(0i32),
&[
Wrapping(-2074640887),
Wrapping(-1719949321),
Wrapping(2018088303),
Wrapping(-547181756),
Wrapping(838957336),
],
);
test_samples(&StandardUniform, (), &[(), (), (), (), ()]);
test_samples(
&StandardUniform,
(false,),
&[(true,), (true,), (false,), (true,), (false,)],
);
test_samples(
&StandardUniform,
(false, false),
&[
(true, true),
(false, true),
(false, false),
(true, false),
(false, false),
],
);
test_samples(&StandardUniform, [0u8; 0], &[[], [], [], [], []]);
test_samples(
&StandardUniform,
[0u8; 3],
&[
[9, 247, 111],
[68, 24, 13],
[174, 19, 194],
[172, 69, 213],
[149, 207, 29],
],
);
}
}