use core::cmp::Ordering;
use core::marker::PhantomData;
use num_traits::Float;
use crate::canonical;
use crate::Primitive;
pub trait ConstraintEq<T>
where
T: Float + Primitive,
{
fn eq(lhs: T, rhs: T) -> bool {
canonical::eq_float(lhs, rhs)
}
}
pub trait ConstraintPartialOrd<T>
where
T: Float + Primitive,
{
fn partial_cmp(lhs: T, rhs: T) -> Option<Ordering> {
lhs.partial_cmp(&rhs)
}
}
impl<T, U> ConstraintPartialOrd<T> for U
where
T: Float + Primitive,
U: ConstraintOrd<T>,
{
fn partial_cmp(lhs: T, rhs: T) -> Option<Ordering> {
Some(U::cmp(lhs, rhs))
}
}
pub trait ConstraintOrd<T>
where
T: Float + Primitive,
{
fn cmp(lhs: T, rhs: T) -> Ordering {
canonical::cmp_float(lhs, rhs)
}
}
pub trait ConstraintInfinity<T>
where
T: Float + Primitive,
{
fn infinity() -> T {
T::infinity()
}
fn neg_infinity() -> T {
T::neg_infinity()
}
fn is_infinite(value: T) -> bool {
value.is_infinite()
}
fn is_finite(value: T) -> bool {
value.is_finite()
}
}
pub trait ConstraintNan<T>
where
T: Float + Primitive,
{
fn nan() -> T {
T::nan()
}
fn is_nan(value: T) -> bool {
value.is_nan()
}
}
pub trait SupersetOf<P> {}
pub trait SubsetOf<P> {}
impl<P, Q> SubsetOf<Q> for P where Q: SupersetOf<P> {}
pub trait FloatConstraint<T>: Copy + PartialEq + PartialOrd + Sized
where
T: Float + Primitive,
{
fn filter(value: T) -> Option<T>;
}
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
pub struct UnitConstraint<T>
where
T: Float + Primitive,
{
phantom: PhantomData<T>,
}
impl<T> FloatConstraint<T> for UnitConstraint<T>
where
T: Float + Primitive,
{
fn filter(value: T) -> Option<T> {
Some(value)
}
}
impl<T> ConstraintEq<T> for UnitConstraint<T> where T: Float + Primitive {}
impl<T> ConstraintOrd<T> for UnitConstraint<T> where T: Float + Primitive {}
impl<T> ConstraintInfinity<T> for UnitConstraint<T> where T: Float + Primitive {}
impl<T> ConstraintNan<T> for UnitConstraint<T> where T: Float + Primitive {}
impl<T> SupersetOf<NotNanConstraint<T>> for UnitConstraint<T> where T: Float + Primitive {}
impl<T> SupersetOf<FiniteConstraint<T>> for UnitConstraint<T> where T: Float + Primitive {}
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
pub struct NotNanConstraint<T>
where
T: Float + Primitive,
{
phantom: PhantomData<T>,
}
impl<T> FloatConstraint<T> for NotNanConstraint<T>
where
T: Float + Primitive,
{
fn filter(value: T) -> Option<T> {
if value.is_nan() {
None
}
else {
Some(value)
}
}
}
impl<T> ConstraintEq<T> for NotNanConstraint<T>
where
T: Float + Primitive,
{
fn eq(lhs: T, rhs: T) -> bool {
lhs == rhs
}
}
impl<T> ConstraintOrd<T> for NotNanConstraint<T>
where
T: Float + Primitive,
{
fn cmp(lhs: T, rhs: T) -> Ordering {
lhs.partial_cmp(&rhs).unwrap()
}
}
impl<T> ConstraintInfinity<T> for NotNanConstraint<T> where T: Float + Primitive {}
impl<T> SupersetOf<FiniteConstraint<T>> for NotNanConstraint<T> where T: Float + Primitive {}
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
pub struct FiniteConstraint<T>
where
T: Float + Primitive,
{
phantom: PhantomData<T>,
}
impl<T> FloatConstraint<T> for FiniteConstraint<T>
where
T: Float + Primitive,
{
fn filter(value: T) -> Option<T> {
if value.is_nan() || value.is_infinite() {
None
}
else {
Some(value)
}
}
}
impl<T> ConstraintEq<T> for FiniteConstraint<T>
where
T: Float + Primitive,
{
fn eq(lhs: T, rhs: T) -> bool {
lhs == rhs
}
}
impl<T> ConstraintOrd<T> for FiniteConstraint<T>
where
T: Float + Primitive,
{
fn cmp(lhs: T, rhs: T) -> Ordering {
lhs.partial_cmp(&rhs).unwrap()
}
}