Skip to main content

icydb_schema/decimal/
compare.rs

1use crate::decimal::Decimal;
2use std::{
3    cmp::Ordering,
4    hash::{Hash, Hasher},
5};
6
7impl Decimal {
8    pub(in crate::decimal) fn cmp_decimal(&self, other: &Self) -> Ordering {
9        match self.scale.cmp(&other.scale) {
10            Ordering::Equal => self.mantissa.cmp(&other.mantissa),
11            Ordering::Less => {
12                let aligned = Self::checked_pow10(other.scale - self.scale)
13                    .and_then(|factor| self.mantissa.checked_mul(factor));
14                // Scale deltas are at most 28, so the factor fits i128. If the
15                // product overflows, its sign puts it beyond every rhs mantissa.
16                aligned.map_or_else(|| self.mantissa.cmp(&0), |lhs| lhs.cmp(&other.mantissa))
17            }
18            Ordering::Greater => {
19                let aligned = Self::checked_pow10(self.scale - other.scale)
20                    .and_then(|factor| other.mantissa.checked_mul(factor));
21                // The same bound applies with rhs aligned; reverse its ordering.
22                aligned.map_or_else(|| 0.cmp(&other.mantissa), |rhs| self.mantissa.cmp(&rhs))
23            }
24        }
25    }
26}
27
28impl PartialEq for Decimal {
29    fn eq(&self, other: &Self) -> bool {
30        let (lhs_m, lhs_s) = self.normalized_parts();
31        let (rhs_m, rhs_s) = other.normalized_parts();
32        lhs_m == rhs_m && lhs_s == rhs_s
33    }
34}
35
36impl Eq for Decimal {}
37
38impl PartialOrd for Decimal {
39    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
40        Some(Ord::cmp(self, other))
41    }
42}
43
44impl Ord for Decimal {
45    fn cmp(&self, other: &Self) -> Ordering {
46        self.cmp_decimal(other)
47    }
48}
49
50impl Hash for Decimal {
51    fn hash<H: Hasher>(&self, state: &mut H) {
52        let (mantissa, scale) = self.normalized_parts();
53        mantissa.hash(state);
54        scale.hash(state);
55    }
56}