rstmt_core/ops/
absmod.rs

1/*
2    Appellation: absmod <module>
3    Contrib: FL03 <jo3mccain@icloud.com>
4*/
5use crate::pitch::PitchTy;
6
7/// The [`PyMod`] trait, inpired by pythons `%` operator, describes a method for finding
8/// the modulo between two numbers which, rather uniquely, preserves the sign of the
9/// _denominator_.
10///
11/// ### Example
12///
13/// ```rust
14/// use rstmt_core::PyMod;
15///
16/// let m = 12;
17/// assert_eq!(22.pymod(m), 10);
18/// assert_eq!(-17.pymod(m), -5);
19///
20/// ```
21pub trait PyMod<Rhs = Self> {
22    type Output;
23
24    fn pymod(&self, rhs: Rhs) -> Self::Output;
25}
26
27/// This trait further generalizes [PyMod] by returning the absolute value of the result;
28/// dropping all signs in the process. This method is particularly useful when working
29/// in environments where the magnitude of the result is more important than the sign.
30///
31/// ### Example
32pub trait AbsMod<Rhs = Self> {
33    type Output;
34
35    fn absmod(&self, rhs: Rhs) -> Self::Output;
36}
37
38pub trait PitchMod {
39    const MOD: PitchTy = crate::MODULUS;
40    type Output;
41
42    fn pitchmod(&self) -> Self::Output;
43}
44
45impl<S> PitchMod for S
46where
47    S: PyMod<PitchTy>,
48{
49    type Output = <S as PyMod<PitchTy>>::Output;
50
51    fn pitchmod(&self) -> Self::Output {
52        self.pymod(Self::MOD)
53    }
54}
55
56/*
57 ************* Implementations *************
58*/
59use core::ops::{Add, Rem};
60use num::traits::{Num, Signed};
61
62impl<T> PyMod<T> for T
63where
64    T: Copy + Num + PartialOrd + Signed,
65{
66    type Output = T;
67
68    fn pymod(&self, y: T) -> Self::Output {
69        crate::pymod(*self, y)
70    }
71}
72
73// impl<A, B, C> AbsMod<B> for A
74// where
75//     A: PyMod<B, Output = C>,
76//     C: Signed,
77// {
78//     type Output = C;
79
80//     fn absmod(&self, rhs: B) -> Self::Output {
81//         self.pymod(rhs).abs()
82//     }
83// }
84
85impl<A, B, C> AbsMod<B> for A
86where
87    A: Copy + Add<C, Output = C> + Rem<B, Output = C>,
88    B: Copy,
89    C: Add<B, Output = C> + Rem<B, Output = C> + Signed,
90{
91    type Output = C;
92
93    fn absmod(&self, rhs: B) -> Self::Output {
94        (((*self % rhs) + rhs) % rhs).abs()
95    }
96}