1use crate::{PitchMod, PyMod};
7use num_traits::{FromPrimitive, One, ToPrimitive, Zero};
8
9pub trait OrderedNum
10where
11 Self: PartialEq + PartialOrd + One + Zero,
12{
13 private! {}
14
15 fn is_positive(&self) -> bool {
16 *self > Self::zero()
17 }
18
19 fn is_negative(&self) -> bool {
20 *self < Self::zero()
21 }
22}
23
24pub trait Numerical
25where
26 Self: OrderedNum
27 + Clone
28 + Copy
29 + Default
30 + FromPrimitive
31 + ToPrimitive
32 + PyMod<Output = Self>
33 + core::fmt::Debug
34 + core::fmt::Display
35 + core::ops::Add<Output = Self>
36 + core::ops::Sub<Output = Self>
37 + core::ops::Mul<Output = Self>
38 + core::ops::Div<Output = Self>
39 + core::ops::Rem<Output = Self>
40 + core::ops::AddAssign
41 + core::ops::DivAssign
42 + core::ops::MulAssign
43 + core::ops::RemAssign
44 + core::ops::SubAssign,
45{
46 private! {}
47
48 fn apply<F, U>(self, f: F) -> U
49 where
50 F: FnOnce(Self) -> U,
51 {
52 f(self)
53 }
54
55 fn abs(self) -> Self
56 where
57 Self: core::ops::Neg<Output = Self>,
58 {
59 if self.is_negative() { -self } else { self }
60 }
61}
62
63pub trait MusicScalar
64where
65 Self: Numerical + crate::PyMod<Output = Self> + crate::PitchMod<Output = Self>,
66{
67 private! {}
68}
69impl<T> OrderedNum for T
74where
75 T: PartialEq + PartialOrd + One + Zero,
76{
77 seal! {}
78}
79
80impl<T> Numerical for T
81where
82 T: Clone
83 + Copy
84 + Default
85 + PartialEq
86 + PartialOrd
87 + FromPrimitive
88 + ToPrimitive
89 + One
90 + Zero
91 + PitchMod<Output = Self>
92 + PyMod<Output = Self>
93 + core::fmt::Debug
94 + core::fmt::Display
95 + core::ops::Add<Output = Self>
96 + core::ops::Sub<Output = Self>
97 + core::ops::Mul<Output = Self>
98 + core::ops::Div<Output = Self>
99 + core::ops::Rem<Output = Self>
100 + core::ops::AddAssign
101 + core::ops::DivAssign
102 + core::ops::MulAssign
103 + core::ops::RemAssign
104 + core::ops::SubAssign,
105{
106 seal! {}
107}
108
109impl<T> MusicScalar for T
110where
111 T: Numerical + PyMod<Output = Self> + PitchMod<Output = Self>,
112{
113 seal! {}
114}
115
116