use crate::_internal::{i2f_bits, randi_wide, u2f_01};
mod sealed {
pub trait Sealed {}
impl Sealed for u32 {}
impl Sealed for u64 {}
}
pub trait Word: sealed::Sealed + Copy {
type Float: Copy;
type Int: Copy;
const BITS: u32;
fn to_f01(self) -> Self::Float;
fn to_randi(self, min: Self::Int, max: Self::Int) -> Self::Int;
fn to_randf(self, min: Self::Float, max: Self::Float) -> Self::Float;
fn to_index(self, len: usize) -> usize;
}
macro_rules! impl_word {
($bits:tt) => {
pastey::paste! {
impl Word for [<u $bits>] {
type Float = [<f $bits>];
type Int = [<i $bits>];
const BITS: u32 = $bits;
#[inline(always)]
fn to_f01(self) -> Self::Float {
u2f_01!([<f $bits>], $bits, self)
}
#[inline(always)]
fn to_randi(self, min: Self::Int, max: Self::Int) -> Self::Int {
let range = (max as randi_wide!(i $bits) - min as randi_wide!(i $bits) + 1)
as randi_wide!(u $bits);
((self as randi_wide!(u $bits) * range) >> $bits) as [<i $bits>] + min
}
#[inline(always)]
fn to_randf(self, min: Self::Float, max: Self::Float) -> Self::Float {
self.to_f01() * (max - min) + min
}
#[inline(always)]
fn to_index(self, len: usize) -> usize {
((self as randi_wide!(u $bits) * len as randi_wide!(u $bits)) >> $bits) as usize
}
}
}
};
}
impl_word!(32);
impl_word!(64);
pub trait Rng {
type Word: Word;
fn nextu(&mut self) -> Self::Word;
#[inline(always)]
fn nextf(&mut self) -> <Self::Word as Word>::Float {
self.nextu().to_f01()
}
#[inline(always)]
fn randi(
&mut self,
min: <Self::Word as Word>::Int,
max: <Self::Word as Word>::Int,
) -> <Self::Word as Word>::Int {
self.nextu().to_randi(min, max)
}
#[inline(always)]
fn randf(
&mut self,
min: <Self::Word as Word>::Float,
max: <Self::Word as Word>::Float,
) -> <Self::Word as Word>::Float {
self.nextu().to_randf(min, max)
}
}
pub trait Seed {
type Seed;
fn from_seed(seed: Self::Seed) -> Self;
}