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