veecle_osal_api/time/
instant.rs

1//! This module implements an [`Instant`] with microsecond precision.
2
3use core::fmt;
4use core::num::NonZeroU64;
5use core::ops::{Add, Sub};
6
7use super::Duration;
8
9/// An Instant in time. Instants should be always increasing and are
10/// generally obtainable through the operating system time driver.
11#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
12pub struct Instant {
13    micros: NonZeroU64,
14}
15
16impl Instant {
17    /// The largest value that can be represented by the [`Instant`] type.
18    ///
19    /// # Examples
20    ///
21    /// ```
22    /// use veecle_osal_api::time::{Duration, Instant, TimeAbstraction};
23    /// use veecle_osal_std::time::Time;
24    ///
25    /// let now = Time::now();
26    ///
27    /// assert!(Instant::MAX > now);
28    /// ```
29    pub const MAX: Instant = Instant {
30        micros: NonZeroU64::MAX,
31    };
32
33    /// The smallest value that can be represented by the [`Instant`] type.
34    ///
35    /// # Examples
36    ///
37    /// ```
38    /// use veecle_osal_api::time::{Duration, Instant, TimeAbstraction};
39    /// use veecle_osal_std::time::Time;
40    ///
41    /// let now = Time::now();
42    ///
43    /// assert!(Instant::MIN <= now);
44    /// ```
45    pub const MIN: Instant = Instant {
46        micros: NonZeroU64::MIN,
47    };
48
49    /// Returns the [`Duration`] between this [`Instant`] and the give one if, and only if,
50    /// the given one is earlier than this, otherwise returns None.
51    ///
52    /// # Examples
53    ///
54    /// ```
55    /// use veecle_osal_api::time::{Duration, Instant, TimeAbstraction};
56    /// use veecle_osal_std::time::Time;
57    ///
58    /// let begin = Time::now();
59    ///
60    /// std::thread::sleep(core::time::Duration::from_millis(1));
61    ///
62    /// let end = Time::now();
63    /// assert!(end.duration_since(begin).unwrap() > Duration::ZERO);
64    /// assert_eq!(begin.duration_since(end), None);
65    /// ```
66    pub const fn duration_since(&self, earlier: Instant) -> Option<Duration> {
67        if self.micros.get() < earlier.micros.get() {
68            return None;
69        }
70
71        Some(Duration::from_micros(
72            self.micros.get() - earlier.micros.get(),
73        ))
74    }
75
76    /// Adds one [`Duration`] to self, returning a new [`Instant`] or None in the event of an overflow.
77    ///
78    /// # Examples
79    ///
80    /// ```
81    /// use veecle_osal_api::time::{Duration, Instant, TimeAbstraction};
82    /// use veecle_osal_std::time::Time;
83    ///
84    /// let now = Time::now();
85    ///
86    /// assert!(now.checked_add(Duration::from_secs(1)).unwrap() > now);
87    /// assert_eq!(now.checked_add(Duration::MAX), None);
88    /// ```
89    pub fn checked_add(self, rhs: Duration) -> Option<Instant> {
90        self.micros
91            .checked_add(rhs.as_micros())
92            .map(|micros| Instant { micros })
93    }
94
95    /// Subs one [`Duration`] from self, returning a new [`Instant`] or None in the event of an underflow.
96    ///
97    /// # Examples
98    ///
99    /// ```
100    /// use veecle_osal_api::time::{Duration, Instant, TimeAbstraction};
101    /// use veecle_osal_std::time::Time;
102    ///
103    /// let begin = Time::now();
104    ///
105    /// std::thread::sleep(core::time::Duration::from_millis(1));
106    ///
107    /// let end = Time::now();
108    ///
109    /// assert!(end.checked_sub(Duration::from_millis(1)).unwrap() < end);
110    /// assert_eq!(end.checked_sub(Duration::MAX), None);
111    /// ```
112    pub fn checked_sub(&self, rhs: Duration) -> Option<Instant> {
113        self.micros
114            .get()
115            .checked_sub(rhs.as_micros())
116            .and_then(NonZeroU64::new)
117            .map(|micros| Instant { micros })
118    }
119}
120
121impl Add<Duration> for Instant {
122    type Output = Self;
123
124    /// # Panics
125    ///
126    /// This function may panic if the resulting instant overflows. See [`Instant::checked_add`] for a version
127    /// without panic.
128    ///
129    /// # Examples
130    ///
131    /// ```
132    /// use veecle_osal_api::time::{Duration, Instant, TimeAbstraction};
133    /// use veecle_osal_std::time::Time;
134    ///
135    /// let now = Time::now();
136    ///
137    /// assert!(now + Duration::from_secs(1) > now);
138    /// ```
139    ///
140    /// ```should_panic
141    /// use veecle_osal_api::time::{Duration, Instant, TimeAbstraction};
142    /// use veecle_osal_std::time::Time;
143    ///
144    /// let now = Time::now();
145    ///
146    /// let _ = now + Duration::MAX;
147    /// ```
148    fn add(self, rhs: Duration) -> Self::Output {
149        let Some(result) = self.checked_add(rhs) else {
150            panic!("overflow when adding a duration to an instant");
151        };
152
153        result
154    }
155}
156
157impl Sub<Duration> for Instant {
158    type Output = Self;
159
160    /// # Panics
161    ///
162    /// This function may panic if the resulting instant underflows. See [`Instant::checked_sub`] for a
163    /// version without panic.
164    ///
165    /// # Examples
166    ///
167    /// ```
168    /// use veecle_osal_api::time::{Duration, Instant, TimeAbstraction};
169    /// use veecle_osal_std::time::Time;
170    ///
171    /// let begin = Time::now();
172    ///
173    /// std::thread::sleep(core::time::Duration::from_millis(1));
174    ///
175    /// let end = Time::now();
176    ///
177    /// assert!(end - Duration::from_millis(1) < end);
178    /// ```
179    ///
180    /// ```should_panic
181    /// use veecle_osal_api::time::{Duration, Instant, TimeAbstraction};
182    /// use veecle_osal_std::time::Time;
183    ///
184    /// let now = Time::now();
185    ///
186    /// let _ = now - Duration::MAX;
187    /// ```
188    fn sub(self, rhs: Duration) -> Self::Output {
189        let Some(result) = self.checked_sub(rhs) else {
190            panic!("underflow when subtracting a duration from an instant");
191        };
192
193        result
194    }
195}
196
197impl fmt::Debug for Instant {
198    /// # Examples
199    ///
200    /// ```
201    /// use veecle_osal_api::time::{Duration, Instant, TimeAbstraction};
202    ///
203    /// let instant = Instant::MIN + Duration::from_millis(1980);
204    /// assert_eq!(format!("{instant:?}"), "1s.980000us");
205    /// ```
206    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
207        self.duration_since(Self::MIN)
208            .expect("instant should be at least Instant::MIN")
209            .fmt(f)
210    }
211}