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