1macro_rules! checked_ilog {
2 ($method: ident $(, $base: ident: $ty: ty)?) => {
3 #[doc = doc::checked::$method!(I)]
4 #[must_use = doc::must_use_op!()]
5 #[inline]
6 pub const fn $method(self $(, $base: $ty)?) -> Option<ExpType> {
7 if self.is_negative() {
8 None
9 } else {
10 self.bits.$method($($base)?)
11 }
12 }
13 }
14}
15
16use crate::doc;
17use crate::helpers::tuple_to_option;
18use crate::ExpType;
19
20macro_rules! checked {
21 ($BUint: ident, $BInt: ident, $Digit: ident) => {
22 #[doc = doc::checked::impl_desc!()]
23 impl<const N: usize> $BInt<N> {
24 #[doc = doc::checked::checked_add!(I)]
25 #[must_use = doc::must_use_op!()]
26 #[inline]
27 pub const fn checked_add(self, rhs: Self) -> Option<Self> {
28 tuple_to_option(self.overflowing_add(rhs))
29 }
30
31 #[doc = doc::checked::checked_add_unsigned!(I)]
32 #[must_use = doc::must_use_op!()]
33 #[inline]
34 pub const fn checked_add_unsigned(self, rhs: $BUint<N>) -> Option<Self> {
35 tuple_to_option(self.overflowing_add_unsigned(rhs))
36 }
37
38 #[doc = doc::checked::checked_sub!(I)]
39 #[must_use = doc::must_use_op!()]
40 #[inline]
41 pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
42 tuple_to_option(self.overflowing_sub(rhs))
43 }
44
45 #[doc = doc::checked::checked_sub_unsigned!(I)]
46 #[must_use = doc::must_use_op!()]
47 #[inline]
48 pub const fn checked_sub_unsigned(self, rhs: $BUint<N>) -> Option<Self> {
49 tuple_to_option(self.overflowing_sub_unsigned(rhs))
50 }
51
52 #[doc = doc::checked::checked_mul!(I)]
53 #[must_use = doc::must_use_op!()]
54 #[inline]
55 pub const fn checked_mul(self, rhs: Self) -> Option<Self> {
56 tuple_to_option(self.overflowing_mul(rhs))
57 }
58
59 #[doc = doc::checked::checked_div!(I)]
60 #[must_use = doc::must_use_op!()]
61 #[inline]
62 pub const fn checked_div(self, rhs: Self) -> Option<Self> {
63 if rhs.is_zero() {
64 None
65 } else {
66 tuple_to_option(self.overflowing_div(rhs))
67 }
68 }
69
70 #[doc = doc::checked::checked_div_euclid!(I)]
71 #[must_use = doc::must_use_op!()]
72 #[inline]
73 pub const fn checked_div_euclid(self, rhs: Self) -> Option<Self> {
74 if rhs.is_zero() {
75 None
76 } else {
77 tuple_to_option(self.overflowing_div_euclid(rhs))
78 }
79 }
80
81 #[doc = doc::checked::checked_rem!(I)]
82 #[must_use = doc::must_use_op!()]
83 #[inline]
84 pub const fn checked_rem(self, rhs: Self) -> Option<Self> {
85 if rhs.is_zero() {
86 None
87 } else {
88 tuple_to_option(self.overflowing_rem(rhs))
89 }
90 }
91
92 #[doc = doc::checked::checked_rem_euclid!(I)]
93 #[must_use = doc::must_use_op!()]
94 #[inline]
95 pub const fn checked_rem_euclid(self, rhs: Self) -> Option<Self> {
96 if rhs.is_zero() {
97 None
98 } else {
99 tuple_to_option(self.overflowing_rem_euclid(rhs))
100 }
101 }
102
103 #[doc = doc::checked::checked_neg!(I)]
104 #[must_use = doc::must_use_op!()]
105 #[inline]
106 pub const fn checked_neg(self) -> Option<Self> {
107 tuple_to_option(self.overflowing_neg())
108 }
109
110 #[doc = doc::checked::checked_shl!(I)]
111 #[must_use = doc::must_use_op!()]
112 #[inline]
113 pub const fn checked_shl(self, rhs: ExpType) -> Option<Self> {
114 tuple_to_option(self.overflowing_shl(rhs))
115 }
116
117 #[doc = doc::checked::checked_shr!(I)]
118 #[must_use = doc::must_use_op!()]
119 #[inline]
120 pub const fn checked_shr(self, rhs: ExpType) -> Option<Self> {
121 tuple_to_option(self.overflowing_shr(rhs))
122 }
123
124 #[doc = doc::checked::checked_abs!(I)]
125 #[must_use = doc::must_use_op!()]
126 #[inline]
127 pub const fn checked_abs(self) -> Option<Self> {
128 tuple_to_option(self.overflowing_abs())
129 }
130
131 #[doc = doc::checked::checked_pow!(I)]
132 #[must_use = doc::must_use_op!()]
133 #[inline]
134 pub const fn checked_pow(self, pow: ExpType) -> Option<Self> {
135 match self.unsigned_abs().checked_pow(pow) {
136 Some(u) => {
137 let out = Self::from_bits(u);
138 let neg = self.is_negative();
139 if !neg || pow & 1 == 0 {
140 if out.is_negative() {
141 None
142 } else {
143 Some(out)
144 }
145 } else {
146 let out = out.wrapping_neg();
147 if !out.is_negative() {
148 None
149 } else {
150 Some(out)
151 }
152 }
153 }
154 None => None,
155 }
156 }
157
158 #[doc = doc::checked::checked_next_multiple_of!(I)]
159 #[must_use = doc::must_use_op!()]
160 #[inline]
161 pub const fn checked_next_multiple_of(self, rhs: Self) -> Option<Self> {
162 if rhs.is_zero() {
163 return None;
164 }
165 let rem = self.wrapping_rem_euclid(rhs);
166 if rem.is_zero() {
167 return Some(self);
168 }
169 if rem.is_negative() == rhs.is_negative() {
170 self.checked_add(rhs.wrapping_sub(rem))
171 } else {
172 self.checked_sub(rem)
173 }
174 }
175
176 #[doc = doc::checked::checked_ilog!(I)]
177 #[must_use = doc::must_use_op!()]
178 #[inline]
179 pub const fn checked_ilog(self, base: Self) -> Option<ExpType> {
180 if base.is_negative() || self.is_negative() {
181 None
182 } else {
183 self.to_bits().checked_ilog(base.to_bits())
184 }
185 }
186
187 checked_ilog!(checked_ilog2);
188 checked_ilog!(checked_ilog10);
189 }
190 };
191}
192
193
194#[cfg(test)]
195crate::test::all_digit_tests! {
196 use crate::test::test_bignum;
197 use crate::test::types::{itest, utest};
198
199 test_bignum! {
200 function: <itest>::checked_add(a: itest, b: itest),
201 cases: [
202 (itest::MAX, -1i8)
203 ]
204 }
205 test_bignum! {
206 function: <itest>::checked_add_unsigned(a: itest, b: utest)
207 }
208 test_bignum! {
209 function: <itest>::checked_sub(a: itest, b: itest),
210 cases: [
211 (itest::MIN, -1i8)
212 ]
213 }
214 test_bignum! {
215 function: <itest>::checked_sub_unsigned(a: itest, b: utest)
216 }
217 test_bignum! {
218 function: <itest>::checked_mul(a: itest, b: itest),
219 cases: [
220 (itest::MIN, -1i8)
221 ]
222 }
223 test_bignum! {
224 function: <itest>::checked_div(a: itest, b: itest),
225 cases: [
226 (0i8, 0i8),
227 (23098403i32 as itest, 0i8),
228 (itest::MIN, -1i8),
229 (8388600i32 as itest, 68201i32 as itest) ]
231 }
232 test_bignum! {
233 function: <itest>::checked_div_euclid(a: itest, b: itest),
234 cases: [
235 (itest::MIN, -1i8),
236 (0i8, 0i8)
237 ]
238 }
239 test_bignum! {
240 function: <itest>::checked_rem(a: itest, b: itest),
241 cases: [
242 (itest::MIN, -1i8),
243 (0i8, 0i8)
244 ]
245 }
246 test_bignum! {
247 function: <itest>::checked_rem_euclid(a: itest, b: itest),
248 skip: b <= u8::MAX as itest,
249 cases: [
250 (itest::MIN, -1i8),
251 (0i8, 0i8)
252 ]
253 }
254 test_bignum! {
255 function: <itest>::checked_neg(a: itest),
256 cases: [
257 (itest::MIN)
258 ]
259 }
260 test_bignum! {
261 function: <itest>::checked_shl(a: itest, b: u16)
262 }
263 test_bignum! {
264 function: <itest>::checked_shr(a: itest, b: u16)
265 }
266 test_bignum! {
267 function: <itest>::checked_pow(a: itest, b: u16),
268 cases: [
269 (2i8, itest::BITS as u16 - 1),
270 (-2i8, itest::BITS as u16 - 1)
271 ]
272 }
273 test_bignum! {
274 function: <itest>::checked_ilog2(a: itest)
275 }
276 test_bignum! {
277 function: <itest>::checked_ilog10(a: itest)
278 }
279 test_bignum! {
280 function: <itest>::checked_ilog(a: itest, b: itest)
281 }
282}
283
284crate::macro_impl!(checked);