Skip to main content

const_num_traits/ops/
wrapping.rs

1//! Wrapping (modular) arithmetic.
2//!
3//! **CT tier A (CT-implementable)** for modular add/sub/mul/neg/shifts/abs on
4//! the builtin integers: branchless on the data. `WrappingDiv`/`WrappingRem`
5//! are CT-hostile (data-dependent division) and `WrappingPow` is
6//! exponent-dependent — Tier C for secret inputs.
7
8use core::num::Wrapping;
9use core::ops::{Add, Div, Mul, Neg, Rem, Shl, Shr, Sub};
10
11macro_rules! wrapping_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 {
17                <$t>::$method(self, v)
18            }
19        }
20        }
21    };
22    ($trait_name:ident, $method:ident, $t:ty, $rhs:ty) => {
23        c0nst::c0nst! {
24        c0nst impl $trait_name<$rhs> for $t {
25            #[inline]
26            fn $method(self, v: $rhs) -> Self {
27                <$t>::$method(self, v)
28            }
29        }
30        }
31    };
32}
33
34c0nst::c0nst! {
35/// Performs addition that wraps around on overflow.
36pub c0nst trait WrappingAdd: Sized + [c0nst] Add<Self> {
37    /// Wrapping (modular) addition. Computes `self + other`, wrapping around at the boundary of
38    /// the type.
39    fn wrapping_add(self, v: Self) -> <Self as Add<Self>>::Output;
40}
41}
42
43wrapping_impl!(WrappingAdd, wrapping_add, u8);
44wrapping_impl!(WrappingAdd, wrapping_add, u16);
45wrapping_impl!(WrappingAdd, wrapping_add, u32);
46wrapping_impl!(WrappingAdd, wrapping_add, u64);
47wrapping_impl!(WrappingAdd, wrapping_add, usize);
48wrapping_impl!(WrappingAdd, wrapping_add, u128);
49
50wrapping_impl!(WrappingAdd, wrapping_add, i8);
51wrapping_impl!(WrappingAdd, wrapping_add, i16);
52wrapping_impl!(WrappingAdd, wrapping_add, i32);
53wrapping_impl!(WrappingAdd, wrapping_add, i64);
54wrapping_impl!(WrappingAdd, wrapping_add, isize);
55wrapping_impl!(WrappingAdd, wrapping_add, i128);
56
57c0nst::c0nst! {
58/// Performs subtraction that wraps around on overflow.
59pub c0nst trait WrappingSub: Sized + [c0nst] Sub<Self> {
60    /// Wrapping (modular) subtraction. Computes `self - other`, wrapping around at the boundary
61    /// of the type.
62    fn wrapping_sub(self, v: Self) -> <Self as Sub<Self>>::Output;
63}
64}
65
66wrapping_impl!(WrappingSub, wrapping_sub, u8);
67wrapping_impl!(WrappingSub, wrapping_sub, u16);
68wrapping_impl!(WrappingSub, wrapping_sub, u32);
69wrapping_impl!(WrappingSub, wrapping_sub, u64);
70wrapping_impl!(WrappingSub, wrapping_sub, usize);
71wrapping_impl!(WrappingSub, wrapping_sub, u128);
72
73wrapping_impl!(WrappingSub, wrapping_sub, i8);
74wrapping_impl!(WrappingSub, wrapping_sub, i16);
75wrapping_impl!(WrappingSub, wrapping_sub, i32);
76wrapping_impl!(WrappingSub, wrapping_sub, i64);
77wrapping_impl!(WrappingSub, wrapping_sub, isize);
78wrapping_impl!(WrappingSub, wrapping_sub, i128);
79
80c0nst::c0nst! {
81/// Performs multiplication that wraps around on overflow.
82pub c0nst trait WrappingMul: Sized + [c0nst] Mul<Self> {
83    /// Wrapping (modular) multiplication. Computes `self * other`, wrapping around at the boundary
84    /// of the type.
85    fn wrapping_mul(self, v: Self) -> <Self as Mul<Self>>::Output;
86}
87}
88
89wrapping_impl!(WrappingMul, wrapping_mul, u8);
90wrapping_impl!(WrappingMul, wrapping_mul, u16);
91wrapping_impl!(WrappingMul, wrapping_mul, u32);
92wrapping_impl!(WrappingMul, wrapping_mul, u64);
93wrapping_impl!(WrappingMul, wrapping_mul, usize);
94wrapping_impl!(WrappingMul, wrapping_mul, u128);
95
96wrapping_impl!(WrappingMul, wrapping_mul, i8);
97wrapping_impl!(WrappingMul, wrapping_mul, i16);
98wrapping_impl!(WrappingMul, wrapping_mul, i32);
99wrapping_impl!(WrappingMul, wrapping_mul, i64);
100wrapping_impl!(WrappingMul, wrapping_mul, isize);
101wrapping_impl!(WrappingMul, wrapping_mul, i128);
102
103macro_rules! wrapping_neg_impl {
104    ($($t:ty)*) => {$(
105        c0nst::c0nst! {
106        c0nst impl WrappingNeg for $t {
107            type Output = $t;
108            #[inline]
109            fn wrapping_neg(self) -> $t {
110                <$t>::wrapping_neg(self)
111            }
112        }
113        }
114    )*};
115}
116
117macro_rules! wrapping_unary_impl {
118    ($trait_name:ident, $method:ident, $t:ty) => {
119        c0nst::c0nst! {
120        c0nst impl $trait_name for $t {
121            #[inline]
122            fn $method(self) -> $t {
123                <$t>::$method(self)
124            }
125        }
126        }
127    };
128}
129
130c0nst::c0nst! {
131/// Performs a negation that does not panic.
132pub c0nst trait WrappingNeg: Sized {
133    /// Wrapping (modular) negation. Computes `-self`,
134    /// wrapping around at the boundary of the type.
135    ///
136    /// Since unsigned types do not have negative equivalents
137    /// all applications of this function will wrap (except for `-0`).
138    /// For values smaller than the corresponding signed type's maximum
139    /// the result is the same as casting the corresponding signed value.
140    /// Any larger values are equivalent to `MAX + 1 - (val - MAX - 1)` where
141    /// `MAX` is the corresponding signed type's maximum.
142    ///
143    /// ```
144    /// use const_num_traits::WrappingNeg;
145    ///
146    /// assert_eq!(100i8.wrapping_neg(), -100);
147    /// assert_eq!((-100i8).wrapping_neg(), 100);
148    /// assert_eq!((-128i8).wrapping_neg(), -128); // wrapped!
149    /// ```
150    type Output;
151    fn wrapping_neg(self) -> Self::Output;
152}
153}
154
155wrapping_neg_impl!(u8 u16 u32 u64 usize u128 i8 i16 i32 i64 isize i128);
156
157macro_rules! wrapping_shift_impl {
158    ($trait_name:ident, $method:ident, $t:ty) => {
159        c0nst::c0nst! {
160        c0nst impl $trait_name for $t {
161            #[inline]
162            fn $method(self, rhs: u32) -> $t {
163                <$t>::$method(self, rhs)
164            }
165        }
166        }
167    };
168}
169
170c0nst::c0nst! {
171/// Performs a left shift that does not panic.
172pub c0nst trait WrappingShl: Sized + [c0nst] Shl<usize> {
173    /// Panic-free bitwise shift-left; yields `self << mask(rhs)`,
174    /// where `mask` removes any high order bits of `rhs` that would
175    /// cause the shift to exceed the bitwidth of the type.
176    ///
177    /// ```
178    /// use const_num_traits::WrappingShl;
179    ///
180    /// let x: u16 = 0x0001;
181    ///
182    /// assert_eq!(WrappingShl::wrapping_shl(x, 0),  0x0001);
183    /// assert_eq!(WrappingShl::wrapping_shl(x, 1),  0x0002);
184    /// assert_eq!(WrappingShl::wrapping_shl(x, 15), 0x8000);
185    /// assert_eq!(WrappingShl::wrapping_shl(x, 16), 0x0001);
186    /// ```
187    fn wrapping_shl(self, rhs: u32) -> <Self as Shl<usize>>::Output;
188}
189}
190
191wrapping_shift_impl!(WrappingShl, wrapping_shl, u8);
192wrapping_shift_impl!(WrappingShl, wrapping_shl, u16);
193wrapping_shift_impl!(WrappingShl, wrapping_shl, u32);
194wrapping_shift_impl!(WrappingShl, wrapping_shl, u64);
195wrapping_shift_impl!(WrappingShl, wrapping_shl, usize);
196wrapping_shift_impl!(WrappingShl, wrapping_shl, u128);
197
198wrapping_shift_impl!(WrappingShl, wrapping_shl, i8);
199wrapping_shift_impl!(WrappingShl, wrapping_shl, i16);
200wrapping_shift_impl!(WrappingShl, wrapping_shl, i32);
201wrapping_shift_impl!(WrappingShl, wrapping_shl, i64);
202wrapping_shift_impl!(WrappingShl, wrapping_shl, isize);
203wrapping_shift_impl!(WrappingShl, wrapping_shl, i128);
204
205c0nst::c0nst! {
206/// Performs a right shift that does not panic.
207pub c0nst trait WrappingShr: Sized + [c0nst] Shr<usize> {
208    /// Panic-free bitwise shift-right; yields `self >> mask(rhs)`,
209    /// where `mask` removes any high order bits of `rhs` that would
210    /// cause the shift to exceed the bitwidth of the type.
211    ///
212    /// ```
213    /// use const_num_traits::WrappingShr;
214    ///
215    /// let x: u16 = 0x8000;
216    ///
217    /// assert_eq!(WrappingShr::wrapping_shr(x, 0),  0x8000);
218    /// assert_eq!(WrappingShr::wrapping_shr(x, 1),  0x4000);
219    /// assert_eq!(WrappingShr::wrapping_shr(x, 15), 0x0001);
220    /// assert_eq!(WrappingShr::wrapping_shr(x, 16), 0x8000);
221    /// ```
222    fn wrapping_shr(self, rhs: u32) -> <Self as Shr<usize>>::Output;
223}
224}
225
226wrapping_shift_impl!(WrappingShr, wrapping_shr, u8);
227wrapping_shift_impl!(WrappingShr, wrapping_shr, u16);
228wrapping_shift_impl!(WrappingShr, wrapping_shr, u32);
229wrapping_shift_impl!(WrappingShr, wrapping_shr, u64);
230wrapping_shift_impl!(WrappingShr, wrapping_shr, usize);
231wrapping_shift_impl!(WrappingShr, wrapping_shr, u128);
232
233wrapping_shift_impl!(WrappingShr, wrapping_shr, i8);
234wrapping_shift_impl!(WrappingShr, wrapping_shr, i16);
235wrapping_shift_impl!(WrappingShr, wrapping_shr, i32);
236wrapping_shift_impl!(WrappingShr, wrapping_shr, i64);
237wrapping_shift_impl!(WrappingShr, wrapping_shr, isize);
238wrapping_shift_impl!(WrappingShr, wrapping_shr, i128);
239
240c0nst::c0nst! {
241/// Performs division that wraps around on overflow.
242pub c0nst trait WrappingDiv: Sized + [c0nst] Div<Self> {
243    /// Wrapping (modular) division. Computes `self / other`, wrapping around
244    /// at the boundary of the type.
245    ///
246    /// The only case where such wrapping can occur is when one divides
247    /// `MIN / -1` on a signed type; this is equivalent to `-MIN`, a positive
248    /// value that is too large to represent in the type. For unsigned types
249    /// this is a normal division and can never wrap.
250    ///
251    /// # Panics
252    ///
253    /// Panics if `other` is zero.
254    ///
255    /// ```
256    /// use const_num_traits::WrappingDiv;
257    ///
258    /// assert_eq!(WrappingDiv::wrapping_div(100i8, 10), 10);
259    /// assert_eq!(WrappingDiv::wrapping_div(i8::MIN, -1), i8::MIN); // wrapped!
260    /// ```
261    fn wrapping_div(self, v: Self) -> <Self as Div<Self>>::Output;
262}
263}
264
265wrapping_impl!(WrappingDiv, wrapping_div, u8);
266wrapping_impl!(WrappingDiv, wrapping_div, u16);
267wrapping_impl!(WrappingDiv, wrapping_div, u32);
268wrapping_impl!(WrappingDiv, wrapping_div, u64);
269wrapping_impl!(WrappingDiv, wrapping_div, usize);
270wrapping_impl!(WrappingDiv, wrapping_div, u128);
271
272wrapping_impl!(WrappingDiv, wrapping_div, i8);
273wrapping_impl!(WrappingDiv, wrapping_div, i16);
274wrapping_impl!(WrappingDiv, wrapping_div, i32);
275wrapping_impl!(WrappingDiv, wrapping_div, i64);
276wrapping_impl!(WrappingDiv, wrapping_div, isize);
277wrapping_impl!(WrappingDiv, wrapping_div, i128);
278
279c0nst::c0nst! {
280/// Performs a remainder operation that wraps around on overflow.
281pub c0nst trait WrappingRem: Sized + [c0nst] Rem<Self> {
282    /// Wrapping (modular) remainder. Computes `self % other`, wrapping around
283    /// at the boundary of the type.
284    ///
285    /// The only case where such wrapping can occur is `MIN % -1` on a signed
286    /// type, where the remainder is defined to be 0. For unsigned types this
287    /// is a normal remainder and can never wrap.
288    ///
289    /// # Panics
290    ///
291    /// Panics if `other` is zero.
292    ///
293    /// ```
294    /// use const_num_traits::WrappingRem;
295    ///
296    /// assert_eq!(WrappingRem::wrapping_rem(100i8, 10), 0);
297    /// assert_eq!(WrappingRem::wrapping_rem(i8::MIN, -1), 0); // wrapped!
298    /// ```
299    fn wrapping_rem(self, v: Self) -> <Self as Rem<Self>>::Output;
300}
301}
302
303wrapping_impl!(WrappingRem, wrapping_rem, u8);
304wrapping_impl!(WrappingRem, wrapping_rem, u16);
305wrapping_impl!(WrappingRem, wrapping_rem, u32);
306wrapping_impl!(WrappingRem, wrapping_rem, u64);
307wrapping_impl!(WrappingRem, wrapping_rem, usize);
308wrapping_impl!(WrappingRem, wrapping_rem, u128);
309
310wrapping_impl!(WrappingRem, wrapping_rem, i8);
311wrapping_impl!(WrappingRem, wrapping_rem, i16);
312wrapping_impl!(WrappingRem, wrapping_rem, i32);
313wrapping_impl!(WrappingRem, wrapping_rem, i64);
314wrapping_impl!(WrappingRem, wrapping_rem, isize);
315wrapping_impl!(WrappingRem, wrapping_rem, i128);
316
317c0nst::c0nst! {
318/// Computes the absolute value, wrapping around on overflow.
319pub c0nst trait WrappingAbs: Sized + [c0nst] Neg {
320    /// Wrapping (modular) absolute value. Computes `self.abs()`, wrapping
321    /// around at the boundary of the type. The only wrapping case is
322    /// `MIN.wrapping_abs() == MIN`.
323    ///
324    /// ```
325    /// use const_num_traits::WrappingAbs;
326    ///
327    /// assert_eq!(WrappingAbs::wrapping_abs(-100i8), 100);
328    /// assert_eq!(WrappingAbs::wrapping_abs(i8::MIN), i8::MIN); // wrapped!
329    /// ```
330    fn wrapping_abs(self) -> <Self as Neg>::Output;
331}
332}
333
334wrapping_unary_impl!(WrappingAbs, wrapping_abs, i8);
335wrapping_unary_impl!(WrappingAbs, wrapping_abs, i16);
336wrapping_unary_impl!(WrappingAbs, wrapping_abs, i32);
337wrapping_unary_impl!(WrappingAbs, wrapping_abs, i64);
338wrapping_unary_impl!(WrappingAbs, wrapping_abs, isize);
339wrapping_unary_impl!(WrappingAbs, wrapping_abs, i128);
340
341c0nst::c0nst! {
342/// Performs exponentiation that wraps around on overflow.
343pub c0nst trait WrappingPow: Sized + [c0nst] Mul<Self> {
344    /// Wrapping (modular) exponentiation. Computes `self.pow(exp)`, wrapping
345    /// around at the boundary of the type.
346    ///
347    /// ```
348    /// use const_num_traits::WrappingPow;
349    ///
350    /// assert_eq!(WrappingPow::wrapping_pow(3u8, 5), 243);
351    /// assert_eq!(WrappingPow::wrapping_pow(3u8, 6), 217); // wrapped!
352    /// ```
353    fn wrapping_pow(self, exp: u32) -> <Self as Mul<Self>>::Output;
354}
355}
356
357wrapping_shift_impl!(WrappingPow, wrapping_pow, u8);
358wrapping_shift_impl!(WrappingPow, wrapping_pow, u16);
359wrapping_shift_impl!(WrappingPow, wrapping_pow, u32);
360wrapping_shift_impl!(WrappingPow, wrapping_pow, u64);
361wrapping_shift_impl!(WrappingPow, wrapping_pow, usize);
362wrapping_shift_impl!(WrappingPow, wrapping_pow, u128);
363
364wrapping_shift_impl!(WrappingPow, wrapping_pow, i8);
365wrapping_shift_impl!(WrappingPow, wrapping_pow, i16);
366wrapping_shift_impl!(WrappingPow, wrapping_pow, i32);
367wrapping_shift_impl!(WrappingPow, wrapping_pow, i64);
368wrapping_shift_impl!(WrappingPow, wrapping_pow, isize);
369wrapping_shift_impl!(WrappingPow, wrapping_pow, i128);
370
371#[test]
372fn test_wrapping_div_rem_abs_pow() {
373    assert_eq!(WrappingDiv::wrapping_div(i8::MIN, -1), i8::MIN);
374    assert_eq!(WrappingDiv::wrapping_div(100u8, 7), 14);
375    assert_eq!(WrappingRem::wrapping_rem(i8::MIN, -1), 0);
376    assert_eq!(WrappingRem::wrapping_rem(100u8, 7), 2);
377    assert_eq!(WrappingAbs::wrapping_abs(i16::MIN), i16::MIN);
378    assert_eq!(WrappingAbs::wrapping_abs(-7i16), 7);
379    assert_eq!(WrappingPow::wrapping_pow(3i8, 5), -13);
380    assert_eq!(WrappingPow::wrapping_pow(2u16, 16), 0);
381}
382
383// Wrapping<T> blanket impls stay non-const: std's `Add`/`Sub`/`Mul`/`Neg`/`Shl`/`Shr`
384// impls for `Wrapping<T>` are not const-trait impls (same situation as Num).
385impl<T: WrappingAdd<Output = T>> WrappingAdd for Wrapping<T>
386where
387    Wrapping<T>: Add<Output = Wrapping<T>>,
388{
389    fn wrapping_add(self, v: Self) -> Self {
390        Wrapping(self.0.wrapping_add(v.0))
391    }
392}
393impl<T: WrappingSub<Output = T>> WrappingSub for Wrapping<T>
394where
395    Wrapping<T>: Sub<Output = Wrapping<T>>,
396{
397    fn wrapping_sub(self, v: Self) -> Self {
398        Wrapping(self.0.wrapping_sub(v.0))
399    }
400}
401impl<T: WrappingMul<Output = T>> WrappingMul for Wrapping<T>
402where
403    Wrapping<T>: Mul<Output = Wrapping<T>>,
404{
405    fn wrapping_mul(self, v: Self) -> Self {
406        Wrapping(self.0.wrapping_mul(v.0))
407    }
408}
409impl<T: WrappingNeg<Output = T>> WrappingNeg for Wrapping<T>
410where
411    Wrapping<T>: Neg<Output = Wrapping<T>>,
412{
413    type Output = Wrapping<T>;
414    fn wrapping_neg(self) -> Self {
415        Wrapping(self.0.wrapping_neg())
416    }
417}
418impl<T: WrappingShl<Output = T>> WrappingShl for Wrapping<T>
419where
420    Wrapping<T>: Shl<usize, Output = Wrapping<T>>,
421{
422    fn wrapping_shl(self, rhs: u32) -> Self {
423        Wrapping(self.0.wrapping_shl(rhs))
424    }
425}
426impl<T: WrappingShr<Output = T>> WrappingShr for Wrapping<T>
427where
428    Wrapping<T>: Shr<usize, Output = Wrapping<T>>,
429{
430    fn wrapping_shr(self, rhs: u32) -> Self {
431        Wrapping(self.0.wrapping_shr(rhs))
432    }
433}
434
435#[test]
436fn test_wrapping_traits() {
437    fn wrapping_add<T: WrappingAdd<Output = T>>(a: T, b: T) -> T {
438        a.wrapping_add(b)
439    }
440    fn wrapping_sub<T: WrappingSub<Output = T>>(a: T, b: T) -> T {
441        a.wrapping_sub(b)
442    }
443    fn wrapping_mul<T: WrappingMul<Output = T>>(a: T, b: T) -> T {
444        a.wrapping_mul(b)
445    }
446    fn wrapping_neg<T: WrappingNeg<Output = T>>(a: T) -> T {
447        a.wrapping_neg()
448    }
449    fn wrapping_shl<T: WrappingShl<Output = T>>(a: T, b: u32) -> T {
450        a.wrapping_shl(b)
451    }
452    fn wrapping_shr<T: WrappingShr<Output = T>>(a: T, b: u32) -> T {
453        a.wrapping_shr(b)
454    }
455    assert_eq!(wrapping_add(255, 1), 0u8);
456    assert_eq!(wrapping_sub(0, 1), 255u8);
457    assert_eq!(wrapping_mul(255, 2), 254u8);
458    assert_eq!(wrapping_neg(255), 1u8);
459    assert_eq!(wrapping_shl(255, 8), 255u8);
460    assert_eq!(wrapping_shr(255, 8), 255u8);
461    assert_eq!(wrapping_add(255, 1), (Wrapping(255u8) + Wrapping(1u8)).0);
462    assert_eq!(wrapping_sub(0, 1), (Wrapping(0u8) - Wrapping(1u8)).0);
463    assert_eq!(wrapping_mul(255, 2), (Wrapping(255u8) * Wrapping(2u8)).0);
464    assert_eq!(wrapping_neg(255), (-Wrapping(255u8)).0);
465    assert_eq!(wrapping_shl(255, 8), (Wrapping(255u8) << 8).0);
466    assert_eq!(wrapping_shr(255, 8), (Wrapping(255u8) >> 8).0);
467}
468
469#[test]
470fn wrapping_is_wrappingadd() {
471    fn require_wrappingadd<T: WrappingAdd<Output = T>>(_: &T) {}
472    require_wrappingadd(&Wrapping(42));
473}
474
475#[test]
476fn wrapping_is_wrappingsub() {
477    fn require_wrappingsub<T: WrappingSub<Output = T>>(_: &T) {}
478    require_wrappingsub(&Wrapping(42));
479}
480
481#[test]
482fn wrapping_is_wrappingmul() {
483    fn require_wrappingmul<T: WrappingMul<Output = T>>(_: &T) {}
484    require_wrappingmul(&Wrapping(42));
485}
486
487#[test]
488fn wrapping_is_wrappingneg() {
489    fn require_wrappingneg<T: WrappingNeg<Output = T>>(_: &T) {}
490    require_wrappingneg(&Wrapping(42));
491}
492
493#[test]
494fn wrapping_is_wrappingshl() {
495    fn require_wrappingshl<T: WrappingShl<Output = T>>(_: &T) {}
496    require_wrappingshl(&Wrapping(42));
497}
498
499#[test]
500fn wrapping_is_wrappingshr() {
501    fn require_wrappingshr<T: WrappingShr<Output = T>>(_: &T) {}
502    require_wrappingshr(&Wrapping(42));
503}