embassy_time/
duration.rs

1use core::fmt;
2use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
3
4use super::{GCD_1K, GCD_1M, TICK_HZ};
5use crate::GCD_1G;
6
7#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
8#[cfg_attr(feature = "defmt", derive(defmt::Format))]
9/// Represents the difference between two [Instant](struct.Instant.html)s
10pub struct Duration {
11    pub(crate) ticks: u64,
12}
13
14impl Duration {
15    /// The smallest value that can be represented by the `Duration` type.
16    pub const MIN: Duration = Duration { ticks: u64::MIN };
17    /// The largest value that can be represented by the `Duration` type.
18    pub const MAX: Duration = Duration { ticks: u64::MAX };
19
20    /// Tick count of the `Duration`.
21    pub const fn as_ticks(&self) -> u64 {
22        self.ticks
23    }
24
25    /// Convert the `Duration` to seconds, rounding down.
26    pub const fn as_secs(&self) -> u64 {
27        self.ticks / TICK_HZ
28    }
29
30    /// Convert the `Duration` to milliseconds, rounding down.
31    pub const fn as_millis(&self) -> u64 {
32        self.ticks * (1000 / GCD_1K) / (TICK_HZ / GCD_1K)
33    }
34
35    /// Convert the `Duration` to microseconds, rounding down.
36    pub const fn as_micros(&self) -> u64 {
37        self.ticks * (1_000_000 / GCD_1M) / (TICK_HZ / GCD_1M)
38    }
39
40    /// Creates a duration from the specified number of clock ticks
41    pub const fn from_ticks(ticks: u64) -> Duration {
42        Duration { ticks }
43    }
44
45    /// Creates a duration from the specified number of seconds, rounding up.
46    pub const fn from_secs(secs: u64) -> Duration {
47        Duration { ticks: secs * TICK_HZ }
48    }
49
50    /// Creates a duration from the specified number of milliseconds, rounding up.
51    pub const fn from_millis(millis: u64) -> Duration {
52        Duration {
53            ticks: div_ceil(millis * (TICK_HZ / GCD_1K), 1000 / GCD_1K),
54        }
55    }
56
57    /// Creates a duration from the specified number of microseconds, rounding up.
58    /// NOTE: Delays this small may be inaccurate.
59    pub const fn from_micros(micros: u64) -> Duration {
60        Duration {
61            ticks: div_ceil(micros * (TICK_HZ / GCD_1M), 1_000_000 / GCD_1M),
62        }
63    }
64
65    /// Creates a duration from the specified number of nanoseconds, rounding up.
66    /// NOTE: Delays this small may be inaccurate.
67    pub const fn from_nanos(micros: u64) -> Duration {
68        Duration {
69            ticks: div_ceil(micros * (TICK_HZ / GCD_1G), 1_000_000_000 / GCD_1G),
70        }
71    }
72
73    /// Creates a duration from the specified number of seconds, rounding down.
74    pub const fn from_secs_floor(secs: u64) -> Duration {
75        Duration { ticks: secs * TICK_HZ }
76    }
77
78    /// Creates a duration from the specified number of milliseconds, rounding down.
79    pub const fn from_millis_floor(millis: u64) -> Duration {
80        Duration {
81            ticks: millis * (TICK_HZ / GCD_1K) / (1000 / GCD_1K),
82        }
83    }
84
85    /// Creates a duration from the specified number of microseconds, rounding down.
86    /// NOTE: Delays this small may be inaccurate.
87    pub const fn from_micros_floor(micros: u64) -> Duration {
88        Duration {
89            ticks: micros * (TICK_HZ / GCD_1M) / (1_000_000 / GCD_1M),
90        }
91    }
92
93    /// Creates a duration corresponding to the specified Hz.
94    /// NOTE: Giving this function a hz >= the TICK_HZ of your platform will clamp the Duration to 1
95    /// tick. Doing so will not deadlock, but will certainly not produce the desired output.
96    pub const fn from_hz(hz: u64) -> Duration {
97        let ticks = {
98            if hz >= TICK_HZ {
99                1
100            } else {
101                (TICK_HZ + hz / 2) / hz
102            }
103        };
104        Duration { ticks }
105    }
106
107    /// Adds one Duration to another, returning a new Duration or None in the event of an overflow.
108    pub fn checked_add(self, rhs: Duration) -> Option<Duration> {
109        self.ticks.checked_add(rhs.ticks).map(|ticks| Duration { ticks })
110    }
111
112    /// Subtracts one Duration to another, returning a new Duration or None in the event of an overflow.
113    pub fn checked_sub(self, rhs: Duration) -> Option<Duration> {
114        self.ticks.checked_sub(rhs.ticks).map(|ticks| Duration { ticks })
115    }
116
117    /// Multiplies one Duration by a scalar u32, returning a new Duration or None in the event of an overflow.
118    pub fn checked_mul(self, rhs: u32) -> Option<Duration> {
119        self.ticks.checked_mul(rhs as _).map(|ticks| Duration { ticks })
120    }
121
122    /// Divides one Duration a scalar u32, returning a new Duration or None in the event of an overflow.
123    pub fn checked_div(self, rhs: u32) -> Option<Duration> {
124        self.ticks.checked_div(rhs as _).map(|ticks| Duration { ticks })
125    }
126}
127
128impl Add for Duration {
129    type Output = Duration;
130
131    fn add(self, rhs: Duration) -> Duration {
132        self.checked_add(rhs).expect("overflow when adding durations")
133    }
134}
135
136impl AddAssign for Duration {
137    fn add_assign(&mut self, rhs: Duration) {
138        *self = *self + rhs;
139    }
140}
141
142impl Sub for Duration {
143    type Output = Duration;
144
145    fn sub(self, rhs: Duration) -> Duration {
146        self.checked_sub(rhs).expect("overflow when subtracting durations")
147    }
148}
149
150impl SubAssign for Duration {
151    fn sub_assign(&mut self, rhs: Duration) {
152        *self = *self - rhs;
153    }
154}
155
156impl Mul<u32> for Duration {
157    type Output = Duration;
158
159    fn mul(self, rhs: u32) -> Duration {
160        self.checked_mul(rhs)
161            .expect("overflow when multiplying duration by scalar")
162    }
163}
164
165impl Mul<Duration> for u32 {
166    type Output = Duration;
167
168    fn mul(self, rhs: Duration) -> Duration {
169        rhs * self
170    }
171}
172
173impl MulAssign<u32> for Duration {
174    fn mul_assign(&mut self, rhs: u32) {
175        *self = *self * rhs;
176    }
177}
178
179impl Div<u32> for Duration {
180    type Output = Duration;
181
182    fn div(self, rhs: u32) -> Duration {
183        self.checked_div(rhs)
184            .expect("divide by zero error when dividing duration by scalar")
185    }
186}
187
188impl DivAssign<u32> for Duration {
189    fn div_assign(&mut self, rhs: u32) {
190        *self = *self / rhs;
191    }
192}
193
194impl<'a> fmt::Display for Duration {
195    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
196        write!(f, "{} ticks", self.ticks)
197    }
198}
199
200#[inline]
201const fn div_ceil(num: u64, den: u64) -> u64 {
202    (num + den - 1) / den
203}
204
205impl TryFrom<core::time::Duration> for Duration {
206    type Error = <u64 as TryFrom<u128>>::Error;
207
208    /// Converts using [`Duration::from_micros`]. Fails if value can not be represented as u64.
209    fn try_from(value: core::time::Duration) -> Result<Self, Self::Error> {
210        Ok(Self::from_micros(value.as_micros().try_into()?))
211    }
212}
213
214impl From<Duration> for core::time::Duration {
215    /// Converts using [`Duration::as_micros`].
216    fn from(value: Duration) -> Self {
217        core::time::Duration::from_micros(value.as_micros())
218    }
219}