refined 0.3.1

Simple refinement types; parse, don't validate!
Documentation
use core::{marker::PhantomData, ops::Div};

use crate::{boundable::*, Predicate, Refinement};

use super::*;

impl<
        const A: usize,
        Type: unsigned::UnsignedBoundable + Div<Output = Type>,
        B: UnsignedMax<Type> + Predicate<Type>,
    > Div<Refinement<Type, B>> for Refinement<Type, unsigned::LessThan<A>>
where
    Refinement<Type, unsigned::LessThan<A>>: Sized,
{
    type Output = Refinement<Type, unsigned::LessThan<A>>;

    fn div(self, rhs: Refinement<Type, B>) -> Self::Output {
        Refinement(self.0 / rhs.0, PhantomData)
    }
}

impl<
        const A: usize,
        Type: unsigned::UnsignedBoundable + Div<Output = Type>,
        B: UnsignedMax<Type> + Predicate<Type>,
    > Div<Refinement<Type, B>> for Refinement<Type, unsigned::LessThanEqual<A>>
where
    Refinement<Type, unsigned::LessThanEqual<A>>: Sized,
{
    type Output = Refinement<Type, unsigned::LessThanEqual<A>>;

    fn div(self, rhs: Refinement<Type, B>) -> Self::Output {
        Refinement(self.0 / rhs.0, PhantomData)
    }
}

impl<
        const A: usize,
        Type: unsigned::UnsignedBoundable + Div<Output = Type>,
        B: UnsignedMin<Type> + Predicate<Type>,
    > Div<Refinement<Type, B>> for Refinement<Type, unsigned::GreaterThan<A>>
where
    Refinement<Type, unsigned::GreaterThan<{ A / B::UMIN }>>: Sized,
{
    type Output = Refinement<Type, unsigned::GreaterThan<{ A / B::UMIN }>>;

    fn div(self, rhs: Refinement<Type, B>) -> Self::Output {
        Refinement(self.0 / rhs.0, PhantomData)
    }
}

impl<
        const A: usize,
        Type: unsigned::UnsignedBoundable + Div<Output = Type>,
        B: UnsignedMin<Type> + Predicate<Type>,
    > Div<Refinement<Type, B>> for Refinement<Type, unsigned::GreaterThanEqual<A>>
where
    Refinement<Type, unsigned::GreaterThanEqual<{ A / B::UMIN }>>: Sized,
{
    type Output = Refinement<Type, unsigned::GreaterThanEqual<{ A / B::UMIN }>>;

    fn div(self, rhs: Refinement<Type, B>) -> Self::Output {
        Refinement(self.0 / rhs.0, PhantomData)
    }
}

impl<
        const MIN: usize,
        const MAX: usize,
        Type: unsigned::UnsignedBoundable + Div<Output = Type>,
        B: UnsignedMinMax<Type> + Predicate<Type>,
    > Div<Refinement<Type, B>> for Refinement<Type, unsigned::OpenInterval<MIN, MAX>>
where
    Refinement<
        Type,
        unsigned::OpenInterval<{ (MIN + 1) / B::UMAX - 1 }, { (MAX - 1) / B::UMIN + 1 }>,
    >: Sized,
{
    type Output = Refinement<
        Type,
        unsigned::OpenInterval<{ (MIN + 1) / B::UMAX - 1 }, { (MAX - 1) / B::UMIN + 1 }>,
    >;

    fn div(self, rhs: Refinement<Type, B>) -> Self::Output {
        Refinement(self.0 / rhs.0, PhantomData)
    }
}

impl<
        const MIN: usize,
        const MAX: usize,
        Type: unsigned::UnsignedBoundable + Div<Output = Type>,
        B: UnsignedMinMax<Type> + Predicate<Type>,
    > Div<Refinement<Type, B>> for Refinement<Type, unsigned::ClosedInterval<MIN, MAX>>
