bit_int/bit_uint/ops.rs
1// SPDX-FileCopyrightText: 2024 Shun Sakai
2//
3// SPDX-License-Identifier: Apache-2.0 OR MIT
4
5//! Constants for [`BitUint`].
6
7use super::BitUint;
8
9macro_rules! impl_ops {
10 ($T:ty) => {
11 impl<const N: u32> BitUint<$T, N> {
12 /// Calculates the addition of `self` and `rhs`.
13 ///
14 /// Returns [`None`] if overflow occurred.
15 ///
16 /// # Examples
17 ///
18 /// ```
19 /// # use bit_int::BitUint;
20 /// #
21 #[doc = concat!("let n = BitUint::<", stringify!($T), ", 6>::new(42).unwrap();")]
22 ///
23 /// assert_eq!(n.checked_add(21).map(BitUint::get), Some(63));
24 /// assert_eq!(n.checked_add(22), None);
25 /// ```
26 #[must_use]
27 #[inline]
28 pub const fn checked_add(self, rhs: $T) -> Option<Self> {
29 if let Some(result) = self.get().checked_add(rhs) {
30 Self::new(result)
31 } else {
32 None
33 }
34 }
35
36 /// Calculates the subtraction of `rhs` from `self`.
37 ///
38 /// Returns [`None`] if overflow occurred.
39 ///
40 /// # Examples
41 ///
42 /// ```
43 /// # use bit_int::BitUint;
44 /// #
45 #[doc = concat!("let n = BitUint::<", stringify!($T), ", 6>::new(42).unwrap();")]
46 ///
47 /// assert_eq!(n.checked_sub(42).map(BitUint::get), Some(0));
48 /// assert_eq!(n.checked_sub(43), None);
49 /// ```
50 #[must_use]
51 #[inline]
52 pub const fn checked_sub(self, rhs: $T) -> Option<Self> {
53 if let Some(result) = self.get().checked_sub(rhs) {
54 Self::new(result)
55 } else {
56 None
57 }
58 }
59
60 /// Calculates the multiplication of `self` and `rhs`.
61 ///
62 /// Returns [`None`] if overflow occurred.
63 ///
64 /// # Examples
65 ///
66 /// ```
67 /// # use bit_int::BitUint;
68 /// #
69 #[doc = concat!("let n = BitUint::<", stringify!($T), ", 6>::new(21).unwrap();")]
70 ///
71 /// assert_eq!(n.checked_mul(2).map(BitUint::get), Some(42));
72 /// assert_eq!(n.checked_mul(4), None);
73 /// ```
74 #[must_use]
75 #[inline]
76 pub const fn checked_mul(self, rhs: $T) -> Option<Self> {
77 if let Some(result) = self.get().checked_mul(rhs) {
78 Self::new(result)
79 } else {
80 None
81 }
82 }
83
84 /// Calculates the divisor when `self` is divided by `rhs`.
85 ///
86 /// Returns [`None`] if `rhs` is `0`.
87 ///
88 /// # Examples
89 ///
90 /// ```
91 /// # use bit_int::BitUint;
92 /// #
93 #[doc = concat!("let n = BitUint::<", stringify!($T), ", 6>::new(42).unwrap();")]
94 ///
95 /// assert_eq!(n.checked_div(2).map(BitUint::get), Some(21));
96 /// assert_eq!(n.checked_div(0), None);
97 /// ```
98 #[must_use]
99 #[inline]
100 pub const fn checked_div(self, rhs: $T) -> Option<Self> {
101 if let Some(result) = self.get().checked_div(rhs) {
102 Self::new(result)
103 } else {
104 None
105 }
106 }
107
108 /// Calculates the quotient of Euclidean division of `self` by `rhs`.
109 ///
110 /// Returns [`None`] if `rhs` is `0`.
111 ///
112 /// # Examples
113 ///
114 /// ```
115 /// # use bit_int::BitUint;
116 /// #
117 #[doc = concat!("let n = BitUint::<", stringify!($T), ", 6>::new(42).unwrap();")]
118 ///
119 /// assert_eq!(n.checked_div_euclid(2).map(BitUint::get), Some(21));
120 /// assert_eq!(n.checked_div_euclid(0), None);
121 /// ```
122 #[must_use]
123 #[inline]
124 pub const fn checked_div_euclid(self, rhs: $T) -> Option<Self> {
125 if let Some(result) = self.get().checked_div_euclid(rhs) {
126 Self::new(result)
127 } else {
128 None
129 }
130 }
131
132 /// Calculates the remainder when `self` is divided by `rhs`.
133 ///
134 /// Returns [`None`] if `rhs` is `0`.
135 ///
136 /// # Examples
137 ///
138 /// ```
139 /// # use bit_int::BitUint;
140 /// #
141 #[doc = concat!("let n = BitUint::<", stringify!($T), ", 3>::new(5).unwrap();")]
142 ///
143 /// assert_eq!(n.checked_rem(2).map(BitUint::get), Some(1));
144 /// assert_eq!(n.checked_rem(0), None);
145 /// ```
146 #[must_use]
147 #[inline]
148 pub const fn checked_rem(self, rhs: $T) -> Option<Self> {
149 if let Some(result) = self.get().checked_rem(rhs) {
150 Self::new(result)
151 } else {
152 None
153 }
154 }
155
156 /// Calculates the multiplication of `self` and `rhs`.
157 ///
158 /// Returns [`None`] if `rhs` is `0`.
159 ///
160 /// # Examples
161 ///
162 /// ```
163 /// # use bit_int::BitUint;
164 /// #
165 #[doc = concat!("let n = BitUint::<", stringify!($T), ", 3>::new(5).unwrap();")]
166 ///
167 /// assert_eq!(n.checked_rem_euclid(2).map(BitUint::get), Some(1));
168 /// assert_eq!(n.checked_rem_euclid(0), None);
169 /// ```
170 #[must_use]
171 #[inline]
172 pub const fn checked_rem_euclid(self, rhs: $T) -> Option<Self> {
173 if let Some(result) = self.get().checked_rem_euclid(rhs) {
174 Self::new(result)
175 } else {
176 None
177 }
178 }
179
180 /// Returns the logarithm of the number with respect to an arbitrary base,
181 /// rounded down.
182 ///
183 /// Returns [`None`] if the number is zero, or if the base is not at least
184 /// 2.
185 ///
186 /// # Examples
187 ///
188 /// ```
189 /// # use bit_int::BitUint;
190 /// #
191 #[doc = concat!("let n = BitUint::<", stringify!($T), ", 3>::new(5).unwrap();")]
192 ///
193 /// assert_eq!(n.checked_ilog(5), Some(1));
194 /// ```
195 #[must_use]
196 #[inline]
197 pub const fn checked_ilog(self, base: $T) -> Option<u32> {
198 self.get().checked_ilog(base)
199 }
200
201 /// Returns the base 2 logarithm of the number, rounded down.
202 ///
203 /// Returns [`None`] if the number is zero.
204 ///
205 /// # Examples
206 ///
207 /// ```
208 /// # use bit_int::BitUint;
209 /// #
210 #[doc = concat!("let n = BitUint::<", stringify!($T), ", 2>::new(2).unwrap();")]
211 ///
212 /// assert_eq!(n.checked_ilog2(), Some(1));
213 /// ```
214 #[must_use]
215 #[inline]
216 pub const fn checked_ilog2(self) -> Option<u32> {
217 self.get().checked_ilog2()
218 }
219
220 /// Returns the base 10 logarithm of the number, rounded down.
221 ///
222 /// Returns [`None`] if the number is zero.
223 ///
224 /// # Examples
225 ///
226 /// ```
227 /// # use bit_int::BitUint;
228 /// #
229 #[doc = concat!("let n = BitUint::<", stringify!($T), ", 4>::new(10).unwrap();")]
230 ///
231 /// assert_eq!(n.checked_ilog10(), Some(1));
232 /// ```
233 #[must_use]
234 #[inline]
235 pub const fn checked_ilog10(self) -> Option<u32> {
236 self.get().checked_ilog10()
237 }
238
239 /// Negates `self`.
240 ///
241 /// Returns [`None`] unless `self` is `0`.
242 ///
243 /// <div class="warning">
244 ///
245 /// Note that negating any positive integer will overflow.
246 ///
247 /// </div>
248 ///
249 /// # Examples
250 ///
251 /// ```
252 /// # use bit_int::BitUint;
253 /// #
254 /// assert_eq!(
255 #[doc = concat!(" BitUint::<", stringify!($T), ", 1>::MIN.checked_neg().map(BitUint::get),")]
256 /// Some(0)
257 /// );
258 #[doc = concat!("assert_eq!(BitUint::<", stringify!($T), ", 1>::MAX.checked_neg(), None);")]
259 /// ```
260 #[must_use]
261 #[inline]
262 pub const fn checked_neg(self) -> Option<Self> {
263 if let Some(result) = self.get().checked_neg() {
264 Self::new(result)
265 } else {
266 None
267 }
268 }
269
270 /// Shifts `self` left by `rhs` bits.
271 ///
272 /// Returns [`None`] if `rhs` is larger than or equal to the number of bits
273 /// in `self`.
274 ///
275 /// # Examples
276 ///
277 /// ```
278 /// # use bit_int::BitUint;
279 /// #
280 #[doc = concat!("let n = BitUint::<", stringify!($T), ", 5>::new(0x01).unwrap();")]
281 #[doc = concat!("let m = BitUint::<", stringify!($T), ", 5>::new(0x10).unwrap();")]
282 ///
283 /// assert_eq!(n.checked_shl(4).map(BitUint::get), Some(0x10));
284 /// assert_eq!(m.checked_shl(129), None);
285 #[doc = concat!("assert_eq!(m.checked_shl(", stringify!($T), "::BITS - 1).map(BitUint::get), Some(0x00));")]
286 /// ```
287 #[must_use]
288 #[inline]
289 pub const fn checked_shl(self, rhs: u32) -> Option<Self> {
290 if let Some(result) = self.get().checked_shl(rhs) {
291 Self::new(result)
292 } else {
293 None
294 }
295 }
296
297 /// Shifts `self` right by `rhs` bits.
298 ///
299 /// Returns [`None`] if `rhs` is larger than or equal to the number of bits
300 /// in `self`.
301 ///
302 /// # Examples
303 ///
304 /// ```
305 /// # use bit_int::BitUint;
306 /// #
307 #[doc = concat!("let n = BitUint::<", stringify!($T), ", 5>::new(0x10).unwrap();")]
308 ///
309 /// assert_eq!(n.checked_shr(4).map(BitUint::get), Some(0x01));
310 /// assert_eq!(n.checked_shr(129), None);
311 /// ```
312 #[must_use]
313 #[inline]
314 pub const fn checked_shr(self, rhs: u32) -> Option<Self> {
315 if let Some(result) = self.get().checked_shr(rhs) {
316 Self::new(result)
317 } else {
318 None
319 }
320 }
321
322 /// Raises `self` to the power of `exp`, using exponentiation by squaring.
323 ///
324 /// Returns [`None`] if overflow occurred.
325 ///
326 /// # Examples
327 ///
328 /// ```
329 /// # use bit_int::BitUint;
330 /// #
331 #[doc = concat!("let n = BitUint::<", stringify!($T), ", 6>::new(2).unwrap();")]
332 ///
333 /// assert_eq!(n.checked_pow(5).map(BitUint::get), Some(32));
334 #[doc = concat!("assert_eq!(BitUint::<", stringify!($T), ", 6>::MAX.checked_pow(2), None);")]
335 /// ```
336 #[must_use]
337 #[inline]
338 pub const fn checked_pow(self, exp: u32) -> Option<Self> {
339 if let Some(result) = self.get().checked_pow(exp) {
340 Self::new(result)
341 } else {
342 None
343 }
344 }
345 }
346 };
347}
348impl_ops!(u8);
349impl_ops!(u16);
350impl_ops!(u32);
351impl_ops!(u64);
352impl_ops!(u128);
353impl_ops!(usize);
354
355#[cfg(test)]
356mod tests {
357 use super::super::BitU8;
358
359 #[test]
360 fn checked_add() {
361 let n = BitU8::<6>::new(42).unwrap();
362
363 assert_eq!(n.checked_add(21).map(BitU8::get), Some(63));
364 assert!(n.checked_add(22).is_none());
365 }
366
367 #[test]
368 const fn checked_add_is_const_fn() {
369 const _: Option<BitU8<6>> = BitU8::<6>::MAX.checked_add(1);
370 }
371
372 #[test]
373 fn checked_sub() {
374 let n = BitU8::<6>::new(42).unwrap();
375
376 assert_eq!(n.checked_sub(42).map(BitU8::get), Some(0));
377 assert!(n.checked_sub(43).is_none());
378 }
379
380 #[test]
381 const fn checked_sub_is_const_fn() {
382 const _: Option<BitU8<6>> = BitU8::<6>::MIN.checked_sub(1);
383 }
384
385 #[test]
386 fn checked_mul() {
387 let n = BitU8::<6>::new(21).unwrap();
388
389 assert_eq!(n.checked_mul(2).map(BitU8::get), Some(42));
390 assert!(n.checked_mul(4).is_none());
391 }
392
393 #[test]
394 const fn checked_mul_is_const_fn() {
395 const _: Option<BitU8<6>> = BitU8::<6>::MAX.checked_mul(2);
396 }
397
398 #[test]
399 fn checked_div() {
400 let n = BitU8::<6>::new(42).unwrap();
401
402 assert_eq!(n.checked_div(2).map(BitU8::get), Some(21));
403 assert!(n.checked_div(0).is_none());
404 }
405
406 #[test]
407 const fn checked_div_is_const_fn() {
408 const _: Option<BitU8<6>> = BitU8::<6>::MAX.checked_div(0);
409 }
410
411 #[test]
412 fn checked_div_euclid() {
413 let n = BitU8::<6>::new(42).unwrap();
414
415 assert_eq!(n.checked_div_euclid(2).map(BitU8::get), Some(21));
416 assert!(n.checked_div_euclid(0).is_none());
417 }
418
419 #[test]
420 const fn checked_div_euclid_is_const_fn() {
421 const _: Option<BitU8<6>> = BitU8::<6>::MAX.checked_div_euclid(0);
422 }
423
424 #[test]
425 fn checked_rem() {
426 let n = BitU8::<3>::new(5).unwrap();
427
428 assert_eq!(n.checked_rem(2).map(BitU8::get), Some(1));
429 assert!(n.checked_rem(0).is_none());
430 }
431
432 #[test]
433 const fn checked_rem_is_const_fn() {
434 const _: Option<BitU8<3>> = BitU8::<3>::MAX.checked_rem(0);
435 }
436
437 #[test]
438 fn checked_rem_euclid() {
439 let n = BitU8::<3>::new(5).unwrap();
440
441 assert_eq!(n.checked_rem_euclid(2).map(BitU8::get), Some(1));
442 assert!(n.checked_rem_euclid(0).is_none());
443 }
444
445 #[test]
446 const fn checked_rem_euclid_is_const_fn() {
447 const _: Option<BitU8<3>> = BitU8::<3>::MAX.checked_rem_euclid(0);
448 }
449
450 #[test]
451 fn checked_ilog() {
452 let n = BitU8::<3>::new(5).unwrap();
453
454 assert_eq!(n.checked_ilog(5), Some(1));
455 assert!(n.checked_ilog(1).is_none());
456 assert!(BitU8::<3>::MIN.checked_ilog(5).is_none());
457 }
458
459 #[test]
460 const fn checked_ilog_is_const_fn() {
461 const _: Option<u32> = BitU8::<3>::MIN.checked_ilog(5);
462 }
463
464 #[test]
465 fn checked_ilog2() {
466 let n = BitU8::<2>::new(2).unwrap();
467
468 assert_eq!(n.checked_ilog2(), Some(1));
469 assert!(BitU8::<2>::MIN.checked_ilog2().is_none());
470 }
471
472 #[test]
473 const fn checked_ilog2_is_const_fn() {
474 const _: Option<u32> = BitU8::<2>::MIN.checked_ilog2();
475 }
476
477 #[test]
478 fn checked_ilog10() {
479 let n = BitU8::<4>::new(10).unwrap();
480
481 assert_eq!(n.checked_ilog10(), Some(1));
482 assert!(BitU8::<4>::MIN.checked_ilog10().is_none());
483 }
484
485 #[test]
486 const fn checked_ilog10_is_const_fn() {
487 const _: Option<u32> = BitU8::<4>::MIN.checked_ilog10();
488 }
489
490 #[test]
491 fn checked_neg() {
492 assert_eq!(BitU8::<1>::MIN.checked_neg().map(BitU8::get), Some(0));
493 assert!(BitU8::<1>::MAX.checked_neg().is_none());
494 }
495
496 #[test]
497 const fn checked_neg_is_const_fn() {
498 const _: Option<BitU8<1>> = BitU8::<1>::MAX.checked_neg();
499 }
500
501 #[test]
502 fn checked_shl() {
503 let n = BitU8::<5>::new(0x01).unwrap();
504 let m = BitU8::<5>::new(0x10).unwrap();
505
506 assert_eq!(n.checked_shl(4).map(BitU8::get), Some(0x10));
507 assert!(m.checked_shl(129).is_none());
508 assert_eq!(m.checked_shl(u8::BITS - 1).map(BitU8::get), Some(0x00));
509 }
510
511 #[test]
512 const fn checked_shl_is_const_fn() {
513 const _: Option<BitU8<5>> = BitU8::<5>::MIN.checked_shl(129);
514 }
515
516 #[test]
517 fn checked_shr() {
518 let n = BitU8::<5>::new(0x10).unwrap();
519
520 assert_eq!(n.checked_shr(4).map(BitU8::get), Some(0x01));
521 assert!(n.checked_shr(129).is_none());
522 }
523
524 #[test]
525 const fn checked_shr_is_const_fn() {
526 const _: Option<BitU8<5>> = BitU8::<5>::MIN.checked_shr(129);
527 }
528
529 #[test]
530 fn checked_pow() {
531 let n = BitU8::<6>::new(2).unwrap();
532
533 assert_eq!(n.checked_pow(5).map(BitU8::get), Some(32));
534 assert!(BitU8::<6>::MAX.checked_pow(2).is_none());
535 }
536
537 #[test]
538 const fn checked_pow_is_const_fn() {
539 const _: Option<BitU8<6>> = BitU8::<6>::MAX.checked_pow(2);
540 }
541}