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}