1use num_traits::{FromPrimitive, Zero};
6
7fn _pymod<A, B, C>(lhs: A, rhs: B) -> C
9where
10 A: core::ops::Rem<B, Output = C>,
11 B: Copy + Zero + PartialOrd,
12 C: core::ops::Add<B, Output = C> + Zero + PartialOrd,
13{
14 let r = lhs % rhs;
15 if (r < C::zero() && rhs > B::zero()) || (r > C::zero() && rhs < B::zero()) {
16 r + rhs
17 } else {
18 r
19 }
20}
21pub trait PyMod<Rhs = Self> {
25 type Output;
26
27 fn pymod(self, rhs: Rhs) -> Self::Output;
28}
29
30pub trait PitchMod {
32 type Output;
33
34 fn pmod(self) -> Self::Output;
35}
36
37impl<A, B, C> PyMod<B> for A
38where
39 A: core::ops::Rem<B, Output = C>,
40 B: Copy + PartialOrd + Zero,
41 C: PartialOrd + Zero + core::ops::Add<B, Output = C>,
42{
43 type Output = C;
44
45 fn pymod(self, rhs: B) -> Self::Output {
46 _pymod(self, rhs)
47 }
48}
49
50impl<A> PitchMod for A
51where
52 A: PyMod<A, Output = A> + FromPrimitive,
53{
54 type Output = A::Output;
55
56 fn pmod(self) -> Self::Output {
57 self.pymod(A::from_i32(12).unwrap())
58 }
59}