1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
use crate::{Denominator, Numerator, Q};
use core::ops::Mul;
use typenum::{Gcd, Gcf, PartialDiv, Prod};

pub trait PrivateMulHelper<Rhs> {
    type Output;
}

impl<Nl, Dl, Nr, Dr, No, Do> PrivateMulHelper<Q<Nr, Dr>> for Q<Nl, Dl>
where
    Nl: Numerator<Dl> + Mul<Nr>,
    Dl: Denominator + Mul<Dr>,
    Nr: Numerator<Dr>,
    Dr: Denominator,
    No: Numerator<Do>,
    Do: Denominator,
    Prod<Nl, Nr>: Gcd<Prod<Dl, Dr>> + PartialDiv<Gcf<Prod<Nl, Nr>, Prod<Dl, Dr>>, Output = No>,
    Prod<Dl, Dr>: PartialDiv<Gcf<Prod<Nl, Nr>, Prod<Dl, Dr>>, Output = Do>,
{
    type Output = Q<No, Do>;
}

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

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

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

    #[test]
    fn test_mul() {
        // zero * zero
        assert!(Q::<Z0>::new() * Q::<Z0>::new() == Q::<Z0>::new());

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

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

        // positive * negative
        assert!(Q::<P2, P3>::new() * Q::<N3, P2>::new() == Q::<N1>::new());

        // negative * zero
        assert!(Q::<N2, P3>::new() * Q::<Z0>::new() == Q::<Z0>::new());

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

        // negative * negative
        assert!(Q::<N2, P3>::new() * Q::<N3, P2>::new() == Q::<P1>::new());
    }
}