use core::ops::{Bound, RangeBounds};
#[cfg(all(feature = "alloc", not(feature = "std")))]
use alloc::{boxed::Box, vec::Vec};
use crate::internal::uniform::IncreasingUniformIter;
pub enum TurboKind {
FAST,
SLOW,
}
pub trait TurboCore {
fn fill_bytes(&self, buffer: &mut [u8]);
}
pub trait GenCore: TurboCore {
const GEN_KIND: TurboKind;
fn gen<const SIZE: usize>(&self) -> [u8; SIZE];
gen_int_const!(gen_u128, u128, "Returns a random `u128` value.");
gen_int_const!(gen_i128, i128, "Returns a random `i128` value.");
gen_int_const!(gen_u64, u64, "Returns a random `u64` value.");
gen_int_const!(gen_i64, i64, "Returns a random `i64` value.");
gen_int_const!(gen_u32, u32, "Returns a random `u32` value.");
gen_int_const!(gen_i32, i32, "Returns a random `i32` value.");
gen_int_const!(gen_u16, u16, "Returns a random `u16` value.");
gen_int_const!(gen_i16, i16, "Returns a random `i16` value.");
gen_int_const!(gen_u8, u8, "Returns a random `u8` value.");
gen_int_const!(gen_i8, i8, "Returns a random `i8` value.");
gen_int_const!(gen_usize, usize, "Returns a random `usize` value.");
gen_int_const!(gen_isize, isize, "Returns a random `isize` value.");
}
pub trait SeededCore: TurboCore {
type Seed: Sized;
fn with_seed(seed: Self::Seed) -> Self;
fn reseed(&self, seed: Self::Seed);
}
pub trait SecureCore: TurboCore {}
pub trait TurboRand: TurboCore + GenCore {
#[inline]
fn u128(&self, bounds: impl RangeBounds<u128>) -> u128 {
let lower = match bounds.start_bound() {
Bound::Included(lower) => *lower,
Bound::Excluded(lower) => lower.saturating_add(1),
Bound::Unbounded => u128::MIN,
};
let upper = match bounds.end_bound() {
Bound::Included(upper) => *upper,
Bound::Excluded(upper) => upper.saturating_sub(1),
Bound::Unbounded => u128::MAX,
};
assert!(lower <= upper, "Range should not be zero sized or invalid");
match (lower, upper) {
(u128::MIN, u128::MAX) => self.gen_u128(),
(_, _) => {
let range = upper.wrapping_sub(lower).wrapping_add(1);
let mut value = self.gen_u128();
let mut high = multiply_high_u128(value, range);
let mut low = value.wrapping_mul(range);
if low < range {
let t = range.wrapping_neg() % range;
while low < t {
value = self.gen_u128();
high = multiply_high_u128(value, range);
low = value.wrapping_mul(range);
}
}
lower.wrapping_add(high)
}
}
}
#[inline]
fn i128(&self, bounds: impl RangeBounds<i128>) -> i128 {
let lower = match bounds.start_bound() {
Bound::Included(lower) => *lower,
Bound::Excluded(lower) => lower.saturating_add(1),
Bound::Unbounded => i128::MIN,
};
let upper = match bounds.end_bound() {
Bound::Included(upper) => *upper,
Bound::Excluded(upper) => upper.saturating_sub(1),
Bound::Unbounded => i128::MAX,
};
assert!(lower <= upper, "Range should not be zero sized or invalid");
match (lower, upper) {
(i128::MIN, i128::MAX) => self.gen_i128(),
(_, _) => {
let range = upper.wrapping_sub(lower).wrapping_add(1) as u128;
let mut value = self.gen_u128();
let mut high = multiply_high_u128(value, range);
let mut low = value.wrapping_mul(range);
if low < range {
let t = range.wrapping_neg() % range;
while low < t {
value = self.gen_u128();
high = multiply_high_u128(value, range);
low = value.wrapping_mul(range);
}
}
lower.wrapping_add(high as i128)
}
}
}
trait_range_int!(u64, u64, u128, gen_u64, "Returns a random `u64` value.");
trait_range_int!(i64, u64, u128, gen_i64, "Returns a random `i64` value.");
trait_range_int!(u32, u32, u64, gen_u32, "Returns a random `u32` value.");
trait_range_int!(i32, u32, u64, gen_i32, "Returns a random `i32` value.");
trait_range_int!(u16, u16, u32, gen_u16, "Returns a random `u16` value.");
trait_range_int!(i16, u16, u32, gen_i16, "Returns a random `i16` value.");
trait_range_int!(u8, u8, u16, gen_u8, "Returns a random `u8` value.");
trait_range_int!(i8, u8, u16, gen_i8, "Returns a random `i8` value.");
#[cfg(target_pointer_width = "16")]
trait_range_int!(
usize,
u16,
u32,
gen_usize,
"Returns a random `usize` within a given range bound."
);
#[cfg(target_pointer_width = "32")]
trait_range_int!(
usize,
u32,
u64,
gen_usize,
"Returns a random `usize` within a given range bound."
);
#[cfg(target_pointer_width = "64")]
trait_range_int!(
usize,
u64,
u128,
gen_usize,
"Returns a random `usize` within a given range bound."
);
#[cfg(target_pointer_width = "16")]
trait_range_int!(
isize,
u16,
u32,
gen_isize,
"Returns a random `isize` within a given range bound."
);
#[cfg(target_pointer_width = "32")]
trait_range_int!(
isize,
u32,
u64,
gen_isize,
"Returns a random `isize` within a given range bound."
);
#[cfg(target_pointer_width = "64")]
trait_range_int!(
isize,
u64,
u128,
gen_isize,
"Returns a random `isize` within a given range bound."
);
trait_float_gen!(
f32,
f32,
u32,
1.0,
gen_u32,
"Returns a random `f32` value between `0.0` and `1.0`."
);
trait_float_gen!(
f32_normalized,
f32,
i32,
2.0,
gen_i32,
"Returns a random `f32` value between `-1.0` and `1.0`."
);
trait_float_gen!(
f64,
f64,
u64,
1.0,
gen_u64,
"Returns a random `f32` value between `0.0` and `1.0`."
);
trait_float_gen!(
f64_normalized,
f64,
i64,
2.0,
gen_i64,
"Returns a random `f32` value between `-1.0` and `1.0`."
);
#[inline]
fn index(&self, bound: impl RangeBounds<usize>) -> usize {
let lower = match bound.start_bound() {
Bound::Included(&val) => val as u64,
Bound::Excluded(&val) => val.saturating_add(1) as u64,
Bound::Unbounded => 0,
};
let upper = match bound.end_bound() {
Bound::Included(&val) => val as u64,
Bound::Excluded(&val) => val.saturating_sub(1) as u64,
Bound::Unbounded => usize::MAX as u64,
};
self.u64(lower..=upper) as usize
}
#[inline]
fn bool(&self) -> bool {
self.gen_u8() % 2 == 0
}
#[inline]
fn chance(&self, rate: f64) -> bool {
const SCALE: f64 = 2.0 * (1u64 << 63) as f64;
assert!(
(0.0..=1.0).contains(&rate),
"rate value is not between 0.0 and 1.0, received {rate}",
);
let rate_int = (rate * SCALE) as u64;
match rate_int {
u64::MAX => true,
0 => false,
_ => self.gen_u64() < rate_int,
}
}
#[inline]
fn sample<'a, T>(&self, list: &'a [T]) -> Option<&'a T> {
self.sample_iter(list.iter())
}
#[inline]
fn sample_iter<T: Iterator>(&self, mut list: T) -> Option<T::Item> {
let (mut lower, mut upper) = list.size_hint();
if upper == Some(lower) {
return match lower {
0 => None,
1 => list.next(),
_ => list.nth(self.index(..lower)),
};
}
let mut result = None;
let mut consumed = 0;
loop {
if lower > 1 {
let index = self.index(..(lower + consumed));
let skip = if index < lower {
result = list.nth(index);
lower - (index + 1)
} else {
lower
};
if upper == Some(lower) {
return result;
}
consumed += lower;
if skip > 0 {
list.nth(skip - 1);
}
} else {
let elem = list.next();
if elem.is_none() {
return result;
}
consumed += 1;
match consumed {
1 => {
result = elem;
}
_ => {
if self.index(..consumed) == 0 {
result = elem;
}
}
};
}
let hint = list.size_hint();
lower = hint.0;
upper = hint.1;
}
}
#[inline]
fn sample_mut<'a, T>(&self, list: &'a mut [T]) -> Option<&'a mut T> {
self.sample_iter(list.iter_mut())
}
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
#[inline]
fn sample_multiple<'a, T>(&self, list: &'a [T], amount: usize) -> Vec<&'a T> {
self.sample_multiple_iter(list.iter(), amount)
}
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
#[inline]
fn sample_multiple_mut<'a, T>(&self, list: &'a mut [T], amount: usize) -> Vec<&'a mut T> {
self.sample_multiple_iter(list.iter_mut(), amount)
}
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
#[inline]
fn sample_multiple_iter<T: Iterator>(&self, mut list: T, amount: usize) -> Vec<T::Item> {
let mut sampled = Vec::with_capacity(amount);
sampled.extend(list.by_ref().take(amount));
if sampled.len() == amount {
list.enumerate()
.map(|(index, elem)| {
let len = index + amount;
(self.index(..=len), elem)
})
.for_each(|(slot_index, elem)| {
if let Some(slot) = sampled.get_mut(slot_index) {
*slot = elem;
}
});
} else {
sampled.shrink_to_fit();
}
sampled
}
#[inline]
fn weighted_sample<'a, T, F>(&self, list: &'a [T], weight_sampler: F) -> Option<&'a T>
where
F: Fn((&T, usize)) -> f64,
{
match list.len() {
0 => None,
1 => list.first(),
len => loop {
let index = self.index(..len);
if let Some(item) = list.get(index) {
if self.chance(weight_sampler((item, index))) {
return Some(item);
}
}
},
}
}
#[inline]
fn weighted_sample_mut<'a, T, F>(
&self,
list: &'a mut [T],
weight_sampler: F,
) -> Option<&'a mut T>
where
F: Fn((&T, usize)) -> f64,
{
match list.len() {
0 => None,
1 => list.first_mut(),
len => loop {
let index = self.index(..len);
if let Some(item) = list.get(index) {
if self.chance(weight_sampler((item, index))) {
return list.get_mut(index);
}
}
},
}
}
#[inline]
fn shuffle<T>(&self, slice: &mut [T]) {
match slice.len() {
len if len < 2 => (),
len => {
self.partial_shuffle(slice, len);
}
}
}
#[inline]
fn partial_shuffle<'a, T>(
&self,
slice: &'a mut [T],
amount: usize,
) -> (&'a mut [T], &'a mut [T]) {
let len = slice.len();
assert!(len > 1);
let n = len.saturating_sub(amount);
match Self::GEN_KIND {
TurboKind::FAST => {
((n.max(1))..len)
.rev()
.for_each(|index| slice.swap(index, self.index(..=index)));
}
TurboKind::SLOW => {
IncreasingUniformIter::new(self, n as u64, len)
.for_each(|(current_index, swap_index)| slice.swap(current_index, swap_index));
}
};
let res = slice.split_at_mut(n);
(res.1, res.0)
}
trait_rand_chars!(
alphabetic,
b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
"Generates a random `char` in ranges a-z and A-Z."
);
trait_rand_chars!(
alphanumeric,
b"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
"Generates a random `char` in ranges a-z, A-Z and 0-9."
);
trait_rand_chars!(
lowercase,
b"abcdefghijklmnopqrstuvwxyz",
"Generates a random `char` in the range a-z."
);
trait_rand_chars!(
uppercase,
b"ABCDEFGHIJKLMNOPQRSTUVWXYZ",
"Generates a random `char` in the range A-Z."
);
#[inline]
fn digit(&self, radix: u8) -> char {
match radix {
0 => panic!("radix cannot be zero"),
1..=36 => {
let num = self.u8(..radix);
if num < 10 {
(b'0' + num) as char
} else {
(b'a' + num - 10) as char
}
}
_ => panic!("radix cannot be greater than 36"),
}
}
#[inline]
fn char(&self, bounds: impl RangeBounds<char>) -> char {
const SURROGATE_START: u32 = 0xd800u32;
const SURROGATE_LENGTH: u32 = 0x800u32;
let lower = match bounds.start_bound() {
Bound::Unbounded => 0u8 as char,
Bound::Included(&x) => x,
Bound::Excluded(&x) => {
let scalar = if x as u32 == SURROGATE_START - 1 {
SURROGATE_START + SURROGATE_LENGTH
} else {
x as u32 + 1
};
char::from_u32(scalar).expect("Invalid exclusive lower character bound")
}
};
let upper = match bounds.end_bound() {
Bound::Unbounded => char::MAX,
Bound::Included(&x) => x,
Bound::Excluded(&x) => {
let scalar = if x as u32 == SURROGATE_START + SURROGATE_LENGTH {
SURROGATE_START - 1
} else {
(x as u32).wrapping_sub(1)
};
char::from_u32(scalar).expect("Invalid exclusive upper character bound")
}
};
assert!(upper >= lower, "Invalid character range");
let lower_scalar = lower as u32;
let upper_scalar = upper as u32;
let gap = if lower_scalar < SURROGATE_START && upper_scalar >= SURROGATE_START {
SURROGATE_LENGTH
} else {
0
};
let range = upper_scalar - gap;
let mut val = self.u32(lower_scalar..=range);
if val >= SURROGATE_START {
val += gap;
}
char::from_u32(val).unwrap()
}
}
pub trait ForkableCore: TurboCore {
fn fork(&self) -> Self;
}
impl<T: TurboCore + GenCore + ?Sized> TurboRand for T {}
#[cfg(feature = "alloc")]
impl<T: TurboCore + ?Sized> TurboCore for Box<T> {
#[inline(always)]
fn fill_bytes(&self, buffer: &mut [u8]) {
(**self).fill_bytes(buffer);
}
}
#[cfg(feature = "alloc")]
impl<T: GenCore + ?Sized> GenCore for Box<T> {
const GEN_KIND: TurboKind = T::GEN_KIND;
#[inline(always)]
fn gen<const SIZE: usize>(&self) -> [u8; SIZE] {
(**self).gen()
}
}
impl<'a, T: TurboCore + ?Sized> TurboCore for &'a T {
#[inline(always)]
fn fill_bytes(&self, buffer: &mut [u8]) {
(**self).fill_bytes(buffer);
}
}
impl<'a, T: GenCore + ?Sized> GenCore for &'a T {
const GEN_KIND: TurboKind = T::GEN_KIND;
#[inline(always)]
fn gen<const SIZE: usize>(&self) -> [u8; SIZE] {
(**self).gen()
}
}
impl<'a, T: TurboCore + ?Sized> TurboCore for &'a mut T {
#[inline(always)]
fn fill_bytes(&self, buffer: &mut [u8]) {
(**self).fill_bytes(buffer);
}
}
impl<'a, T: GenCore + ?Sized> GenCore for &'a mut T {
const GEN_KIND: TurboKind = T::GEN_KIND;
#[inline(always)]
fn gen<const SIZE: usize>(&self) -> [u8; SIZE] {
(**self).gen()
}
}
#[cfg(feature = "alloc")]
impl<T: TurboCore + SecureCore + ?Sized> SecureCore for Box<T> {}
#[inline]
fn multiply_high_u128(a: u128, b: u128) -> u128 {
let a_low = a as u64 as u128;
let a_high = (a >> 64) as u64 as u128;
let b_low = b as u64 as u128;
let b_high = (b >> 64) as u64 as u128;
let carry = (a_low * b_low) >> 64;
let a_high_x_b_low = a_high * b_low;
let a_low_x_b_high = a_low * b_high;
let carry = (a_high_x_b_low as u64 as u128 + a_low_x_b_high as u64 as u128 + carry) >> 64;
a_high * b_high + (a_high_x_b_low >> 64) + (a_low_x_b_high >> 64) + carry
}
#[cfg(test)]
mod tests {
use core::cell::Cell;
use super::*;
struct TestRng(Cell<u8>);
impl TestRng {
fn new() -> Self {
Self(Cell::new(0))
}
fn next(&self) -> u8 {
let value = self.0.get();
self.0.set(value.wrapping_add(1));
value
}
}
impl TurboCore for TestRng {
fn fill_bytes(&self, buffer: &mut [u8]) {
buffer.iter_mut().for_each(|slot| *slot = self.next());
}
}
impl GenCore for TestRng {
const GEN_KIND: TurboKind = TurboKind::FAST;
fn gen<const SIZE: usize>(&self) -> [u8; SIZE] {
core::array::from_fn(|_| self.next())
}
}
impl SeededCore for TestRng {
type Seed = u8;
fn with_seed(seed: Self::Seed) -> Self {
Self(Cell::new(seed))
}
fn reseed(&self, seed: Self::Seed) {
self.0.set(seed);
}
}
#[test]
fn auto_trait_application() {
let rng = TestRng::new();
fn use_rng<T: TurboRand>(source: &T) -> u8 {
source.u8(..)
}
let value = use_rng(&rng);
assert_eq!(value, 0);
}
#[test]
fn seeded_methods() {
let rng = TestRng::with_seed(5);
fn test_seeded_methods<T: GenCore + SeededCore>(source: &T)
where
T: SeededCore<Seed = u8>,
{
let values = source.gen();
assert_eq!(&values, &[5, 6, 7]);
source.reseed(3);
let values = source.gen();
assert_eq!(&values, &[3, 4, 5]);
}
test_seeded_methods(&rng);
}
#[cfg(feature = "alloc")]
#[test]
fn object_safe_core() {
let rng = Box::new(TestRng::with_seed(1));
fn test_dyn_rng(rng: Box<dyn TurboCore>) {
let mut buffer = [0u8; 3];
rng.fill_bytes(&mut buffer);
assert_eq!(&buffer, &[1, 2, 3]);
}
test_dyn_rng(rng);
}
#[cfg(feature = "alloc")]
#[test]
fn boxed_methods() {
let rng = Box::new(TestRng::with_seed(1));
assert_eq!(&rng.gen(), &[1, 2]);
fn test_boxed_turborand<T: TurboRand>(boxed: T) {
assert_eq!(boxed.u8(..), 3);
}
test_boxed_turborand(rng);
}
#[test]
fn ref_methods() {
let mut rng = TestRng::with_seed(1);
fn test_ref_methods<T: GenCore>(reffed: T, expected: [u8; 3]) {
assert_eq!(reffed.gen(), expected);
}
test_ref_methods(&rng, [1, 2, 3]);
test_ref_methods(&mut rng, [4, 5, 6]);
}
}