ruint/
cmp.rs

1use crate::Uint;
2use core::cmp::Ordering;
3
4impl<const BITS: usize, const LIMBS: usize> PartialOrd for Uint<BITS, LIMBS> {
5    #[inline]
6    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
7        Some(self.cmp(other))
8    }
9}
10
11impl<const BITS: usize, const LIMBS: usize> Ord for Uint<BITS, LIMBS> {
12    #[inline]
13    fn cmp(&self, rhs: &Self) -> Ordering {
14        crate::algorithms::cmp(self.as_limbs(), rhs.as_limbs())
15    }
16}
17
18/// Implements `PartialEq` and `PartialOrd` for `Uint` and primitive integers.
19///
20/// This intentionally does not use `<$t>::try_from` to avoid unnecessary
21/// checks for non-limb-sized primitive integers.
22macro_rules! impl_for_primitives {
23    ($($t:ty),* $(,)?) => {
24        $(
25            impl<const BITS: usize, const LIMBS: usize> PartialEq<$t> for Uint<BITS, LIMBS> {
26                #[inline]
27                #[allow(unused_comparisons)] // Both signed and unsigned integers use this.
28                #[allow(clippy::cast_possible_truncation)] // Unreachable.
29                fn eq(&self, &other: &$t) -> bool {
30                    (other >= 0) & (if <$t>::BITS <= u64::BITS {
31                        u64::try_from(self).ok() == Some(other as u64)
32                    } else {
33                        u128::try_from(self).ok() == Some(other as u128)
34                    })
35                }
36            }
37
38            impl<const BITS: usize, const LIMBS: usize> PartialOrd<$t> for Uint<BITS, LIMBS> {
39                #[inline]
40                #[allow(unused_comparisons)] // Both signed and unsigned integers use this.
41                #[allow(clippy::cast_possible_truncation)] // Unreachable.
42                fn partial_cmp(&self, &other: &$t) -> Option<Ordering> {
43                    if other < 0 {
44                        return Some(Ordering::Greater);
45                    }
46
47                    if <$t>::BITS <= u64::BITS {
48                        let Ok(self_t) = u64::try_from(self) else {
49                            return Some(Ordering::Greater);
50                        };
51                        self_t.partial_cmp(&(other as u64))
52                    } else {
53                        let Ok(self_t) = u128::try_from(self) else {
54                            return Some(Ordering::Greater);
55                        };
56                        self_t.partial_cmp(&(other as u128))
57                    }
58                }
59            }
60        )*
61    };
62}
63
64#[rustfmt::skip]
65impl_for_primitives!(
66    u8, u16, u32, u64, u128, usize,
67    i8, i16, i32, i64, i128, isize,
68);
69
70impl<const BITS: usize, const LIMBS: usize> Uint<BITS, LIMBS> {
71    /// Returns `true` if the value is zero.
72    #[inline]
73    #[must_use]
74    pub fn is_zero(&self) -> bool {
75        *self == Self::ZERO
76    }
77
78    /// Returns `true` if the value is zero.
79    ///
80    /// Note that this currently might perform worse than
81    /// [`is_zero`](Self::is_zero).
82    #[inline]
83    #[must_use]
84    pub const fn const_is_zero(&self) -> bool {
85        self.const_eq(&Self::ZERO)
86    }
87
88    /// Returns `true` if `self` equals `other`.
89    ///
90    /// Note that this currently might perform worse than the derived
91    /// `PartialEq` (`==` operator).
92    #[inline]
93    #[must_use]
94    pub const fn const_eq(&self, other: &Self) -> bool {
95        // TODO: Replace with `self == other` and deprecate once `PartialEq` is const.
96        let a = self.as_limbs();
97        let b = other.as_limbs();
98        let mut i = 0;
99        let mut r = true;
100        while i < LIMBS {
101            r &= a[i] == b[i];
102            i += 1;
103        }
104        r
105    }
106}
107
108#[cfg(test)]
109mod tests {
110    use crate::Uint;
111
112    #[test]
113    fn test_is_zero() {
114        assert!(Uint::<0, 0>::ZERO.is_zero());
115        assert!(Uint::<1, 1>::ZERO.is_zero());
116        assert!(Uint::<7, 1>::ZERO.is_zero());
117        assert!(Uint::<64, 1>::ZERO.is_zero());
118
119        assert!(!Uint::<1, 1>::from_limbs([1]).is_zero());
120        assert!(!Uint::<7, 1>::from_limbs([1]).is_zero());
121        assert!(!Uint::<64, 1>::from_limbs([1]).is_zero());
122    }
123}