Skip to main content

frclib_core/time/
instant.rs

1use std::{
2    ops::{Add, AddAssign, Sub, SubAssign},
3    time::Duration,
4};
5
6type StdInstant = std::time::Instant;
7
8#[ctor::ctor]
9static START_INSTANT: StdInstant = StdInstant::now();
10
11/// A new-type wrapper around [`std::time::Duration`]
12/// that can be used as an alternative to [`std::time::Instant`].
13///
14/// Unlike [`std::time::Instant`], this type is not guaranteed to be monotonic.
15/// Can be safely converted to and from [`std::time::Instant`] but is not recommended unless you know what you're doing.
16#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
17pub struct Instant(Duration);
18
19impl Instant {
20    /// Returns an instant corresponding to "uptime" of the program.
21    #[must_use]
22    pub fn now() -> Self {
23        Self(super::uptime())
24    }
25
26    /// Returns the amount of time elapsed from another instant to this one,
27    /// or zero duration if that instant is later than this one.
28    #[must_use]
29    pub fn duration_since(&self, earlier: Self) -> Duration {
30        self.checked_duration_since(earlier).unwrap_or_default()
31    }
32
33    /// Returns the amount of time elapsed since this instant.
34    #[must_use]
35    pub fn elapsed(&self) -> Duration {
36        Self::now().duration_since(*self)
37    }
38
39    /// Returns `Some(t)` where `t` is the time `self + duration` if `t` can be represented as
40    /// `Instant` (which means it's inside the bounds of the underlying data structure), `None`
41    /// otherwise.
42    pub fn checked_add(&self, duration: Duration) -> Option<Self> {
43        self.0.checked_add(duration).map(Instant)
44    }
45
46    /// Returns `Some(t)` where `t` is the time `self - duration` if `t` can be represented as
47    /// `Instant` (which means it's inside the bounds of the underlying data structure), `None`
48    /// otherwise.
49    pub fn checked_sub(&self, duration: Duration) -> Option<Self> {
50        self.0.checked_sub(duration).map(Instant)
51    }
52
53    /// Returns the amount of time elapsed from another instant to this one, or None if that
54    /// instant is later than this one.
55    #[must_use]
56    pub fn checked_duration_since(&self, earlier: Self) -> Option<Duration> {
57        if earlier.0 > self.0 {
58            None
59        } else {
60            Some(self.0 - earlier.0)
61        }
62    }
63
64    /// Returns the amount of time elapsed from another instant to this one, or zero duration if
65    /// that instant is later than this one.
66    #[must_use]
67    pub fn saturating_duration_since(&self, earlier: Self) -> Duration {
68        self.checked_duration_since(earlier).unwrap_or_default()
69    }
70}
71
72impl Add<Duration> for Instant {
73    type Output = Self;
74
75    fn add(self, rhs: Duration) -> Self {
76        Self(self.0 + rhs)
77    }
78}
79
80impl AddAssign<Duration> for Instant {
81    fn add_assign(&mut self, rhs: Duration) {
82        self.0 += rhs;
83    }
84}
85
86impl Sub<Duration> for Instant {
87    type Output = Self;
88
89    fn sub(self, rhs: Duration) -> Self {
90        Self(self.0 - rhs)
91    }
92}
93
94impl Sub<Self> for Instant {
95    type Output = Duration;
96
97    fn sub(self, rhs: Self) -> Duration {
98        self.duration_since(rhs)
99    }
100}
101
102impl SubAssign<Duration> for Instant {
103    fn sub_assign(&mut self, rhs: Duration) {
104        self.0 -= rhs;
105    }
106}
107
108impl From<StdInstant> for Instant {
109    fn from(instant: StdInstant) -> Self {
110        Self(instant.duration_since(*START_INSTANT))
111    }
112}
113
114impl From<Instant> for StdInstant {
115    fn from(instant: Instant) -> Self {
116        *START_INSTANT + instant.0
117    }
118}