1use super::{
2 FixedUInt, MachineWord, PanicReason, add_impl, const_ct_select, maybe_panic_if, sub_impl,
3};
4use crate::machineword::ConstMachineWord;
5use const_num_traits::ops::ct::{CtCheckedAdd, CtCheckedSub};
6use const_num_traits::{
7 Bounded, CheckedAdd, CheckedSub, ConstZero, OverflowingAdd, OverflowingSub, Personality,
8 PersonalityTag, SaturatingAdd, SaturatingSub, WrappingAdd, WrappingSub,
9};
10
11c0nst::c0nst! {
12 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> OverflowingAdd 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 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> OverflowingSub 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 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> WrappingAdd for FixedUInt<T, N, P> {
29 fn wrapping_add(self, other: Self) -> Self {
30 <Self as OverflowingAdd>::overflowing_add(self, other).0
31 }
32 }
33
34 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> WrappingSub for FixedUInt<T, N, P> {
35 fn wrapping_sub(self, other: Self) -> Self {
36 <Self as OverflowingSub>::overflowing_sub(self, other).0
37 }
38 }
39
40 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> CheckedAdd for FixedUInt<T, N, P> {
41 fn checked_add(self, other: Self) -> Option<Self> {
42 let (res, overflow) = <Self as OverflowingAdd>::overflowing_add(self, other);
43 if overflow { None } else { Some(res) }
44 }
45 }
46
47 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> CheckedSub for FixedUInt<T, N, P> {
48 fn checked_sub(self, other: Self) -> Option<Self> {
49 let (res, overflow) = <Self as OverflowingSub>::overflowing_sub(self, other);
50 if overflow { None } else { Some(res) }
51 }
52 }
53
54 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> SaturatingAdd for FixedUInt<T, N, P> {
55 fn saturating_add(self, other: Self) -> Self {
56 let (res, overflow) = <Self as OverflowingAdd>::overflowing_add(self, other);
57 match P::TAG {
58 PersonalityTag::Nct => if overflow { <Self as Bounded>::max_value() } else { res },
59 PersonalityTag::Ct => const_ct_select(res, <Self as Bounded>::max_value(), overflow as u8),
60 }
61 }
62 }
63
64 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> SaturatingSub for FixedUInt<T, N, P> {
65 fn saturating_sub(self, other: Self) -> Self {
66 let (res, overflow) = <Self as OverflowingSub>::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 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> 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 OverflowingAdd>::overflowing_add(self, other);
78 maybe_panic_if::<P>(overflow, PanicReason::Add);
79 res
80 }
81 }
82
83 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> 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 OverflowingSub>::overflowing_sub(self, other);
87 maybe_panic_if::<P>(overflow, PanicReason::Sub);
88 res
89 }
90 }
91
92 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> 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 OverflowingAdd>::overflowing_add(self, *other);
96 maybe_panic_if::<P>(overflow, PanicReason::Add);
97 res
98 }
99 }
100
101 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> 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 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<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 OverflowingAdd>::overflowing_add(*self, *other);
114 maybe_panic_if::<P>(overflow, PanicReason::Add);
115 res
116 }
117 }
118
119 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> 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 OverflowingSub>::overflowing_sub(self, *other);
123 maybe_panic_if::<P>(overflow, PanicReason::Sub);
124 res
125 }
126 }
127
128 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> 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 OverflowingSub>::overflowing_sub(*self, other);
132 maybe_panic_if::<P>(overflow, PanicReason::Sub);
133 res
134 }
135 }
136
137 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> 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 OverflowingSub>::overflowing_sub(*self, *other);
141 maybe_panic_if::<P>(overflow, PanicReason::Sub);
142 res
143 }
144 }
145
146 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> 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 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> 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 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> 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 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> 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 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> OverflowingAdd for &FixedUInt<T, N, P> {
192 fn overflowing_add(self, other: Self) -> (FixedUInt<T, N, P>, bool) {
193 <FixedUInt<T, N, P> as OverflowingAdd>::overflowing_add(*self, *other)
194 }
195 }
196
197 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> OverflowingSub for &FixedUInt<T, N, P> {
198 fn overflowing_sub(self, other: Self) -> (FixedUInt<T, N, P>, bool) {
199 <FixedUInt<T, N, P> as OverflowingSub>::overflowing_sub(*self, *other)
200 }
201 }
202
203 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> WrappingAdd for &FixedUInt<T, N, P> {
204 fn wrapping_add(self, other: Self) -> FixedUInt<T, N, P> {
205 <FixedUInt<T, N, P> as WrappingAdd>::wrapping_add(*self, *other)
206 }
207 }
208
209 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> WrappingSub for &FixedUInt<T, N, P> {
210 fn wrapping_sub(self, other: Self) -> FixedUInt<T, N, P> {
211 <FixedUInt<T, N, P> as WrappingSub>::wrapping_sub(*self, *other)
212 }
213 }
214
215 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> CheckedAdd for &FixedUInt<T, N, P> {
216 fn checked_add(self, other: Self) -> Option<FixedUInt<T, N, P>> {
217 <FixedUInt<T, N, P> as CheckedAdd>::checked_add(*self, *other)
218 }
219 }
220
221 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> CheckedSub for &FixedUInt<T, N, P> {
222 fn checked_sub(self, other: Self) -> Option<FixedUInt<T, N, P>> {
223 <FixedUInt<T, N, P> as CheckedSub>::checked_sub(*self, *other)
224 }
225 }
226
227 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> SaturatingAdd for &FixedUInt<T, N, P> {
228 fn saturating_add(self, other: Self) -> FixedUInt<T, N, P> {
229 <FixedUInt<T, N, P> as SaturatingAdd>::saturating_add(*self, *other)
230 }
231 }
232
233 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> SaturatingSub for &FixedUInt<T, N, P> {
234 fn saturating_sub(self, other: Self) -> FixedUInt<T, N, P> {
235 <FixedUInt<T, N, P> as SaturatingSub>::saturating_sub(*self, *other)
236 }
237 }
238}
239
240#[cfg(feature = "num-traits")]
241impl<T: MachineWord, const N: usize, P: Personality> num_traits::ops::overflowing::OverflowingAdd
242 for FixedUInt<T, N, P>
243{
244 fn overflowing_add(&self, other: &Self) -> (Self, bool) {
245 <Self as OverflowingAdd>::overflowing_add(*self, *other)
246 }
247}
248
249#[cfg(feature = "num-traits")]
250impl<T: MachineWord, const N: usize, P: Personality> num_traits::WrappingAdd
251 for FixedUInt<T, N, P>
252{
253 fn wrapping_add(&self, other: &Self) -> Self {
254 <Self as WrappingAdd>::wrapping_add(*self, *other)
255 }
256}
257
258#[cfg(feature = "num-traits")]
259impl<T: MachineWord, const N: usize, P: Personality> num_traits::CheckedAdd for FixedUInt<T, N, P> {
260 fn checked_add(&self, other: &Self) -> Option<Self> {
261 <Self as CheckedAdd>::checked_add(*self, *other)
262 }
263}
264
265#[cfg(feature = "num-traits")]
266impl<T: MachineWord, const N: usize, P: Personality> num_traits::ops::saturating::SaturatingAdd
267 for FixedUInt<T, N, P>
268{
269 fn saturating_add(&self, other: &Self) -> Self {
270 <Self as SaturatingAdd>::saturating_add(*self, *other)
271 }
272}
273
274#[cfg(feature = "num-traits")]
275impl<T: MachineWord, const N: usize, P: Personality> num_traits::ops::overflowing::OverflowingSub
276 for FixedUInt<T, N, P>
277{
278 fn overflowing_sub(&self, other: &Self) -> (Self, bool) {
279 <Self as OverflowingSub>::overflowing_sub(*self, *other)
280 }
281}
282
283#[cfg(feature = "num-traits")]
284impl<T: MachineWord, const N: usize, P: Personality> num_traits::WrappingSub
285 for FixedUInt<T, N, P>
286{
287 fn wrapping_sub(&self, other: &Self) -> Self {
288 <Self as WrappingSub>::wrapping_sub(*self, *other)
289 }
290}
291
292#[cfg(feature = "num-traits")]
293impl<T: MachineWord, const N: usize, P: Personality> num_traits::CheckedSub for FixedUInt<T, N, P> {
294 fn checked_sub(&self, other: &Self) -> Option<Self> {
295 <Self as CheckedSub>::checked_sub(*self, *other)
296 }
297}
298
299#[cfg(feature = "num-traits")]
300impl<T: MachineWord, const N: usize, P: Personality> num_traits::ops::saturating::SaturatingSub
301 for FixedUInt<T, N, P>
302{
303 fn saturating_sub(&self, other: &Self) -> Self {
304 <Self as SaturatingSub>::saturating_sub(*self, *other)
305 }
306}
307
308#[cfg(feature = "num-traits")]
310impl<T: MachineWord, const N: usize, P: Personality> num_traits::Saturating for FixedUInt<T, N, P> {
311 fn saturating_add(self, other: Self) -> Self {
312 <Self as SaturatingAdd>::saturating_add(self, other)
313 }
314
315 fn saturating_sub(self, other: Self) -> Self {
316 <Self as SaturatingSub>::saturating_sub(self, other)
317 }
318}
319
320impl<T: MachineWord, const N: usize, P: Personality> CtCheckedAdd for FixedUInt<T, N, P> {
327 fn ct_checked_add(&self, v: &Self) -> subtle::CtOption<Self> {
328 let (val, overflow) = <Self as OverflowingAdd>::overflowing_add(*self, *v);
329 subtle::CtOption::new(val, subtle::Choice::from(!overflow as u8))
330 }
331}
332
333impl<T: MachineWord, const N: usize, P: Personality> CtCheckedSub for FixedUInt<T, N, P> {
334 fn ct_checked_sub(&self, v: &Self) -> subtle::CtOption<Self> {
335 let (val, overflow) = <Self as OverflowingSub>::overflowing_sub(*self, *v);
336 subtle::CtOption::new(val, subtle::Choice::from(!overflow as u8))
337 }
338}
339
340#[cfg(test)]
341#[allow(clippy::op_ref)]
344mod tests {
345 use super::*;
346 use crate::machineword::ConstMachineWord;
347 use const_num_traits::Bounded;
348 use const_num_traits::{
349 CheckedAdd, CheckedSub, OverflowingAdd, OverflowingSub, WrappingAdd, WrappingSub,
350 };
351
352 c0nst::c0nst! {
353 pub c0nst fn const_overflowing_add<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(
355 a: &FixedUInt<T, N, P>,
356 b: &FixedUInt<T, N, P>
357 ) -> (FixedUInt<T, N, P>, bool) {
358 <FixedUInt<T, N, P> as OverflowingAdd>::overflowing_add(*a, *b)
359 }
360
361 pub c0nst fn const_overflowing_sub<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(
363 a: &FixedUInt<T, N, P>,
364 b: &FixedUInt<T, N, P>
365 ) -> (FixedUInt<T, N, P>, bool) {
366 <FixedUInt<T, N, P> as OverflowingSub>::overflowing_sub(*a, *b)
367 }
368
369 pub c0nst fn const_add<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(
371 a: FixedUInt<T, N, P>,
372 b: FixedUInt<T, N, P>
373 ) -> FixedUInt<T, N, P> {
374 a + b
375 }
376
377 pub c0nst fn const_sub<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(
379 a: FixedUInt<T, N, P>,
380 b: FixedUInt<T, N, P>
381 ) -> FixedUInt<T, N, P> {
382 a - b
383 }
384
385 pub c0nst fn const_wrapping_add<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(
387 a: &FixedUInt<T, N, P>,
388 b: &FixedUInt<T, N, P>
389 ) -> FixedUInt<T, N, P> {
390 <FixedUInt<T, N, P> as WrappingAdd>::wrapping_add(*a, *b)
391 }
392
393 pub c0nst fn const_wrapping_sub<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(
395 a: &FixedUInt<T, N, P>,
396 b: &FixedUInt<T, N, P>
397 ) -> FixedUInt<T, N, P> {
398 <FixedUInt<T, N, P> as WrappingSub>::wrapping_sub(*a, *b)
399 }
400
401 pub c0nst fn const_checked_add<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(
403 a: &FixedUInt<T, N, P>,
404 b: &FixedUInt<T, N, P>
405 ) -> Option<FixedUInt<T, N, P>> {
406 <FixedUInt<T, N, P> as CheckedAdd>::checked_add(*a, *b)
407 }
408
409 pub c0nst fn const_checked_sub<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(
411 a: &FixedUInt<T, N, P>,
412 b: &FixedUInt<T, N, P>
413 ) -> Option<FixedUInt<T, N, P>> {
414 <FixedUInt<T, N, P> as CheckedSub>::checked_sub(*a, *b)
415 }
416 }
417
418 #[test]
419 fn test_add_combinations() {
420 let a = FixedUInt::<u8, 2>::from(12u8);
421 let b = FixedUInt::<u8, 2>::from(3u8);
422 let expected = FixedUInt::<u8, 2>::from(15u8);
423
424 assert_eq!(a + b, expected);
426 assert_eq!(a + &b, expected);
428 assert_eq!(&a + b, expected);
430 assert_eq!(&a + &b, expected);
432 }
433
434 #[test]
435 fn test_sub_combinations() {
436 let a = FixedUInt::<u8, 2>::from(15u8);
437 let b = FixedUInt::<u8, 2>::from(3u8);
438 let expected = FixedUInt::<u8, 2>::from(12u8);
439
440 assert_eq!(a - b, expected);
442 assert_eq!(a - &b, expected);
444 assert_eq!(&a - b, expected);
446 assert_eq!(&a - &b, expected);
448 }
449
450 #[test]
451 fn test_const_overflowing_add() {
452 let a = FixedUInt::<u8, 2>::from(12u8);
454 let b = FixedUInt::<u8, 2>::from(3u8);
455 let (result, overflow) = const_overflowing_add(&a, &b);
456 assert_eq!(result, FixedUInt::<u8, 2>::from(15u8));
457 assert!(!overflow);
458
459 let a = <FixedUInt<u8, 2> as Bounded>::max_value();
461 let b = <FixedUInt<u8, 2> as Bounded>::max_value();
462 let (result, overflow) = const_overflowing_add(&a, &b);
463 assert_eq!(result, FixedUInt::<u8, 2>::from(u16::MAX - 1));
465 assert!(overflow);
466
467 let max = <FixedUInt<u8, 2> as Bounded>::max_value();
469 let one = FixedUInt::<u8, 2>::from(1u8);
470 let (_, overflow) = const_overflowing_add(&max, &one);
471 assert!(overflow);
472
473 #[cfg(feature = "nightly")]
474 {
475 const A: FixedUInt<u8, 2> = FixedUInt::from_array([12, 0]);
476 const B: FixedUInt<u8, 2> = FixedUInt::from_array([3, 0]);
477 const RESULT: (FixedUInt<u8, 2>, bool) = const_overflowing_add(&A, &B);
478 assert_eq!(RESULT.0.array, [15, 0]);
479 assert!(!RESULT.1);
480 }
481 }
482
483 #[test]
484 fn test_const_overflowing_sub() {
485 let a = FixedUInt::<u8, 2>::from(15u8);
487 let b = FixedUInt::<u8, 2>::from(3u8);
488 let (result, overflow) = const_overflowing_sub(&a, &b);
489 assert_eq!(result, FixedUInt::<u8, 2>::from(12u8));
490 assert!(!overflow);
491
492 let a = FixedUInt::<u8, 2>::from(0u8);
494 let b = FixedUInt::<u8, 2>::from(1u8);
495 let (_, overflow) = const_overflowing_sub(&a, &b);
496 assert!(overflow);
497
498 #[cfg(feature = "nightly")]
499 {
500 const A: FixedUInt<u8, 2> = FixedUInt::from_array([15, 0]);
501 const B: FixedUInt<u8, 2> = FixedUInt::from_array([3, 0]);
502 const RESULT: (FixedUInt<u8, 2>, bool) = const_overflowing_sub(&A, &B);
503 assert_eq!(RESULT.0.array, [12, 0]);
504 assert!(!RESULT.1);
505 }
506 }
507
508 #[test]
509 fn test_const_add_op() {
510 let a = FixedUInt::<u8, 2>::from(12u8);
511 let b = FixedUInt::<u8, 2>::from(3u8);
512 let result = const_add(a, b);
513 assert_eq!(result, FixedUInt::<u8, 2>::from(15u8));
514
515 let a = FixedUInt::<u32, 2>::from(100u32);
517 let b = FixedUInt::<u32, 2>::from(200u32);
518 let result = const_add(a, b);
519 assert_eq!(result, FixedUInt::<u32, 2>::from(300u32));
520
521 #[cfg(feature = "nightly")]
522 {
523 const A: FixedUInt<u8, 2> = FixedUInt::from_array([12, 0]);
524 const B: FixedUInt<u8, 2> = FixedUInt::from_array([3, 0]);
525 const RESULT: FixedUInt<u8, 2> = const_add(A, B);
526 assert_eq!(RESULT.array, [15, 0]);
527 }
528 }
529
530 #[test]
531 fn test_const_sub_op() {
532 let a = FixedUInt::<u8, 2>::from(15u8);
533 let b = FixedUInt::<u8, 2>::from(3u8);
534 let result = const_sub(a, b);
535 assert_eq!(result, FixedUInt::<u8, 2>::from(12u8));
536
537 let a = FixedUInt::<u32, 2>::from(300u32);
539 let b = FixedUInt::<u32, 2>::from(100u32);
540 let result = const_sub(a, b);
541 assert_eq!(result, FixedUInt::<u32, 2>::from(200u32));
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> = const_sub(A, B);
548 assert_eq!(RESULT.array, [12, 0]);
549 }
550 }
551
552 #[test]
553 fn test_const_wrapping_checked() {
554 let a = FixedUInt::<u8, 2>::from(100u8);
556 let b = FixedUInt::<u8, 2>::from(50u8);
557 let result = const_wrapping_add(&a, &b);
558 assert_eq!(result, FixedUInt::<u8, 2>::from(150u8));
559
560 let max = <FixedUInt<u8, 2> as Bounded>::max_value();
562 let one = FixedUInt::<u8, 2>::from(1u8);
563 let result = const_wrapping_add(&max, &one);
564 assert_eq!(result, FixedUInt::<u8, 2>::from(0u8));
565
566 let a = FixedUInt::<u8, 2>::from(100u8);
568 let b = FixedUInt::<u8, 2>::from(50u8);
569 let result = const_wrapping_sub(&a, &b);
570 assert_eq!(result, FixedUInt::<u8, 2>::from(50u8));
571
572 let zero = FixedUInt::<u8, 2>::from(0u8);
574 let one = FixedUInt::<u8, 2>::from(1u8);
575 let result = const_wrapping_sub(&zero, &one);
576 assert_eq!(result, <FixedUInt::<u8, 2> as Bounded>::max_value());
577
578 let a = FixedUInt::<u8, 2>::from(100u8);
580 let b = FixedUInt::<u8, 2>::from(50u8);
581 let result = const_checked_add(&a, &b);
582 assert_eq!(result, Some(FixedUInt::<u8, 2>::from(150u8)));
583
584 let max = <FixedUInt<u8, 2> as Bounded>::max_value();
586 let one = FixedUInt::<u8, 2>::from(1u8);
587 let result = const_checked_add(&max, &one);
588 assert_eq!(result, None);
589
590 let a = FixedUInt::<u8, 2>::from(100u8);
592 let b = FixedUInt::<u8, 2>::from(50u8);
593 let result = const_checked_sub(&a, &b);
594 assert_eq!(result, Some(FixedUInt::<u8, 2>::from(50u8)));
595
596 let zero = FixedUInt::<u8, 2>::from(0u8);
598 let one = FixedUInt::<u8, 2>::from(1u8);
599 let result = const_checked_sub(&zero, &one);
600 assert_eq!(result, None);
601
602 #[cfg(feature = "nightly")]
603 {
604 const A: FixedUInt<u8, 2> = FixedUInt::from_array([100, 0]);
605 const B: FixedUInt<u8, 2> = FixedUInt::from_array([50, 0]);
606
607 const WRAP_ADD: FixedUInt<u8, 2> = const_wrapping_add(&A, &B);
608 const WRAP_SUB: FixedUInt<u8, 2> = const_wrapping_sub(&A, &B);
609 const CHECK_ADD: Option<FixedUInt<u8, 2>> = const_checked_add(&A, &B);
610 const CHECK_SUB: Option<FixedUInt<u8, 2>> = const_checked_sub(&A, &B);
611
612 assert_eq!(WRAP_ADD.array, [150, 0]);
613 assert_eq!(WRAP_SUB.array, [50, 0]);
614 assert!(CHECK_ADD.is_some());
615 assert!(CHECK_SUB.is_some());
616
617 const MAX: FixedUInt<u8, 2> = FixedUInt::from_array([255, 255]);
618 const ONE: FixedUInt<u8, 2> = FixedUInt::from_array([1, 0]);
619 const CHECK_ADD_OVERFLOW: Option<FixedUInt<u8, 2>> = const_checked_add(&MAX, &ONE);
620 assert!(CHECK_ADD_OVERFLOW.is_none());
621 }
622 }
623
624 #[test]
625 fn ct_checked_add_masks_overflow() {
626 use CtCheckedAdd;
627 type U16 = FixedUInt<u8, 2>;
628 let a = U16::from(100u8);
629 let b = U16::from(50u8);
630 let ok = a.ct_checked_add(&b);
631 assert!(bool::from(ok.is_some()));
632 assert_eq!(ok.unwrap(), U16::from(150u8));
633 let max = <U16 as const_num_traits::Bounded>::max_value();
635 let one = U16::from(1u8);
636 let bad = max.ct_checked_add(&one);
637 assert!(!bool::from(bad.is_some()));
638 }
639
640 #[test]
641 fn ct_checked_sub_masks_underflow() {
642 use CtCheckedSub;
643 type U16 = FixedUInt<u8, 2>;
644 let ok = U16::from(100u8).ct_checked_sub(&U16::from(50u8));
645 assert!(bool::from(ok.is_some()));
646 assert_eq!(ok.unwrap(), U16::from(50u8));
647 let bad = U16::from(0u8).ct_checked_sub(&U16::from(1u8));
649 assert!(!bool::from(bad.is_some()));
650 }
651}