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!(n.checked_add(22).is_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!(n.checked_sub(43).is_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!(n.checked_mul(4).is_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!(n.checked_div(0).is_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!(n.checked_div_euclid(0).is_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!(n.checked_rem(0).is_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!(n.checked_rem_euclid(0).is_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            /// Note that negating any positive integer will overflow.
244            ///
245            /// # Examples
246            ///
247            /// ```
248            /// # use bit_int::BitUint;
249            /// #
250            /// assert_eq!(
251            #[doc = concat!("    BitUint::<", stringify!($T), ", 1>::MIN.checked_neg().map(BitUint::get),")]
252            ///     Some(0)
253            /// );
254            #[doc = concat!("assert!(BitUint::<", stringify!($T), ", 1>::MAX.checked_neg().is_none());")]
255            /// ```
256            #[must_use]
257            #[inline]
258            pub const fn checked_neg(self) -> Option<Self> {
259                if let Some(result) = self.get().checked_neg() {
260                    Self::new(result)
261                } else {
262                    None
263                }
264            }
265
266            /// Shifts `self` left by `rhs` bits.
267            ///
268            /// Returns [`None`] if `rhs` is larger than or equal to the number of bits
269            /// in `self`.
270            ///
271            /// # Examples
272            ///
273            /// ```
274            /// # use bit_int::BitUint;
275            /// #
276            #[doc = concat!("let n = BitUint::<", stringify!($T), ", 5>::new(0x01).unwrap();")]
277            #[doc = concat!("let m = BitUint::<", stringify!($T), ", 5>::new(0x10).unwrap();")]
278            ///
279            /// assert_eq!(n.checked_shl(4).map(BitUint::get), Some(0x10));
280            /// assert!(m.checked_shl(129).is_none());
281            #[doc = concat!("assert_eq!(m.checked_shl(", stringify!($T), "::BITS - 1).map(BitUint::get), Some(0x00));")]
282            /// ```
283            #[must_use]
284            #[inline]
285            pub const fn checked_shl(self, rhs: u32) -> Option<Self> {
286                if let Some(result) = self.get().checked_shl(rhs) {
287                    Self::new(result)
288                } else {
289                    None
290                }
291            }
292
293            /// Shifts `self` right by `rhs` bits.
294            ///
295            /// Returns [`None`] if `rhs` is larger than or equal to the number of bits
296            /// in `self`.
297            ///
298            /// # Examples
299            ///
300            /// ```
301            /// # use bit_int::BitUint;
302            /// #
303            #[doc = concat!("let n = BitUint::<", stringify!($T), ", 5>::new(0x10).unwrap();")]
304            ///
305            /// assert_eq!(n.checked_shr(4).map(BitUint::get), Some(0x01));
306            /// assert!(n.checked_shr(129).is_none());
307            /// ```
308            #[must_use]
309            #[inline]
310            pub const fn checked_shr(self, rhs: u32) -> Option<Self> {
311                if let Some(result) = self.get().checked_shr(rhs) {
312                    Self::new(result)
313                } else {
314                    None
315                }
316            }
317
318            /// Raises `self` to the power of `exp`, using exponentiation by squaring.
319            ///
320            /// Returns [`None`] if overflow occurred.
321            ///
322            /// # Examples
323            ///
324            /// ```
325            /// # use bit_int::BitUint;
326            /// #
327            #[doc = concat!("let n = BitUint::<", stringify!($T), ", 6>::new(2).unwrap();")]
328            ///
329            /// assert_eq!(n.checked_pow(5).map(BitUint::get), Some(32));
330            #[doc = concat!("assert!(BitUint::<", stringify!($T), ", 6>::MAX.checked_pow(2).is_none());")]
331            /// ```
332            #[must_use]
333            #[inline]
334            pub const fn checked_pow(self, exp: u32) -> Option<Self> {
335                if let Some(result) = self.get().checked_pow(exp) {
336                    Self::new(result)
337                } else {
338                    None
339                }
340            }
341        }
342    };
343}
344impl_ops!(u8);
345impl_ops!(u16);
346impl_ops!(u32);
347impl_ops!(u64);
348impl_ops!(u128);
349impl_ops!(usize);
350
351#[cfg(test)]
352mod tests {
353    use super::super::BitU8;
354
355    #[test]
356    fn checked_add() {
357        let n = BitU8::<6>::new(42).unwrap();
358
359        assert_eq!(n.checked_add(21).map(BitU8::get), Some(63));
360        assert!(n.checked_add(22).is_none());
361    }
362
363    #[test]
364    const fn checked_add_is_const_fn() {
365        const _: Option<BitU8<6>> = BitU8::<6>::MAX.checked_add(1);
366    }
367
368    #[test]
369    fn checked_sub() {
370        let n = BitU8::<6>::new(42).unwrap();
371
372        assert_eq!(n.checked_sub(42).map(BitU8::get), Some(0));
373        assert!(n.checked_sub(43).is_none());
374    }
375
376    #[test]
377    const fn checked_sub_is_const_fn() {
378        const _: Option<BitU8<6>> = BitU8::<6>::MIN.checked_sub(1);
379    }
380
381    #[test]
382    fn checked_mul() {
383        let n = BitU8::<6>::new(21).unwrap();
384
385        assert_eq!(n.checked_mul(2).map(BitU8::get), Some(42));
386        assert!(n.checked_mul(4).is_none());
387    }
388
389    #[test]
390    const fn checked_mul_is_const_fn() {
391        const _: Option<BitU8<6>> = BitU8::<6>::MAX.checked_mul(2);
392    }
393
394    #[test]
395    fn checked_div() {
396        let n = BitU8::<6>::new(42).unwrap();
397
398        assert_eq!(n.checked_div(2).map(BitU8::get), Some(21));
399        assert!(n.checked_div(0).is_none());
400    }
401
402    #[test]
403    const fn checked_div_is_const_fn() {
404        const _: Option<BitU8<6>> = BitU8::<6>::MAX.checked_div(0);
405    }
406
407    #[test]
408    fn checked_div_euclid() {
409        let n = BitU8::<6>::new(42).unwrap();
410
411        assert_eq!(n.checked_div_euclid(2).map(BitU8::get), Some(21));
412        assert!(n.checked_div_euclid(0).is_none());
413    }
414
415    #[test]
416    const fn checked_div_euclid_is_const_fn() {
417        const _: Option<BitU8<6>> = BitU8::<6>::MAX.checked_div_euclid(0);
418    }
419
420    #[test]
421    fn checked_rem() {
422        let n = BitU8::<3>::new(5).unwrap();
423
424        assert_eq!(n.checked_rem(2).map(BitU8::get), Some(1));
425        assert!(n.checked_rem(0).is_none());
426    }
427
428    #[test]
429    const fn checked_rem_is_const_fn() {
430        const _: Option<BitU8<3>> = BitU8::<3>::MAX.checked_rem(0);
431    }
432
433    #[test]
434    fn checked_rem_euclid() {
435        let n = BitU8::<3>::new(5).unwrap();
436
437        assert_eq!(n.checked_rem_euclid(2).map(BitU8::get), Some(1));
438        assert!(n.checked_rem_euclid(0).is_none());
439    }
440
441    #[test]
442    const fn checked_rem_euclid_is_const_fn() {
443        const _: Option<BitU8<3>> = BitU8::<3>::MAX.checked_rem_euclid(0);
444    }
445
446    #[test]
447    fn checked_ilog() {
448        let n = BitU8::<3>::new(5).unwrap();
449
450        assert_eq!(n.checked_ilog(5), Some(1));
451        assert!(n.checked_ilog(1).is_none());
452        assert!(BitU8::<3>::MIN.checked_ilog(5).is_none());
453    }
454
455    #[test]
456    const fn checked_ilog_is_const_fn() {
457        const _: Option<u32> = BitU8::<3>::MIN.checked_ilog(5);
458    }
459
460    #[test]
461    fn checked_ilog2() {
462        let n = BitU8::<2>::new(2).unwrap();
463
464        assert_eq!(n.checked_ilog2(), Some(1));
465        assert!(BitU8::<2>::MIN.checked_ilog2().is_none());
466    }
467
468    #[test]
469    const fn checked_ilog2_is_const_fn() {
470        const _: Option<u32> = BitU8::<2>::MIN.checked_ilog2();
471    }
472
473    #[test]
474    fn checked_ilog10() {
475        let n = BitU8::<4>::new(10).unwrap();
476
477        assert_eq!(n.checked_ilog10(), Some(1));
478        assert!(BitU8::<4>::MIN.checked_ilog10().is_none());
479    }
480
481    #[test]
482    const fn checked_ilog10_is_const_fn() {
483        const _: Option<u32> = BitU8::<4>::MIN.checked_ilog10();
484    }
485
486    #[test]
487    fn checked_neg() {
488        assert_eq!(BitU8::<1>::MIN.checked_neg().map(BitU8::get), Some(0));
489        assert!(BitU8::<1>::MAX.checked_neg().is_none());
490    }
491
492    #[test]
493    const fn checked_neg_is_const_fn() {
494        const _: Option<BitU8<1>> = BitU8::<1>::MAX.checked_neg();
495    }
496
497    #[test]
498    fn checked_shl() {
499        let n = BitU8::<5>::new(0x01).unwrap();
500        let m = BitU8::<5>::new(0x10).unwrap();
501
502        assert_eq!(n.checked_shl(4).map(BitU8::get), Some(0x10));
503        assert!(m.checked_shl(129).is_none());
504        assert_eq!(m.checked_shl(u8::BITS - 1).map(BitU8::get), Some(0x00));
505    }
506
507    #[test]
508    const fn checked_shl_is_const_fn() {
509        const _: Option<BitU8<5>> = BitU8::<5>::MIN.checked_shl(129);
510    }
511
512    #[test]
513    fn checked_shr() {
514        let n = BitU8::<5>::new(0x10).unwrap();
515
516        assert_eq!(n.checked_shr(4).map(BitU8::get), Some(0x01));
517        assert!(n.checked_shr(129).is_none());
518    }
519
520    #[test]
521    const fn checked_shr_is_const_fn() {
522        const _: Option<BitU8<5>> = BitU8::<5>::MIN.checked_shr(129);
523    }
524
525    #[test]
526    fn checked_pow() {
527        let n = BitU8::<6>::new(2).unwrap();
528
529        assert_eq!(n.checked_pow(5).map(BitU8::get), Some(32));
530        assert!(BitU8::<6>::MAX.checked_pow(2).is_none());
531    }
532
533    #[test]
534    const fn checked_pow_is_const_fn() {
535        const _: Option<BitU8<6>> = BitU8::<6>::MAX.checked_pow(2);
536    }
537}