Skip to main content

bacnet_time/
instant.rs

1//! [`Instant`]: a point on the caller's monotonic timeline.
2
3use core::ops::{Add, AddAssign, Sub, SubAssign};
4
5use crate::{Duration, NANOS_PER_MICRO, NANOS_PER_MILLI, NANOS_PER_SEC};
6
7/// A point on the caller's monotonic timeline, in nanoseconds since an
8/// epoch the caller chooses.
9///
10/// `+` and `-` with a [`Duration`] saturate at [`Instant::MAX`] and at the
11/// epoch, and the time from a later instant to an earlier one, `earlier -
12/// later`, is [`Duration::ZERO`].
13#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
14pub struct Instant(u64);
15
16impl Instant {
17    /// The epoch.
18    pub const ZERO: Self = Self(0);
19    /// The latest representable instant, about 584 years after the epoch.
20    pub const MAX: Self = Self(u64::MAX);
21
22    /// The instant `nanos` nanoseconds after the epoch.
23    #[must_use]
24    pub const fn from_nanos(nanos: u64) -> Self {
25        Self(nanos)
26    }
27
28    /// The instant `micros` microseconds after the epoch, saturating at
29    /// [`Instant::MAX`].
30    #[must_use]
31    pub const fn from_micros(micros: u64) -> Self {
32        Self(micros.saturating_mul(NANOS_PER_MICRO))
33    }
34
35    /// The instant `millis` milliseconds after the epoch, saturating at
36    /// [`Instant::MAX`].
37    #[must_use]
38    pub const fn from_millis(millis: u64) -> Self {
39        Self(millis.saturating_mul(NANOS_PER_MILLI))
40    }
41
42    /// The instant `secs` seconds after the epoch, saturating at
43    /// [`Instant::MAX`].
44    #[must_use]
45    pub const fn from_secs(secs: u64) -> Self {
46        Self(secs.saturating_mul(NANOS_PER_SEC))
47    }
48
49    /// Nanoseconds since the epoch.
50    #[must_use]
51    pub const fn as_nanos(self) -> u64 {
52        self.0
53    }
54
55    /// Whole microseconds since the epoch, rounded toward zero.
56    #[must_use]
57    pub const fn as_micros(self) -> u64 {
58        self.since_epoch().as_micros()
59    }
60
61    /// Whole milliseconds since the epoch, rounded toward zero.
62    #[must_use]
63    pub const fn as_millis(self) -> u64 {
64        self.since_epoch().as_millis()
65    }
66
67    /// Whole seconds since the epoch, rounded toward zero.
68    #[must_use]
69    pub const fn as_secs(self) -> u64 {
70        self.since_epoch().as_secs()
71    }
72
73    /// `self + duration`, or `None` past [`Instant::MAX`].
74    #[must_use]
75    pub const fn checked_add(self, duration: Duration) -> Option<Self> {
76        match self.0.checked_add(duration.as_nanos()) {
77            Some(nanos) => Some(Self(nanos)),
78            None => None,
79        }
80    }
81
82    /// `self + duration`, clamped at [`Instant::MAX`].
83    #[must_use]
84    pub const fn saturating_add(self, duration: Duration) -> Self {
85        Self(self.0.saturating_add(duration.as_nanos()))
86    }
87
88    /// `self - duration`, or `None` before the epoch.
89    #[must_use]
90    pub const fn checked_sub(self, duration: Duration) -> Option<Self> {
91        match self.0.checked_sub(duration.as_nanos()) {
92            Some(nanos) => Some(Self(nanos)),
93            None => None,
94        }
95    }
96
97    /// `self - duration`, clamped at the epoch.
98    #[must_use]
99    pub const fn saturating_sub(self, duration: Duration) -> Self {
100        Self(self.0.saturating_sub(duration.as_nanos()))
101    }
102
103    /// The time from `earlier` to `self`, or `None` when `earlier` is later.
104    #[must_use]
105    pub const fn checked_duration_since(self, earlier: Self) -> Option<Duration> {
106        match self.0.checked_sub(earlier.0) {
107            Some(nanos) => Some(Duration::from_nanos(nanos)),
108            None => None,
109        }
110    }
111
112    /// The time from `earlier` to `self`, or zero when `earlier` is later.
113    #[must_use]
114    pub const fn saturating_duration_since(self, earlier: Self) -> Duration {
115        Duration::from_nanos(self.0.saturating_sub(earlier.0))
116    }
117
118    /// The earlier of `self` and `other`: [`Ord::min`] for a `const`
119    /// context.
120    #[must_use]
121    pub const fn min(self, other: Self) -> Self {
122        if self.0 <= other.0 {
123            self
124        } else {
125            other
126        }
127    }
128
129    /// The later of `self` and `other`: [`Ord::max`] for a `const` context.
130    #[must_use]
131    pub const fn max(self, other: Self) -> Self {
132        if self.0 >= other.0 {
133            self
134        } else {
135            other
136        }
137    }
138
139    /// The time from the epoch to `self`.
140    const fn since_epoch(self) -> Duration {
141        Duration::from_nanos(self.0)
142    }
143}
144
145impl Add<Duration> for Instant {
146    type Output = Self;
147
148    /// Saturating, as [`Instant::saturating_add`].
149    fn add(self, rhs: Duration) -> Self {
150        self.saturating_add(rhs)
151    }
152}
153
154impl AddAssign<Duration> for Instant {
155    /// Saturating, as [`Instant::saturating_add`].
156    fn add_assign(&mut self, rhs: Duration) {
157        *self = self.saturating_add(rhs);
158    }
159}
160
161impl Sub<Duration> for Instant {
162    type Output = Self;
163
164    /// Saturating, as [`Instant::saturating_sub`].
165    fn sub(self, rhs: Duration) -> Self {
166        self.saturating_sub(rhs)
167    }
168}
169
170impl SubAssign<Duration> for Instant {
171    /// Saturating, as [`Instant::saturating_sub`].
172    fn sub_assign(&mut self, rhs: Duration) {
173        *self = self.saturating_sub(rhs);
174    }
175}
176
177impl Sub for Instant {
178    type Output = Duration;
179
180    /// Saturating, as [`Instant::saturating_duration_since`].
181    fn sub(self, rhs: Self) -> Duration {
182        self.saturating_duration_since(rhs)
183    }
184}