Skip to main content

fixed_bigint/fixeduint/
add_sub_impl.rs

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