where
    Refinement<Type, unsigned::ClosedInterval<{ MIN / B::UMAX }, { MAX / B::UMIN }>>: Sized,
{
    type Output = Refinement<Type, unsigned::ClosedInterval<{ MIN / B::UMAX }, { MAX / B::UMIN }>>;

    fn div(self, rhs: Refinement<Type, B>) -> Self::Output {
        Refinement(self.0 / rhs.0, PhantomData)
    }
}

impl<
        const MIN: usize,
        const MAX: usize,
        Type: unsigned::UnsignedBoundable + Div<Output = Type>,
        B: UnsignedMinMax<Type> + Predicate<Type>,
    > Div<Refinement<Type, B>> for Refinement<Type, unsigned::OpenClosedInterval<MIN, MAX>>
where
    Refinement<Type, unsigned::OpenClosedInterval<{ (MIN + 1) / B::UMAX - 1 }, { MAX / B::UMIN }>>:
        Sized,
{
    type Output = Refinement<
        Type,
        unsigned::OpenClosedInterval<{ (MIN + 1) / B::UMAX - 1 }, { MAX / B::UMIN }>,
    >;

    fn div(self, rhs: Refinement<Type, B>) -> Self::Output {
        Refinement(self.0 / rhs.0, PhantomData)
    }
}

impl<
        const MIN: usize,
        const MAX: usize,
        Type: unsigned::UnsignedBoundable + Div<Output = Type>,
        B: UnsignedMinMax<Type> + Predicate<Type>,
    > Div<Refinement<Type, B>> for Refinement<Type, unsigned::ClosedOpenInterval<MIN, MAX>>
where
    Refinement<Type, unsigned::ClosedOpenInterval<{ MIN / B::UMAX }, { (MAX - 1) / B::UMIN + 1 }>>:
        Sized,
{
    type Output = Refinement<
        Type,
        unsigned::ClosedOpenInterval<{ MIN / B::UMAX }, { (MAX - 1) / B::UMIN + 1 }>,
    >;

    fn div(self, rhs: Refinement<Type, B>) -> Self::Output {
        Refinement(self.0 / rhs.0, PhantomData)
    }
}

#[cfg(test)]
mod unsigned_tests {
    use super::*;
    use crate::prelude::*;

    #[test]
    fn test_lt_div_lt() {
        let a = Refinement::<u8, unsigned::LessThan<10>>::refine(6).unwrap();
        let b = Refinement::<u8, unsigned::LessThan<10>>::refine(3).unwrap();
        let c: Refinement<u8, unsigned::LessThan<10>> = a / b;
        assert_eq!(*c, 2);
    }

    #[test]
    fn test_lte_div_lte() {
        let a = Refinement::<u8, unsigned::LessThanEqual<10>>::refine(6).unwrap();
        let b = Refinement::<u8, unsigned::LessThanEqual<10>>::refine(3).unwrap();
        let c: Refinement<u8, unsigned::LessThanEqual<10>> = a / b;
        assert_eq!(*c, 2);
    }

    #[test]
    fn test_lte_div_lt() {
        let a = Refinement::<u8, unsigned::LessThanEqual<10>>::refine(6).unwrap();
        let b = Refinement::<u8, unsigned::LessThan<11>>::refine(3).unwrap();
        let c: Refinement<u8, unsigned::LessThanEqual<10>> = a / b;
        assert_eq!(*c, 2);
    }

    #[test]
    fn test_gt_div_gt() {
        let a = Refinement::<u8, unsigned::GreaterThan<10>>::refine(15).unwrap();
        let b = Refinement::<u8, unsigned::GreaterThan<10>>::refine(13).unwrap();
        let c: Refinement<u8, unsigned::GreaterThan<0>> = a / b;
        assert_eq!(*c, 1);
    }

    #[test]
    fn test_gt_div_gte() {
        let a = Refinement::<u8, unsigned::GreaterThan<10>>::refine(15).unwrap();
        let b = Refinement::<u8, unsigned::GreaterThanEqual<3>>::refine(3).unwrap();
        let c: Refinement<u8, unsigned::GreaterThan<3>> = a / b;
        assert_eq!(*c, 5);
    }

