#![no_std]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![forbid(unsafe_code)]
#![warn(missing_docs, missing_debug_implementations, rust_2018_idioms)]
#![doc(
html_favicon_url = "https://raw.githubusercontent.com/smol-rs/smol/master/assets/images/logo_fullsize_transparent.png"
)]
#![doc(
html_logo_url = "https://raw.githubusercontent.com/smol-rs/smol/master/assets/images/logo_fullsize_transparent.png"
)]
#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(feature = "std")]
extern crate std;
use core::convert::{TryFrom, TryInto};
use core::ops::{Bound, RangeBounds};
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
mod global_rng;
#[cfg(feature = "std")]
pub use global_rng::*;
#[derive(Debug, PartialEq, Eq)]
pub struct Rng(u64);
impl Clone for Rng {
fn clone(&self) -> Rng {
Rng::with_seed(self.0)
}
}
impl Rng {
#[inline]
fn gen_u32(&mut self) -> u32 {
self.gen_u64() as u32
}
#[inline]
fn gen_u64(&mut self) -> u64 {
const WY_CONST_0: u64 = 0x2d35_8dcc_aa6c_78a5;
const WY_CONST_1: u64 = 0x8bb8_4b93_962e_acc9;
let s = self.0.wrapping_add(WY_CONST_0);
self.0 = s;
let t = u128::from(s) * u128::from(s ^ WY_CONST_1);
(t as u64) ^ (t >> 64) as u64
}
#[inline]
fn gen_u128(&mut self) -> u128 {
(u128::from(self.gen_u64()) << 64) | u128::from(self.gen_u64())
}
#[inline]
fn gen_mod_u32(&mut self, n: u32) -> u32 {
let mut r = self.gen_u32();
let mut hi = mul_high_u32(r, n);
let mut lo = r.wrapping_mul(n);
if lo < n {
let t = n.wrapping_neg() % n;
while lo < t {
r = self.gen_u32();
hi = mul_high_u32(r, n);
lo = r.wrapping_mul(n);
}
}
hi
}
#[inline]
fn gen_mod_u64(&mut self, n: u64) -> u64 {
let mut r = self.gen_u64();
let mut hi = mul_high_u64(r, n);
let mut lo = r.wrapping_mul(n);
if lo < n {
let t = n.wrapping_neg() % n;
while lo < t {
r = self.gen_u64();
hi = mul_high_u64(r, n);
lo = r.wrapping_mul(n);
}
}
hi
}
#[inline]
fn gen_mod_u128(&mut self, n: u128) -> u128 {
let mut r = self.gen_u128();
let mut hi = mul_high_u128(r, n);
let mut lo = r.wrapping_mul(n);
if lo < n {
let t = n.wrapping_neg() % n;
while lo < t {
r = self.gen_u128();
hi = mul_high_u128(r, n);
lo = r.wrapping_mul(n);
}
}
hi
}
}
#[inline]
fn mul_high_u32(a: u32, b: u32) -> u32 {
(((a as u64) * (b as u64)) >> 32) as u32
}
#[inline]
fn mul_high_u64(a: u64, b: u64) -> u64 {
(((a as u128) * (b as u128)) >> 64) as u64
}
#[inline]
fn mul_high_u128(a: u128, b: u128) -> u128 {
let a_lo = a as u64 as u128;
let a_hi = (a >> 64) as u64 as u128;
let b_lo = b as u64 as u128;
let b_hi = (b >> 64) as u64 as u128;
let carry = (a_lo * b_lo) >> 64;
let carry = ((a_hi * b_lo) as u64 as u128 + (a_lo * b_hi) as u64 as u128 + carry) >> 64;
a_hi * b_hi + ((a_hi * b_lo) >> 64) + ((a_lo * b_hi) >> 64) + carry
}
macro_rules! rng_integer {
($t:tt, $unsigned_t:tt, $gen:tt, $mod:tt, $doc:tt) => {
#[doc = $doc]
#[inline]
pub fn $t(&mut self, range: impl RangeBounds<$t>) -> $t {
let panic_empty_range = || {
panic!(
"empty range: {:?}..{:?}",
range.start_bound(),
range.end_bound()
)
};
let low = match range.start_bound() {
Bound::Unbounded => core::$t::MIN,
Bound::Included(&x) => x,
Bound::Excluded(&x) => x.checked_add(1).unwrap_or_else(panic_empty_range),
};
let high = match range.end_bound() {
Bound::Unbounded => core::$t::MAX,
Bound::Included(&x) => x,
Bound::Excluded(&x) => x.checked_sub(1).unwrap_or_else(panic_empty_range),
};
if low > high {
panic_empty_range();
}
if low == core::$t::MIN && high == core::$t::MAX {
self.$gen() as $t
} else {
let len = high.wrapping_sub(low).wrapping_add(1);
low.wrapping_add(self.$mod(len as $unsigned_t as _) as $t)
}
}
};
}
impl Rng {
#[inline]
#[must_use = "this creates a new instance of `Rng`; if you want to initialize the thread-local generator, use `fastrand::seed()` instead"]
pub fn with_seed(seed: u64) -> Self {
Rng(seed)
}
#[inline]
#[must_use = "this creates a new instance of `Rng`"]
pub fn fork(&mut self) -> Self {
Rng::with_seed(self.gen_u64())
}
#[inline]
pub fn alphabetic(&mut self) -> char {
const CHARS: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
*self.choice(CHARS).unwrap() as char
}
#[inline]
pub fn alphanumeric(&mut self) -> char {
const CHARS: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
*self.choice(CHARS).unwrap() as char
}
#[inline]
pub fn bool(&mut self) -> bool {
self.u8(..) % 2 == 0
}
#[inline]
pub fn digit(&mut self, base: u32) -> char {
if base == 0 {
panic!("base cannot be zero");
}
if base > 36 {
panic!("base cannot be larger than 36");
}
let num = self.u8(..base as u8);
if num < 10 {
(b'0' + num) as char
} else {
(b'a' + num - 10) as char
}
}
pub fn f32(&mut self) -> f32 {
let b = 32;
let f = core::f32::MANTISSA_DIGITS - 1;
f32::from_bits((1 << (b - 2)) - (1 << f) + (self.u32(..) >> (b - f))) - 1.0
}
pub fn f64(&mut self) -> f64 {
let b = 64;
let f = core::f64::MANTISSA_DIGITS - 1;
f64::from_bits((1 << (b - 2)) - (1 << f) + (self.u64(..) >> (b - f))) - 1.0
}
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
pub fn choose_multiple<I: IntoIterator>(&mut self, source: I, amount: usize) -> Vec<I::Item> {
let mut reservoir = Vec::with_capacity(amount);
let mut iter = source.into_iter();
reservoir.extend(iter.by_ref().take(amount));
if reservoir.len() == amount {
for (i, elem) in iter.enumerate() {
let end = i + 1 + amount;
let k = self.usize(0..end);
if let Some(slot) = reservoir.get_mut(k) {
*slot = elem;
}
}
} else {
if reservoir.capacity() > 3 * reservoir.len() {
reservoir.shrink_to_fit();
}
}
reservoir
}
rng_integer!(
i8,
u8,
gen_u32,
gen_mod_u32,
"Generates a random `i8` in the given range."
);
rng_integer!(
i16,
u16,
gen_u32,
gen_mod_u32,
"Generates a random `i16` in the given range."
);
rng_integer!(
i32,
u32,
gen_u32,
gen_mod_u32,
"Generates a random `i32` in the given range."
);
rng_integer!(
i64,
u64,
gen_u64,
gen_mod_u64,
"Generates a random `i64` in the given range."
);
rng_integer!(
i128,
u128,
gen_u128,
gen_mod_u128,
"Generates a random `i128` in the given range."
);
#[cfg(target_pointer_width = "16")]
rng_integer!(
isize,
usize,
gen_u32,
gen_mod_u32,
"Generates a random `isize` in the given range."
);
#[cfg(target_pointer_width = "32")]
rng_integer!(
isize,
usize,
gen_u32,
gen_mod_u32,
"Generates a random `isize` in the given range."
);
#[cfg(target_pointer_width = "64")]
rng_integer!(
isize,
usize,
gen_u64,
gen_mod_u64,
"Generates a random `isize` in the given range."
);
#[inline]
pub fn lowercase(&mut self) -> char {
const CHARS: &[u8] = b"abcdefghijklmnopqrstuvwxyz";
*self.choice(CHARS).unwrap() as char
}
#[inline]
pub fn seed(&mut self, seed: u64) {
self.0 = seed;
}
#[inline]
pub fn get_seed(&self) -> u64 {
self.0
}
#[inline]
pub fn choice<I>(&mut self, iter: I) -> Option<I::Item>
where
I: IntoIterator,
I::IntoIter: ExactSizeIterator,
{
let mut iter = iter.into_iter();
let len = iter.len();
if len == 0 {
return None;
}
let index = self.usize(0..len);
iter.nth(index)
}
#[inline]
pub fn shuffle<T>(&mut self, slice: &mut [T]) {
for i in 1..slice.len() {
slice.swap(i, self.usize(..=i));
}
}
#[inline]
pub fn fill(&mut self, slice: &mut [u8]) {
let mut chunks = slice.chunks_exact_mut(core::mem::size_of::<u64>());
for chunk in chunks.by_ref() {
let n = self.gen_u64().to_ne_bytes();
chunk.copy_from_slice(&n);
}
let remainder = chunks.into_remainder();
if !remainder.is_empty() {
let n = self.gen_u64().to_ne_bytes();
remainder.copy_from_slice(&n[..remainder.len()]);
}
}
rng_integer!(
u8,
u8,
gen_u32,
gen_mod_u32,
"Generates a random `u8` in the given range."
);
rng_integer!(
u16,
u16,
gen_u32,
gen_mod_u32,
"Generates a random `u16` in the given range."
);
rng_integer!(
u32,
u32,
gen_u32,
gen_mod_u32,
"Generates a random `u32` in the given range."
);
rng_integer!(
u64,
u64,
gen_u64,
gen_mod_u64,
"Generates a random `u64` in the given range."
);
rng_integer!(
u128,
u128,
gen_u128,
gen_mod_u128,
"Generates a random `u128` in the given range."
);
#[cfg(target_pointer_width = "16")]
rng_integer!(
usize,
usize,
gen_u32,
gen_mod_u32,
"Generates a random `usize` in the given range."
);
#[cfg(target_pointer_width = "32")]
rng_integer!(
usize,
usize,
gen_u32,
gen_mod_u32,
"Generates a random `usize` in the given range."
);
#[cfg(target_pointer_width = "64")]
rng_integer!(
usize,
usize,
gen_u64,
gen_mod_u64,
"Generates a random `usize` in the given range."
);
#[inline]
pub fn uppercase(&mut self) -> char {
const CHARS: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
*self.choice(CHARS).unwrap() as char
}
#[inline]
pub fn char(&mut self, range: impl RangeBounds<char>) -> char {
let panic_empty_range = || {
panic!(
"empty range: {:?}..{:?}",
range.start_bound(),
range.end_bound()
)
};
let surrogate_start = 0xd800u32;
let surrogate_len = 0x800u32;
let low = match range.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_len
} else {
x as u32 + 1
};
char::try_from(scalar).unwrap_or_else(|_| panic_empty_range())
}
};
let high = match range.end_bound() {
Bound::Unbounded => core::char::MAX,
Bound::Included(&x) => x,
Bound::Excluded(&x) => {
let scalar = if x as u32 == surrogate_start + surrogate_len {
surrogate_start - 1
} else {
(x as u32).wrapping_sub(1)
};
char::try_from(scalar).unwrap_or_else(|_| panic_empty_range())
}
};
if low > high {
panic_empty_range();
}
let gap = if (low as u32) < surrogate_start && (high as u32) >= surrogate_start {
surrogate_len
} else {
0
};
let range = high as u32 - low as u32 - gap;
let mut val = self.u32(0..=range) + low as u32;
if val >= surrogate_start {
val += gap;
}
val.try_into().unwrap()
}
}