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}