1use std::{
2 fmt::Display,
3 ops::{AddAssign, DivAssign, MulAssign, SubAssign},
4};
5
6use num_traits::Num;
7use std::fmt::Debug;
8
9pub trait MIDINumInto<T: MIDINum> {
10 fn midi_num_into(&self) -> T;
31}
32
33pub trait MIDINumFrom<T: MIDINum> {
34 fn midi_num_from(val: T) -> Self;
55}
56
57pub trait MIDINum:
58 Num
59 + PartialOrd
60 + PartialEq
61 + AddAssign
62 + SubAssign
63 + DivAssign
64 + MulAssign
65 + Copy
66 + Sized
67 + Debug
68 + Display
69 + Send
70 + Sync
71 + MIDINumFrom<i32>
72 + MIDINumFrom<f32>
73 + MIDINumFrom<f64>
74 + MIDINumFrom<i64>
75 + MIDINumFrom<u32>
76 + MIDINumFrom<u64>
77 + MIDINumInto<i32>
78 + MIDINumInto<f32>
79 + MIDINumInto<f64>
80 + MIDINumInto<i64>
81 + MIDINumInto<u32>
82 + MIDINumInto<u64>
83{
84 fn saturating_add(self, other: Self) -> Self;
85 fn saturating_sub(self, other: Self) -> Self;
86}
87
88macro_rules! impl_delta_from_to {
89 ($from:ident, $to:ident) => {
90 impl MIDINumInto<$to> for $from {
91 fn midi_num_into(&self) -> $to {
92 *self as $to
93 }
94 }
95
96 impl MIDINumFrom<$to> for $from {
97 fn midi_num_from(val: $to) -> Self {
98 val as $from
99 }
100 }
101 };
102}
103
104macro_rules! impl_delta_from {
105 ($from:ident) => {
106 impl_delta_from_to!($from, i32);
107 impl_delta_from_to!($from, u32);
108 impl_delta_from_to!($from, i64);
109 impl_delta_from_to!($from, u64);
110 impl_delta_from_to!($from, f32);
111 impl_delta_from_to!($from, f64);
112 };
113}
114
115impl_delta_from!(i32);
116impl_delta_from!(u32);
117impl_delta_from!(i64);
118impl_delta_from!(u64);
119impl_delta_from!(f32);
120impl_delta_from!(f64);
121
122macro_rules! impl_midi_num_for_int {
123 ($int:ident) => {
124 impl MIDINum for $int {
125 fn saturating_add(self, other: Self) -> Self {
126 self.saturating_add(other)
127 }
128
129 fn saturating_sub(self, other: Self) -> Self {
130 self.saturating_sub(other)
131 }
132 }
133 };
134}
135
136macro_rules! impl_midi_num_for_float {
137 ($int:ident) => {
138 impl MIDINum for $int {
139 fn saturating_add(self, other: Self) -> Self {
140 self + other
141 }
142
143 fn saturating_sub(self, other: Self) -> Self {
144 self - other
145 }
146 }
147 };
148}
149
150impl_midi_num_for_int!(i32);
151impl_midi_num_for_int!(u32);
152impl_midi_num_for_int!(i64);
153impl_midi_num_for_int!(u64);
154impl_midi_num_for_float!(f32);
155impl_midi_num_for_float!(f64);
156
157#[cfg(test)]
158mod tests {
159 use crate::num::{MIDINumFrom, MIDINumInto};
160 #[test]
161 fn casts_delta_into() {
162 let dt_i32: i32 = 10;
163 let dt_u64: u64 = 10;
164
165 let dt_f32: f32 = dt_i32.midi_num_into();
166 let dt_f64: f64 = dt_i32.midi_num_into();
167 let dt_u32: u32 = dt_u64.midi_num_into();
168 let dt_i64: i64 = dt_u64.midi_num_into();
169
170 assert_eq!(dt_f32, 10f32);
171 assert_eq!(dt_f64, 10f64);
172 assert_eq!(dt_u32, 10u32);
173 assert_eq!(dt_i64, 10i64);
174 }
175
176 #[test]
177 fn casts_delta_from() {
178 let dt_i32: i32 = 10;
179 let dt_u64: u64 = 10;
180
181 let dt_f32 = f32::midi_num_from(dt_i32);
182 let dt_f64 = f64::midi_num_from(dt_i32);
183 let dt_u32 = u32::midi_num_from(dt_u64);
184 let dt_i64 = i64::midi_num_from(dt_u64);
185
186 assert_eq!(dt_f32, 10f32);
187 assert_eq!(dt_f64, 10f64);
188 assert_eq!(dt_u32, 10u32);
189 assert_eq!(dt_i64, 10i64);
190 }
191}