use core::ops::{Add, Div, Mul, RangeBounds, Rem, Sub};
use crate::{Random, RandomSource};
pub trait Num: Sized + Copy {
const MAX: Self;
const MIN: Self;
fn abs(&self) -> Self { *self }
}
macro_rules! impl_for_numeric {
($($t:ident),* $(,)?) => {
$(
impl Num for $t {
const MAX: Self = $t :: MAX;
const MIN: Self = $t :: MIN;
}
)*
};
}
macro_rules! impl_for_signed_numeric {
($($t:ident),* $(,)?) => {
$(
impl Num for $t {
const MAX: Self = $t :: MAX;
const MIN: Self = $t :: MIN;
fn abs(&self) -> Self {
$t::abs(*self)
}
}
)*
};
}
impl_for_numeric!(u8, u16, u32, u64, u128, usize);
impl_for_signed_numeric!(i8, i16, i32, i64, i128, isize);
pub struct Simple<T> {
low: T,
high: T,
}
impl<T> Simple<T>
where
T: Add<Output = T> + Sub<Output = T> + From<u8> + Copy + Num + PartialOrd
{
pub fn new<R: RangeBounds<T>>(range: R) -> Option<Self> {
use core::ops::Bound;
let low = match range.start_bound() {
Bound::Included(n) => *n,
Bound::Excluded(n) => *n + T::from(1),
Bound::Unbounded => T::MIN,
};
let high = match range.end_bound() {
Bound::Included(n) => *n,
Bound::Excluded(n) => *n - T::from(1),
Bound::Unbounded => T::MAX,
};
if low >= high {
None
} else {
Some(Self { low, high })
}
}
}
pub trait Distribution<T: Random> {
fn sample<S>(&self, source: &mut S) -> T
where
S: RandomSource + ?Sized;
}
impl<T> Distribution<T> for Simple<T>
where
T: Random + PartialOrd + Add<Output = T> + Sub<Output = T>
+ Mul<Output = T> + Div<Output = T> + Rem<Output = T> + Num + Copy
+ From<u8>
{
fn sample<S>(&self, source: &mut S) -> T
where
S: RandomSource + ?Sized
{
let val = T::random(source).abs();
let diff = self.high - self.low.abs();
(val % (T::from(1) + diff)) + self.low
}
}