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}