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