1use super::{
2 FixedUInt, MachineWord, PanicReason, add_impl, add_with_carry, const_ct_select, maybe_panic_if,
3 sub_impl, sub_with_borrow,
4};
5use crate::machineword::ConstMachineWord;
6use const_num_traits::ops::ct::{CtCheckedAdd, CtCheckedSub};
7use const_num_traits::{
8 Bounded, CheckedAdd, CheckedSub, ConstZero, OverflowingAdd, OverflowingSub, Personality,
9 PersonalityTag, SaturatingAdd, SaturatingSub, WrappingAdd, WrappingSub, Zero,
10};
11
12c0nst::c0nst! {
13 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> OverflowingAdd for FixedUInt<T, N, P> {
14 type Output = FixedUInt<T, N, P>;
15 fn overflowing_add(self, other: Self) -> (Self, bool) {
16 let mut ret = self;
17 let overflow = add_impl(&mut ret.array, &other.array);
18 (ret, overflow)
19 }
20 }
21
22 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> OverflowingSub for FixedUInt<T, N, P> {
23 type Output = FixedUInt<T, N, P>;
24 fn overflowing_sub(self, other: Self) -> (Self, bool) {
25 let mut ret = self;
26 let overflow = sub_impl(&mut ret.array, &other.array);
27 (ret, overflow)
28 }
29 }
30
31 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> WrappingAdd for FixedUInt<T, N, P> {
32 type Output = FixedUInt<T, N, P>;
33 fn wrapping_add(self, other: Self) -> Self {
34 <Self as OverflowingAdd>::overflowing_add(self, other).0
35 }
36 }
37
38 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> WrappingSub for FixedUInt<T, N, P> {
39 type Output = FixedUInt<T, N, P>;
40 fn wrapping_sub(self, other: Self) -> Self {
41 <Self as OverflowingSub>::overflowing_sub(self, other).0
42 }
43 }
44
45 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> CheckedAdd for FixedUInt<T, N, P> {
46 type Output = FixedUInt<T, N, P>;
47 fn checked_add(self, other: Self) -> Option<Self> {
48 let (res, overflow) = <Self as OverflowingAdd>::overflowing_add(self, other);
49 if overflow { None } else { Some(res) }
50 }
51 }
52
53 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> CheckedSub for FixedUInt<T, N, P> {
54 type Output = FixedUInt<T, N, P>;
55 fn checked_sub(self, other: Self) -> Option<Self> {
56 let (res, overflow) = <Self as OverflowingSub>::overflowing_sub(self, other);
57 if overflow { None } else { Some(res) }
58 }
59 }
60
61 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> SaturatingAdd for FixedUInt<T, N, P> {
62 type Output = FixedUInt<T, N, P>;
63 fn saturating_add(self, other: Self) -> Self {
64 let (res, overflow) = <Self as OverflowingAdd>::overflowing_add(self, other);
65 match P::TAG {
66 PersonalityTag::Nct => if overflow { <Self as Bounded>::max_value() } else { res },
67 PersonalityTag::Ct => const_ct_select(res, <Self as Bounded>::max_value(), overflow as u8),
68 }
69 }
70 }
71
72 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> SaturatingSub for FixedUInt<T, N, P> {
73 type Output = FixedUInt<T, N, P>;
74 fn saturating_sub(self, other: Self) -> Self {
75 let (res, overflow) = <Self as OverflowingSub>::overflowing_sub(self, other);
76 match P::TAG {
77 PersonalityTag::Nct => if overflow { <Self as ConstZero>::ZERO } else { res },
78 PersonalityTag::Ct => const_ct_select(res, <Self as ConstZero>::ZERO, overflow as u8),
79 }
80 }
81 }
82
83 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Add for FixedUInt<T, N, P> {
84 type Output = Self;
85 fn add(self, other: Self) -> Self {
86 let (res, overflow) = <Self as OverflowingAdd>::overflowing_add(self, other);
87 maybe_panic_if::<P>(overflow, PanicReason::Add);
88 res
89 }
90 }
91
92 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Sub for FixedUInt<T, N, P> {
93 type Output = Self;
94 fn sub(self, other: Self) -> Self {
95 let (res, overflow) = <Self as OverflowingSub>::overflowing_sub(self, other);
96 maybe_panic_if::<P>(overflow, PanicReason::Sub);
97 res
98 }
99 }
100
101 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Add<&'_ Self> for FixedUInt<T, N, P> {
102 type Output = Self;
103 fn add(self, other: &Self) -> Self {
104 let (res, overflow) = <Self as OverflowingAdd>::overflowing_add(self, *other);
105 maybe_panic_if::<P>(overflow, PanicReason::Add);
106 res
107 }
108 }
109
110 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Add<FixedUInt<T, N, P>> for &FixedUInt<T, N, P> {
111 type Output = FixedUInt<T, N, P>;
112 fn add(self, other: FixedUInt<T, N, P>) -> Self::Output {
113 let (array, overflow) = add_with_carry(&self.array, &other.array, false);
117 maybe_panic_if::<P>(overflow, PanicReason::Add);
118 FixedUInt::from_array(array)
119 }
120 }
121
122 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Add<Self> for &FixedUInt<T, N, P> {
123 type Output = FixedUInt<T, N, P>;
124 fn add(self, other: Self) -> Self::Output {
125 let (res, overflow) = <Self as OverflowingAdd>::overflowing_add(self, other);
126 maybe_panic_if::<P>(overflow, PanicReason::Add);
127 res
128 }
129 }
130
131 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Sub<&'_ Self> for FixedUInt<T, N, P> {
132 type Output = Self;
133 fn sub(self, other: &Self) -> Self {
134 let (res, overflow) = <Self as OverflowingSub>::overflowing_sub(self, *other);
135 maybe_panic_if::<P>(overflow, PanicReason::Sub);
136 res
137 }
138 }
139
140 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Sub<FixedUInt<T, N, P>> for &FixedUInt<T, N, P> {
141 type Output = FixedUInt<T, N, P>;
142 fn sub(self, other: FixedUInt<T, N, P>) -> Self::Output {
143 let (array, borrow) = sub_with_borrow(&self.array, &other.array, false);
144 maybe_panic_if::<P>(borrow, PanicReason::Sub);
145 FixedUInt::from_array(array)
146 }
147 }
148
149 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::Sub<Self> for &FixedUInt<T, N, P> {
150 type Output = FixedUInt<T, N, P>;
151 fn sub(self, other: Self) -> Self::Output {
152 let (res, borrow) = <Self as OverflowingSub>::overflowing_sub(self, other);
153 maybe_panic_if::<P>(borrow, PanicReason::Sub);
154 res
155 }
156 }
157
158 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::AddAssign<Self> for FixedUInt<T, N, P> {
159 fn add_assign(&mut self, other: Self) {
160 let mut array = self.array;
161 let overflow = add_impl(&mut array, &other.array);
162 maybe_panic_if::<P>(overflow, PanicReason::Add);
163 self.array = array;
164 }
165 }
166
167 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::AddAssign<&'_ Self> for FixedUInt<T, N, P> {
168 fn add_assign(&mut self, other: &Self) {
169 let mut array = self.array;
170 let overflow = add_impl(&mut array, &other.array);
171 maybe_panic_if::<P>(overflow, PanicReason::Add);
172 self.array = array;
173 }
174 }
175
176 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::SubAssign<Self> for FixedUInt<T, N, P> {
177 fn sub_assign(&mut self, other: Self) {
178 let mut array = self.array;
179 let overflow = sub_impl(&mut array, &other.array);
180 maybe_panic_if::<P>(overflow, PanicReason::Sub);
181 self.array = array;
182 }
183 }
184
185 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> core::ops::SubAssign<&'_ Self> for FixedUInt<T, N, P> {
186 fn sub_assign(&mut self, other: &Self) {
187 let mut array = self.array;
188 let overflow = sub_impl(&mut array, &other.array);
189 maybe_panic_if::<P>(overflow, PanicReason::Sub);
190 self.array = array;
191 }
192 }
193
194 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> OverflowingAdd for &FixedUInt<T, N, P> {
213 type Output = FixedUInt<T, N, P>;
214 fn overflowing_add(self, other: Self) -> (FixedUInt<T, N, P>, bool) {
215 let (array, overflow) = add_with_carry(&self.array, &other.array, false);
216 (FixedUInt::from_array(array), overflow)
217 }
218 }
219
220 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> OverflowingSub for &FixedUInt<T, N, P> {
221 type Output = FixedUInt<T, N, P>;
222 fn overflowing_sub(self, other: Self) -> (FixedUInt<T, N, P>, bool) {
223 let (array, borrow) = sub_with_borrow(&self.array, &other.array, false);
224 (FixedUInt::from_array(array), borrow)
225 }
226 }
227
228 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> WrappingAdd for &FixedUInt<T, N, P> {
229 type Output = FixedUInt<T, N, P>;
230 fn wrapping_add(self, other: Self) -> FixedUInt<T, N, P> {
231 let (array, _carry) = add_with_carry(&self.array, &other.array, false);
232 FixedUInt::from_array(array)
233 }
234 }
235
236 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> WrappingSub for &FixedUInt<T, N, P> {
237 type Output = FixedUInt<T, N, P>;
238 fn wrapping_sub(self, other: Self) -> FixedUInt<T, N, P> {
239 let (array, _borrow) = sub_with_borrow(&self.array, &other.array, false);
240 FixedUInt::from_array(array)
241 }
242 }
243
244 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> CheckedAdd for &FixedUInt<T, N, P> {
245 type Output = FixedUInt<T, N, P>;
246 fn checked_add(self, other: Self) -> Option<FixedUInt<T, N, P>> {
247 let (res, overflow) = <Self as OverflowingAdd>::overflowing_add(self, other);
248 if overflow { None } else { Some(res) }
249 }
250 }
251
252 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> CheckedSub for &FixedUInt<T, N, P> {
253 type Output = FixedUInt<T, N, P>;
254 fn checked_sub(self, other: Self) -> Option<FixedUInt<T, N, P>> {
255 let (res, borrow) = <Self as OverflowingSub>::overflowing_sub(self, other);
256 if borrow { None } else { Some(res) }
257 }
258 }
259
260 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> SaturatingAdd for &FixedUInt<T, N, P> {
261 type Output = FixedUInt<T, N, P>;
262 fn saturating_add(self, other: Self) -> FixedUInt<T, N, P> {
263 let (res, overflow) = <Self as OverflowingAdd>::overflowing_add(self, other);
264 if overflow {
265 <FixedUInt<T, N, P> as Bounded>::max_value()
266 } else {
267 res
268 }
269 }
270 }
271
272 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> SaturatingSub for &FixedUInt<T, N, P> {
273 type Output = FixedUInt<T, N, P>;
274 fn saturating_sub(self, other: Self) -> FixedUInt<T, N, P> {
275 let (res, borrow) = <Self as OverflowingSub>::overflowing_sub(self, other);
276 if borrow {
277 <FixedUInt<T, N, P> as Zero>::zero()
278 } else {
279 res
280 }
281 }
282 }
283}
284
285#[cfg(feature = "num-traits")]
286impl<T: MachineWord, const N: usize, P: Personality> num_traits::ops::overflowing::OverflowingAdd
287 for FixedUInt<T, N, P>
288{
289 fn overflowing_add(&self, other: &Self) -> (Self, bool) {
290 <&Self as OverflowingAdd>::overflowing_add(self, other)
291 }
292}
293
294#[cfg(feature = "num-traits")]
295impl<T: MachineWord, const N: usize, P: Personality> num_traits::WrappingAdd
296 for FixedUInt<T, N, P>
297{
298 fn wrapping_add(&self, other: &Self) -> Self {
299 <&Self as WrappingAdd>::wrapping_add(self, other)
300 }
301}
302
303#[cfg(feature = "num-traits")]
304impl<T: MachineWord, const N: usize, P: Personality> num_traits::CheckedAdd for FixedUInt<T, N, P> {
305 fn checked_add(&self, other: &Self) -> Option<Self> {
306 <&Self as CheckedAdd>::checked_add(self, other)
307 }
308}
309
310#[cfg(feature = "num-traits")]
311impl<T: MachineWord, const N: usize, P: Personality> num_traits::ops::saturating::SaturatingAdd
312 for FixedUInt<T, N, P>
313{
314 fn saturating_add(&self, other: &Self) -> Self {
315 <&Self as SaturatingAdd>::saturating_add(self, other)
316 }
317}
318
319#[cfg(feature = "num-traits")]
320impl<T: MachineWord, const N: usize, P: Personality> num_traits::ops::overflowing::OverflowingSub
321 for FixedUInt<T, N, P>
322{
323 fn overflowing_sub(&self, other: &Self) -> (Self, bool) {
324 <&Self as OverflowingSub>::overflowing_sub(self, other)
325 }
326}
327
328#[cfg(feature = "num-traits")]
329impl<T: MachineWord, const N: usize, P: Personality> num_traits::WrappingSub
330 for FixedUInt<T, N, P>
331{
332 fn wrapping_sub(&self, other: &Self) -> Self {
333 <&Self as WrappingSub>::wrapping_sub(self, other)
334 }
335}
336
337#[cfg(feature = "num-traits")]
338impl<T: MachineWord, const N: usize, P: Personality> num_traits::CheckedSub for FixedUInt<T, N, P> {
339 fn checked_sub(&self, other: &Self) -> Option<Self> {
340 <&Self as CheckedSub>::checked_sub(self, other)
341 }
342}
343
344#[cfg(feature = "num-traits")]
345impl<T: MachineWord, const N: usize, P: Personality> num_traits::ops::saturating::SaturatingSub
346 for FixedUInt<T, N, P>
347{
348 fn saturating_sub(&self, other: &Self) -> Self {
349 <&Self as SaturatingSub>::saturating_sub(self, other)
350 }
351}
352
353#[cfg(feature = "num-traits")]
355impl<T: MachineWord, const N: usize, P: Personality> num_traits::Saturating for FixedUInt<T, N, P> {
356 fn saturating_add(self, other: Self) -> Self {
357 <Self as SaturatingAdd>::saturating_add(self, other)
358 }
359
360 fn saturating_sub(self, other: Self) -> Self {
361 <Self as SaturatingSub>::saturating_sub(self, other)
362 }
363}
364
365impl<T: MachineWord, const N: usize, P: Personality> CtCheckedAdd for FixedUInt<T, N, P> {
372 fn ct_checked_add(&self, v: &Self) -> subtle::CtOption<Self> {
373 let (val, overflow) = <&Self as OverflowingAdd>::overflowing_add(self, v);
374 subtle::CtOption::new(val, subtle::Choice::from(!overflow as u8))
375 }
376}
377
378impl<T: MachineWord, const N: usize, P: Personality> CtCheckedSub for FixedUInt<T, N, P> {
379 fn ct_checked_sub(&self, v: &Self) -> subtle::CtOption<Self> {
380 let (val, overflow) = <&Self as OverflowingSub>::overflowing_sub(self, v);
381 subtle::CtOption::new(val, subtle::Choice::from(!overflow as u8))
382 }
383}
384
385#[cfg(test)]
386#[allow(clippy::op_ref)]
389mod tests {
390 use super::*;
391 use crate::machineword::ConstMachineWord;
392 use const_num_traits::Bounded;
393 use const_num_traits::{
394 CheckedAdd, CheckedSub, OverflowingAdd, OverflowingSub, WrappingAdd, WrappingSub,
395 };
396
397 c0nst::c0nst! {
398 pub c0nst fn const_overflowing_add<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(
400 a: &FixedUInt<T, N, P>,
401 b: &FixedUInt<T, N, P>
402 ) -> (FixedUInt<T, N, P>, bool) {
403 <FixedUInt<T, N, P> as OverflowingAdd>::overflowing_add(*a, *b)
404 }
405
406 pub c0nst fn const_overflowing_sub<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(
408 a: &FixedUInt<T, N, P>,
409 b: &FixedUInt<T, N, P>
410 ) -> (FixedUInt<T, N, P>, bool) {
411 <FixedUInt<T, N, P> as OverflowingSub>::overflowing_sub(*a, *b)
412 }
413
414 pub c0nst fn const_add<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(
416 a: FixedUInt<T, N, P>,
417 b: FixedUInt<T, N, P>
418 ) -> FixedUInt<T, N, P> {
419 a + b
420 }
421
422 pub c0nst fn const_sub<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(
424 a: FixedUInt<T, N, P>,
425 b: FixedUInt<T, N, P>
426 ) -> FixedUInt<T, N, P> {
427 a - b
428 }
429
430 pub c0nst fn const_wrapping_add<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(
432 a: &FixedUInt<T, N, P>,
433 b: &FixedUInt<T, N, P>
434 ) -> FixedUInt<T, N, P> {
435 <FixedUInt<T, N, P> as WrappingAdd>::wrapping_add(*a, *b)
436 }
437
438 pub c0nst fn const_wrapping_sub<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(
440 a: &FixedUInt<T, N, P>,
441 b: &FixedUInt<T, N, P>
442 ) -> FixedUInt<T, N, P> {
443 <FixedUInt<T, N, P> as WrappingSub>::wrapping_sub(*a, *b)
444 }
445
446 pub c0nst fn const_checked_add<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(
448 a: &FixedUInt<T, N, P>,
449 b: &FixedUInt<T, N, P>
450 ) -> Option<FixedUInt<T, N, P>> {
451 <FixedUInt<T, N, P> as CheckedAdd>::checked_add(*a, *b)
452 }
453
454 pub c0nst fn const_checked_sub<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(
456 a: &FixedUInt<T, N, P>,
457 b: &FixedUInt<T, N, P>
458 ) -> Option<FixedUInt<T, N, P>> {
459 <FixedUInt<T, N, P> as CheckedSub>::checked_sub(*a, *b)
460 }
461 }
462
463 #[test]
464 fn test_add_combinations() {
465 let a = FixedUInt::<u8, 2>::from(12u8);
466 let b = FixedUInt::<u8, 2>::from(3u8);
467 let expected = FixedUInt::<u8, 2>::from(15u8);
468
469 assert_eq!(a + b, expected);
471 assert_eq!(a + &b, expected);
473 assert_eq!(&a + b, expected);
475 assert_eq!(&a + &b, expected);
477 }
478
479 #[test]
480 fn test_sub_combinations() {
481 let a = FixedUInt::<u8, 2>::from(15u8);
482 let b = FixedUInt::<u8, 2>::from(3u8);
483 let expected = FixedUInt::<u8, 2>::from(12u8);
484
485 assert_eq!(a - b, expected);
487 assert_eq!(a - &b, expected);
489 assert_eq!(&a - b, expected);
491 assert_eq!(&a - &b, expected);
493 }
494
495 #[test]
496 fn test_const_overflowing_add() {
497 let a = FixedUInt::<u8, 2>::from(12u8);
499 let b = FixedUInt::<u8, 2>::from(3u8);
500 let (result, overflow) = const_overflowing_add(&a, &b);
501 assert_eq!(result, FixedUInt::<u8, 2>::from(15u8));
502 assert!(!overflow);
503
504 let a = <FixedUInt<u8, 2> as Bounded>::max_value();
506 let b = <FixedUInt<u8, 2> as Bounded>::max_value();
507 let (result, overflow) = const_overflowing_add(&a, &b);
508 assert_eq!(result, FixedUInt::<u8, 2>::from(u16::MAX - 1));
510 assert!(overflow);
511
512 let max = <FixedUInt<u8, 2> as Bounded>::max_value();
514 let one = FixedUInt::<u8, 2>::from(1u8);
515 let (_, overflow) = const_overflowing_add(&max, &one);
516 assert!(overflow);
517
518 #[cfg(feature = "nightly")]
519 {
520 const A: FixedUInt<u8, 2> = FixedUInt::from_array([12, 0]);
521 const B: FixedUInt<u8, 2> = FixedUInt::from_array([3, 0]);
522 const RESULT: (FixedUInt<u8, 2>, bool) = const_overflowing_add(&A, &B);
523 assert_eq!(RESULT.0.array, [15, 0]);
524 assert!(!RESULT.1);
525 }
526 }
527
528 #[test]
529 fn test_const_overflowing_sub() {
530 let a = FixedUInt::<u8, 2>::from(15u8);
532 let b = FixedUInt::<u8, 2>::from(3u8);
533 let (result, overflow) = const_overflowing_sub(&a, &b);
534 assert_eq!(result, FixedUInt::<u8, 2>::from(12u8));
535 assert!(!overflow);
536
537 let a = FixedUInt::<u8, 2>::from(0u8);
539 let b = FixedUInt::<u8, 2>::from(1u8);
540 let (_, overflow) = const_overflowing_sub(&a, &b);
541 assert!(overflow);
542
543 #[cfg(feature = "nightly")]
544 {
545 const A: FixedUInt<u8, 2> = FixedUInt::from_array([15, 0]);
546 const B: FixedUInt<u8, 2> = FixedUInt::from_array([3, 0]);
547 const RESULT: (FixedUInt<u8, 2>, bool) = const_overflowing_sub(&A, &B);
548 assert_eq!(RESULT.0.array, [12, 0]);
549 assert!(!RESULT.1);
550 }
551 }
552
553 #[test]
554 fn test_const_add_op() {
555 let a = FixedUInt::<u8, 2>::from(12u8);
556 let b = FixedUInt::<u8, 2>::from(3u8);
557 let result = const_add(a, b);
558 assert_eq!(result, FixedUInt::<u8, 2>::from(15u8));
559
560 let a = FixedUInt::<u32, 2>::from(100u32);
562 let b = FixedUInt::<u32, 2>::from(200u32);
563 let result = const_add(a, b);
564 assert_eq!(result, FixedUInt::<u32, 2>::from(300u32));
565
566 #[cfg(feature = "nightly")]
567 {
568 const A: FixedUInt<u8, 2> = FixedUInt::from_array([12, 0]);
569 const B: FixedUInt<u8, 2> = FixedUInt::from_array([3, 0]);
570 const RESULT: FixedUInt<u8, 2> = const_add(A, B);
571 assert_eq!(RESULT.array, [15, 0]);
572 }
573 }
574
575 #[test]
576 fn test_const_sub_op() {
577 let a = FixedUInt::<u8, 2>::from(15u8);
578 let b = FixedUInt::<u8, 2>::from(3u8);
579 let result = const_sub(a, b);
580 assert_eq!(result, FixedUInt::<u8, 2>::from(12u8));
581
582 let a = FixedUInt::<u32, 2>::from(300u32);
584 let b = FixedUInt::<u32, 2>::from(100u32);
585 let result = const_sub(a, b);
586 assert_eq!(result, FixedUInt::<u32, 2>::from(200u32));
587
588 #[cfg(feature = "nightly")]
589 {
590 const A: FixedUInt<u8, 2> = FixedUInt::from_array([15, 0]);
591 const B: FixedUInt<u8, 2> = FixedUInt::from_array([3, 0]);
592 const RESULT: FixedUInt<u8, 2> = const_sub(A, B);
593 assert_eq!(RESULT.array, [12, 0]);
594 }
595 }
596
597 #[test]
598 fn test_const_wrapping_checked() {
599 let a = FixedUInt::<u8, 2>::from(100u8);
601 let b = FixedUInt::<u8, 2>::from(50u8);
602 let result = const_wrapping_add(&a, &b);
603 assert_eq!(result, FixedUInt::<u8, 2>::from(150u8));
604
605 let max = <FixedUInt<u8, 2> as Bounded>::max_value();
607 let one = FixedUInt::<u8, 2>::from(1u8);
608 let result = const_wrapping_add(&max, &one);
609 assert_eq!(result, FixedUInt::<u8, 2>::from(0u8));
610
611 let a = FixedUInt::<u8, 2>::from(100u8);
613 let b = FixedUInt::<u8, 2>::from(50u8);
614 let result = const_wrapping_sub(&a, &b);
615 assert_eq!(result, FixedUInt::<u8, 2>::from(50u8));
616
617 let zero = FixedUInt::<u8, 2>::from(0u8);
619 let one = FixedUInt::<u8, 2>::from(1u8);
620 let result = const_wrapping_sub(&zero, &one);
621 assert_eq!(result, <FixedUInt::<u8, 2> as Bounded>::max_value());
622
623 let a = FixedUInt::<u8, 2>::from(100u8);
625 let b = FixedUInt::<u8, 2>::from(50u8);
626 let result = const_checked_add(&a, &b);
627 assert_eq!(result, Some(FixedUInt::<u8, 2>::from(150u8)));
628
629 let max = <FixedUInt<u8, 2> as Bounded>::max_value();
631 let one = FixedUInt::<u8, 2>::from(1u8);
632 let result = const_checked_add(&max, &one);
633 assert_eq!(result, None);
634
635 let a = FixedUInt::<u8, 2>::from(100u8);
637 let b = FixedUInt::<u8, 2>::from(50u8);
638 let result = const_checked_sub(&a, &b);
639 assert_eq!(result, Some(FixedUInt::<u8, 2>::from(50u8)));
640
641 let zero = FixedUInt::<u8, 2>::from(0u8);
643 let one = FixedUInt::<u8, 2>::from(1u8);
644 let result = const_checked_sub(&zero, &one);
645 assert_eq!(result, None);
646
647 #[cfg(feature = "nightly")]
648 {
649 const A: FixedUInt<u8, 2> = FixedUInt::from_array([100, 0]);
650 const B: FixedUInt<u8, 2> = FixedUInt::from_array([50, 0]);
651
652 const WRAP_ADD: FixedUInt<u8, 2> = const_wrapping_add(&A, &B);
653 const WRAP_SUB: FixedUInt<u8, 2> = const_wrapping_sub(&A, &B);
654 const CHECK_ADD: Option<FixedUInt<u8, 2>> = const_checked_add(&A, &B);
655 const CHECK_SUB: Option<FixedUInt<u8, 2>> = const_checked_sub(&A, &B);
656
657 assert_eq!(WRAP_ADD.array, [150, 0]);
658 assert_eq!(WRAP_SUB.array, [50, 0]);
659 assert!(CHECK_ADD.is_some());
660 assert!(CHECK_SUB.is_some());
661
662 const MAX: FixedUInt<u8, 2> = FixedUInt::from_array([255, 255]);
663 const ONE: FixedUInt<u8, 2> = FixedUInt::from_array([1, 0]);
664 const CHECK_ADD_OVERFLOW: Option<FixedUInt<u8, 2>> = const_checked_add(&MAX, &ONE);
665 assert!(CHECK_ADD_OVERFLOW.is_none());
666 }
667 }
668
669 #[test]
670 fn ct_checked_add_masks_overflow() {
671 use CtCheckedAdd;
672 type U16 = FixedUInt<u8, 2>;
673 let a = U16::from(100u8);
674 let b = U16::from(50u8);
675 let ok = a.ct_checked_add(&b);
676 assert!(bool::from(ok.is_some()));
677 assert_eq!(ok.unwrap(), U16::from(150u8));
678 let max = <U16 as const_num_traits::Bounded>::max_value();
680 let one = U16::from(1u8);
681 let bad = max.ct_checked_add(&one);
682 assert!(!bool::from(bad.is_some()));
683 }
684
685 #[test]
686 fn ct_checked_sub_masks_underflow() {
687 use CtCheckedSub;
688 type U16 = FixedUInt<u8, 2>;
689 let ok = U16::from(100u8).ct_checked_sub(&U16::from(50u8));
690 assert!(bool::from(ok.is_some()));
691 assert_eq!(ok.unwrap(), U16::from(50u8));
692 let bad = U16::from(0u8).ct_checked_sub(&U16::from(1u8));
694 assert!(!bool::from(bad.is_some()));
695 }
696}