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))]
9pub struct Duration {
11 pub(crate) ticks: u64,
12}
13
14impl Duration {
15 pub const MIN: Duration = Duration { ticks: u64::MIN };
17 pub const MAX: Duration = Duration { ticks: u64::MAX };
19
20 pub const fn as_ticks(&self) -> u64 {
22 self.ticks
23 }
24
25 pub const fn as_secs(&self) -> u64 {
27 self.ticks / TICK_HZ
28 }
29
30 pub const fn as_millis(&self) -> u64 {
32 self.ticks * (1000 / GCD_1K) / (TICK_HZ / GCD_1K)
33 }
34
35 pub const fn as_micros(&self) -> u64 {
37 self.ticks * (1_000_000 / GCD_1M) / (TICK_HZ / GCD_1M)
38 }
39
40 pub const fn from_ticks(ticks: u64) -> Duration {
42 Duration { ticks }
43 }
44
45 pub const fn from_secs(secs: u64) -> Duration {
47 Duration { ticks: secs * TICK_HZ }
48 }
49
50 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 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 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 pub const fn from_secs_floor(secs: u64) -> Duration {
75 Duration { ticks: secs * TICK_HZ }
76 }
77
78 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 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 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 pub fn checked_add(self, rhs: Duration) -> Option<Duration> {
109 self.ticks.checked_add(rhs.ticks).map(|ticks| Duration { ticks })
110 }
111
112 pub fn checked_sub(self, rhs: Duration) -> Option<Duration> {
114 self.ticks.checked_sub(rhs.ticks).map(|ticks| Duration { ticks })
115 }
116
117 pub fn checked_mul(self, rhs: u32) -> Option<Duration> {
119 self.ticks.checked_mul(rhs as _).map(|ticks| Duration { ticks })
120 }
121
122 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 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 fn from(value: Duration) -> Self {
217 core::time::Duration::from_micros(value.as_micros())
218 }
219}