    #[test]
    fn test_gte_div_gte() {
        let a = Refinement::<u8, unsigned::GreaterThanEqual<10>>::refine(12).unwrap();
        let b = Refinement::<u8, unsigned::GreaterThanEqual<3>>::refine(3).unwrap();
        let c: Refinement<u8, unsigned::GreaterThanEqual<3>> = a / b;
        assert_eq!(*c, 4);
    }

    #[test]
    fn test_gte_div_gt() {
        let a = Refinement::<u8, unsigned::GreaterThanEqual<12>>::refine(15).unwrap();
        let b = Refinement::<u8, unsigned::GreaterThan<3>>::refine(4).unwrap();
        let c: Refinement<u8, unsigned::GreaterThanEqual<3>> = a / b;
        assert_eq!(*c, 3);
    }

    #[test]
    fn test_open_closed_interval_div() {
        let a = Refinement::<u8, unsigned::OpenClosedInterval<15, 20>>::refine(16).unwrap();
        let b = Refinement::<u8, unsigned::OpenClosedInterval<3, 6>>::refine(6).unwrap();
        let c: Refinement<u8, unsigned::OpenClosedInterval<1, 5>> = a / b;
        assert_eq!(*c, 2);
    }

    #[test]
    fn test_closed_open_interval_div() {
        let a = Refinement::<u8, unsigned::ClosedOpenInterval<50, 100>>::refine(99).unwrap();
        let b = Refinement::<u8, unsigned::ClosedOpenInterval<5, 10>>::refine(5).unwrap();
        let c: Refinement<u8, unsigned::ClosedOpenInterval<5, 20>> = a / b;
        assert_eq!(*c, 19);
    }

    #[test]
    fn test_open_interval_div() {
        let a = Refinement::<u8, unsigned::OpenInterval<15, 30>>::refine(16).unwrap();
        let b = Refinement::<u8, unsigned::OpenInterval<3, 6>>::refine(5).unwrap();
        let c: Refinement<u8, unsigned::OpenInterval<2, 8>> = a / b;
        assert_eq!(*c, 3);
    }

    #[test]
    fn test_closed_interval_div() {
        let a = Refinement::<u8, unsigned::ClosedInterval<15, 50>>::refine(30).unwrap();
        let b = Refinement::<u8, unsigned::ClosedInterval<3, 6>>::refine(6).unwrap();
        let c: Refinement<u8, unsigned::ClosedInterval<2, 16>> = a / b;
        assert_eq!(*c, 5);
    }
}

impl<
        const MIN: isize,
        const MAX: isize,
        Type: signed::SignedBoundable + Div<Output = Type>,
        B: SignedMinMax<Type> + Predicate<Type>,
    > Div<Refinement<Type, B>> for Refinement<Type, signed::OpenInterval<MIN, MAX>>
where
    Refinement<
        Type,
        signed::OpenInterval<
            { min_div(MIN + 1, MAX - 1, B::UMIN, B::UMAX) - 1 },
            { max_div(MIN + 1, MAX - 1, B::UMIN, B::UMAX) + 1 },
        >,
    >: Sized,
{
    type Output = Refinement<
        Type,
        signed::OpenInterval<
            { min_div(MIN + 1, MAX - 1, B::UMIN, B::UMAX) - 1 },
            { max_div(MIN + 1, MAX - 1, B::UMIN, B::UMAX) + 1 },
        >,
    >;

    fn div(self, rhs: Refinement<Type, B>) -> Self::Output {
        Refinement(self.0 / rhs.0, PhantomData)
    }
}

impl<
        const MIN: isize,
        const MAX: isize,
        Type: signed::SignedBoundable + Div<Output = Type>,
        B: SignedMinMax<Type> + Predicate<Type>,
    > Div<Refinement<Type, B>> for Refinement<Type, signed::ClosedInterval<MIN, MAX>>
where
    Refinement<
        Type,
        signed::ClosedInterval<
            { min_div(MIN, MAX, B::UMIN, B::UMAX) },
            { max_div(MIN, MAX, B::UMIN, B::UMAX) },
        >,
    >: Sized,
{
    type Output = Refinement<
        Type,
        signed::ClosedInterval<
            { min_div(MIN, MAX, B::UMIN, B::UMAX) },
            { max_div(MIN, MAX, B::UMIN, B::UMAX) },
        >,
    >;

    fn div(self, rhs: Refinement<Type, B>) -> Self::Output {
        Refinement(self.0 / rhs.0, PhantomData)
    }
}

