typerat 0.0.4

Type-level rational numbers based on `typenum`.
Documentation
use crate::{Denominator, NonZero, Numerator, Q};
use core::ops::{Mul, Rem};
use typenum::{Abs, AbsVal, Gcd, Gcf, Max, Maximum, Mod, PartialDiv, Prod, P1};

pub trait PrivateRemHelper<Rhs> {
    type Output;
}

impl<Nl, Dl, Nr, Dr, No, Do> PrivateRemHelper<Q<Nr, Dr>> for Q<Nl, Dl>
where
    Q<Nr, Dr>: NonZero,
    Nl: Numerator<Dl> + Mul<Dr>,
    Dl: Denominator + Mul<Dr>,
    Nr: Numerator<Dr> + Mul<Dl>,
    Dr: Denominator,
    No: Numerator<Do>,
    Do: Denominator,
    Prod<Nr, Dl>: Abs,
    AbsVal<Prod<Nr, Dl>>: Max<P1>,
    Prod<Nl, Dr>: Rem<Maximum<AbsVal<Prod<Nr, Dl>>, P1>>,
    Mod<Prod<Nl, Dr>, Maximum<AbsVal<Prod<Nr, Dl>>, P1>>: Gcd<Prod<Dl, Dr>>
        + PartialDiv<
            Gcf<Mod<Prod<Nl, Dr>, Maximum<AbsVal<Prod<Nr, Dl>>, P1>>, Prod<Dl, Dr>>,
            Output = No,
        >,
    Prod<Dl, Dr>: PartialDiv<
        Gcf<Mod<Prod<Nl, Dr>, Maximum<AbsVal<Prod<Nr, Dl>>, P1>>, Prod<Dl, Dr>>,
        Output = Do,
    >,
{
    type Output = Q<No, Do>;
}

impl<Nl, Dl, Nr, Dr, No, Do> Rem<Q<Nr, Dr>> for Q<Nl, Dl>
where
    Self: PrivateRemHelper<Q<Nr, Dr>, Output = Q<No, Do>>,
    Q<Nr, Dr>: NonZero,
    Nl: Numerator<Dl>,
    Dl: Denominator,
    Nr: Numerator<Dr>,
    Dr: Denominator,
    No: Numerator<Do>,
    Do: Denominator,
{
    type Output = Q<No, Do>;

    fn rem(self, rhs: Q<Nr, Dr>) -> Self::Output {
        let _ = rhs;
        Self::Output::new()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use typenum::consts::*;

    #[test]
    fn test_rem() {
        // zero % positive
        assert!(Q::<Z0>::new() % Q::<P1, P2>::new() == Q::<Z0>::new());

        // zero % negative
        assert!(Q::<Z0>::new() % Q::<N1, P2>::new() == Q::<Z0>::new());

        // positive % zero
        // let _ = Q::<P1, P2>::new() % Q::<Z0>::new();

        // positive % positive
        assert!(Q::<P2, P3>::new() % Q::<P1, P2>::new() == Q::<P1, P6>::new());

        // positive % negative
        assert!(Q::<P2, P3>::new() % Q::<N1, P2>::new() == Q::<P1, P6>::new());

        // negative % positive
        assert!(Q::<N2, P3>::new() % Q::<P1, P2>::new() == Q::<N1, P6>::new());

        // negative % negative
        assert!(Q::<N2, P3>::new() % Q::<N1, P2>::new() == Q::<N1, P6>::new());
    }
}