rstmt_core/traits/
num.rs

1/*
2    Appellation: num <module>
3    Contrib: @FL03
4*/
5use num_traits::{FromPrimitive, Zero};
6
7/// a functional implementation of python's modulo operator
8fn _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}
21/// The [`PyMod`] trait defines a pythonic modulo operator that can be used to perform modulo
22/// operations similar to Python's `%` operator, which behaves differently than Rust's `%`
23/// operator when dealing with negative numbers.
24pub trait PyMod<Rhs = Self> {
25    type Output;
26
27    fn pymod(self, rhs: Rhs) -> Self::Output;
28}
29
30/// this trait relies on a python modulo operator with a divisor of 12
31pub 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}