1use core::ops::{Add, Div, Mul, Rem, Shl, Shr, Sub};
2
3/// Performs addition that returns `None` instead of wrapping around on
4/// overflow.
5pub trait CheckedAdd: Sized + Add<Self, Output = Self> {
6 /// Adds two numbers, checking for overflow. If overflow happens, `None` is
7 /// returned.
8 fn checked_add(&self, v: &Self) -> Option<Self>;
9}
10
11macro_rules! checked_impl {
12 ($trait_name:ident, $method:ident, $t:ty) => {
13 impl $trait_name for $t {
14 #[inline]
15 fn $method(&self, v: &$t) -> Option<$t> {
16 <$t>::$method(*self, *v)
17 }
18 }
19 };
20}
21
22checked_impl!(CheckedAdd, checked_add, u8);
23checked_impl!(CheckedAdd, checked_add, u16);
24checked_impl!(CheckedAdd, checked_add, u32);
25checked_impl!(CheckedAdd, checked_add, u64);
26checked_impl!(CheckedAdd, checked_add, usize);
27checked_impl!(CheckedAdd, checked_add, u128);
28
29checked_impl!(CheckedAdd, checked_add, i8);
30checked_impl!(CheckedAdd, checked_add, i16);
31checked_impl!(CheckedAdd, checked_add, i32);
32checked_impl!(CheckedAdd, checked_add, i64);
33checked_impl!(CheckedAdd, checked_add, isize);
34checked_impl!(CheckedAdd, checked_add, i128);
35
36/// Performs subtraction that returns `None` instead of wrapping around on underflow.
37pub trait CheckedSub: Sized + Sub<Self, Output = Self> {
38 /// Subtracts two numbers, checking for underflow. If underflow happens,
39 /// `None` is returned.
40 fn checked_sub(&self, v: &Self) -> Option<Self>;
41}
42
43checked_impl!(CheckedSub, checked_sub, u8);
44checked_impl!(CheckedSub, checked_sub, u16);
45checked_impl!(CheckedSub, checked_sub, u32);
46checked_impl!(CheckedSub, checked_sub, u64);
47checked_impl!(CheckedSub, checked_sub, usize);
48checked_impl!(CheckedSub, checked_sub, u128);
49
50checked_impl!(CheckedSub, checked_sub, i8);
51checked_impl!(CheckedSub, checked_sub, i16);
52checked_impl!(CheckedSub, checked_sub, i32);
53checked_impl!(CheckedSub, checked_sub, i64);
54checked_impl!(CheckedSub, checked_sub, isize);
55checked_impl!(CheckedSub, checked_sub, i128);
56
57/// Performs multiplication that returns `None` instead of wrapping around on underflow or
58/// overflow.
59pub trait CheckedMul: Sized + Mul<Self, Output = Self> {
60 /// Multiplies two numbers, checking for underflow or overflow. If underflow
61 /// or overflow happens, `None` is returned.
62 fn checked_mul(&self, v: &Self) -> Option<Self>;
63}
64
65checked_impl!(CheckedMul, checked_mul, u8);
66checked_impl!(CheckedMul, checked_mul, u16);
67checked_impl!(CheckedMul, checked_mul, u32);
68checked_impl!(CheckedMul, checked_mul, u64);
69checked_impl!(CheckedMul, checked_mul, usize);
70checked_impl!(CheckedMul, checked_mul, u128);
71
72checked_impl!(CheckedMul, checked_mul, i8);
73checked_impl!(CheckedMul, checked_mul, i16);
74checked_impl!(CheckedMul, checked_mul, i32);
75checked_impl!(CheckedMul, checked_mul, i64);
76checked_impl!(CheckedMul, checked_mul, isize);
77checked_impl!(CheckedMul, checked_mul, i128);
78
79/// Performs division that returns `None` instead of panicking on division by zero and instead of
80/// wrapping around on underflow and overflow.
81pub trait CheckedDiv: Sized + Div<Self, Output = Self> {
82 /// Divides two numbers, checking for underflow, overflow and division by
83 /// zero. If any of that happens, `None` is returned.
84 fn checked_div(&self, v: &Self) -> Option<Self>;
85}
86
87checked_impl!(CheckedDiv, checked_div, u8);
88checked_impl!(CheckedDiv, checked_div, u16);
89checked_impl!(CheckedDiv, checked_div, u32);
90checked_impl!(CheckedDiv, checked_div, u64);
91checked_impl!(CheckedDiv, checked_div, usize);
92checked_impl!(CheckedDiv, checked_div, u128);
93
94checked_impl!(CheckedDiv, checked_div, i8);
95checked_impl!(CheckedDiv, checked_div, i16);
96checked_impl!(CheckedDiv, checked_div, i32);
97checked_impl!(CheckedDiv, checked_div, i64);
98checked_impl!(CheckedDiv, checked_div, isize);
99checked_impl!(CheckedDiv, checked_div, i128);
100
101/// Performs an integral remainder that returns `None` instead of panicking on division by zero and
102/// instead of wrapping around on underflow and overflow.
103pub trait CheckedRem: Sized + Rem<Self, Output = Self> {
104 /// Finds the remainder of dividing two numbers, checking for underflow, overflow and division
105 /// by zero. If any of that happens, `None` is returned.
106 ///
107 /// # Examples
108 ///
109 /// ```
110 /// use num_traits::CheckedRem;
111 /// use std::i32::MIN;
112 ///
113 /// assert_eq!(CheckedRem::checked_rem(&10, &7), Some(3));
114 /// assert_eq!(CheckedRem::checked_rem(&10, &-7), Some(3));
115 /// assert_eq!(CheckedRem::checked_rem(&-10, &7), Some(-3));
116 /// assert_eq!(CheckedRem::checked_rem(&-10, &-7), Some(-3));
117 ///
118 /// assert_eq!(CheckedRem::checked_rem(&10, &0), None);
119 ///
120 /// assert_eq!(CheckedRem::checked_rem(&MIN, &1), Some(0));
121 /// assert_eq!(CheckedRem::checked_rem(&MIN, &-1), None);
122 /// ```
123 fn checked_rem(&self, v: &Self) -> Option<Self>;
124}
125
126checked_impl!(CheckedRem, checked_rem, u8);
127checked_impl!(CheckedRem, checked_rem, u16);
128checked_impl!(CheckedRem, checked_rem, u32);
129checked_impl!(CheckedRem, checked_rem, u64);
130checked_impl!(CheckedRem, checked_rem, usize);
131checked_impl!(CheckedRem, checked_rem, u128);
132
133checked_impl!(CheckedRem, checked_rem, i8);
134checked_impl!(CheckedRem, checked_rem, i16);
135checked_impl!(CheckedRem, checked_rem, i32);
136checked_impl!(CheckedRem, checked_rem, i64);
137checked_impl!(CheckedRem, checked_rem, isize);
138checked_impl!(CheckedRem, checked_rem, i128);
139
140macro_rules! checked_impl_unary {
141 ($trait_name:ident, $method:ident, $t:ty) => {
142 impl $trait_name for $t {
143 #[inline]
144 fn $method(&self) -> Option<$t> {
145 <$t>::$method(*self)
146 }
147 }
148 };
149}
150
151/// Performs negation that returns `None` if the result can't be represented.
152pub trait CheckedNeg: Sized {
153 /// Negates a number, returning `None` for results that can't be represented, like signed `MIN`
154 /// values that can't be positive, or non-zero unsigned values that can't be negative.
155 ///
156 /// # Examples
157 ///
158 /// ```
159 /// use num_traits::CheckedNeg;
160 /// use std::i32::MIN;
161 ///
162 /// assert_eq!(CheckedNeg::checked_neg(&1_i32), Some(-1));
163 /// assert_eq!(CheckedNeg::checked_neg(&-1_i32), Some(1));
164 /// assert_eq!(CheckedNeg::checked_neg(&MIN), None);
165 ///
166 /// assert_eq!(CheckedNeg::checked_neg(&0_u32), Some(0));
167 /// assert_eq!(CheckedNeg::checked_neg(&1_u32), None);
168 /// ```
169 fn checked_neg(&self) -> Option<Self>;
170}
171
172checked_impl_unary!(CheckedNeg, checked_neg, u8);
173checked_impl_unary!(CheckedNeg, checked_neg, u16);
174checked_impl_unary!(CheckedNeg, checked_neg, u32);
175checked_impl_unary!(CheckedNeg, checked_neg, u64);
176checked_impl_unary!(CheckedNeg, checked_neg, usize);
177checked_impl_unary!(CheckedNeg, checked_neg, u128);
178
179checked_impl_unary!(CheckedNeg, checked_neg, i8);
180checked_impl_unary!(CheckedNeg, checked_neg, i16);
181checked_impl_unary!(CheckedNeg, checked_neg, i32);
182checked_impl_unary!(CheckedNeg, checked_neg, i64);
183checked_impl_unary!(CheckedNeg, checked_neg, isize);
184checked_impl_unary!(CheckedNeg, checked_neg, i128);
185
186/// Performs a left shift that returns `None` on shifts larger than
187/// or equal to the type width.
188pub trait CheckedShl: Sized + Shl<u32, Output = Self> {
189 /// Checked shift left. Computes `self << rhs`, returning `None`
190 /// if `rhs` is larger than or equal to the number of bits in `self`.
191 ///
192 /// ```
193 /// use num_traits::CheckedShl;
194 ///
195 /// let x: u16 = 0x0001;
196 ///
197 /// assert_eq!(CheckedShl::checked_shl(&x, 0), Some(0x0001));
198 /// assert_eq!(CheckedShl::checked_shl(&x, 1), Some(0x0002));
199 /// assert_eq!(CheckedShl::checked_shl(&x, 15), Some(0x8000));
200 /// assert_eq!(CheckedShl::checked_shl(&x, 16), None);
201 /// ```
202 fn checked_shl(&self, rhs: u32) -> Option<Self>;
203}
204
205macro_rules! checked_shift_impl {
206 ($trait_name:ident, $method:ident, $t:ty) => {
207 impl $trait_name for $t {
208 #[inline]
209 fn $method(&self, rhs: u32) -> Option<$t> {
210 <$t>::$method(*self, rhs)
211 }
212 }
213 };
214}
215
216checked_shift_impl!(CheckedShl, checked_shl, u8);
217checked_shift_impl!(CheckedShl, checked_shl, u16);
218checked_shift_impl!(CheckedShl, checked_shl, u32);
219checked_shift_impl!(CheckedShl, checked_shl, u64);
220checked_shift_impl!(CheckedShl, checked_shl, usize);
221checked_shift_impl!(CheckedShl, checked_shl, u128);
222
223checked_shift_impl!(CheckedShl, checked_shl, i8);
224checked_shift_impl!(CheckedShl, checked_shl, i16);
225checked_shift_impl!(CheckedShl, checked_shl, i32);
226checked_shift_impl!(CheckedShl, checked_shl, i64);
227checked_shift_impl!(CheckedShl, checked_shl, isize);
228checked_shift_impl!(CheckedShl, checked_shl, i128);
229
230/// Performs a right shift that returns `None` on shifts larger than
231/// or equal to the type width.
232pub trait CheckedShr: Sized + Shr<u32, Output = Self> {
233 /// Checked shift right. Computes `self >> rhs`, returning `None`
234 /// if `rhs` is larger than or equal to the number of bits in `self`.
235 ///
236 /// ```
237 /// use num_traits::CheckedShr;
238 ///
239 /// let x: u16 = 0x8000;
240 ///
241 /// assert_eq!(CheckedShr::checked_shr(&x, 0), Some(0x8000));
242 /// assert_eq!(CheckedShr::checked_shr(&x, 1), Some(0x4000));
243 /// assert_eq!(CheckedShr::checked_shr(&x, 15), Some(0x0001));
244 /// assert_eq!(CheckedShr::checked_shr(&x, 16), None);
245 /// ```
246 fn checked_shr(&self, rhs: u32) -> Option<Self>;
247}
248
249checked_shift_impl!(CheckedShr, checked_shr, u8);
250checked_shift_impl!(CheckedShr, checked_shr, u16);
251checked_shift_impl!(CheckedShr, checked_shr, u32);
252checked_shift_impl!(CheckedShr, checked_shr, u64);
253checked_shift_impl!(CheckedShr, checked_shr, usize);
254checked_shift_impl!(CheckedShr, checked_shr, u128);
255
256checked_shift_impl!(CheckedShr, checked_shr, i8);
257checked_shift_impl!(CheckedShr, checked_shr, i16);
258checked_shift_impl!(CheckedShr, checked_shr, i32);
259checked_shift_impl!(CheckedShr, checked_shr, i64);
260checked_shift_impl!(CheckedShr, checked_shr, isize);
261checked_shift_impl!(CheckedShr, checked_shr, i128);
262