use crate::{Cast, Infallible, RandQualities, is, whilst};
#[doc = crate::_tags!(rand)]
#[doc = crate::_doc_meta!{location("num/prob/rand")}]
pub trait RandSeedable: Sized {
type RandSeed: Clone + Default + AsRef<[u8]> + AsMut<[u8]>;
fn rand_from_seed(seed: Self::RandSeed) -> Self;
fn rand_try_from_source<R>(source: &mut R) -> Result<Self, R::Error>
where
R: RandTry + ?Sized,
{
let mut seed = Self::RandSeed::default();
source.rand_try_fill_bytes(seed.as_mut())?;
Ok(Self::rand_from_seed(seed))
}
#[must_use]
#[inline(always)]
fn rand_from_source<R>(source: &mut R) -> Self
where
R: Rand + ?Sized,
{
match Self::rand_try_from_source(source) {
Ok(value) => value,
Err(error) => match error {},
}
}
}
#[doc = crate::_tags!(rand)]
#[doc = crate::_doc_meta!{location("num/prob/rand")}]
pub trait RandTry {
type Error;
const RAND_OUTPUT_BITS: u32;
const RAND_STATE_BITS: u32;
const RAND_QUALITIES: RandQualities;
fn rand_try_next_u64(&mut self) -> Result<u64, Self::Error>;
#[must_use]
#[inline(always)]
fn rand_qualities(&self) -> RandQualities {
Self::RAND_QUALITIES
}
#[inline(always)]
fn rand_try_next_u128(&mut self) -> Result<u128, Self::Error> {
let pair = [self.rand_try_next_u64()?, self.rand_try_next_u64()?];
Ok(Cast::<u128>::from_u64_le(pair))
}
#[inline(always)]
fn rand_try_next_u32(&mut self) -> Result<u32, Self::Error> {
Ok(self.rand_try_next_u64()? as u32)
}
#[inline(always)]
fn rand_try_next_u16(&mut self) -> Result<u16, Self::Error> {
Ok(self.rand_try_next_u64()? as u16)
}
#[inline(always)]
fn rand_try_next_u8(&mut self) -> Result<u8, Self::Error> {
Ok(self.rand_try_next_u16()? as u8)
}
#[inline(always)]
fn rand_try_next_bool(&mut self) -> Result<bool, Self::Error> {
Ok((self.rand_try_next_u64()? & 1) != 0)
}
fn rand_try_fill_bytes(&mut self, buffer: &mut [u8]) -> Result<(), Self::Error> {
let mut i = 0;
let len = buffer.len();
while i + 8 <= len {
buffer[i..i + 8].copy_from_slice(&self.rand_try_next_u64()?.to_ne_bytes());
i += 8;
}
if i < len {
let tail = self.rand_try_next_u64()?.to_ne_bytes();
buffer[i..].copy_from_slice(&tail[..len - i]);
}
Ok(())
}
fn rand_try_below(&mut self, upper: u64) -> Result<u64, Self::Error> {
assert!(upper > 0);
let zone = u64::MAX - (u64::MAX % upper);
loop {
let v = self.rand_try_next_u64()?;
is! { v < zone, return Ok(v % upper) }
}
}
#[inline(always)]
#[track_caller]
fn rand_try_range(&mut self, low: u64, high: u64) -> Result<u64, Self::Error> {
assert!(low < high);
Ok(low + self.rand_try_below(high - low)?)
}
#[inline(always)]
fn rand_try_roll(&mut self, sides: u64) -> Result<u64, Self::Error> {
Ok(self.rand_try_below(sides)? + 1)
}
fn rand_try_shuffle<T>(&mut self, slice: &mut [T]) -> Result<(), Self::Error> {
whilst! { i in rev 1..slice.len(); {
let j = self.rand_try_below((i + 1) as u64)? as usize;
slice.swap(i, j);
}}
Ok(())
}
fn rand_try_choose_reservoir<I, F>(
&mut self,
iter: I,
mut valid: F,
) -> Result<Option<I::Item>, Self::Error>
where
I: IntoIterator,
F: FnMut(&I::Item) -> bool,
{
let (mut seen, mut picked) = (0u64, None);
for item in iter {
if valid(&item) {
seen = seen.checked_add(1).expect("too many valid random candidates");
is! { self.rand_try_below(seen)? == 0, picked = Some(item) }
}
}
Ok(picked)
}
fn rand_try_choose_scored<I, F>(
&mut self,
iter: I,
mut valid: F,
) -> Result<Option<I::Item>, Self::Error>
where
I: IntoIterator,
F: FnMut(&I::Item) -> bool,
{
let (mut picked, mut best_score, mut ties) = (None, 0u64, 0u64);
for item in iter {
if valid(&item) {
let score = self.rand_try_next_u64()?;
if picked.is_none() || score > best_score {
picked = Some(item);
best_score = score;
ties = 1;
} else if score == best_score {
ties = ties.checked_add(1).expect("too many tied random candidates");
is! { self.rand_try_below(ties)? == 0, picked = Some(item) }
}
}
}
Ok(picked)
}
}
impl<R> Rand for R where R: RandTry<Error = Infallible> + ?Sized {}
#[doc = crate::_tags!(rand)]
#[doc = crate::_doc_meta!{location("num/prob/rand")}]
#[rustfmt::skip]
pub trait Rand: RandTry<Error = Infallible> {
#[inline(always)]
fn rand_next_u128(&mut self) -> u128 {
match self.rand_try_next_u128() { Ok(v) => v, Err(e) => match e {} }
}
#[inline(always)]
fn rand_next_u64(&mut self) -> u64 {
match self.rand_try_next_u64() { Ok(v) => v, Err(e) => match e {} }
}
#[inline(always)]
fn rand_next_u32(&mut self) -> u32 {
match self.rand_try_next_u32() { Ok(v) => v, Err(e) => match e {} }
}
#[inline(always)]
fn rand_next_u16(&mut self) -> u16 {
match self.rand_try_next_u16() { Ok(v) => v, Err(e) => match e {} }
}
#[inline(always)]
fn rand_next_u8(&mut self) -> u8 {
match self.rand_try_next_u8() { Ok(v) => v, Err(e) => match e {} }
}
#[inline(always)]
fn rand_next_bool(&mut self) -> bool {
match self.rand_try_next_bool() { Ok(v) => v, Err(e) => match e {} }
}
#[inline(always)]
fn rand_fill_bytes(&mut self, buf: &mut [u8]) {
match self.rand_try_fill_bytes(buf) { Ok(()) => {} Err(e) => match e {} }
}
#[inline(always)]
fn rand_below(&mut self, upper: u64) -> u64 {
match self.rand_try_below(upper) { Ok(v) => v, Err(e) => match e {} }
}
#[inline(always)]
#[track_caller]
fn rand_range(&mut self, low: u64, high: u64) -> u64 {
match self.rand_try_range(low, high) { Ok(v) => v, Err(e) => match e {} }
}
#[inline(always)]
fn rand_roll(&mut self, sides: u64) -> u64 {
match self.rand_try_roll(sides) { Ok(v) => v, Err(e) => match e {} }
}
#[inline(always)]
fn rand_shuffle<T>(&mut self, slice: &mut [T]) {
match self.rand_try_shuffle(slice) { Ok(()) => {} Err(e) => match e {} }
}
#[inline(always)]
fn rand_choose_reservoir<I, F>(&mut self, iter: I, valid: F) -> Option<I::Item>
where I: IntoIterator, F: FnMut(&I::Item) -> bool {
match self.rand_try_choose_reservoir(iter, valid) { Ok(v) => v, Err(e) => match e {} }
}
#[inline(always)]
fn rand_choose_scored<I, F>(&mut self, iter: I, valid: F) -> Option<I::Item>
where I: IntoIterator, F: FnMut(&I::Item) -> bool {
match self.rand_try_choose_scored(iter, valid) { Ok(v) => v, Err(e) => match e {} }
}
}