1use super::{const_div_rem, const_mul, maybe_panic, FixedUInt, MachineWord, PanicReason};
2use crate::const_numtraits::{
3 ConstBounded, ConstCheckedDiv, ConstCheckedMul, ConstCheckedRem, ConstOverflowingMul,
4 ConstSaturatingMul, ConstWrappingMul, ConstZero,
5};
6use crate::machineword::ConstMachineWord;
7
8impl<T: MachineWord, const N: usize> num_traits::ops::overflowing::OverflowingMul
9 for FixedUInt<T, N>
10{
11 fn overflowing_mul(&self, other: &Self) -> (Self, bool) {
12 <Self as ConstOverflowingMul>::overflowing_mul(self, other)
13 }
14}
15
16c0nst::c0nst! {
17 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst ConstOverflowingMul for FixedUInt<T, N> {
18 fn overflowing_mul(&self, other: &Self) -> (Self, bool) {
19 let (array, overflow) = const_mul::<T, N, true>(&self.array, &other.array, Self::WORD_BITS);
20 (Self { array }, overflow)
21 }
22 }
23
24 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst ConstWrappingMul for FixedUInt<T, N> {
25 fn wrapping_mul(&self, other: &Self) -> Self {
26 let (array, _) = const_mul::<T, N, false>(&self.array, &other.array, Self::WORD_BITS);
27 Self { array }
28 }
29 }
30
31 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst ConstCheckedMul for FixedUInt<T, N> {
32 fn checked_mul(&self, other: &Self) -> Option<Self> {
33 let (res, overflow) = <Self as ConstOverflowingMul>::overflowing_mul(self, other);
34 if overflow { None } else { Some(res) }
35 }
36 }
37
38 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst ConstSaturatingMul for FixedUInt<T, N> {
39 fn saturating_mul(&self, other: &Self) -> Self {
40 let (res, overflow) = <Self as ConstOverflowingMul>::overflowing_mul(self, other);
41 if overflow { <Self as ConstBounded>::max_value() } else { res }
42 }
43 }
44}
45
46c0nst::c0nst! {
47 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::Mul for FixedUInt<T, N> {
48 type Output = Self;
49 fn mul(self, other: Self) -> Self::Output {
50 let (array, overflow) = const_mul::<T, N, true>(&self.array, &other.array, Self::WORD_BITS);
51 if overflow {
52 maybe_panic(PanicReason::Mul);
53 }
54 Self { array }
55 }
56 }
57
58 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::Mul<&FixedUInt<T, N>> for FixedUInt<T, N> {
59 type Output = Self;
60 fn mul(self, other: &FixedUInt<T, N>) -> Self::Output {
61 let (array, overflow) = const_mul::<T, N, true>(&self.array, &other.array, Self::WORD_BITS);
62 if overflow {
63 maybe_panic(PanicReason::Mul);
64 }
65 Self { array }
66 }
67 }
68
69 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::Mul<FixedUInt<T, N>> for &FixedUInt<T, N> {
70 type Output = FixedUInt<T, N>;
71 fn mul(self, other: FixedUInt<T, N>) -> Self::Output {
72 let (array, overflow) = const_mul::<T, N, true>(&self.array, &other.array, Self::Output::WORD_BITS);
73 if overflow {
74 maybe_panic(PanicReason::Mul);
75 }
76 FixedUInt { array }
77 }
78 }
79
80 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::Mul<&FixedUInt<T, N>> for &FixedUInt<T, N> {
81 type Output = FixedUInt<T, N>;
82 fn mul(self, other: &FixedUInt<T, N>) -> Self::Output {
83 let (array, overflow) = const_mul::<T, N, true>(&self.array, &other.array, Self::Output::WORD_BITS);
84 if overflow {
85 maybe_panic(PanicReason::Mul);
86 }
87 FixedUInt { array }
88 }
89 }
90
91 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::Mul<&&FixedUInt<T, N>> for &FixedUInt<T, N> {
92 type Output = FixedUInt<T, N>;
93 fn mul(self, other: &&FixedUInt<T, N>) -> Self::Output {
94 let (array, overflow) = const_mul::<T, N, true>(&self.array, &other.array, Self::Output::WORD_BITS);
95 if overflow {
96 maybe_panic(PanicReason::Mul);
97 }
98 FixedUInt { array }
99 }
100 }
101
102 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::MulAssign for FixedUInt<T, N> {
103 fn mul_assign(&mut self, other: Self) {
104 let (array, overflow) = const_mul::<T, N, true>(&self.array, &other.array, Self::WORD_BITS);
105 if overflow {
106 maybe_panic(PanicReason::Mul);
107 }
108 *self = Self { array };
109 }
110 }
111
112 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::MulAssign<&FixedUInt<T, N>> for FixedUInt<T, N> {
113 fn mul_assign(&mut self, other: &FixedUInt<T, N>) {
114 let (array, overflow) = const_mul::<T, N, true>(&self.array, &other.array, Self::WORD_BITS);
115 if overflow {
116 maybe_panic(PanicReason::Mul);
117 }
118 *self = Self { array };
119 }
120 }
121}
122
123impl<T: MachineWord, const N: usize> num_traits::WrappingMul for FixedUInt<T, N> {
125 fn wrapping_mul(&self, other: &Self) -> Self {
126 <Self as ConstWrappingMul>::wrapping_mul(self, other)
127 }
128}
129
130impl<T: MachineWord, const N: usize> num_traits::CheckedMul for FixedUInt<T, N> {
131 fn checked_mul(&self, other: &Self) -> Option<Self> {
132 <Self as ConstCheckedMul>::checked_mul(self, other)
133 }
134}
135
136impl<T: MachineWord, const N: usize> num_traits::ops::saturating::SaturatingMul
137 for FixedUInt<T, N>
138{
139 fn saturating_mul(&self, other: &Self) -> Self {
140 <Self as ConstSaturatingMul>::saturating_mul(self, other)
141 }
142}
143
144c0nst::c0nst! {
145 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::Div for FixedUInt<T, N> {
146 type Output = Self;
147 fn div(self, other: Self) -> Self::Output {
148 Self { array: const_div_rem(&self.array, &other.array).0 }
149 }
150 }
151
152 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::Div<&FixedUInt<T, N>> for FixedUInt<T, N> {
153 type Output = Self;
154 fn div(self, other: &FixedUInt<T, N>) -> Self::Output {
155 Self { array: const_div_rem(&self.array, &other.array).0 }
156 }
157 }
158
159 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst 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 Self::Output { array: const_div_rem(&self.array, &other.array).0 }
163 }
164 }
165
166 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::Div<&FixedUInt<T, N>> for &FixedUInt<T, N> {
167 type Output = FixedUInt<T, N>;
168 fn div(self, other: &FixedUInt<T, N>) -> Self::Output {
169 Self::Output { array: const_div_rem(&self.array, &other.array).0 }
170 }
171 }
172
173 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::DivAssign for FixedUInt<T, N> {
174 fn div_assign(&mut self, other: Self) {
175 self.array = const_div_rem(&self.array, &other.array).0;
176 }
177 }
178
179 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::DivAssign<&FixedUInt<T, N>> for FixedUInt<T, N> {
180 fn div_assign(&mut self, other: &FixedUInt<T, N>) {
181 self.array = const_div_rem(&self.array, &other.array).0;
182 }
183 }
184}
185
186c0nst::c0nst! {
187 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst ConstCheckedDiv for FixedUInt<T, N> {
188 fn checked_div(&self, other: &Self) -> Option<Self> {
189 if <Self as ConstZero>::is_zero(other) {
190 None
191 } else {
192 Some(*self / *other)
193 }
194 }
195 }
196}
197
198impl<T: MachineWord, const N: usize> num_traits::CheckedDiv for FixedUInt<T, N> {
199 fn checked_div(&self, other: &Self) -> Option<Self> {
200 <Self as ConstCheckedDiv>::checked_div(self, other)
201 }
202}
203
204c0nst::c0nst! {
205 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::Rem for FixedUInt<T, N> {
206 type Output = Self;
207 fn rem(self, other: Self) -> Self::Output {
208 Self { array: const_div_rem(&self.array, &other.array).1 }
209 }
210 }
211
212 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::Rem<&FixedUInt<T, N>> for FixedUInt<T, N> {
213 type Output = Self;
214 fn rem(self, other: &FixedUInt<T, N>) -> Self::Output {
215 Self { array: const_div_rem(&self.array, &other.array).1 }
216 }
217 }
218
219 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::Rem<FixedUInt<T, N>> for &FixedUInt<T, N> {
220 type Output = FixedUInt<T, N>;
221 fn rem(self, other: FixedUInt<T, N>) -> Self::Output {
222 Self::Output { array: const_div_rem(&self.array, &other.array).1 }
223 }
224 }
225
226 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::Rem<&FixedUInt<T, N>> for &FixedUInt<T, N> {
227 type Output = FixedUInt<T, N>;
228 fn rem(self, other: &FixedUInt<T, N>) -> Self::Output {
229 Self::Output { array: const_div_rem(&self.array, &other.array).1 }
230 }
231 }
232
233 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::RemAssign for FixedUInt<T, N> {
234 fn rem_assign(&mut self, other: Self) {
235 self.array = const_div_rem(&self.array, &other.array).1;
236 }
237 }
238
239 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::RemAssign<&FixedUInt<T, N>> for FixedUInt<T, N> {
240 fn rem_assign(&mut self, other: &FixedUInt<T, N>) {
241 self.array = const_div_rem(&self.array, &other.array).1;
242 }
243 }
244}
245
246c0nst::c0nst! {
247 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst ConstCheckedRem for FixedUInt<T, N> {
248 fn checked_rem(&self, other: &Self) -> Option<Self> {
249 if <Self as ConstZero>::is_zero(other) {
250 None
251 } else {
252 Some(*self % *other)
253 }
254 }
255 }
256}
257
258impl<T: MachineWord, const N: usize> num_traits::CheckedRem for FixedUInt<T, N> {
259 fn checked_rem(&self, other: &Self) -> Option<Self> {
260 <Self as ConstCheckedRem>::checked_rem(self, other)
261 }
262}
263
264#[cfg(test)]
266c0nst::c0nst! {
267 pub c0nst fn const_wrapping_mul<T: [c0nst] ConstMachineWord + MachineWord, const N: usize>(
268 a: &FixedUInt<T, N>,
269 b: &FixedUInt<T, N>
270 ) -> FixedUInt<T, N> {
271 <FixedUInt<T, N> as ConstWrappingMul>::wrapping_mul(a, b)
272 }
273
274 pub c0nst fn const_checked_mul<T: [c0nst] ConstMachineWord + MachineWord, const N: usize>(
275 a: &FixedUInt<T, N>,
276 b: &FixedUInt<T, N>
277 ) -> Option<FixedUInt<T, N>> {
278 <FixedUInt<T, N> as ConstCheckedMul>::checked_mul(a, b)
279 }
280
281 pub c0nst fn const_saturating_mul<T: [c0nst] ConstMachineWord + MachineWord, const N: usize>(
282 a: &FixedUInt<T, N>,
283 b: &FixedUInt<T, N>
284 ) -> FixedUInt<T, N> {
285 <FixedUInt<T, N> as ConstSaturatingMul>::saturating_mul(a, b)
286 }
287
288 pub c0nst fn const_overflowing_mul<T: [c0nst] ConstMachineWord + MachineWord, const N: usize>(
289 a: &FixedUInt<T, N>,
290 b: &FixedUInt<T, N>
291 ) -> (FixedUInt<T, N>, bool) {
292 <FixedUInt<T, N> as ConstOverflowingMul>::overflowing_mul(a, b)
293 }
294
295 pub c0nst fn const_checked_div<T: [c0nst] ConstMachineWord + MachineWord, const N: usize>(
296 a: &FixedUInt<T, N>,
297 b: &FixedUInt<T, N>
298 ) -> Option<FixedUInt<T, N>> {
299 <FixedUInt<T, N> as ConstCheckedDiv>::checked_div(a, b)
300 }
301
302 pub c0nst fn const_checked_rem<T: [c0nst] ConstMachineWord + MachineWord, const N: usize>(
303 a: &FixedUInt<T, N>,
304 b: &FixedUInt<T, N>
305 ) -> Option<FixedUInt<T, N>> {
306 <FixedUInt<T, N> as ConstCheckedRem>::checked_rem(a, b)
307 }
308}
309
310#[cfg(test)]
311mod tests {
312 use super::*;
313
314 #[test]
315 fn test_basic_mul() {
316 let a = FixedUInt::<u8, 2>::from(123u8);
317 let b = FixedUInt::<u8, 2>::from(234u8);
318 let c = a * b;
319 assert_eq!(c, FixedUInt::<u8, 2>::from(28782u16));
320 }
321
322 #[test]
323 fn test_mul_combinations() {
324 let a = FixedUInt::<u8, 2>::from(12u8);
325 let b = FixedUInt::<u8, 2>::from(3u8);
326 let expected = FixedUInt::<u8, 2>::from(36u8);
327
328 assert_eq!(a * b, expected);
330 assert_eq!(a * &b, expected);
332 assert_eq!(&a * b, expected);
334 assert_eq!(&a * &b, expected);
336 }
337
338 #[test]
339 fn test_div_combinations() {
340 let a = FixedUInt::<u8, 2>::from(36u8);
341 let b = FixedUInt::<u8, 2>::from(3u8);
342 let expected = FixedUInt::<u8, 2>::from(12u8);
343
344 assert_eq!(a / b, expected);
346 assert_eq!(a / &b, expected);
348 assert_eq!(&a / b, expected);
350 assert_eq!(&a / &b, expected);
352 }
353
354 #[test]
355 fn test_rem_combinations() {
356 let a = FixedUInt::<u8, 2>::from(37u8);
357 let b = FixedUInt::<u8, 2>::from(3u8);
358 let expected = FixedUInt::<u8, 2>::from(1u8); assert_eq!(a % b, expected);
362 assert_eq!(a % &b, expected);
364 assert_eq!(&a % b, expected);
366 assert_eq!(&a % &b, expected);
368 }
369
370 #[test]
371 fn test_const_mul_traits() {
372 let a = FixedUInt::<u8, 2>::from(12u8);
373 let b = FixedUInt::<u8, 2>::from(3u8);
374 let expected = FixedUInt::<u8, 2>::from(36u8);
375
376 assert_eq!(const_wrapping_mul(&a, &b), expected);
378
379 assert_eq!(const_checked_mul(&a, &b), Some(expected));
381
382 assert_eq!(const_saturating_mul(&a, &b), expected);
384
385 let (result, overflow) = const_overflowing_mul(&a, &b);
387 assert_eq!(result, expected);
388 assert!(!overflow);
389
390 let large = FixedUInt::<u8, 2>::from(256u16); assert_eq!(const_checked_mul(&large, &large), None);
395
396 let saturated = const_saturating_mul(&large, &large);
398 assert_eq!(saturated, FixedUInt::<u8, 2>::from(0xFFFFu16));
399
400 let (_, overflow) = const_overflowing_mul(&large, &large);
402 assert!(overflow);
403
404 #[cfg(feature = "nightly")]
405 {
406 const A: FixedUInt<u8, 2> = FixedUInt { array: [12, 0] };
407 const B: FixedUInt<u8, 2> = FixedUInt { array: [3, 0] };
408
409 const WRAPPING_RESULT: FixedUInt<u8, 2> = const_wrapping_mul(&A, &B);
410 assert_eq!(WRAPPING_RESULT.array, [36, 0]);
411
412 const CHECKED_RESULT: Option<FixedUInt<u8, 2>> = const_checked_mul(&A, &B);
413 assert!(CHECKED_RESULT.is_some());
414
415 const SATURATING_RESULT: FixedUInt<u8, 2> = const_saturating_mul(&A, &B);
416 assert_eq!(SATURATING_RESULT.array, [36, 0]);
417
418 const OVERFLOWING_RESULT: (FixedUInt<u8, 2>, bool) = const_overflowing_mul(&A, &B);
419 assert_eq!(OVERFLOWING_RESULT.0.array, [36, 0]);
420 assert!(!OVERFLOWING_RESULT.1);
421 }
422 }
423
424 #[test]
425 fn test_const_checked_div_rem() {
426 let a = FixedUInt::<u8, 2>::from(36u8);
427 let b = FixedUInt::<u8, 2>::from(5u8);
428 let zero = FixedUInt::<u8, 2>::from(0u8);
429
430 assert_eq!(
432 const_checked_div(&a, &b),
433 Some(FixedUInt::<u8, 2>::from(7u8))
434 ); assert_eq!(const_checked_div(&a, &zero), None);
438
439 assert_eq!(
441 const_checked_rem(&a, &b),
442 Some(FixedUInt::<u8, 2>::from(1u8))
443 ); assert_eq!(const_checked_rem(&a, &zero), None);
447
448 #[cfg(feature = "nightly")]
449 {
450 const A: FixedUInt<u8, 2> = FixedUInt { array: [36, 0] };
451 const B: FixedUInt<u8, 2> = FixedUInt { array: [5, 0] };
452 const ZERO: FixedUInt<u8, 2> = FixedUInt { array: [0, 0] };
453
454 const CHECKED_DIV_OK: Option<FixedUInt<u8, 2>> = const_checked_div(&A, &B);
455 const CHECKED_DIV_ZERO: Option<FixedUInt<u8, 2>> = const_checked_div(&A, &ZERO);
456 const CHECKED_REM_OK: Option<FixedUInt<u8, 2>> = const_checked_rem(&A, &B);
457 const CHECKED_REM_ZERO: Option<FixedUInt<u8, 2>> = const_checked_rem(&A, &ZERO);
458
459 assert_eq!(CHECKED_DIV_OK, Some(FixedUInt { array: [7, 0] }));
460 assert_eq!(CHECKED_DIV_ZERO, None);
461 assert_eq!(CHECKED_REM_OK, Some(FixedUInt { array: [1, 0] }));
462 assert_eq!(CHECKED_REM_ZERO, None);
463 }
464 }
465}