rstmt_traits/ops/
pymod.rs1use crate::OrderedNum;
6use num_traits::{FromPrimitive, Zero};
7
8fn _pymod<A, B, C>(lhs: A, rhs: B) -> C
10where
11 B: PartialOrd + Zero,
12 C: PartialOrd + Zero + core::ops::Add<B, Output = C>,
13 for<'a> A: core::ops::Rem<&'a B, Output = C>,
14{
15 let r = lhs % &rhs;
16 if (r < <C>::zero() && rhs > <B>::zero()) || (r > <C>::zero() && rhs < <B>::zero()) {
17 r + rhs
18 } else {
19 r
20 }
21}
22
23pub trait PyMod<Rhs = Self> {
27 type Output;
28
29 fn pymod(self, rhs: Rhs) -> Self::Output;
30}
31
32pub trait PitchMod {
35 type Output;
36
37 fn pmod(self) -> Self::Output;
38}
39
40impl<A, B, C> PyMod<B> for A
44where
45 B: OrderedNum,
46 C: OrderedNum + core::ops::Add<B, Output = C>,
47 for<'a> A: core::ops::Rem<&'a B, Output = C>,
48{
49 type Output = C;
50
51 fn pymod(self, rhs: B) -> Self::Output {
52 let r = self % &rhs;
53 if (r.is_negative() && rhs.is_positive()) || (r.is_positive() && rhs.is_negative()) {
54 r + rhs
55 } else {
56 r
57 }
58 }
59}
60
61impl<A> PitchMod for A
62where
63 A: PyMod<A, Output = A> + FromPrimitive,
64{
65 type Output = A::Output;
66
67 fn pmod(self) -> Self::Output {
68 self.pymod(A::from_u8(12).unwrap())
69 }
70}