Skip to main content

embassy_time/
instant.rs

1use core::fmt;
2use core::ops::{Add, AddAssign, Sub, SubAssign};
3
4use super::{Duration, GCD_1G, GCD_1K, GCD_1M, TICK_HZ};
5
6#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
7#[cfg_attr(feature = "defmt", derive(defmt::Format))]
8/// An Instant in time, based on the MCU's clock ticks since startup.
9pub struct Instant {
10    ticks: u64,
11}
12
13impl Instant {
14    /// The smallest (earliest) value that can be represented by the `Instant` type.
15    pub const MIN: Instant = Instant { ticks: u64::MIN };
16    /// The largest (latest) value that can be represented by the `Instant` type.
17    pub const MAX: Instant = Instant { ticks: u64::MAX };
18
19    /// Returns an Instant representing the current time.
20    #[inline]
21    pub fn now() -> Instant {
22        Instant {
23            ticks: embassy_time_driver::now(),
24        }
25    }
26
27    /// Create an Instant from a tick count since system boot.
28    pub const fn from_ticks(ticks: u64) -> Self {
29        Self { ticks }
30    }
31
32    /// Create an Instant from a nanosecond count since system boot.
33    pub const fn from_nanos(nanos: u64) -> Self {
34        Self {
35            ticks: nanos * (TICK_HZ / GCD_1G) / (1_000_000_000 / GCD_1G),
36        }
37    }
38
39    /// Create an Instant from a microsecond count since system boot.
40    pub const fn from_micros(micros: u64) -> Self {
41        Self {
42            ticks: micros * (TICK_HZ / GCD_1M) / (1_000_000 / GCD_1M),
43        }
44    }
45
46    /// Create an Instant from a millisecond count since system boot.
47    pub const fn from_millis(millis: u64) -> Self {
48        Self {
49            ticks: millis * (TICK_HZ / GCD_1K) / (1000 / GCD_1K),
50        }
51    }
52
53    /// Create an Instant from a second count since system boot.
54    pub const fn from_secs(seconds: u64) -> Self {
55        Self {
56            ticks: seconds * TICK_HZ,
57        }
58    }
59
60    /// Try to create an Instant from a nanosecond count since system boot.
61    /// Fails if the number of nanoseconds is too large.
62    pub const fn try_from_nanos(nanos: u64) -> Option<Self> {
63        let Some(value) = nanos.checked_mul(TICK_HZ / GCD_1G) else {
64            return None;
65        };
66        Some(Self {
67            ticks: value / (1_000_000_000 / GCD_1G),
68        })
69    }
70
71    /// Try to create an Instant from a microsecond count since system boot.
72    /// Fails if the number of microseconds is too large.
73    pub const fn try_from_micros(micros: u64) -> Option<Self> {
74        let Some(value) = micros.checked_mul(TICK_HZ / GCD_1M) else {
75            return None;
76        };
77        Some(Self {
78            ticks: value / (1_000_000 / GCD_1M),
79        })
80    }
81
82    /// Try to create an Instant from a millisecond count since system boot.
83    /// Fails if the number of milliseconds is too large.
84    pub const fn try_from_millis(millis: u64) -> Option<Self> {
85        let Some(value) = millis.checked_mul(TICK_HZ / GCD_1K) else {
86            return None;
87        };
88        Some(Self {
89            ticks: value / (1000 / GCD_1K),
90        })
91    }
92
93    /// Try to create an Instant from a second count since system boot.
94    /// Fails if the number of seconds is too large.
95    pub const fn try_from_secs(seconds: u64) -> Option<Self> {
96        let Some(ticks) = seconds.checked_mul(TICK_HZ) else {
97            return None;
98        };
99        Some(Self { ticks })
100    }
101
102    /// Tick count since system boot.
103    pub const fn as_ticks(&self) -> u64 {
104        self.ticks
105    }
106
107    /// Seconds since system boot.
108    pub const fn as_secs(&self) -> u64 {
109        self.ticks / TICK_HZ
110    }
111
112    /// Milliseconds since system boot.
113    pub const fn as_millis(&self) -> u64 {
114        self.ticks * (1000 / GCD_1K) / (TICK_HZ / GCD_1K)
115    }
116
117    /// Microseconds since system boot.
118    pub const fn as_micros(&self) -> u64 {
119        self.ticks * (1_000_000 / GCD_1M) / (TICK_HZ / GCD_1M)
120    }
121
122    /// Nanoseconds since system boot.
123    pub const fn as_nanos(&self) -> u64 {
124        self.ticks * (1_000_000_000 / GCD_1G) / (TICK_HZ / GCD_1G)
125    }
126
127    /// Duration between this Instant and another Instant
128    /// Panics on over/underflow.
129    pub fn duration_since(&self, earlier: Instant) -> Duration {
130        Duration {
131            ticks: unwrap!(self.ticks.checked_sub(earlier.ticks)),
132        }
133    }
134
135    /// Duration between this Instant and another Instant
136    pub fn checked_duration_since(&self, earlier: Instant) -> Option<Duration> {
137        if self.ticks < earlier.ticks {
138            None
139        } else {
140            Some(Duration {
141                ticks: self.ticks - earlier.ticks,
142            })
143        }
144    }
145
146    /// Returns the duration since the "earlier" Instant.
147    /// If the "earlier" instant is in the future, the duration is set to zero.
148    pub fn saturating_duration_since(&self, earlier: Instant) -> Duration {
149        Duration {
150            ticks: if self.ticks < earlier.ticks {
151                0
152            } else {
153                self.ticks - earlier.ticks
154            },
155        }
156    }
157
158    /// Duration elapsed since this Instant.
159    pub fn elapsed(&self) -> Duration {
160        Instant::now() - *self
161    }
162
163    /// Adds one Duration to self, returning a new `Instant` or None in the event of an overflow.
164    pub fn checked_add(&self, duration: Duration) -> Option<Instant> {
165        self.ticks.checked_add(duration.ticks).map(|ticks| Instant { ticks })
166    }
167
168    /// Subtracts one Duration to self, returning a new `Instant` or None in the event of an overflow.
169    pub fn checked_sub(&self, duration: Duration) -> Option<Instant> {
170        self.ticks.checked_sub(duration.ticks).map(|ticks| Instant { ticks })
171    }
172
173    /// Adds a Duration to self. In case of overflow, the maximum value is returned.
174    pub fn saturating_add(mut self, duration: Duration) -> Self {
175        self.ticks = self.ticks.saturating_add(duration.ticks);
176        self
177    }
178
179    /// Subtracts a Duration from self. In case of overflow, the minimum value is returned.
180    pub fn saturating_sub(mut self, duration: Duration) -> Self {
181        self.ticks = self.ticks.saturating_sub(duration.ticks);
182        self
183    }
184}
185
186impl Add<Duration> for Instant {
187    type Output = Instant;
188
189    fn add(self, other: Duration) -> Instant {
190        self.checked_add(other)
191            .expect("overflow when adding duration to instant")
192    }
193}
194
195impl AddAssign<Duration> for Instant {
196    fn add_assign(&mut self, other: Duration) {
197        *self = *self + other;
198    }
199}
200
201impl Sub<Duration> for Instant {
202    type Output = Instant;
203
204    fn sub(self, other: Duration) -> Instant {
205        self.checked_sub(other)
206            .expect("overflow when subtracting duration from instant")
207    }
208}
209
210impl SubAssign<Duration> for Instant {
211    fn sub_assign(&mut self, other: Duration) {
212        *self = *self - other;
213    }
214}
215
216impl Sub<Instant> for Instant {
217    type Output = Duration;
218
219    fn sub(self, other: Instant) -> Duration {
220        self.duration_since(other)
221    }
222}
223
224impl<'a> fmt::Display for Instant {
225    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
226        write!(f, "{} ticks", self.ticks)
227    }
228}