impl<
        const MIN: isize,
        const MAX: isize,
        Type: signed::SignedBoundable + Div<Output = Type>,
        B: SignedMinMax<Type> + Predicate<Type>,
    > Div<Refinement<Type, B>> for Refinement<Type, signed::OpenClosedInterval<MIN, MAX>>
where
    Refinement<
        Type,
        signed::OpenClosedInterval<
            { min_div(MIN + 1, MAX, B::UMIN, B::UMAX) - 1 },
            { max_div(MIN + 1, MAX, B::UMIN, B::UMAX) },
        >,
    >: Sized,
{
    type Output = Refinement<
        Type,
        signed::OpenClosedInterval<
            { min_div(MIN + 1, MAX, B::UMIN, B::UMAX) - 1 },
            { max_div(MIN + 1, MAX, B::UMIN, B::UMAX) },
        >,
    >;

    fn div(self, rhs: Refinement<Type, B>) -> Self::Output {
        Refinement(self.0 / rhs.0, PhantomData)
    }
}

impl<
        const MIN: isize,
        const MAX: isize,
        Type: signed::SignedBoundable + Div<Output = Type>,
        B: SignedMinMax<Type> + Predicate<Type>,
    > Div<Refinement<Type, B>> for Refinement<Type, signed::ClosedOpenInterval<MIN, MAX>>
where
    Refinement<
        Type,
        signed::ClosedOpenInterval<
            { min_div(MIN, MAX - 1, B::UMIN, B::UMAX) },
            { max_div(MIN, MAX - 1, B::UMIN, B::UMAX) + 1 },
        >,
    >: Sized,
{
    type Output = Refinement<
        Type,
        signed::ClosedOpenInterval<
            { min_div(MIN, MAX - 1, B::UMIN, B::UMAX) },
            { max_div(MIN, MAX - 1, B::UMIN, B::UMAX) + 1 },
        >,
    >;

    fn div(self, rhs: Refinement<Type, B>) -> Self::Output {
        Refinement(self.0 / rhs.0, PhantomData)
    }
}

#[cfg(test)]
mod signed_tests {
    use super::*;
    use crate::prelude::*;

    #[test]
    fn test_open_closed_interval_div() {
        let a = Refinement::<i8, signed::OpenClosedInterval<15, 20>>::refine(16).unwrap();
        let b = Refinement::<i8, signed::OpenClosedInterval<3, 6>>::refine(6).unwrap();
        let c: Refinement<i8, signed::OpenClosedInterval<1, 5>> = a / b;
        assert_eq!(*c, 2);
    }

    #[test]
    fn test_closed_open_interval_div() {
        let a = Refinement::<i8, signed::ClosedOpenInterval<50, 100>>::refine(99).unwrap();
        let b = Refinement::<i8, signed::ClosedOpenInterval<5, 10>>::refine(5).unwrap();
        let c: Refinement<i8, signed::ClosedOpenInterval<5, 20>> = a / b;
        assert_eq!(*c, 19);
    }

    #[test]
    fn test_open_interval_div() {
        let a = Refinement::<i8, signed::OpenInterval<-30, -15>>::refine(-16).unwrap();
        let b = Refinement::<i8, signed::OpenInterval<-10, -5>>::refine(-9).unwrap();
        let c: Refinement<i8, signed::OpenInterval<0, 5>> = a / b;
        assert_eq!(*c, 1);
    }

    #[test]
    fn test_closed_interval_div() {
        let a = Refinement::<i8, signed::ClosedInterval<-15, 50>>::refine(50).unwrap();
        let b = Refinement::<i8, signed::ClosedInterval<-6, -3>>::refine(-3).unwrap();
        let c: Refinement<i8, signed::ClosedInterval<-16, 5>> = a / b;
        assert_eq!(*c, -16);
    }
}