Skip to main content

const_num_traits/ops/
saturating.rs

1//! Saturating arithmetic.
2//!
3//! **CT tier A (CT-implementable)** for add/sub/mul/neg/abs/pow-style
4//! saturation: it is expressible as a branchless select on an overflow mask.
5//! `SaturatingDiv` is CT-hostile — it performs data-dependent division and
6//! panics on a zero divisor — so it is Tier C for secret inputs.
7
8use core::ops::{Add, Div, Mul, Neg, Sub};
9
10c0nst::c0nst! {
11/// Saturating math operations. Deprecated, use `SaturatingAdd`, `SaturatingSub` and
12/// `SaturatingMul` instead.
13pub c0nst trait Saturating {
14    /// Saturating addition operator.
15    /// Returns a+b, saturating at the numeric bounds instead of overflowing.
16    fn saturating_add(self, v: Self) -> Self;
17
18    /// Saturating subtraction operator.
19    /// Returns a-b, saturating at the numeric bounds instead of overflowing.
20    fn saturating_sub(self, v: Self) -> Self;
21}
22}
23
24macro_rules! deprecated_saturating_impl {
25    ($trait_name:ident for $($t:ty)*) => {$(
26        c0nst::c0nst! {
27        c0nst impl $trait_name for $t {
28            #[inline]
29            fn saturating_add(self, v: Self) -> Self {
30                Self::saturating_add(self, v)
31            }
32
33            #[inline]
34            fn saturating_sub(self, v: Self) -> Self {
35                Self::saturating_sub(self, v)
36            }
37        }
38        }
39    )*}
40}
41
42deprecated_saturating_impl!(Saturating for isize i8 i16 i32 i64 i128);
43deprecated_saturating_impl!(Saturating for usize u8 u16 u32 u64 u128);
44
45macro_rules! saturating_impl {
46    ($trait_name:ident, $method:ident, $t:ty) => {
47        c0nst::c0nst! {
48        c0nst impl $trait_name for $t {
49            #[inline]
50            fn $method(self, v: Self) -> Self {
51                <$t>::$method(self, v)
52            }
53        }
54        }
55    };
56}
57
58c0nst::c0nst! {
59/// Performs addition that saturates at the numeric bounds instead of overflowing.
60pub c0nst trait SaturatingAdd: Sized + [c0nst] Add<Self> {
61    /// Saturating addition. Computes `self + other`, saturating at the relevant high or low boundary of
62    /// the type.
63    fn saturating_add(self, v: Self) -> <Self as Add<Self>>::Output;
64}
65}
66
67saturating_impl!(SaturatingAdd, saturating_add, u8);
68saturating_impl!(SaturatingAdd, saturating_add, u16);
69saturating_impl!(SaturatingAdd, saturating_add, u32);
70saturating_impl!(SaturatingAdd, saturating_add, u64);
71saturating_impl!(SaturatingAdd, saturating_add, usize);
72saturating_impl!(SaturatingAdd, saturating_add, u128);
73
74saturating_impl!(SaturatingAdd, saturating_add, i8);
75saturating_impl!(SaturatingAdd, saturating_add, i16);
76saturating_impl!(SaturatingAdd, saturating_add, i32);
77saturating_impl!(SaturatingAdd, saturating_add, i64);
78saturating_impl!(SaturatingAdd, saturating_add, isize);
79saturating_impl!(SaturatingAdd, saturating_add, i128);
80
81c0nst::c0nst! {
82/// Performs subtraction that saturates at the numeric bounds instead of overflowing.
83pub c0nst trait SaturatingSub: Sized + [c0nst] Sub<Self> {
84    /// Saturating subtraction. Computes `self - other`, saturating at the relevant high or low boundary of
85    /// the type.
86    fn saturating_sub(self, v: Self) -> <Self as Sub<Self>>::Output;
87}
88}
89
90saturating_impl!(SaturatingSub, saturating_sub, u8);
91saturating_impl!(SaturatingSub, saturating_sub, u16);
92saturating_impl!(SaturatingSub, saturating_sub, u32);
93saturating_impl!(SaturatingSub, saturating_sub, u64);
94saturating_impl!(SaturatingSub, saturating_sub, usize);
95saturating_impl!(SaturatingSub, saturating_sub, u128);
96
97saturating_impl!(SaturatingSub, saturating_sub, i8);
98saturating_impl!(SaturatingSub, saturating_sub, i16);
99saturating_impl!(SaturatingSub, saturating_sub, i32);
100saturating_impl!(SaturatingSub, saturating_sub, i64);
101saturating_impl!(SaturatingSub, saturating_sub, isize);
102saturating_impl!(SaturatingSub, saturating_sub, i128);
103
104c0nst::c0nst! {
105/// Performs multiplication that saturates at the numeric bounds instead of overflowing.
106pub c0nst trait SaturatingMul: Sized + [c0nst] Mul<Self> {
107    /// Saturating multiplication. Computes `self * other`, saturating at the relevant high or low boundary of
108    /// the type.
109    fn saturating_mul(self, v: Self) -> <Self as Mul<Self>>::Output;
110}
111}
112
113saturating_impl!(SaturatingMul, saturating_mul, u8);
114saturating_impl!(SaturatingMul, saturating_mul, u16);
115saturating_impl!(SaturatingMul, saturating_mul, u32);
116saturating_impl!(SaturatingMul, saturating_mul, u64);
117saturating_impl!(SaturatingMul, saturating_mul, usize);
118saturating_impl!(SaturatingMul, saturating_mul, u128);
119
120saturating_impl!(SaturatingMul, saturating_mul, i8);
121saturating_impl!(SaturatingMul, saturating_mul, i16);
122saturating_impl!(SaturatingMul, saturating_mul, i32);
123saturating_impl!(SaturatingMul, saturating_mul, i64);
124saturating_impl!(SaturatingMul, saturating_mul, isize);
125saturating_impl!(SaturatingMul, saturating_mul, i128);
126
127c0nst::c0nst! {
128/// Performs division that saturates at the numeric bounds instead of overflowing.
129pub c0nst trait SaturatingDiv: Sized + [c0nst] Div<Self> {
130    /// Saturating division. Computes `self / other`, saturating at the
131    /// relevant high or low boundary of the type. The only saturating case is
132    /// `MIN / -1` on a signed type, which saturates to `MAX`.
133    ///
134    /// # Panics
135    ///
136    /// Panics if `other` is zero.
137    ///
138    /// ```
139    /// use const_num_traits::SaturatingDiv;
140    ///
141    /// assert_eq!(SaturatingDiv::saturating_div(5i32, 2), 2);
142    /// assert_eq!(SaturatingDiv::saturating_div(i32::MIN, -1), i32::MAX);
143    /// ```
144    fn saturating_div(self, v: Self) -> <Self as Div<Self>>::Output;
145}
146}
147
148saturating_impl!(SaturatingDiv, saturating_div, u8);
149saturating_impl!(SaturatingDiv, saturating_div, u16);
150saturating_impl!(SaturatingDiv, saturating_div, u32);
151saturating_impl!(SaturatingDiv, saturating_div, u64);
152saturating_impl!(SaturatingDiv, saturating_div, usize);
153saturating_impl!(SaturatingDiv, saturating_div, u128);
154
155saturating_impl!(SaturatingDiv, saturating_div, i8);
156saturating_impl!(SaturatingDiv, saturating_div, i16);
157saturating_impl!(SaturatingDiv, saturating_div, i32);
158saturating_impl!(SaturatingDiv, saturating_div, i64);
159saturating_impl!(SaturatingDiv, saturating_div, isize);
160saturating_impl!(SaturatingDiv, saturating_div, i128);
161
162macro_rules! saturating_unary_impl {
163    ($trait_name:ident, $method:ident, $t:ty) => {
164        c0nst::c0nst! {
165        c0nst impl $trait_name for $t {
166            #[inline]
167            fn $method(self) -> $t {
168                <$t>::$method(self)
169            }
170        }
171        }
172    };
173}
174
175c0nst::c0nst! {
176/// Performs negation that saturates at the numeric bounds instead of overflowing.
177pub c0nst trait SaturatingNeg: Sized + [c0nst] Neg {
178    /// Saturating negation. Computes `-self`, saturating at the numeric
179    /// bounds: `MIN.saturating_neg()` is `MAX`.
180    ///
181    /// ```
182    /// use const_num_traits::SaturatingNeg;
183    ///
184    /// assert_eq!(SaturatingNeg::saturating_neg(-5i32), 5);
185    /// assert_eq!(SaturatingNeg::saturating_neg(i32::MIN), i32::MAX);
186    /// ```
187    fn saturating_neg(self) -> <Self as Neg>::Output;
188}
189}
190
191saturating_unary_impl!(SaturatingNeg, saturating_neg, i8);
192saturating_unary_impl!(SaturatingNeg, saturating_neg, i16);
193saturating_unary_impl!(SaturatingNeg, saturating_neg, i32);
194saturating_unary_impl!(SaturatingNeg, saturating_neg, i64);
195saturating_unary_impl!(SaturatingNeg, saturating_neg, isize);
196saturating_unary_impl!(SaturatingNeg, saturating_neg, i128);
197
198c0nst::c0nst! {
199/// Computes the absolute value, saturating at the numeric bounds instead of overflowing.
200pub c0nst trait SaturatingAbs: Sized + [c0nst] Neg {
201    /// Saturating absolute value. Computes `self.abs()`, saturating at the
202    /// numeric bounds: `MIN.saturating_abs()` is `MAX`.
203    ///
204    /// ```
205    /// use const_num_traits::SaturatingAbs;
206    ///
207    /// assert_eq!(SaturatingAbs::saturating_abs(-5i32), 5);
208    /// assert_eq!(SaturatingAbs::saturating_abs(i32::MIN), i32::MAX);
209    /// ```
210    fn saturating_abs(self) -> <Self as Neg>::Output;
211}
212}
213
214saturating_unary_impl!(SaturatingAbs, saturating_abs, i8);
215saturating_unary_impl!(SaturatingAbs, saturating_abs, i16);
216saturating_unary_impl!(SaturatingAbs, saturating_abs, i32);
217saturating_unary_impl!(SaturatingAbs, saturating_abs, i64);
218saturating_unary_impl!(SaturatingAbs, saturating_abs, isize);
219saturating_unary_impl!(SaturatingAbs, saturating_abs, i128);
220
221macro_rules! saturating_pow_impl {
222    ($t:ty) => {
223        c0nst::c0nst! {
224        c0nst impl SaturatingPow for $t {
225            #[inline]
226            fn saturating_pow(self, exp: u32) -> $t {
227                <$t>::saturating_pow(self, exp)
228            }
229        }
230        }
231    };
232}
233
234c0nst::c0nst! {
235/// Performs exponentiation that saturates at the numeric bounds instead of overflowing.
236pub c0nst trait SaturatingPow: Sized + [c0nst] Mul<Self> {
237    /// Saturating exponentiation. Computes `self.pow(exp)`, saturating at the
238    /// relevant high or low boundary of the type.
239    ///
240    /// ```
241    /// use const_num_traits::SaturatingPow;
242    ///
243    /// assert_eq!(SaturatingPow::saturating_pow(4u8, 3), 64);
244    /// assert_eq!(SaturatingPow::saturating_pow(4u8, 4), u8::MAX);
245    /// assert_eq!(SaturatingPow::saturating_pow(-2i8, 7), i8::MIN);
246    /// ```
247    fn saturating_pow(self, exp: u32) -> <Self as Mul<Self>>::Output;
248}
249}
250
251saturating_pow_impl!(u8);
252saturating_pow_impl!(u16);
253saturating_pow_impl!(u32);
254saturating_pow_impl!(u64);
255saturating_pow_impl!(usize);
256saturating_pow_impl!(u128);
257
258saturating_pow_impl!(i8);
259saturating_pow_impl!(i16);
260saturating_pow_impl!(i32);
261saturating_pow_impl!(i64);
262saturating_pow_impl!(isize);
263saturating_pow_impl!(i128);
264
265#[test]
266fn test_saturating_div_neg_abs_pow() {
267    assert_eq!(SaturatingDiv::saturating_div(i8::MIN, -1), i8::MAX);
268    assert_eq!(SaturatingDiv::saturating_div(100u8, 7), 14);
269    assert_eq!(SaturatingNeg::saturating_neg(i16::MIN), i16::MAX);
270    assert_eq!(SaturatingNeg::saturating_neg(7i16), -7);
271    assert_eq!(SaturatingAbs::saturating_abs(i16::MIN), i16::MAX);
272    assert_eq!(SaturatingAbs::saturating_abs(-7i16), 7);
273    assert_eq!(SaturatingPow::saturating_pow(2u16, 17), u16::MAX);
274    assert_eq!(SaturatingPow::saturating_pow(-2i16, 15), i16::MIN);
275}
276
277#[test]
278fn test_saturating_traits() {
279    fn saturating_add<T: SaturatingAdd<Output = T>>(a: T, b: T) -> T {
280        a.saturating_add(b)
281    }
282    fn saturating_sub<T: SaturatingSub<Output = T>>(a: T, b: T) -> T {
283        a.saturating_sub(b)
284    }
285    fn saturating_mul<T: SaturatingMul<Output = T>>(a: T, b: T) -> T {
286        a.saturating_mul(b)
287    }
288    assert_eq!(saturating_add(255, 1), 255u8);
289    assert_eq!(saturating_add(127, 1), 127i8);
290    assert_eq!(saturating_add(-128, -1), -128i8);
291    assert_eq!(saturating_sub(0, 1), 0u8);
292    assert_eq!(saturating_sub(-128, 1), -128i8);
293    assert_eq!(saturating_sub(127, -1), 127i8);
294    assert_eq!(saturating_mul(255, 2), 255u8);
295    assert_eq!(saturating_mul(127, 2), 127i8);
296    assert_eq!(saturating_mul(-128, 2), -128i8);
297}