1use super::{add_impl, maybe_panic, sub_impl, FixedUInt, MachineWord, PanicReason};
2use crate::const_numtraits::{
3 ConstBounded, ConstCheckedAdd, ConstCheckedSub, ConstOverflowingAdd, ConstOverflowingSub,
4 ConstSaturatingAdd, ConstSaturatingSub, ConstWrappingAdd, ConstWrappingSub, ConstZero,
5};
6use crate::machineword::ConstMachineWord;
7
8c0nst::c0nst! {
9 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst crate::const_numtraits::ConstOverflowingAdd for FixedUInt<T, N> {
10 fn overflowing_add(&self, other: &Self) -> (Self, bool) {
11 let mut ret = *self;
12 let overflow = add_impl(&mut ret.array, &other.array);
13 (ret, overflow)
14 }
15 }
16
17 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst crate::const_numtraits::ConstOverflowingSub for FixedUInt<T, N> {
18 fn overflowing_sub(&self, other: &Self) -> (Self, bool) {
19 let mut ret = *self;
20 let overflow = sub_impl(&mut ret.array, &other.array);
21 (ret, overflow)
22 }
23 }
24
25 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst ConstWrappingAdd for FixedUInt<T, N> {
26 fn wrapping_add(&self, other: &Self) -> Self {
27 <Self as ConstOverflowingAdd>::overflowing_add(self, other).0
28 }
29 }
30
31 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst ConstWrappingSub for FixedUInt<T, N> {
32 fn wrapping_sub(&self, other: &Self) -> Self {
33 <Self as ConstOverflowingSub>::overflowing_sub(self, other).0
34 }
35 }
36
37 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst ConstCheckedAdd for FixedUInt<T, N> {
38 fn checked_add(&self, other: &Self) -> Option<Self> {
39 let (res, overflow) = <Self as ConstOverflowingAdd>::overflowing_add(self, other);
40 if overflow { None } else { Some(res) }
41 }
42 }
43
44 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst ConstCheckedSub for FixedUInt<T, N> {
45 fn checked_sub(&self, other: &Self) -> Option<Self> {
46 let (res, overflow) = <Self as ConstOverflowingSub>::overflowing_sub(self, other);
47 if overflow { None } else { Some(res) }
48 }
49 }
50
51 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst ConstSaturatingAdd for FixedUInt<T, N> {
52 fn saturating_add(&self, other: &Self) -> Self {
53 let (res, overflow) = <Self as ConstOverflowingAdd>::overflowing_add(self, other);
54 if overflow { <Self as ConstBounded>::max_value() } else { res }
55 }
56 }
57
58 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst ConstSaturatingSub for FixedUInt<T, N> {
59 fn saturating_sub(&self, other: &Self) -> Self {
60 let (res, overflow) = <Self as ConstOverflowingSub>::overflowing_sub(self, other);
61 if overflow { <Self as ConstZero>::zero() } else { res }
62 }
63 }
64
65 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::Add for FixedUInt<T, N> {
66 type Output = Self;
67 fn add(self, other: Self) -> Self {
68 let (res, overflow) = <Self as crate::const_numtraits::ConstOverflowingAdd>::overflowing_add(&self, &other);
69 if overflow {
70 maybe_panic(PanicReason::Add);
71 }
72 res
73 }
74 }
75
76 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::Sub for FixedUInt<T, N> {
77 type Output = Self;
78 fn sub(self, other: Self) -> Self {
79 let (res, overflow) = <Self as crate::const_numtraits::ConstOverflowingSub>::overflowing_sub(&self, &other);
80 if overflow {
81 maybe_panic(PanicReason::Sub);
82 }
83 res
84 }
85 }
86
87 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::Add<&'_ Self> for FixedUInt<T, N> {
88 type Output = Self;
89 fn add(self, other: &Self) -> Self {
90 let (res, overflow) = <Self as crate::const_numtraits::ConstOverflowingAdd>::overflowing_add(&self, other);
91 if overflow {
92 maybe_panic(PanicReason::Add);
93 }
94 res
95 }
96 }
97
98 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::Add<FixedUInt<T, N>> for &FixedUInt<T, N> {
99 type Output = FixedUInt<T, N>;
100 fn add(self, other: FixedUInt<T, N>) -> Self::Output {
101 let (res, overflow) = <FixedUInt<T, N> as crate::const_numtraits::ConstOverflowingAdd>::overflowing_add(self, &other);
102 if overflow {
103 maybe_panic(PanicReason::Add);
104 }
105 res
106 }
107 }
108
109 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::Add<Self> for &FixedUInt<T, N> {
110 type Output = FixedUInt<T, N>;
111 fn add(self, other: Self) -> Self::Output {
112 let (res, overflow) = <FixedUInt<T, N> as crate::const_numtraits::ConstOverflowingAdd>::overflowing_add(self, other);
113 if overflow {
114 maybe_panic(PanicReason::Add);
115 }
116 res
117 }
118 }
119
120 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::Sub<&'_ Self> for FixedUInt<T, N> {
121 type Output = Self;
122 fn sub(self, other: &Self) -> Self {
123 let (res, overflow) = <Self as crate::const_numtraits::ConstOverflowingSub>::overflowing_sub(&self, other);
124 if overflow {
125 maybe_panic(PanicReason::Sub);
126 }
127 res
128 }
129 }
130
131 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::Sub<FixedUInt<T, N>> for &FixedUInt<T, N> {
132 type Output = FixedUInt<T, N>;
133 fn sub(self, other: FixedUInt<T, N>) -> Self::Output {
134 let (res, overflow) = <FixedUInt<T, N> as crate::const_numtraits::ConstOverflowingSub>::overflowing_sub(self, &other);
135 if overflow {
136 maybe_panic(PanicReason::Sub);
137 }
138 res
139 }
140 }
141
142 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::Sub<Self> for &FixedUInt<T, N> {
143 type Output = FixedUInt<T, N>;
144 fn sub(self, other: Self) -> Self::Output {
145 let (res, overflow) = <FixedUInt<T, N> as crate::const_numtraits::ConstOverflowingSub>::overflowing_sub(self, other);
146 if overflow {
147 maybe_panic(PanicReason::Sub);
148 }
149 res
150 }
151 }
152
153 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::AddAssign<Self> for FixedUInt<T, N> {
154 fn add_assign(&mut self, other: Self) {
155 if add_impl(&mut self.array, &other.array) {
156 maybe_panic(PanicReason::Add);
157 }
158 }
159 }
160
161 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::AddAssign<&'_ Self> for FixedUInt<T, N> {
162 fn add_assign(&mut self, other: &Self) {
163 if add_impl(&mut self.array, &other.array) {
164 maybe_panic(PanicReason::Add);
165 }
166 }
167 }
168
169 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::SubAssign<Self> for FixedUInt<T, N> {
170 fn sub_assign(&mut self, other: Self) {
171 if sub_impl(&mut self.array, &other.array) {
172 maybe_panic(PanicReason::Sub);
173 }
174 }
175 }
176
177 impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst core::ops::SubAssign<&'_ Self> for FixedUInt<T, N> {
178 fn sub_assign(&mut self, other: &Self) {
179 if sub_impl(&mut self.array, &other.array) {
180 maybe_panic(PanicReason::Sub);
181 }
182 }
183 }
184}
185
186impl<T: MachineWord, const N: usize> num_traits::ops::overflowing::OverflowingAdd
187 for FixedUInt<T, N>
188{
189 fn overflowing_add(&self, other: &Self) -> (Self, bool) {
190 <Self as crate::const_numtraits::ConstOverflowingAdd>::overflowing_add(self, other)
191 }
192}
193
194impl<T: MachineWord, const N: usize> num_traits::WrappingAdd for FixedUInt<T, N> {
195 fn wrapping_add(&self, other: &Self) -> Self {
196 <Self as ConstWrappingAdd>::wrapping_add(self, other)
197 }
198}
199
200impl<T: MachineWord, const N: usize> num_traits::CheckedAdd for FixedUInt<T, N> {
201 fn checked_add(&self, other: &Self) -> Option<Self> {
202 <Self as ConstCheckedAdd>::checked_add(self, other)
203 }
204}
205
206impl<T: MachineWord, const N: usize> num_traits::ops::saturating::SaturatingAdd
207 for FixedUInt<T, N>
208{
209 fn saturating_add(&self, other: &Self) -> Self {
210 <Self as ConstSaturatingAdd>::saturating_add(self, other)
211 }
212}
213
214impl<T: MachineWord, const N: usize> num_traits::ops::overflowing::OverflowingSub
215 for FixedUInt<T, N>
216{
217 fn overflowing_sub(&self, other: &Self) -> (Self, bool) {
218 <Self as crate::const_numtraits::ConstOverflowingSub>::overflowing_sub(self, other)
219 }
220}
221
222impl<T: MachineWord, const N: usize> num_traits::WrappingSub for FixedUInt<T, N> {
223 fn wrapping_sub(&self, other: &Self) -> Self {
224 <Self as ConstWrappingSub>::wrapping_sub(self, other)
225 }
226}
227
228impl<T: MachineWord, const N: usize> num_traits::CheckedSub for FixedUInt<T, N> {
229 fn checked_sub(&self, other: &Self) -> Option<Self> {
230 <Self as ConstCheckedSub>::checked_sub(self, other)
231 }
232}
233
234impl<T: MachineWord, const N: usize> num_traits::ops::saturating::SaturatingSub
235 for FixedUInt<T, N>
236{
237 fn saturating_sub(&self, other: &Self) -> Self {
238 <Self as ConstSaturatingSub>::saturating_sub(self, other)
239 }
240}
241
242impl<T: MachineWord, const N: usize> num_traits::Saturating for FixedUInt<T, N> {
244 fn saturating_add(self, other: Self) -> Self {
245 <Self as ConstSaturatingAdd>::saturating_add(&self, &other)
246 }
247
248 fn saturating_sub(self, other: Self) -> Self {
249 <Self as ConstSaturatingSub>::saturating_sub(&self, &other)
250 }
251}
252
253#[cfg(test)]
254mod tests {
255 use super::*;
256 use crate::const_numtraits::{
257 ConstCheckedAdd, ConstCheckedSub, ConstOverflowingAdd, ConstOverflowingSub,
258 ConstWrappingAdd, ConstWrappingSub,
259 };
260 use crate::machineword::ConstMachineWord;
261 use num_traits::Bounded;
262
263 c0nst::c0nst! {
264 pub c0nst fn const_overflowing_add<T: [c0nst] ConstMachineWord + MachineWord, const N: usize>(
266 a: &FixedUInt<T, N>,
267 b: &FixedUInt<T, N>
268 ) -> (FixedUInt<T, N>, bool) {
269 <FixedUInt<T, N> as ConstOverflowingAdd>::overflowing_add(a, b)
270 }
271
272 pub c0nst fn const_overflowing_sub<T: [c0nst] ConstMachineWord + MachineWord, const N: usize>(
274 a: &FixedUInt<T, N>,
275 b: &FixedUInt<T, N>
276 ) -> (FixedUInt<T, N>, bool) {
277 <FixedUInt<T, N> as ConstOverflowingSub>::overflowing_sub(a, b)
278 }
279
280 pub c0nst fn const_add<T: [c0nst] ConstMachineWord + MachineWord, const N: usize>(
282 a: FixedUInt<T, N>,
283 b: FixedUInt<T, N>
284 ) -> FixedUInt<T, N> {
285 a + b
286 }
287
288 pub c0nst fn const_sub<T: [c0nst] ConstMachineWord + MachineWord, const N: usize>(
290 a: FixedUInt<T, N>,
291 b: FixedUInt<T, N>
292 ) -> FixedUInt<T, N> {
293 a - b
294 }
295
296 pub c0nst fn const_wrapping_add<T: [c0nst] ConstMachineWord + MachineWord, const N: usize>(
298 a: &FixedUInt<T, N>,
299 b: &FixedUInt<T, N>
300 ) -> FixedUInt<T, N> {
301 <FixedUInt<T, N> as ConstWrappingAdd>::wrapping_add(a, b)
302 }
303
304 pub c0nst fn const_wrapping_sub<T: [c0nst] ConstMachineWord + MachineWord, const N: usize>(
306 a: &FixedUInt<T, N>,
307 b: &FixedUInt<T, N>
308 ) -> FixedUInt<T, N> {
309 <FixedUInt<T, N> as ConstWrappingSub>::wrapping_sub(a, b)
310 }
311
312 pub c0nst fn const_checked_add<T: [c0nst] ConstMachineWord + MachineWord, const N: usize>(
314 a: &FixedUInt<T, N>,
315 b: &FixedUInt<T, N>
316 ) -> Option<FixedUInt<T, N>> {
317 <FixedUInt<T, N> as ConstCheckedAdd>::checked_add(a, b)
318 }
319
320 pub c0nst fn const_checked_sub<T: [c0nst] ConstMachineWord + MachineWord, const N: usize>(
322 a: &FixedUInt<T, N>,
323 b: &FixedUInt<T, N>
324 ) -> Option<FixedUInt<T, N>> {
325 <FixedUInt<T, N> as ConstCheckedSub>::checked_sub(a, b)
326 }
327 }
328
329 #[test]
330 fn test_add_combinations() {
331 let a = FixedUInt::<u8, 2>::from(12u8);
332 let b = FixedUInt::<u8, 2>::from(3u8);
333 let expected = FixedUInt::<u8, 2>::from(15u8);
334
335 assert_eq!(a + b, expected);
337 assert_eq!(a + &b, expected);
339 assert_eq!(&a + b, expected);
341 assert_eq!(&a + &b, expected);
343 }
344
345 #[test]
346 fn test_sub_combinations() {
347 let a = FixedUInt::<u8, 2>::from(15u8);
348 let b = FixedUInt::<u8, 2>::from(3u8);
349 let expected = FixedUInt::<u8, 2>::from(12u8);
350
351 assert_eq!(a - b, expected);
353 assert_eq!(a - &b, expected);
355 assert_eq!(&a - b, expected);
357 assert_eq!(&a - &b, expected);
359 }
360
361 #[test]
362 fn test_const_overflowing_add() {
363 let a = FixedUInt::<u8, 2>::from(12u8);
365 let b = FixedUInt::<u8, 2>::from(3u8);
366 let (result, overflow) = const_overflowing_add(&a, &b);
367 assert_eq!(result, FixedUInt::<u8, 2>::from(15u8));
368 assert!(!overflow);
369
370 let a = <FixedUInt<u8, 2> as Bounded>::max_value();
372 let b = <FixedUInt<u8, 2> as Bounded>::max_value();
373 let (result, overflow) = const_overflowing_add(&a, &b);
374 assert_eq!(result, FixedUInt::<u8, 2>::from(u16::MAX - 1));
376 assert!(overflow);
377
378 let max = <FixedUInt<u8, 2> as Bounded>::max_value();
380 let one = FixedUInt::<u8, 2>::from(1u8);
381 let (_, overflow) = const_overflowing_add(&max, &one);
382 assert!(overflow);
383
384 #[cfg(feature = "nightly")]
385 {
386 const A: FixedUInt<u8, 2> = FixedUInt { array: [12, 0] };
387 const B: FixedUInt<u8, 2> = FixedUInt { array: [3, 0] };
388 const RESULT: (FixedUInt<u8, 2>, bool) = const_overflowing_add(&A, &B);
389 assert_eq!(RESULT.0.array, [15, 0]);
390 assert!(!RESULT.1);
391 }
392 }
393
394 #[test]
395 fn test_const_overflowing_sub() {
396 let a = FixedUInt::<u8, 2>::from(15u8);
398 let b = FixedUInt::<u8, 2>::from(3u8);
399 let (result, overflow) = const_overflowing_sub(&a, &b);
400 assert_eq!(result, FixedUInt::<u8, 2>::from(12u8));
401 assert!(!overflow);
402
403 let a = FixedUInt::<u8, 2>::from(0u8);
405 let b = FixedUInt::<u8, 2>::from(1u8);
406 let (_, overflow) = const_overflowing_sub(&a, &b);
407 assert!(overflow);
408
409 #[cfg(feature = "nightly")]
410 {
411 const A: FixedUInt<u8, 2> = FixedUInt { array: [15, 0] };
412 const B: FixedUInt<u8, 2> = FixedUInt { array: [3, 0] };
413 const RESULT: (FixedUInt<u8, 2>, bool) = const_overflowing_sub(&A, &B);
414 assert_eq!(RESULT.0.array, [12, 0]);
415 assert!(!RESULT.1);
416 }
417 }
418
419 #[test]
420 fn test_const_add_op() {
421 let a = FixedUInt::<u8, 2>::from(12u8);
422 let b = FixedUInt::<u8, 2>::from(3u8);
423 let result = const_add(a, b);
424 assert_eq!(result, FixedUInt::<u8, 2>::from(15u8));
425
426 let a = FixedUInt::<u32, 2>::from(100u32);
428 let b = FixedUInt::<u32, 2>::from(200u32);
429 let result = const_add(a, b);
430 assert_eq!(result, FixedUInt::<u32, 2>::from(300u32));
431
432 #[cfg(feature = "nightly")]
433 {
434 const A: FixedUInt<u8, 2> = FixedUInt { array: [12, 0] };
435 const B: FixedUInt<u8, 2> = FixedUInt { array: [3, 0] };
436 const RESULT: FixedUInt<u8, 2> = const_add(A, B);
437 assert_eq!(RESULT.array, [15, 0]);
438 }
439 }
440
441 #[test]
442 fn test_const_sub_op() {
443 let a = FixedUInt::<u8, 2>::from(15u8);
444 let b = FixedUInt::<u8, 2>::from(3u8);
445 let result = const_sub(a, b);
446 assert_eq!(result, FixedUInt::<u8, 2>::from(12u8));
447
448 let a = FixedUInt::<u32, 2>::from(300u32);
450 let b = FixedUInt::<u32, 2>::from(100u32);
451 let result = const_sub(a, b);
452 assert_eq!(result, FixedUInt::<u32, 2>::from(200u32));
453
454 #[cfg(feature = "nightly")]
455 {
456 const A: FixedUInt<u8, 2> = FixedUInt { array: [15, 0] };
457 const B: FixedUInt<u8, 2> = FixedUInt { array: [3, 0] };
458 const RESULT: FixedUInt<u8, 2> = const_sub(A, B);
459 assert_eq!(RESULT.array, [12, 0]);
460 }
461 }
462
463 #[test]
464 fn test_const_wrapping_checked() {
465 let a = FixedUInt::<u8, 2>::from(100u8);
467 let b = FixedUInt::<u8, 2>::from(50u8);
468 let result = const_wrapping_add(&a, &b);
469 assert_eq!(result, FixedUInt::<u8, 2>::from(150u8));
470
471 let max = <FixedUInt<u8, 2> as Bounded>::max_value();
473 let one = FixedUInt::<u8, 2>::from(1u8);
474 let result = const_wrapping_add(&max, &one);
475 assert_eq!(result, FixedUInt::<u8, 2>::from(0u8));
476
477 let a = FixedUInt::<u8, 2>::from(100u8);
479 let b = FixedUInt::<u8, 2>::from(50u8);
480 let result = const_wrapping_sub(&a, &b);
481 assert_eq!(result, FixedUInt::<u8, 2>::from(50u8));
482
483 let zero = FixedUInt::<u8, 2>::from(0u8);
485 let one = FixedUInt::<u8, 2>::from(1u8);
486 let result = const_wrapping_sub(&zero, &one);
487 assert_eq!(result, <FixedUInt::<u8, 2> as Bounded>::max_value());
488
489 let a = FixedUInt::<u8, 2>::from(100u8);
491 let b = FixedUInt::<u8, 2>::from(50u8);
492 let result = const_checked_add(&a, &b);
493 assert_eq!(result, Some(FixedUInt::<u8, 2>::from(150u8)));
494
495 let max = <FixedUInt<u8, 2> as Bounded>::max_value();
497 let one = FixedUInt::<u8, 2>::from(1u8);
498 let result = const_checked_add(&max, &one);
499 assert_eq!(result, None);
500
501 let a = FixedUInt::<u8, 2>::from(100u8);
503 let b = FixedUInt::<u8, 2>::from(50u8);
504 let result = const_checked_sub(&a, &b);
505 assert_eq!(result, Some(FixedUInt::<u8, 2>::from(50u8)));
506
507 let zero = FixedUInt::<u8, 2>::from(0u8);
509 let one = FixedUInt::<u8, 2>::from(1u8);
510 let result = const_checked_sub(&zero, &one);
511 assert_eq!(result, None);
512
513 #[cfg(feature = "nightly")]
514 {
515 const A: FixedUInt<u8, 2> = FixedUInt { array: [100, 0] };
516 const B: FixedUInt<u8, 2> = FixedUInt { array: [50, 0] };
517
518 const WRAP_ADD: FixedUInt<u8, 2> = const_wrapping_add(&A, &B);
519 const WRAP_SUB: FixedUInt<u8, 2> = const_wrapping_sub(&A, &B);
520 const CHECK_ADD: Option<FixedUInt<u8, 2>> = const_checked_add(&A, &B);
521 const CHECK_SUB: Option<FixedUInt<u8, 2>> = const_checked_sub(&A, &B);
522
523 assert_eq!(WRAP_ADD.array, [150, 0]);
524 assert_eq!(WRAP_SUB.array, [50, 0]);
525 assert!(CHECK_ADD.is_some());
526 assert!(CHECK_SUB.is_some());
527
528 const MAX: FixedUInt<u8, 2> = FixedUInt { array: [255, 255] };
529 const ONE: FixedUInt<u8, 2> = FixedUInt { array: [1, 0] };
530 const CHECK_ADD_OVERFLOW: Option<FixedUInt<u8, 2>> = const_checked_add(&MAX, &ONE);
531 assert!(CHECK_ADD_OVERFLOW.is_none());
532 }
533 }
534}