embassy_time/
instant.rs

1use core::fmt;
2use core::ops::{Add, AddAssign, Sub, SubAssign};
3
4use super::{Duration, 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 microsecond count since system boot.
33    pub const fn from_micros(micros: u64) -> Self {
34        Self {
35            ticks: micros * (TICK_HZ / GCD_1M) / (1_000_000 / GCD_1M),
36        }
37    }
38
39    /// Create an Instant from a millisecond count since system boot.
40    pub const fn from_millis(millis: u64) -> Self {
41        Self {
42            ticks: millis * (TICK_HZ / GCD_1K) / (1000 / GCD_1K),
43        }
44    }
45
46    /// Create an Instant from a second count since system boot.
47    pub const fn from_secs(seconds: u64) -> Self {
48        Self {
49            ticks: seconds * TICK_HZ,
50        }
51    }
52
53    /// Try to create an Instant from a microsecond count since system boot.
54    /// Fails if the number of microseconds is too large.
55    pub const fn try_from_micros(micros: u64) -> Option<Self> {
56        let Some(value) = micros.checked_mul(TICK_HZ / GCD_1M) else {
57            return None;
58        };
59        Some(Self {
60            ticks: value / (1_000_000 / GCD_1M),
61        })
62    }
63
64    /// Try to create an Instant from a millisecond count since system boot.
65    /// Fails if the number of milliseconds is too large.
66    pub const fn try_from_millis(millis: u64) -> Option<Self> {
67        let Some(value) = millis.checked_mul(TICK_HZ / GCD_1K) else {
68            return None;
69        };
70        Some(Self {
71            ticks: value / (1000 / GCD_1K),
72        })
73    }
74
75    /// Try to create an Instant from a second count since system boot.
76    /// Fails if the number of seconds is too large.
77    pub const fn try_from_secs(seconds: u64) -> Option<Self> {
78        let Some(ticks) = seconds.checked_mul(TICK_HZ) else {
79            return None;
80        };
81        Some(Self { ticks })
82    }
83
84    /// Tick count since system boot.
85    pub const fn as_ticks(&self) -> u64 {
86        self.ticks
87    }
88
89    /// Seconds since system boot.
90    pub const fn as_secs(&self) -> u64 {
91        self.ticks / TICK_HZ
92    }
93
94    /// Milliseconds since system boot.
95    pub const fn as_millis(&self) -> u64 {
96        self.ticks * (1000 / GCD_1K) / (TICK_HZ / GCD_1K)
97    }
98
99    /// Microseconds since system boot.
100    pub const fn as_micros(&self) -> u64 {
101        self.ticks * (1_000_000 / GCD_1M) / (TICK_HZ / GCD_1M)
102    }
103
104    /// Duration between this Instant and another Instant
105    /// Panics on over/underflow.
106    pub fn duration_since(&self, earlier: Instant) -> Duration {
107        Duration {
108            ticks: unwrap!(self.ticks.checked_sub(earlier.ticks)),
109        }
110    }
111
112    /// Duration between this Instant and another Instant
113    pub fn checked_duration_since(&self, earlier: Instant) -> Option<Duration> {
114        if self.ticks < earlier.ticks {
115            None
116        } else {
117            Some(Duration {
118                ticks: self.ticks - earlier.ticks,
119            })
120        }
121    }
122
123    /// Returns the duration since the "earlier" Instant.
124    /// If the "earlier" instant is in the future, the duration is set to zero.
125    pub fn saturating_duration_since(&self, earlier: Instant) -> Duration {
126        Duration {
127            ticks: if self.ticks < earlier.ticks {
128                0
129            } else {
130                self.ticks - earlier.ticks
131            },
132        }
133    }
134
135    /// Duration elapsed since this Instant.
136    pub fn elapsed(&self) -> Duration {
137        Instant::now() - *self
138    }
139
140    /// Adds one Duration to self, returning a new `Instant` or None in the event of an overflow.
141    pub fn checked_add(&self, duration: Duration) -> Option<Instant> {
142        self.ticks.checked_add(duration.ticks).map(|ticks| Instant { ticks })
143    }
144
145    /// Subtracts one Duration to self, returning a new `Instant` or None in the event of an overflow.
146    pub fn checked_sub(&self, duration: Duration) -> Option<Instant> {
147        self.ticks.checked_sub(duration.ticks).map(|ticks| Instant { ticks })
148    }
149
150    /// Adds a Duration to self. In case of overflow, the maximum value is returned.
151    pub fn saturating_add(mut self, duration: Duration) -> Self {
152        self.ticks = self.ticks.saturating_add(duration.ticks);
153        self
154    }
155
156    /// Subtracts a Duration from self. In case of overflow, the minimum value is returned.
157    pub fn saturating_sub(mut self, duration: Duration) -> Self {
158        self.ticks = self.ticks.saturating_sub(duration.ticks);
159        self
160    }
161}
162
163impl Add<Duration> for Instant {
164    type Output = Instant;
165
166    fn add(self, other: Duration) -> Instant {
167        self.checked_add(other)
168            .expect("overflow when adding duration to instant")
169    }
170}
171
172impl AddAssign<Duration> for Instant {
173    fn add_assign(&mut self, other: Duration) {
174        *self = *self + other;
175    }
176}
177
178impl Sub<Duration> for Instant {
179    type Output = Instant;
180
181    fn sub(self, other: Duration) -> Instant {
182        self.checked_sub(other)
183            .expect("overflow when subtracting duration from instant")
184    }
185}
186
187impl SubAssign<Duration> for Instant {
188    fn sub_assign(&mut self, other: Duration) {
189        *self = *self - other;
190    }
191}
192
193impl Sub<Instant> for Instant {
194    type Output = Duration;
195
196    fn sub(self, other: Instant) -> Duration {
197        self.duration_since(other)
198    }
199}
200
201impl<'a> fmt::Display for Instant {
202    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
203        write!(f, "{} ticks", self.ticks)
204    }
205}