use crate::{SignedUnitInterval, UnitInterval, UnitIntervalFloat};
use ::rand::Rng;
use ::rand_distr::{Beta, Distribution, Open01, OpenClosed01, StandardUniform};
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct CheckedUnitIntervalDistribution<D> {
distribution: D,
}
impl<D> CheckedUnitIntervalDistribution<D> {
#[inline]
pub const fn new(distribution: D) -> Self {
Self { distribution }
}
#[inline]
pub const fn as_inner(&self) -> &D {
&self.distribution
}
#[inline]
pub fn into_inner(self) -> D {
self.distribution
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct SaturatingUnitIntervalDistribution<D> {
distribution: D,
}
impl<D> SaturatingUnitIntervalDistribution<D> {
#[inline]
pub const fn new(distribution: D) -> Self {
Self { distribution }
}
#[inline]
pub const fn as_inner(&self) -> &D {
&self.distribution
}
#[inline]
pub fn into_inner(self) -> D {
self.distribution
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct CheckedSignedUnitIntervalDistribution<D> {
distribution: D,
}
impl<D> CheckedSignedUnitIntervalDistribution<D> {
#[inline]
pub const fn new(distribution: D) -> Self {
Self { distribution }
}
#[inline]
pub const fn as_inner(&self) -> &D {
&self.distribution
}
#[inline]
pub fn into_inner(self) -> D {
self.distribution
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct SaturatingSignedUnitIntervalDistribution<D> {
distribution: D,
}
impl<D> SaturatingSignedUnitIntervalDistribution<D> {
#[inline]
pub const fn new(distribution: D) -> Self {
Self { distribution }
}
#[inline]
pub const fn as_inner(&self) -> &D {
&self.distribution
}
#[inline]
pub fn into_inner(self) -> D {
self.distribution
}
}
impl<T, D> Distribution<Option<UnitInterval<T>>> for CheckedUnitIntervalDistribution<D>
where
T: UnitIntervalFloat,
D: Distribution<T>,
{
#[inline]
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Option<UnitInterval<T>> {
UnitInterval::new(self.distribution.sample(rng))
}
}
impl<T, D> Distribution<UnitInterval<T>> for SaturatingUnitIntervalDistribution<D>
where
T: UnitIntervalFloat,
D: Distribution<T>,
{
#[inline]
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> UnitInterval<T> {
UnitInterval::saturating(self.distribution.sample(rng))
}
}
impl<T, D> Distribution<Option<SignedUnitInterval<T>>> for CheckedSignedUnitIntervalDistribution<D>
where
T: UnitIntervalFloat,
D: Distribution<T>,
{
#[inline]
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Option<SignedUnitInterval<T>> {
SignedUnitInterval::new(self.distribution.sample(rng))
}
}
impl<T, D> Distribution<SignedUnitInterval<T>> for SaturatingSignedUnitIntervalDistribution<D>
where
T: UnitIntervalFloat,
D: Distribution<T>,
{
#[inline]
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> SignedUnitInterval<T> {
SignedUnitInterval::saturating(self.distribution.sample(rng))
}
}
impl<T> Distribution<UnitInterval<T>> for StandardUniform
where
T: UnitIntervalFloat,
StandardUniform: Distribution<T>,
{
#[inline]
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> UnitInterval<T> {
UnitInterval::from_inner(<Self as Distribution<T>>::sample(self, rng))
}
}
impl<T> Distribution<SignedUnitInterval<T>> for StandardUniform
where
T: UnitIntervalFloat,
StandardUniform: Distribution<T>,
{
#[inline]
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> SignedUnitInterval<T> {
let value = <Self as Distribution<T>>::sample(self, rng) * (T::ONE + T::ONE) - T::ONE;
SignedUnitInterval::from_inner(value)
}
}
macro_rules! impl_unit_interval_distribution {
($distribution:ty, $float:ty) => {
impl Distribution<UnitInterval<$float>> for $distribution {
#[inline]
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> UnitInterval<$float> {
UnitInterval::from_inner(<Self as Distribution<$float>>::sample(self, rng))
}
}
};
}
impl_unit_interval_distribution!(Open01, f32);
impl_unit_interval_distribution!(Open01, f64);
impl_unit_interval_distribution!(OpenClosed01, f32);
impl_unit_interval_distribution!(OpenClosed01, f64);
impl_unit_interval_distribution!(Beta<f32>, f32);
impl_unit_interval_distribution!(Beta<f64>, f64);