fugit/
duration.rs

1use crate::helpers::{self, Helpers};
2use crate::Rate;
3use core::cmp::Ordering;
4use core::convert;
5use core::ops;
6
7/// Represents a duration of time.
8///
9/// The generic `T` can either be `u32` or `u64`, and the const generics represent the ratio of the
10/// ticks contained within the duration: `duration in seconds = NOM / DENOM * ticks`
11#[derive(Clone, Copy, Debug)]
12pub struct Duration<T, const NOM: u32, const DENOM: u32> {
13    pub(crate) ticks: T,
14}
15
16macro_rules! shorthand {
17    ($i:ty, $nom:literal, $denum:literal, $unit:ident, $to_unit:ident, $unital:ident, $unitstr:literal) => {
18        #[doc = concat!("Convert the Duration to an integer number of ", $unitstr, ".")]
19        #[inline]
20        pub const fn $to_unit(&self) -> $i {
21            (Helpers::<$nom, $denum, NOM, DENOM>::LD_TIMES_RN as $i * self.ticks)
22                / Helpers::<$nom, $denum, NOM, DENOM>::RD_TIMES_LN as $i
23        }
24
25        #[doc = concat!("Shorthand for creating a duration which represents ", $unitstr, ".")]
26        #[inline]
27        pub const fn $unit(val: $i) -> Self {
28            Self::from_ticks(
29                (Helpers::<$nom, $denum, NOM, DENOM>::RD_TIMES_LN as $i * val)
30                    / Helpers::<$nom, $denum, NOM, DENOM>::LD_TIMES_RN as $i
31            )
32        }
33
34        #[doc = concat!("Shorthand for creating a duration which represents ", $unitstr, " (ceil rounded).")]
35        #[inline]
36        pub const fn $unital(val: $i) -> Self {
37            let mul = Helpers::<$nom, $denum, NOM, DENOM>::RD_TIMES_LN as $i * val;
38            let ld_times_rn = Helpers::<$nom, $denum, NOM, DENOM>::LD_TIMES_RN as $i;
39            Self::from_ticks(if mul % ld_times_rn == 0 {
40                mul / ld_times_rn
41            } else {
42                mul / ld_times_rn + 1
43            })
44        }
45    };
46}
47
48macro_rules! impl_duration_for_integer {
49    ($i:ty) => {
50        impl<const NOM: u32, const DENOM: u32> Duration<$i, NOM, DENOM> {
51            /// Create a `Duration` from a ticks value.
52            ///
53            /// ```
54            /// # use fugit::*;
55            #[doc = concat!("let _d = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(1);")]
56            /// ```
57            #[inline]
58            pub const fn from_ticks(ticks: $i) -> Self {
59                helpers::greater_than_0::<NOM>();
60                helpers::greater_than_0::<DENOM>();
61
62                Duration { ticks }
63            }
64
65            /// Extract the ticks from a `Duration`.
66            ///
67            /// ```
68            /// # use fugit::*;
69            #[doc = concat!("let d = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(234);")]
70            ///
71            /// assert_eq!(d.ticks(), 234);
72            /// ```
73            #[inline]
74            pub const fn ticks(&self) -> $i {
75                self.ticks
76            }
77
78            /// Returns true if this `Duration` spans no time
79            ///
80            /// ```
81            /// # use fugit::*;
82            #[doc = concat!("let zero = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(0);")]
83            #[doc = concat!("let one = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(1);")]
84            ///
85            /// assert_eq!(zero.is_zero(), true);
86            /// assert_eq!(one.is_zero(), false);
87            /// ```
88            #[inline]
89            pub const fn is_zero(&self) -> bool {
90                self.ticks == 0
91            }
92
93            /// Add two durations while checking for overflow.
94            ///
95            /// ```
96            /// # use fugit::*;
97            #[doc = concat!("let d1 = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(1);")]
98            #[doc = concat!("let d2 = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(2);")]
99            #[doc = concat!("let d3 = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(", stringify!($i), "::MAX);")]
100            ///
101            /// assert_eq!(d1.checked_add(d2).unwrap().ticks(), 3);
102            /// assert_eq!(d1.checked_add(d3), None);
103            /// ```
104            pub const fn checked_add<const O_NOM: u32, const O_DENOM: u32>(
105                self,
106                other: Duration<$i, O_NOM, O_DENOM>,
107            ) -> Option<Self> {
108                if Helpers::<NOM, DENOM, O_NOM, O_DENOM>::SAME_BASE {
109                    if let Some(ticks) = self.ticks.checked_add(other.ticks) {
110                        Some(Duration::<$i, NOM, DENOM>::from_ticks(ticks))
111                    } else {
112                        None
113                    }
114                } else {
115                    if let Some(lh) = other
116                        .ticks
117                        .checked_mul(Helpers::<NOM, DENOM, O_NOM, O_DENOM>::LD_TIMES_RN as $i)
118                    {
119                        let ticks = lh / Helpers::<NOM, DENOM, O_NOM, O_DENOM>::RD_TIMES_LN as $i;
120
121                        if let Some(ticks) = self.ticks.checked_add(ticks) {
122                            Some(Duration::<$i, NOM, DENOM>::from_ticks(ticks))
123                        } else {
124                            None
125                        }
126                    } else {
127                        None
128                    }
129                }
130            }
131
132            /// Subtract two durations while checking for overflow.
133            ///
134            /// ```
135            /// # use fugit::*;
136            #[doc = concat!("let d1 = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(1);")]
137            #[doc = concat!("let d2 = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(2);")]
138            #[doc = concat!("let d3 = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(", stringify!($i), "::MAX);")]
139            ///
140            /// assert_eq!(d2.checked_sub(d1).unwrap().ticks(), 1);
141            /// assert_eq!(d1.checked_sub(d3), None);
142            /// ```
143            pub const fn checked_sub<const O_NOM: u32, const O_DENOM: u32>(
144                self,
145                other: Duration<$i, O_NOM, O_DENOM>,
146            ) -> Option<Self> {
147                if Helpers::<NOM, DENOM, O_NOM, O_DENOM>::SAME_BASE {
148                    if let Some(ticks) = self.ticks.checked_sub(other.ticks) {
149                        Some(Duration::<$i, NOM, DENOM>::from_ticks(ticks))
150                    } else {
151                        None
152                    }
153                } else {
154                    if let Some(lh) = other
155                        .ticks
156                        .checked_mul(Helpers::<NOM, DENOM, O_NOM, O_DENOM>::LD_TIMES_RN as $i)
157                    {
158                        let ticks = lh / Helpers::<NOM, DENOM, O_NOM, O_DENOM>::RD_TIMES_LN as $i;
159
160                        if let Some(ticks) = self.ticks.checked_sub(ticks) {
161                            Some(Duration::<$i, NOM, DENOM>::from_ticks(ticks))
162                        } else {
163                            None
164                        }
165                    } else {
166                        None
167                    }
168                }
169            }
170
171            #[doc = concat!("Const `cmp` for ", stringify!($i))]
172            #[inline(always)]
173            const fn _const_cmp(a: $i, b: $i) -> Ordering {
174                if a < b {
175                    Ordering::Less
176                } else if a > b {
177                    Ordering::Greater
178                } else {
179                    Ordering::Equal
180                }
181            }
182
183            /// Const partial comparison.
184            ///
185            /// ```
186            /// # use fugit::*;
187            #[doc = concat!("let d1 = Duration::<", stringify!($i), ", 1, 1_00>::from_ticks(1);")]
188            #[doc = concat!("let d2 = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(1);")]
189            ///
190            /// assert_eq!(d1.const_partial_cmp(d2), Some(core::cmp::Ordering::Greater));
191            /// ```
192            #[inline]
193            pub const fn const_partial_cmp<const R_NOM: u32, const R_DENOM: u32>(
194                self,
195                other: Duration<$i, R_NOM, R_DENOM>
196            ) -> Option<Ordering> {
197                //
198                // We want to check:
199                //
200                // n_lh / d_lh * lh_ticks {cmp} n_rh / d_rh * rh_ticks
201                //
202                // simplify to
203                //
204                // n_lh * d_rh * lh_ticks {cmp} n_rh * d_lh * rh_ticks
205                //
206                // find gdc(n_lh * d_rh, n_rh * d_lh) and use that to make the constants minimal (done
207                // with the `helpers::Helpers` struct)
208                //
209                // then perform the comparison in a comparable basis
210                //
211
212                if Helpers::<NOM, DENOM, R_NOM, R_DENOM>::SAME_BASE {
213                    // If we are in the same base, comparison in trivial
214                    Some(Self::_const_cmp(self.ticks, other.ticks))
215                } else {
216                    let lh = self
217                        .ticks
218                        .checked_mul(Helpers::<NOM, DENOM, R_NOM, R_DENOM>::RD_TIMES_LN as $i);
219                    let rh = other
220                        .ticks
221                        .checked_mul(Helpers::<NOM, DENOM, R_NOM, R_DENOM>::LD_TIMES_RN as $i);
222
223                    if let (Some(lh), Some(rh)) = (lh, rh) {
224                        Some(Self::_const_cmp(lh, rh))
225                    } else {
226                        None
227                    }
228                }
229            }
230
231            /// Const equality check.
232            ///
233            /// ```
234            /// # use fugit::*;
235            #[doc = concat!("let d1 = Duration::<", stringify!($i), ", 1, 1_00>::from_ticks(1);")]
236            #[doc = concat!("let d2 = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(10);")]
237            ///
238            /// assert!(d1.const_eq(d2));
239            /// ```
240            #[inline]
241            pub const fn const_eq<const R_NOM: u32, const R_DENOM: u32>(
242                self,
243                other: Duration<$i, R_NOM, R_DENOM>
244            ) -> bool {
245                if Helpers::<NOM, DENOM, R_NOM, R_DENOM>::SAME_BASE {
246                    // If we are in the same base, comparison in trivial
247                    self.ticks == other.ticks
248                } else {
249                    let lh = self
250                        .ticks
251                        .checked_mul(Helpers::<NOM, DENOM, R_NOM, R_DENOM>::RD_TIMES_LN as $i);
252                    let rh = other
253                        .ticks
254                        .checked_mul(Helpers::<NOM, DENOM, R_NOM, R_DENOM>::LD_TIMES_RN as $i);
255
256                    if let (Some(lh), Some(rh)) = (lh, rh) {
257                        lh == rh
258                    } else {
259                        false
260                    }
261                }
262            }
263
264            /// Const try from, checking for overflow.
265            ///
266            /// ```
267            /// # use fugit::*;
268            #[doc = concat!("let d1 = Duration::<", stringify!($i), ", 1, 1_00>::from_ticks(1);")]
269            #[doc = concat!("let d2 = Duration::<", stringify!($i), ", 1, 1_000>::const_try_from(d1);")]
270            ///
271            /// assert_eq!(d2.unwrap().ticks(), 10);
272            /// ```
273            pub const fn const_try_from<const I_NOM: u32, const I_DENOM: u32>(
274                duration: Duration<$i, I_NOM, I_DENOM>,
275            ) -> Option<Self> {
276                if Helpers::<I_NOM, I_DENOM, NOM, DENOM>::SAME_BASE {
277                    Some(Self::from_ticks(duration.ticks))
278                } else {
279                    if let Some(lh) = (duration.ticks as u64)
280                        .checked_mul(Helpers::<I_NOM, I_DENOM, NOM, DENOM>::RD_TIMES_LN as u64)
281                    {
282                        let ticks = lh / Helpers::<I_NOM, I_DENOM, NOM, DENOM>::LD_TIMES_RN as u64;
283
284                        if ticks <= <$i>::MAX as u64 {
285                            Some(Self::from_ticks(ticks as $i))
286                        } else {
287                            None
288                        }
289                    } else {
290                        None
291                    }
292                }
293            }
294
295            /// Const try into, checking for overflow.
296            ///
297            /// ```
298            /// # use fugit::*;
299            #[doc = concat!("let d1 = Duration::<", stringify!($i), ", 1, 1_00>::from_ticks(1);")]
300            #[doc = concat!("let d2: Option<Duration::<", stringify!($i), ", 1, 1_000>> = d1.const_try_into();")]
301            ///
302            /// assert_eq!(d2.unwrap().ticks(), 10);
303            /// ```
304            #[inline]
305            pub const fn const_try_into<const O_NOM: u32, const O_DENOM: u32>(
306                self,
307            ) -> Option<Duration<$i, O_NOM, O_DENOM>> {
308                Duration::<$i, O_NOM, O_DENOM>::const_try_from(self)
309            }
310
311            /// Const try into rate, checking for divide-by-zero.
312            ///
313            /// ```
314            /// # use fugit::*;
315            #[doc = concat!("let d1 = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(2);")]
316            #[doc = concat!("let r1: Option<Rate::<", stringify!($i), ", 1, 1>> = d1.try_into_rate();")]
317            ///
318            /// assert_eq!(r1.unwrap().raw(), 500);
319            /// ```
320            #[inline]
321            pub const fn try_into_rate<const O_NOM: u32, const O_DENOM: u32>(
322                self,
323            ) -> Option<Rate<$i, O_NOM, O_DENOM>> {
324                Rate::<$i, O_NOM, O_DENOM>::try_from_duration(self)
325            }
326
327            /// Convert from duration to rate.
328            #[inline]
329            pub const fn into_rate<const O_NOM: u32, const O_DENOM: u32>(
330                self,
331            ) -> Rate<$i, O_NOM, O_DENOM> {
332                if let Some(v) = self.try_into_rate() {
333                    v
334                } else {
335                    panic!("Into rate failed, divide-by-zero!");
336                }
337            }
338
339            /// Const try from rate, checking for divide-by-zero.
340            ///
341            /// ```
342            /// # use fugit::*;
343            #[doc = concat!("let r1 = Rate::<", stringify!($i), ", 1, 1>::from_raw(1);")]
344            #[doc = concat!("let d1 = Duration::<", stringify!($i), ", 1, 1_000>::try_from_rate(r1);")]
345            ///
346            /// assert_eq!(d1.unwrap().ticks(), 1_000);
347            /// ```
348            #[inline]
349            pub const fn try_from_rate<const I_NOM: u32, const I_DENOM: u32>(
350                rate: Rate<$i, I_NOM, I_DENOM>,
351            ) -> Option<Self> {
352                if rate.raw > 0 {
353                    Some(Self::from_ticks(
354                        Helpers::<I_NOM, I_DENOM, NOM, DENOM>::RATE_TO_DURATION_NUMERATOR as $i
355                        / rate.raw
356                    ))
357                } else {
358                    None
359                }
360            }
361
362            /// Convert from rate to duration.
363            #[inline]
364            pub const fn from_rate<const I_NOM: u32, const I_DENOM: u32>(
365                rate: Rate<$i, I_NOM, I_DENOM>,
366            ) -> Self {
367                if let Some(v) = Self::try_from_rate(rate) {
368                    v
369                } else {
370                    panic!("From rate failed, divide-by-zero!");
371                }
372            }
373
374            /// Convert between bases for a duration.
375            ///
376            /// Unfortunately not a `From` impl due to collision with the std lib.
377            ///
378            /// ```
379            /// # use fugit::*;
380            #[doc = concat!("let d1 = Duration::<", stringify!($i), ", 1, 100>::from_ticks(1);")]
381            #[doc = concat!("let d2: Duration::<", stringify!($i), ", 1, 1_000> = d1.convert();")]
382            ///
383            /// assert_eq!(d2.ticks(), 10);
384            /// ```
385            /// Can be used in const contexts. Compilation will fail if the conversion causes overflow
386            /// ```compile_fail
387            /// # use fugit::*;
388            #[doc = concat!("const TICKS: ", stringify!($i), "= ", stringify!($i), "::MAX - 10;")]
389            #[doc = concat!("const D1: Duration::<", stringify!($i), ", 1, 100> = Duration::<", stringify!($i), ", 1, 100>::from_ticks(TICKS);")]
390            /// // Fails conversion due to tick overflow
391            #[doc = concat!("const D2: Duration::<", stringify!($i), ", 1, 200> = D1.convert();")]
392            #[inline]
393            pub const fn convert<const O_NOM: u32, const O_DENOM: u32>(
394                self,
395            ) -> Duration<$i, O_NOM, O_DENOM> {
396                if let Some(v) = self.const_try_into() {
397                    v
398                } else {
399                    panic!("Convert failed!");
400                }
401            }
402
403            shorthand!($i, 1, 1_000_000_000, nanos, to_nanos, nanos_at_least, "nanoseconds");
404            shorthand!($i, 1, 1_000_000, micros, to_micros, micros_at_least, "microseconds");
405            shorthand!($i, 1, 1_000, millis, to_millis, millis_at_least, "milliseconds");
406            shorthand!($i, 1, 1, secs, to_secs, secs_at_least, "seconds");
407            shorthand!($i, 60, 1, minutes, to_minutes, minutes_at_least, "minutes");
408            shorthand!($i, 3600, 1, hours, to_hours, hours_at_least, "hours");
409
410            /// Shorthand for creating a duration which represents hertz.
411            #[inline]
412            #[allow(non_snake_case)]
413            pub const fn Hz(val: $i) -> Self {
414                Self::from_rate(crate::Hertz::<$i>::from_raw(val))
415            }
416
417            /// Shorthand for creating a duration which represents kilohertz.
418            #[inline]
419            #[allow(non_snake_case)]
420            pub const fn kHz(val: $i) -> Self {
421                Self::from_rate(crate::Kilohertz::<$i>::from_raw(val))
422            }
423
424            /// Shorthand for creating a duration which represents megahertz.
425            #[inline]
426            #[allow(non_snake_case)]
427            pub const fn MHz(val: $i) -> Self {
428                Self::from_rate(crate::Megahertz::<$i>::from_raw(val))
429            }
430        }
431
432        impl<const L_NOM: u32, const L_DENOM: u32, const R_NOM: u32, const R_DENOM: u32>
433            PartialOrd<Duration<$i, R_NOM, R_DENOM>> for Duration<$i, L_NOM, L_DENOM>
434        {
435            #[inline]
436            fn partial_cmp(&self, other: &Duration<$i, R_NOM, R_DENOM>) -> Option<Ordering> {
437                self.const_partial_cmp(*other)
438            }
439        }
440
441        impl<const NOM: u32, const DENOM: u32> Ord for Duration<$i, NOM, DENOM> {
442            #[inline]
443            fn cmp(&self, other: &Self) -> Ordering {
444                Self::_const_cmp(self.ticks, other.ticks)
445            }
446        }
447
448        impl<const L_NOM: u32, const L_DENOM: u32, const R_NOM: u32, const R_DENOM: u32>
449            PartialEq<Duration<$i, R_NOM, R_DENOM>> for Duration<$i, L_NOM, L_DENOM>
450        {
451            #[inline]
452            fn eq(&self, other: &Duration<$i, R_NOM, R_DENOM>) -> bool {
453                self.const_eq(*other)
454            }
455        }
456
457        impl<const NOM: u32, const DENOM: u32> Eq for Duration<$i, NOM, DENOM> {}
458
459        // Duration - Duration = Duration (only same base until const_generics_defaults is
460        // stabilized)
461        impl<const NOM: u32, const DENOM: u32> ops::Sub<Duration<$i, NOM, DENOM>>
462            for Duration<$i, NOM, DENOM>
463        {
464            type Output = Duration<$i, NOM, DENOM>;
465
466            #[inline]
467            fn sub(self, other: Duration<$i, NOM, DENOM>) -> Self::Output {
468                if let Some(v) = self.checked_sub(other) {
469                    v
470                } else {
471                    panic!("Sub failed!");
472                }
473            }
474        }
475
476        // Duration -= Duration
477        impl<const NOM: u32, const DENOM: u32> ops::SubAssign<Duration<$i, NOM, DENOM>>
478            for Duration<$i, NOM, DENOM>
479        {
480            #[inline]
481            fn sub_assign(&mut self, other: Self) {
482                *self = *self - other;
483            }
484        }
485
486        // Duration + Duration = Duration (only same base until const_generics_defaults is
487        // stabilized)
488        impl<const NOM: u32, const DENOM: u32> ops::Add<Duration<$i, NOM, DENOM>>
489            for Duration<$i, NOM, DENOM>
490        {
491            type Output = Duration<$i, NOM, DENOM>;
492
493            #[inline]
494            fn add(self, other: Duration<$i, NOM, DENOM>) -> Self::Output {
495                if let Some(v) = self.checked_add(other) {
496                    v
497                } else {
498                    panic!("Add failed!");
499                }
500            }
501        }
502
503        // Duration += Duration
504        impl<const NOM: u32, const DENOM: u32> ops::AddAssign<Duration<$i, NOM, DENOM>>
505            for Duration<$i, NOM, DENOM>
506        {
507            #[inline]
508            fn add_assign(&mut self, other: Self) {
509                *self = *self + other;
510            }
511        }
512
513        // integer * Duration = Duration
514        impl<const NOM: u32, const DENOM: u32> ops::Mul<Duration<$i, NOM, DENOM>> for u32 {
515            type Output = Duration<$i, NOM, DENOM>;
516
517            #[inline]
518            fn mul(self, mut other: Duration<$i, NOM, DENOM>) -> Self::Output {
519                other.ticks *= self as $i;
520                other
521            }
522        }
523
524        // Duration * integer = Duration
525        impl<const NOM: u32, const DENOM: u32> ops::Mul<u32> for Duration<$i, NOM, DENOM> {
526            type Output = Duration<$i, NOM, DENOM>;
527
528            #[inline]
529            fn mul(mut self, other: u32) -> Self::Output {
530                self.ticks *= other as $i;
531                self
532            }
533        }
534
535        // Duration *= integer
536        impl<const NOM: u32, const DENOM: u32> ops::MulAssign<u32>
537            for Duration<$i, NOM, DENOM>
538        {
539            #[inline]
540            fn mul_assign(&mut self, other: u32) {
541                *self = *self * other;
542            }
543        }
544
545        // Duration / integer = Duration
546        impl<const NOM: u32, const DENOM: u32> ops::Div<u32> for Duration<$i, NOM, DENOM> {
547            type Output = Duration<$i, NOM, DENOM>;
548
549            #[inline]
550            fn div(mut self, other: u32) -> Self::Output {
551                self.ticks /= other as $i;
552                self
553            }
554        }
555
556        // Duration /= integer
557        impl<const NOM: u32, const DENOM: u32> ops::DivAssign<u32>
558            for Duration<$i, NOM, DENOM>
559        {
560            #[inline]
561            fn div_assign(&mut self, other: u32) {
562                *self = *self / other;
563            }
564        }
565
566        // Duration / Duration = integer
567        impl<const L_NOM: u32, const L_DENOM: u32, const R_NOM: u32, const R_DENOM: u32> ops::Div<Duration<$i, R_NOM, R_DENOM>>
568            for Duration<$i, L_NOM, L_DENOM>
569        {
570            type Output = $i;
571
572            #[inline]
573            fn div(self, other: Duration<$i, R_NOM, R_DENOM>) -> Self::Output {
574                let conv: Duration<$i, R_NOM, R_DENOM> = self.convert();
575                conv.ticks / other.ticks
576            }
577        }
578
579        #[cfg(feature = "defmt")]
580        impl<const NOM: u32, const DENOM: u32> defmt::Format for Duration<$i, NOM, DENOM>
581        {
582            fn format(&self, f: defmt::Formatter) {
583                if NOM == 3_600 && DENOM == 1 {
584                    defmt::write!(f, "{} h", self.ticks)
585                } else if NOM == 60 && DENOM == 1 {
586                    defmt::write!(f, "{} min", self.ticks)
587                } else if NOM == 1 && DENOM == 1 {
588                    defmt::write!(f, "{} s", self.ticks)
589                } else if NOM == 1 && DENOM == 1_000 {
590                    defmt::write!(f, "{} ms", self.ticks)
591                } else if NOM == 1 && DENOM == 1_000_000 {
592                    defmt::write!(f, "{} us", self.ticks)
593                } else if NOM == 1 && DENOM == 1_000_000_000 {
594                    defmt::write!(f, "{} ns", self.ticks)
595                } else {
596                    defmt::write!(f, "{} ticks @ ({}/{})", self.ticks, NOM, DENOM)
597                }
598            }
599        }
600
601        impl<const NOM: u32, const DENOM: u32> core::fmt::Display for Duration<$i, NOM, DENOM> {
602            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
603                if NOM == 3_600 && DENOM == 1 {
604                    write!(f, "{} h", self.ticks)
605                } else if NOM == 60 && DENOM == 1 {
606                    write!(f, "{} min", self.ticks)
607                } else if NOM == 1 && DENOM == 1 {
608                    write!(f, "{} s", self.ticks)
609                } else if NOM == 1 && DENOM == 1_000 {
610                    write!(f, "{} ms", self.ticks)
611                } else if NOM == 1 && DENOM == 1_000_000 {
612                    write!(f, "{} us", self.ticks)
613                } else if NOM == 1 && DENOM == 1_000_000_000 {
614                    write!(f, "{} ns", self.ticks)
615                } else {
616                    write!(f, "{} ticks @ ({}/{})", self.ticks, NOM, DENOM)
617                }
618            }
619        }
620    };
621}
622
623impl_duration_for_integer!(u32);
624impl_duration_for_integer!(u64);
625
626//
627// Operations between u32 and u64 Durations
628//
629
630impl<const NOM: u32, const DENOM: u32> From<Duration<u32, NOM, DENOM>>
631    for Duration<u64, NOM, DENOM>
632{
633    #[inline]
634    fn from(val: Duration<u32, NOM, DENOM>) -> Duration<u64, NOM, DENOM> {
635        Duration::<u64, NOM, DENOM>::from_ticks(val.ticks() as u64)
636    }
637}
638
639impl<const NOM: u32, const DENOM: u32> convert::TryFrom<Duration<u64, NOM, DENOM>>
640    for Duration<u32, NOM, DENOM>
641{
642    type Error = ();
643
644    #[inline]
645    fn try_from(val: Duration<u64, NOM, DENOM>) -> Result<Duration<u32, NOM, DENOM>, ()> {
646        Ok(Duration::<u32, NOM, DENOM>::from_ticks(
647            val.ticks().try_into().map_err(|_| ())?,
648        ))
649    }
650}
651
652// Duration - Duration = Duration (to make shorthands work, until const_generics_defaults is
653// stabilized)
654impl<const NOM: u32, const DENOM: u32> ops::Sub<Duration<u32, NOM, DENOM>>
655    for Duration<u64, NOM, DENOM>
656{
657    type Output = Duration<u64, NOM, DENOM>;
658
659    #[inline]
660    fn sub(self, other: Duration<u32, NOM, DENOM>) -> Self::Output {
661        if let Some(v) =
662            self.checked_sub(Duration::<u64, NOM, DENOM>::from_ticks(other.ticks() as u64))
663        {
664            v
665        } else {
666            panic!("Sub failed!");
667        }
668    }
669}
670
671// Duration -= Duration (to make shorthands work, until const_generics_defaults is stabilized)
672impl<const NOM: u32, const DENOM: u32> ops::SubAssign<Duration<u32, NOM, DENOM>>
673    for Duration<u64, NOM, DENOM>
674{
675    #[inline]
676    fn sub_assign(&mut self, other: Duration<u32, NOM, DENOM>) {
677        *self = *self - other;
678    }
679}
680
681// Duration + Duration = Duration (to make shorthands work, until const_generics_defaults is
682// stabilized)
683impl<const NOM: u32, const DENOM: u32> ops::Add<Duration<u32, NOM, DENOM>>
684    for Duration<u64, NOM, DENOM>
685{
686    type Output = Duration<u64, NOM, DENOM>;
687
688    #[inline]
689    fn add(self, other: Duration<u32, NOM, DENOM>) -> Self::Output {
690        if let Some(v) =
691            self.checked_add(Duration::<u64, NOM, DENOM>::from_ticks(other.ticks() as u64))
692        {
693            v
694        } else {
695            panic!("Add failed!");
696        }
697    }
698}
699
700// Duration += Duration (to make shorthands work, until const_generics_defaults is stabilized)
701impl<const NOM: u32, const DENOM: u32> ops::AddAssign<Duration<u32, NOM, DENOM>>
702    for Duration<u64, NOM, DENOM>
703{
704    #[inline]
705    fn add_assign(&mut self, other: Duration<u32, NOM, DENOM>) {
706        *self = *self + other;
707    }
708}
709
710impl<const L_NOM: u32, const L_DENOM: u32, const R_NOM: u32, const R_DENOM: u32>
711    PartialOrd<Duration<u32, R_NOM, R_DENOM>> for Duration<u64, L_NOM, L_DENOM>
712{
713    #[inline]
714    fn partial_cmp(&self, other: &Duration<u32, R_NOM, R_DENOM>) -> Option<Ordering> {
715        self.partial_cmp(&Duration::<u64, R_NOM, R_DENOM>::from_ticks(
716            other.ticks() as u64
717        ))
718    }
719}
720
721impl<const L_NOM: u32, const L_DENOM: u32, const R_NOM: u32, const R_DENOM: u32>
722    PartialEq<Duration<u32, R_NOM, R_DENOM>> for Duration<u64, L_NOM, L_DENOM>
723{
724    #[inline]
725    fn eq(&self, other: &Duration<u32, R_NOM, R_DENOM>) -> bool {
726        self.eq(&Duration::<u64, R_NOM, R_DENOM>::from_ticks(
727            other.ticks() as u64
728        ))
729    }
730}
731
732impl<const L_NOM: u32, const L_DENOM: u32, const R_NOM: u32, const R_DENOM: u32>
733    PartialOrd<Duration<u64, R_NOM, R_DENOM>> for Duration<u32, L_NOM, L_DENOM>
734{
735    #[inline]
736    fn partial_cmp(&self, other: &Duration<u64, R_NOM, R_DENOM>) -> Option<Ordering> {
737        Duration::<u64, L_NOM, L_DENOM>::from_ticks(self.ticks as u64).partial_cmp(other)
738    }
739}
740
741impl<const L_NOM: u32, const L_DENOM: u32, const R_NOM: u32, const R_DENOM: u32>
742    PartialEq<Duration<u64, R_NOM, R_DENOM>> for Duration<u32, L_NOM, L_DENOM>
743{
744    #[inline]
745    fn eq(&self, other: &Duration<u64, R_NOM, R_DENOM>) -> bool {
746        Duration::<u64, L_NOM, L_DENOM>::from_ticks(self.ticks as u64).eq(other)
747    }
748}
749
750/// Extension trait for simple short-hands for u32 Durations
751pub trait ExtU32 {
752    /// Shorthand for creating a duration which represents nanoseconds.
753    fn nanos<const NOM: u32, const DENOM: u32>(self) -> Duration<u32, NOM, DENOM>;
754
755    /// Shorthand for creating a duration which represents microseconds.
756    fn micros<const NOM: u32, const DENOM: u32>(self) -> Duration<u32, NOM, DENOM>;
757
758    /// Shorthand for creating a duration which represents milliseconds.
759    fn millis<const NOM: u32, const DENOM: u32>(self) -> Duration<u32, NOM, DENOM>;
760
761    /// Shorthand for creating a duration which represents seconds.
762    fn secs<const NOM: u32, const DENOM: u32>(self) -> Duration<u32, NOM, DENOM>;
763
764    /// Shorthand for creating a duration which represents minutes.
765    fn minutes<const NOM: u32, const DENOM: u32>(self) -> Duration<u32, NOM, DENOM>;
766
767    /// Shorthand for creating a duration which represents hours.
768    fn hours<const NOM: u32, const DENOM: u32>(self) -> Duration<u32, NOM, DENOM>;
769}
770
771impl ExtU32 for u32 {
772    #[inline]
773    fn nanos<const NOM: u32, const DENOM: u32>(self) -> Duration<u32, NOM, DENOM> {
774        Duration::<u32, NOM, DENOM>::nanos(self)
775    }
776
777    #[inline]
778    fn micros<const NOM: u32, const DENOM: u32>(self) -> Duration<u32, NOM, DENOM> {
779        Duration::<u32, NOM, DENOM>::micros(self)
780    }
781
782    #[inline]
783    fn millis<const NOM: u32, const DENOM: u32>(self) -> Duration<u32, NOM, DENOM> {
784        Duration::<u32, NOM, DENOM>::millis(self)
785    }
786
787    #[inline]
788    fn secs<const NOM: u32, const DENOM: u32>(self) -> Duration<u32, NOM, DENOM> {
789        Duration::<u32, NOM, DENOM>::secs(self)
790    }
791
792    #[inline]
793    fn minutes<const NOM: u32, const DENOM: u32>(self) -> Duration<u32, NOM, DENOM> {
794        Duration::<u32, NOM, DENOM>::minutes(self)
795    }
796
797    #[inline]
798    fn hours<const NOM: u32, const DENOM: u32>(self) -> Duration<u32, NOM, DENOM> {
799        Duration::<u32, NOM, DENOM>::hours(self)
800    }
801}
802
803/// Extension trait for simple short-hands for u32 Durations (ceil rounded)
804pub trait ExtU32Ceil {
805    /// Shorthand for creating a duration which represents nanoseconds.
806    fn nanos_at_least<const NOM: u32, const DENOM: u32>(self) -> Duration<u32, NOM, DENOM>;
807
808    /// Shorthand for creating a duration which represents microseconds.
809    fn micros_at_least<const NOM: u32, const DENOM: u32>(self) -> Duration<u32, NOM, DENOM>;
810
811    /// Shorthand for creating a duration which represents milliseconds.
812    fn millis_at_least<const NOM: u32, const DENOM: u32>(self) -> Duration<u32, NOM, DENOM>;
813
814    /// Shorthand for creating a duration which represents seconds.
815    fn secs_at_least<const NOM: u32, const DENOM: u32>(self) -> Duration<u32, NOM, DENOM>;
816
817    /// Shorthand for creating a duration which represents minutes.
818    fn minutes_at_least<const NOM: u32, const DENOM: u32>(self) -> Duration<u32, NOM, DENOM>;
819
820    /// Shorthand for creating a duration which represents hours.
821    fn hours_at_least<const NOM: u32, const DENOM: u32>(self) -> Duration<u32, NOM, DENOM>;
822}
823
824impl ExtU32Ceil for u32 {
825    #[inline]
826    fn nanos_at_least<const NOM: u32, const DENOM: u32>(self) -> Duration<u32, NOM, DENOM> {
827        Duration::<u32, NOM, DENOM>::nanos_at_least(self)
828    }
829
830    #[inline]
831    fn micros_at_least<const NOM: u32, const DENOM: u32>(self) -> Duration<u32, NOM, DENOM> {
832        Duration::<u32, NOM, DENOM>::micros_at_least(self)
833    }
834
835    #[inline]
836    fn millis_at_least<const NOM: u32, const DENOM: u32>(self) -> Duration<u32, NOM, DENOM> {
837        Duration::<u32, NOM, DENOM>::millis_at_least(self)
838    }
839
840    #[inline]
841    fn secs_at_least<const NOM: u32, const DENOM: u32>(self) -> Duration<u32, NOM, DENOM> {
842        Duration::<u32, NOM, DENOM>::secs_at_least(self)
843    }
844
845    #[inline]
846    fn minutes_at_least<const NOM: u32, const DENOM: u32>(self) -> Duration<u32, NOM, DENOM> {
847        Duration::<u32, NOM, DENOM>::minutes_at_least(self)
848    }
849
850    #[inline]
851    fn hours_at_least<const NOM: u32, const DENOM: u32>(self) -> Duration<u32, NOM, DENOM> {
852        Duration::<u32, NOM, DENOM>::hours_at_least(self)
853    }
854}
855
856/// Extension trait for simple short-hands for u64 Durations
857pub trait ExtU64 {
858    /// Shorthand for creating a duration which represents nanoseconds.
859    fn nanos<const NOM: u32, const DENOM: u32>(self) -> Duration<u64, NOM, DENOM>;
860
861    /// Shorthand for creating a duration which represents microseconds.
862    fn micros<const NOM: u32, const DENOM: u32>(self) -> Duration<u64, NOM, DENOM>;
863
864    /// Shorthand for creating a duration which represents milliseconds.
865    fn millis<const NOM: u32, const DENOM: u32>(self) -> Duration<u64, NOM, DENOM>;
866
867    /// Shorthand for creating a duration which represents seconds.
868    fn secs<const NOM: u32, const DENOM: u32>(self) -> Duration<u64, NOM, DENOM>;
869
870    /// Shorthand for creating a duration which represents minutes.
871    fn minutes<const NOM: u32, const DENOM: u32>(self) -> Duration<u64, NOM, DENOM>;
872
873    /// Shorthand for creating a duration which represents hours.
874    fn hours<const NOM: u32, const DENOM: u32>(self) -> Duration<u64, NOM, DENOM>;
875}
876
877impl ExtU64 for u64 {
878    #[inline]
879    fn nanos<const NOM: u32, const DENOM: u32>(self) -> Duration<u64, NOM, DENOM> {
880        Duration::<u64, NOM, DENOM>::nanos(self)
881    }
882
883    #[inline]
884    fn micros<const NOM: u32, const DENOM: u32>(self) -> Duration<u64, NOM, DENOM> {
885        Duration::<u64, NOM, DENOM>::micros(self)
886    }
887
888    #[inline]
889    fn millis<const NOM: u32, const DENOM: u32>(self) -> Duration<u64, NOM, DENOM> {
890        Duration::<u64, NOM, DENOM>::millis(self)
891    }
892
893    #[inline]
894    fn secs<const NOM: u32, const DENOM: u32>(self) -> Duration<u64, NOM, DENOM> {
895        Duration::<u64, NOM, DENOM>::secs(self)
896    }
897
898    #[inline]
899    fn minutes<const NOM: u32, const DENOM: u32>(self) -> Duration<u64, NOM, DENOM> {
900        Duration::<u64, NOM, DENOM>::minutes(self)
901    }
902
903    #[inline]
904    fn hours<const NOM: u32, const DENOM: u32>(self) -> Duration<u64, NOM, DENOM> {
905        Duration::<u64, NOM, DENOM>::hours(self)
906    }
907}
908
909/// Extension trait for simple short-hands for u64 Durations (ceil rounded)
910pub trait ExtU64Ceil {
911    /// Shorthand for creating a duration which represents nanoseconds.
912    fn nanos_at_least<const NOM: u32, const DENOM: u32>(self) -> Duration<u64, NOM, DENOM>;
913
914    /// Shorthand for creating a duration which represents microseconds.
915    fn micros_at_least<const NOM: u32, const DENOM: u32>(self) -> Duration<u64, NOM, DENOM>;
916
917    /// Shorthand for creating a duration which represents milliseconds.
918    fn millis_at_least<const NOM: u32, const DENOM: u32>(self) -> Duration<u64, NOM, DENOM>;
919
920    /// Shorthand for creating a duration which represents seconds.
921    fn secs_at_least<const NOM: u32, const DENOM: u32>(self) -> Duration<u64, NOM, DENOM>;
922
923    /// Shorthand for creating a duration which represents minutes.
924    fn minutes_at_least<const NOM: u32, const DENOM: u32>(self) -> Duration<u64, NOM, DENOM>;
925
926    /// Shorthand for creating a duration which represents hours.
927    fn hours_at_least<const NOM: u32, const DENOM: u32>(self) -> Duration<u64, NOM, DENOM>;
928}
929
930impl ExtU64Ceil for u64 {
931    #[inline]
932    fn nanos_at_least<const NOM: u32, const DENOM: u32>(self) -> Duration<u64, NOM, DENOM> {
933        Duration::<u64, NOM, DENOM>::nanos_at_least(self)
934    }
935
936    #[inline]
937    fn micros_at_least<const NOM: u32, const DENOM: u32>(self) -> Duration<u64, NOM, DENOM> {
938        Duration::<u64, NOM, DENOM>::micros_at_least(self)
939    }
940
941    #[inline]
942    fn millis_at_least<const NOM: u32, const DENOM: u32>(self) -> Duration<u64, NOM, DENOM> {
943        Duration::<u64, NOM, DENOM>::millis_at_least(self)
944    }
945
946    #[inline]
947    fn secs_at_least<const NOM: u32, const DENOM: u32>(self) -> Duration<u64, NOM, DENOM> {
948        Duration::<u64, NOM, DENOM>::secs_at_least(self)
949    }
950
951    #[inline]
952    fn minutes_at_least<const NOM: u32, const DENOM: u32>(self) -> Duration<u64, NOM, DENOM> {
953        Duration::<u64, NOM, DENOM>::minutes_at_least(self)
954    }
955
956    #[inline]
957    fn hours_at_least<const NOM: u32, const DENOM: u32>(self) -> Duration<u64, NOM, DENOM> {
958        Duration::<u64, NOM, DENOM>::hours_at_least(self)
959    }
960}