Skip to main content

const_num_traits/ops/
overflowing.rs

1//! Overflowing arithmetic: the wrapped value plus an overflow flag.
2//!
3//! **CT tier A (CT-implementable)** for add/sub/mul/neg/shifts/abs: the flag is
4//! designed to be consumed arithmetically (`carry as T`), as in multi-word
5//! arithmetic; convert it to a mask rather than branching on it in constant-time
6//! code. `OverflowingDiv`/`OverflowingRem` are CT-hostile (data-dependent
7//! division) and `OverflowingPow` is exponent-dependent — Tier C for secrets.
8
9macro_rules! overflowing_impl {
10    ($trait_name:ident, $method:ident, $t:ty) => {
11        c0nst::c0nst! {
12        c0nst impl $trait_name for $t {
13            type Output = $t;
14            #[inline]
15            fn $method(self, v: Self) -> (Self, bool) {
16                <$t>::$method(self, v)
17            }
18        }
19        }
20    };
21}
22
23c0nst::c0nst! {
24/// Performs addition with a flag for overflow.
25pub c0nst trait OverflowingAdd: Sized {
26    /// The result type (`Self` for the primitive impls).
27    type Output;
28    /// Returns a tuple of the sum along with a boolean indicating whether an arithmetic overflow would occur.
29    /// If an overflow would have occurred then the wrapped value is returned.
30    fn overflowing_add(self, v: Self) -> (Self::Output, bool);
31}
32}
33
34overflowing_impl!(OverflowingAdd, overflowing_add, u8);
35overflowing_impl!(OverflowingAdd, overflowing_add, u16);
36overflowing_impl!(OverflowingAdd, overflowing_add, u32);
37overflowing_impl!(OverflowingAdd, overflowing_add, u64);
38overflowing_impl!(OverflowingAdd, overflowing_add, usize);
39overflowing_impl!(OverflowingAdd, overflowing_add, u128);
40
41overflowing_impl!(OverflowingAdd, overflowing_add, i8);
42overflowing_impl!(OverflowingAdd, overflowing_add, i16);
43overflowing_impl!(OverflowingAdd, overflowing_add, i32);
44overflowing_impl!(OverflowingAdd, overflowing_add, i64);
45overflowing_impl!(OverflowingAdd, overflowing_add, isize);
46overflowing_impl!(OverflowingAdd, overflowing_add, i128);
47
48c0nst::c0nst! {
49/// Performs substraction with a flag for overflow.
50pub c0nst trait OverflowingSub: Sized {
51    /// The result type (`Self` for the primitive impls).
52    type Output;
53    /// Returns a tuple of the difference along with a boolean indicating whether an arithmetic overflow would occur.
54    /// If an overflow would have occurred then the wrapped value is returned.
55    fn overflowing_sub(self, v: Self) -> (Self::Output, bool);
56}
57}
58
59overflowing_impl!(OverflowingSub, overflowing_sub, u8);
60overflowing_impl!(OverflowingSub, overflowing_sub, u16);
61overflowing_impl!(OverflowingSub, overflowing_sub, u32);
62overflowing_impl!(OverflowingSub, overflowing_sub, u64);
63overflowing_impl!(OverflowingSub, overflowing_sub, usize);
64overflowing_impl!(OverflowingSub, overflowing_sub, u128);
65
66overflowing_impl!(OverflowingSub, overflowing_sub, i8);
67overflowing_impl!(OverflowingSub, overflowing_sub, i16);
68overflowing_impl!(OverflowingSub, overflowing_sub, i32);
69overflowing_impl!(OverflowingSub, overflowing_sub, i64);
70overflowing_impl!(OverflowingSub, overflowing_sub, isize);
71overflowing_impl!(OverflowingSub, overflowing_sub, i128);
72
73c0nst::c0nst! {
74/// Performs multiplication with a flag for overflow.
75pub c0nst trait OverflowingMul: Sized {
76    /// The result type (`Self` for the primitive impls).
77    type Output;
78    /// Returns a tuple of the product along with a boolean indicating whether an arithmetic overflow would occur.
79    /// If an overflow would have occurred then the wrapped value is returned.
80    fn overflowing_mul(self, v: Self) -> (Self::Output, bool);
81}
82}
83
84overflowing_impl!(OverflowingMul, overflowing_mul, u8);
85overflowing_impl!(OverflowingMul, overflowing_mul, u16);
86overflowing_impl!(OverflowingMul, overflowing_mul, u32);
87overflowing_impl!(OverflowingMul, overflowing_mul, u64);
88overflowing_impl!(OverflowingMul, overflowing_mul, usize);
89overflowing_impl!(OverflowingMul, overflowing_mul, u128);
90
91overflowing_impl!(OverflowingMul, overflowing_mul, i8);
92overflowing_impl!(OverflowingMul, overflowing_mul, i16);
93overflowing_impl!(OverflowingMul, overflowing_mul, i32);
94overflowing_impl!(OverflowingMul, overflowing_mul, i64);
95overflowing_impl!(OverflowingMul, overflowing_mul, isize);
96overflowing_impl!(OverflowingMul, overflowing_mul, i128);
97
98c0nst::c0nst! {
99/// Performs division with a flag for overflow.
100pub c0nst trait OverflowingDiv: Sized {
101    /// The result type (`Self` for the primitive impls).
102    type Output;
103    /// Returns a tuple of the quotient along with a boolean indicating whether
104    /// an arithmetic overflow would occur. The only overflowing case is
105    /// `MIN / -1` on a signed type, where the wrapped value is returned.
106    ///
107    /// # Panics
108    ///
109    /// Panics if `v` is zero.
110    fn overflowing_div(self, v: Self) -> (Self::Output, bool);
111}
112}
113
114overflowing_impl!(OverflowingDiv, overflowing_div, u8);
115overflowing_impl!(OverflowingDiv, overflowing_div, u16);
116overflowing_impl!(OverflowingDiv, overflowing_div, u32);
117overflowing_impl!(OverflowingDiv, overflowing_div, u64);
118overflowing_impl!(OverflowingDiv, overflowing_div, usize);
119overflowing_impl!(OverflowingDiv, overflowing_div, u128);
120
121overflowing_impl!(OverflowingDiv, overflowing_div, i8);
122overflowing_impl!(OverflowingDiv, overflowing_div, i16);
123overflowing_impl!(OverflowingDiv, overflowing_div, i32);
124overflowing_impl!(OverflowingDiv, overflowing_div, i64);
125overflowing_impl!(OverflowingDiv, overflowing_div, isize);
126overflowing_impl!(OverflowingDiv, overflowing_div, i128);
127
128c0nst::c0nst! {
129/// Performs a remainder operation with a flag for overflow.
130pub c0nst trait OverflowingRem: Sized {
131    /// The result type (`Self` for the primitive impls).
132    type Output;
133    /// Returns a tuple of the remainder along with a boolean indicating
134    /// whether an arithmetic overflow would occur. The only overflowing case
135    /// is `MIN % -1` on a signed type, where the remainder is 0.
136    ///
137    /// # Panics
138    ///
139    /// Panics if `v` is zero.
140    fn overflowing_rem(self, v: Self) -> (Self::Output, bool);
141}
142}
143
144overflowing_impl!(OverflowingRem, overflowing_rem, u8);
145overflowing_impl!(OverflowingRem, overflowing_rem, u16);
146overflowing_impl!(OverflowingRem, overflowing_rem, u32);
147overflowing_impl!(OverflowingRem, overflowing_rem, u64);
148overflowing_impl!(OverflowingRem, overflowing_rem, usize);
149overflowing_impl!(OverflowingRem, overflowing_rem, u128);
150
151overflowing_impl!(OverflowingRem, overflowing_rem, i8);
152overflowing_impl!(OverflowingRem, overflowing_rem, i16);
153overflowing_impl!(OverflowingRem, overflowing_rem, i32);
154overflowing_impl!(OverflowingRem, overflowing_rem, i64);
155overflowing_impl!(OverflowingRem, overflowing_rem, isize);
156overflowing_impl!(OverflowingRem, overflowing_rem, i128);
157
158macro_rules! overflowing_neg_impl {
159    ($($t:ty)*) => {$(
160        c0nst::c0nst! {
161        c0nst impl OverflowingNeg for $t {
162            type Output = $t;
163            #[inline]
164            fn overflowing_neg(self) -> ($t, bool) { <$t>::overflowing_neg(self) }
165        }
166        }
167    )*};
168}
169
170macro_rules! overflowing_unary_impl {
171    ($trait_name:ident, $method:ident, $t:ty) => {
172        c0nst::c0nst! {
173        c0nst impl $trait_name for $t {
174            type Output = $t;
175            #[inline]
176            fn $method(self) -> ($t, bool) {
177                <$t>::$method(self)
178            }
179        }
180        }
181    };
182}
183
184c0nst::c0nst! {
185/// Performs negation with a flag for overflow.
186pub c0nst trait OverflowingNeg: Sized {
187    /// Returns a tuple of the negated value along with a boolean indicating
188    /// whether an arithmetic overflow would occur. For unsigned types, any
189    /// nonzero value overflows; for signed types only `MIN` does.
190    type Output;
191    fn overflowing_neg(self) -> (Self::Output, bool);
192}
193}
194
195overflowing_neg_impl!(u8 u16 u32 u64 usize u128 i8 i16 i32 i64 isize i128);
196
197c0nst::c0nst! {
198/// Computes the absolute value with a flag for overflow.
199pub c0nst trait OverflowingAbs: Sized {
200    /// The result type (`Self` for the primitive impls).
201    type Output;
202    /// Returns a tuple of the absolute value along with a boolean indicating
203    /// whether an arithmetic overflow would occur. The only overflowing case
204    /// is `MIN.overflowing_abs()` which returns `(MIN, true)`.
205    fn overflowing_abs(self) -> (Self::Output, bool);
206}
207}
208
209overflowing_unary_impl!(OverflowingAbs, overflowing_abs, i8);
210overflowing_unary_impl!(OverflowingAbs, overflowing_abs, i16);
211overflowing_unary_impl!(OverflowingAbs, overflowing_abs, i32);
212overflowing_unary_impl!(OverflowingAbs, overflowing_abs, i64);
213overflowing_unary_impl!(OverflowingAbs, overflowing_abs, isize);
214overflowing_unary_impl!(OverflowingAbs, overflowing_abs, i128);
215
216macro_rules! overflowing_u32_rhs_impl {
217    ($trait_name:ident, $method:ident, $t:ty) => {
218        c0nst::c0nst! {
219        c0nst impl $trait_name for $t {
220            type Output = $t;
221            #[inline]
222            fn $method(self, rhs: u32) -> ($t, bool) {
223                <$t>::$method(self, rhs)
224            }
225        }
226        }
227    };
228}
229
230c0nst::c0nst! {
231/// Performs a left shift with a flag for overflow.
232pub c0nst trait OverflowingShl: Sized {
233    /// The result type (`Self` for the primitive impls).
234    type Output;
235    /// Shifts `self` left by a `rhs` masked to the bit width of the type, and
236    /// returns a boolean indicating whether `rhs` was larger than or equal to
237    /// the number of bits.
238    ///
239    /// ```
240    /// use const_num_traits::ops::overflowing::OverflowingShl;
241    ///
242    /// assert_eq!(OverflowingShl::overflowing_shl(0x1u16, 4), (0x10, false));
243    /// assert_eq!(OverflowingShl::overflowing_shl(0x1u16, 20), (0x10, true));
244    /// ```
245    fn overflowing_shl(self, rhs: u32) -> (Self::Output, bool);
246}
247}
248
249overflowing_u32_rhs_impl!(OverflowingShl, overflowing_shl, u8);
250overflowing_u32_rhs_impl!(OverflowingShl, overflowing_shl, u16);
251overflowing_u32_rhs_impl!(OverflowingShl, overflowing_shl, u32);
252overflowing_u32_rhs_impl!(OverflowingShl, overflowing_shl, u64);
253overflowing_u32_rhs_impl!(OverflowingShl, overflowing_shl, usize);
254overflowing_u32_rhs_impl!(OverflowingShl, overflowing_shl, u128);
255
256overflowing_u32_rhs_impl!(OverflowingShl, overflowing_shl, i8);
257overflowing_u32_rhs_impl!(OverflowingShl, overflowing_shl, i16);
258overflowing_u32_rhs_impl!(OverflowingShl, overflowing_shl, i32);
259overflowing_u32_rhs_impl!(OverflowingShl, overflowing_shl, i64);
260overflowing_u32_rhs_impl!(OverflowingShl, overflowing_shl, isize);
261overflowing_u32_rhs_impl!(OverflowingShl, overflowing_shl, i128);
262
263c0nst::c0nst! {
264/// Performs a right shift with a flag for overflow.
265pub c0nst trait OverflowingShr: Sized {
266    /// The result type (`Self` for the primitive impls).
267    type Output;
268    /// Shifts `self` right by a `rhs` masked to the bit width of the type, and
269    /// returns a boolean indicating whether `rhs` was larger than or equal to
270    /// the number of bits.
271    ///
272    /// ```
273    /// use const_num_traits::ops::overflowing::OverflowingShr;
274    ///
275    /// assert_eq!(OverflowingShr::overflowing_shr(0x10u16, 4), (0x1, false));
276    /// assert_eq!(OverflowingShr::overflowing_shr(0x10u16, 20), (0x1, true));
277    /// ```
278    fn overflowing_shr(self, rhs: u32) -> (Self::Output, bool);
279}
280}
281
282overflowing_u32_rhs_impl!(OverflowingShr, overflowing_shr, u8);
283overflowing_u32_rhs_impl!(OverflowingShr, overflowing_shr, u16);
284overflowing_u32_rhs_impl!(OverflowingShr, overflowing_shr, u32);
285overflowing_u32_rhs_impl!(OverflowingShr, overflowing_shr, u64);
286overflowing_u32_rhs_impl!(OverflowingShr, overflowing_shr, usize);
287overflowing_u32_rhs_impl!(OverflowingShr, overflowing_shr, u128);
288
289overflowing_u32_rhs_impl!(OverflowingShr, overflowing_shr, i8);
290overflowing_u32_rhs_impl!(OverflowingShr, overflowing_shr, i16);
291overflowing_u32_rhs_impl!(OverflowingShr, overflowing_shr, i32);
292overflowing_u32_rhs_impl!(OverflowingShr, overflowing_shr, i64);
293overflowing_u32_rhs_impl!(OverflowingShr, overflowing_shr, isize);
294overflowing_u32_rhs_impl!(OverflowingShr, overflowing_shr, i128);
295
296c0nst::c0nst! {
297/// Performs exponentiation with a flag for overflow.
298pub c0nst trait OverflowingPow: Sized {
299    /// The result type (`Self` for the primitive impls).
300    type Output;
301    /// Raises `self` to the power of `exp`, returning a tuple of the
302    /// (possibly wrapped) result and a boolean indicating whether an
303    /// arithmetic overflow occurred.
304    fn overflowing_pow(self, exp: u32) -> (Self::Output, bool);
305}
306}
307
308overflowing_u32_rhs_impl!(OverflowingPow, overflowing_pow, u8);
309overflowing_u32_rhs_impl!(OverflowingPow, overflowing_pow, u16);
310overflowing_u32_rhs_impl!(OverflowingPow, overflowing_pow, u32);
311overflowing_u32_rhs_impl!(OverflowingPow, overflowing_pow, u64);
312overflowing_u32_rhs_impl!(OverflowingPow, overflowing_pow, usize);
313overflowing_u32_rhs_impl!(OverflowingPow, overflowing_pow, u128);
314
315overflowing_u32_rhs_impl!(OverflowingPow, overflowing_pow, i8);
316overflowing_u32_rhs_impl!(OverflowingPow, overflowing_pow, i16);
317overflowing_u32_rhs_impl!(OverflowingPow, overflowing_pow, i32);
318overflowing_u32_rhs_impl!(OverflowingPow, overflowing_pow, i64);
319overflowing_u32_rhs_impl!(OverflowingPow, overflowing_pow, isize);
320overflowing_u32_rhs_impl!(OverflowingPow, overflowing_pow, i128);
321
322#[test]
323fn test_overflowing_extended_traits() {
324    assert_eq!(
325        OverflowingDiv::overflowing_div(i8::MIN, -1),
326        (i8::MIN, true)
327    );
328    assert_eq!(OverflowingDiv::overflowing_div(100u8, 7), (14, false));
329    assert_eq!(OverflowingRem::overflowing_rem(i8::MIN, -1), (0, true));
330    assert_eq!(OverflowingNeg::overflowing_neg(1u8), (255, true));
331    assert_eq!(OverflowingNeg::overflowing_neg(0u8), (0, false));
332    assert_eq!(OverflowingNeg::overflowing_neg(i8::MIN), (i8::MIN, true));
333    assert_eq!(OverflowingAbs::overflowing_abs(i8::MIN), (i8::MIN, true));
334    assert_eq!(OverflowingAbs::overflowing_abs(-7i8), (7, false));
335    assert_eq!(OverflowingShl::overflowing_shl(1u8, 8), (1, true));
336    assert_eq!(OverflowingShr::overflowing_shr(0x80u8, 9), (0x40, true));
337    assert_eq!(OverflowingPow::overflowing_pow(3u8, 6), (217, true));
338    assert_eq!(OverflowingPow::overflowing_pow(3i32, 4), (81, false));
339}
340
341#[test]
342fn test_overflowing_traits() {
343    fn overflowing_add<T: OverflowingAdd<Output = T>>(a: T, b: T) -> (T, bool) {
344        a.overflowing_add(b)
345    }
346    fn overflowing_sub<T: OverflowingSub<Output = T>>(a: T, b: T) -> (T, bool) {
347        a.overflowing_sub(b)
348    }
349    fn overflowing_mul<T: OverflowingMul<Output = T>>(a: T, b: T) -> (T, bool) {
350        a.overflowing_mul(b)
351    }
352    assert_eq!(overflowing_add(5i16, 2), (7, false));
353    assert_eq!(overflowing_add(i16::MAX, 1), (i16::MIN, true));
354    assert_eq!(overflowing_sub(5i16, 2), (3, false));
355    assert_eq!(overflowing_sub(i16::MIN, 1), (i16::MAX, true));
356    assert_eq!(overflowing_mul(5i16, 2), (10, false));
357    assert_eq!(overflowing_mul(1_000_000_000i32, 10), (1410065408, true));
358}