bit_int/bit_int/
ops.rs

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