fixed_bigint/fixeduint/
mul_div_impl.rs

1use num_traits::ops::overflowing::OverflowingMul;
2use num_traits::{Bounded, Zero};
3
4use super::{maybe_panic, FixedUInt, MachineWord, PanicReason};
5
6impl<T: MachineWord, const N: usize> num_traits::ops::overflowing::OverflowingMul
7    for FixedUInt<T, N>
8{
9    fn overflowing_mul(&self, other: &Self) -> (Self, bool) {
10        Self::mul_impl::<true>(self, other)
11    }
12}
13
14impl<T: MachineWord, const N: usize> core::ops::Mul for FixedUInt<T, N> {
15    type Output = Self;
16    fn mul(self, other: Self) -> <Self as core::ops::Mul<Self>>::Output {
17        let res = self.overflowing_mul(&other);
18        if res.1 {
19            maybe_panic(PanicReason::Mul);
20        }
21        res.0
22    }
23}
24
25impl<T: MachineWord, const N: usize> core::ops::Mul<&'_ Self> for FixedUInt<T, N> {
26    type Output = Self;
27    fn mul(self, other: &Self) -> <Self as core::ops::Mul<Self>>::Output {
28        let res = self.overflowing_mul(other);
29        if res.1 {
30            maybe_panic(PanicReason::Mul);
31        }
32        res.0
33    }
34}
35
36impl<T: MachineWord, const N: usize> core::ops::Mul<FixedUInt<T, N>> for &FixedUInt<T, N> {
37    type Output = FixedUInt<T, N>;
38    fn mul(self, other: FixedUInt<T, N>) -> Self::Output {
39        let res = self.overflowing_mul(&other);
40        if res.1 {
41            maybe_panic(PanicReason::Mul);
42        }
43        res.0
44    }
45}
46
47impl<T: MachineWord, const N: usize> core::ops::Mul<Self> for &FixedUInt<T, N> {
48    type Output = FixedUInt<T, N>;
49    fn mul(self, other: Self) -> Self::Output {
50        let res = self.overflowing_mul(other);
51        if res.1 {
52            maybe_panic(PanicReason::Mul);
53        }
54        res.0
55    }
56}
57
58impl<T: MachineWord, const N: usize> core::ops::Mul<&Self> for &FixedUInt<T, N> {
59    type Output = FixedUInt<T, N>;
60    fn mul(self, other: &Self) -> Self::Output {
61        let res = self.overflowing_mul(other);
62        if res.1 {
63            maybe_panic(PanicReason::Mul);
64        }
65        res.0
66    }
67}
68
69impl<T: MachineWord, const N: usize> num_traits::WrappingMul for FixedUInt<T, N> {
70    fn wrapping_mul(&self, other: &Self) -> Self {
71        Self::mul_impl::<false>(self, other).0
72    }
73}
74
75impl<T: MachineWord, const N: usize> num_traits::CheckedMul for FixedUInt<T, N> {
76    fn checked_mul(&self, other: &Self) -> Option<Self> {
77        let res = self.overflowing_mul(other);
78        if res.1 {
79            None
80        } else {
81            Some(res.0)
82        }
83    }
84}
85
86impl<T: MachineWord, const N: usize> num_traits::ops::saturating::SaturatingMul
87    for FixedUInt<T, N>
88{
89    fn saturating_mul(&self, other: &Self) -> Self {
90        let res = self.overflowing_mul(other);
91        if res.1 {
92            Self::max_value()
93        } else {
94            res.0
95        }
96    }
97}
98
99impl<T: MachineWord, const N: usize> core::ops::MulAssign<Self> for FixedUInt<T, N> {
100    fn mul_assign(&mut self, other: Self) {
101        let res = self.overflowing_mul(&other);
102        *self = res.0;
103        if res.1 {
104            maybe_panic(PanicReason::Mul);
105        }
106    }
107}
108
109impl<T: MachineWord, const N: usize> core::ops::MulAssign<&'_ Self> for FixedUInt<T, N> {
110    fn mul_assign(&mut self, other: &Self) {
111        let res = self.overflowing_mul(other);
112        *self = res.0;
113        if res.1 {
114            maybe_panic(PanicReason::Mul);
115        }
116    }
117}
118
119impl<T: MachineWord, const N: usize> core::ops::Div for FixedUInt<T, N> {
120    type Output = Self;
121    fn div(self, other: Self) -> <Self as core::ops::Div<Self>>::Output {
122        if other.is_zero() {
123            maybe_panic(PanicReason::DivByZero)
124        }
125        Self::div_impl(&self, &other)
126    }
127}
128
129impl<T: MachineWord, const N: usize> core::ops::Div<&'_ Self> for FixedUInt<T, N> {
130    type Output = Self;
131    fn div(self, other: &Self) -> <Self as core::ops::Div<Self>>::Output {
132        if other.is_zero() {
133            maybe_panic(PanicReason::DivByZero)
134        }
135        Self::div_impl(&self, other)
136    }
137}
138
139impl<T: MachineWord, const N: usize> core::ops::Div<Self> for &FixedUInt<T, N> {
140    type Output = FixedUInt<T, N>;
141    fn div(self, other: Self) -> Self::Output {
142        if other.is_zero() {
143            maybe_panic(PanicReason::DivByZero)
144        }
145        Self::Output::div_impl(self, other)
146    }
147}
148
149impl<T: MachineWord, const N: usize> core::ops::Div<&Self> for &FixedUInt<T, N> {
150    type Output = FixedUInt<T, N>;
151    fn div(self, other: &Self) -> Self::Output {
152        if other.is_zero() {
153            maybe_panic(PanicReason::DivByZero)
154        }
155        Self::Output::div_impl(self, other)
156    }
157}
158
159impl<T: MachineWord, const N: usize> core::ops::Div<FixedUInt<T, N>> for &FixedUInt<T, N> {
160    type Output = FixedUInt<T, N>;
161    fn div(self, other: FixedUInt<T, N>) -> Self::Output {
162        if other.is_zero() {
163            maybe_panic(PanicReason::DivByZero)
164        }
165        Self::Output::div_impl(self, &other)
166    }
167}
168
169impl<T: MachineWord, const N: usize> num_traits::CheckedDiv for FixedUInt<T, N> {
170    fn checked_div(&self, other: &Self) -> Option<Self> {
171        if other.is_zero() {
172            None
173        } else {
174            Some(core::ops::Div::<Self>::div(*self, *other))
175        }
176    }
177}
178
179impl<T: MachineWord, const N: usize> core::ops::DivAssign<Self> for FixedUInt<T, N> {
180    fn div_assign(&mut self, other: Self) {
181        if other.is_zero() {
182            maybe_panic(PanicReason::DivByZero)
183        }
184        Self::div_assign_impl(self, &other);
185    }
186}
187
188impl<T: MachineWord, const N: usize> core::ops::DivAssign<&'_ Self> for FixedUInt<T, N> {
189    fn div_assign(&mut self, other: &Self) {
190        if other.is_zero() {
191            maybe_panic(PanicReason::DivByZero)
192        }
193        Self::div_assign_impl(self, other);
194    }
195}
196
197impl<T: MachineWord, const N: usize> core::ops::Rem for FixedUInt<T, N> {
198    type Output = Self;
199    fn rem(self, other: Self) -> Self {
200        if other.is_zero() {
201            maybe_panic(PanicReason::RemByZero)
202        }
203        self.div_rem(&other).1
204    }
205}
206
207impl<T: MachineWord, const N: usize> core::ops::Rem<&'_ Self> for FixedUInt<T, N> {
208    type Output = Self;
209    fn rem(self, other: &Self) -> Self {
210        if other.is_zero() {
211            maybe_panic(PanicReason::RemByZero)
212        }
213        self.div_rem(other).1
214    }
215}
216
217impl<T: MachineWord, const N: usize> core::ops::Rem<Self> for &FixedUInt<T, N> {
218    type Output = FixedUInt<T, N>;
219    fn rem(self, other: Self) -> Self::Output {
220        if other.is_zero() {
221            maybe_panic(PanicReason::RemByZero)
222        }
223        self.div_rem(other).1
224    }
225}
226
227impl<T: MachineWord, const N: usize> core::ops::Rem<&Self> for &FixedUInt<T, N> {
228    type Output = FixedUInt<T, N>;
229    fn rem(self, other: &Self) -> Self::Output {
230        if other.is_zero() {
231            maybe_panic(PanicReason::RemByZero)
232        }
233        self.div_rem(other).1
234    }
235}
236
237impl<T: MachineWord, const N: usize> num_traits::CheckedRem for FixedUInt<T, N> {
238    fn checked_rem(&self, other: &Self) -> Option<Self> {
239        if other.is_zero() {
240            None
241        } else {
242            Some(core::ops::Rem::<Self>::rem(*self, *other))
243        }
244    }
245}
246
247impl<T: MachineWord, const N: usize> core::ops::RemAssign<Self> for FixedUInt<T, N> {
248    fn rem_assign(&mut self, other: Self) {
249        if other.is_zero() {
250            maybe_panic(PanicReason::RemByZero)
251        }
252        *self = self.div_rem(&other).1;
253    }
254}
255
256impl<T: MachineWord, const N: usize> core::ops::RemAssign<&'_ Self> for FixedUInt<T, N> {
257    fn rem_assign(&mut self, other: &Self) {
258        if other.is_zero() {
259            maybe_panic(PanicReason::RemByZero)
260        }
261        *self = self.div_rem(other).1;
262    }
263}
264
265impl<T: MachineWord, const N: usize> core::ops::Rem<FixedUInt<T, N>> for &FixedUInt<T, N> {
266    type Output = FixedUInt<T, N>;
267    fn rem(self, other: FixedUInt<T, N>) -> Self::Output {
268        if other.is_zero() {
269            maybe_panic(PanicReason::RemByZero)
270        }
271        self.div_rem(&other).1
272    }
273}
274
275#[cfg(test)]
276mod tests {
277    use super::*;
278
279    #[test]
280    fn test_basic_mul() {
281        let a = FixedUInt::<u8, 2>::from(123u8);
282        let b = FixedUInt::<u8, 2>::from(234u8);
283        let c = a * b;
284        assert_eq!(c, FixedUInt::<u8, 2>::from(28782u16));
285    }
286
287    #[test]
288    fn test_mul_combinations() {
289        let a = FixedUInt::<u8, 2>::from(12u8);
290        let b = FixedUInt::<u8, 2>::from(3u8);
291        let expected = FixedUInt::<u8, 2>::from(36u8);
292
293        // value * value
294        assert_eq!(a * b, expected);
295        // value * ref
296        assert_eq!(a * &b, expected);
297        // ref * value
298        assert_eq!(&a * b, expected);
299        // ref * ref
300        assert_eq!(&a * &b, expected);
301    }
302
303    #[test]
304    fn test_div_combinations() {
305        let a = FixedUInt::<u8, 2>::from(36u8);
306        let b = FixedUInt::<u8, 2>::from(3u8);
307        let expected = FixedUInt::<u8, 2>::from(12u8);
308
309        // value / value
310        assert_eq!(a / b, expected);
311        // value / ref
312        assert_eq!(a / &b, expected);
313        // ref / value
314        assert_eq!(&a / b, expected);
315        // ref / ref
316        assert_eq!(&a / &b, expected);
317    }
318
319    #[test]
320    fn test_rem_combinations() {
321        let a = FixedUInt::<u8, 2>::from(37u8);
322        let b = FixedUInt::<u8, 2>::from(3u8);
323        let expected = FixedUInt::<u8, 2>::from(1u8); // 37 % 3 = 1
324
325        // value % value
326        assert_eq!(a % b, expected);
327        // value % ref
328        assert_eq!(a % &b, expected);
329        // ref % value
330        assert_eq!(&a % b, expected);
331        // ref % ref
332        assert_eq!(&a % &b, expected);
333    }
334}