Skip to main content

deep_time/dt/
ops.rs

1use crate::Dt;
2use core::cmp::Ordering;
3use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
4
5impl Add<Dt> for Dt {
6    type Output = Self;
7
8    #[inline]
9    fn add(self, rhs: Dt) -> Self {
10        self.add(rhs)
11    }
12}
13
14impl AddAssign<Dt> for Dt {
15    #[inline]
16    fn add_assign(&mut self, rhs: Dt) {
17        *self = self.add(rhs);
18    }
19}
20
21impl Sub<Dt> for Dt {
22    type Output = Self;
23
24    #[inline]
25    fn sub(self, rhs: Dt) -> Self {
26        self.sub(rhs)
27    }
28}
29
30impl SubAssign<Dt> for Dt {
31    #[inline]
32    fn sub_assign(&mut self, rhs: Dt) {
33        *self = self.sub(rhs);
34    }
35}
36
37impl Neg for Dt {
38    type Output = Self;
39
40    /// Negates this `Dt` (returns the additive inverse).
41    #[inline]
42    fn neg(self) -> Self {
43        self.neg()
44    }
45}
46
47impl Mul<i64> for Dt {
48    type Output = Self;
49
50    /// Multiplies this `Dt` by an integer scalar.
51    #[inline]
52    fn mul(self, rhs: i64) -> Self {
53        self.mul(rhs)
54    }
55}
56
57impl MulAssign<i64> for Dt {
58    /// Multiplies this `Dt` by an integer scalar in place.
59    #[inline]
60    fn mul_assign(&mut self, rhs: i64) {
61        *self = self.mul(rhs);
62    }
63}
64
65impl Div<i64> for Dt {
66    type Output = Self;
67
68    /// Divides this `Dt` by an integer scalar.
69    #[inline]
70    fn div(self, rhs: i64) -> Self {
71        self.div(rhs)
72    }
73}
74
75impl DivAssign<i64> for Dt {
76    /// Divides this `Dt` by an integer scalar in place.
77    #[inline]
78    fn div_assign(&mut self, rhs: i64) {
79        *self = self.div(rhs);
80    }
81}
82
83impl Dt {
84    /// Compares the time values represented by two `Dt`s.
85    ///
86    /// - This comparison is based on the raw `(sec, attos)` representation
87    /// after normalizing (without mutating self or other) any un-carried
88    /// attoseconds.
89    /// - Does **not** perform scale conversion.
90    pub const fn cmp(&self, other: &Self) -> Ordering {
91        let a = self.carry_attos();
92        let b = other.carry_attos();
93
94        if a.sec < b.sec {
95            Ordering::Less
96        } else if a.sec > b.sec {
97            Ordering::Greater
98        } else if a.attos < b.attos {
99            Ordering::Less
100        } else if a.attos > b.attos {
101            Ordering::Greater
102        } else {
103            Ordering::Equal
104        }
105    }
106
107    /// Returns the smaller of two `Dt`s according to the total physical-time order
108    /// defined by [`Self::cmp`].
109    ///
110    /// This is a `const fn` and can be used in const contexts.
111    #[inline]
112    pub const fn min(self, other: Self) -> Self {
113        match self.cmp(&other) {
114            Ordering::Greater => other,
115            _ => self,
116        }
117    }
118
119    /// Returns the larger of two `Dt`s according to the total physical-time order
120    /// defined by [`Self::cmp`].
121    ///
122    /// See [`Self::min`] for more details.
123    #[inline]
124    pub const fn max(self, other: Self) -> Self {
125        match self.cmp(&other) {
126            Ordering::Less => other,
127            _ => self,
128        }
129    }
130
131    /// True if both sides have matching `sec` and `attos` fields.
132    ///
133    /// This is a `const fn` so it can be used in const contexts.
134    #[inline]
135    pub const fn eq(&self, other: &Self) -> bool {
136        matches!(Dt::cmp(self, other), Ordering::Equal)
137    }
138
139    /// Returns `true` if this `Dt` is less than the other.
140    ///
141    /// This is a `const fn` so it can be used in const contexts.
142    pub const fn lt(&self, other: &Self) -> bool {
143        matches!(self.cmp(other), Ordering::Less)
144    }
145
146    /// Returns `true` if this `Dt` is greater than the other.
147    ///
148    /// This is a `const fn` so it can be used in const contexts.
149    pub const fn gt(&self, other: &Self) -> bool {
150        matches!(self.cmp(other), Ordering::Greater)
151    }
152
153    /// Returns `true` if this `Dt` is less than or equal to the other.
154    ///
155    /// This is a `const fn` so it can be used in const contexts.
156    pub const fn le(&self, other: &Self) -> bool {
157        !matches!(self.cmp(other), Ordering::Greater)
158    }
159
160    /// Returns `true` if this `Dt` is greater than or equal to the other.
161    ///
162    /// This is a `const fn` so it can be used in const contexts.
163    pub const fn ge(&self, other: &Self) -> bool {
164        !matches!(self.cmp(other), Ordering::Less)
165    }
166}
167
168impl PartialEq for Dt {
169    #[inline]
170    fn eq(&self, other: &Self) -> bool {
171        Dt::eq(self, other)
172    }
173}
174
175impl Eq for Dt {}
176
177impl PartialOrd for Dt {
178    #[inline]
179    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
180        Some(Dt::cmp(self, other))
181    }
182}
183
184impl Ord for Dt {
185    #[inline]
186    fn cmp(&self, other: &Self) -> Ordering {
187        Dt::cmp(self, other)
188    }
189}
190
191impl core::hash::Hash for Dt {
192    /// Hashes the canonical TAI representation so that two `Dt`s that are
193    /// physically equal (after conversion) produce the same hash, regardless of
194    /// the original [`Scale`].
195    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
196        self.sec.hash(state);
197        self.attos.hash(state);
198    }
199}