Skip to main content

fugit/
duration.rs

1use crate::helpers::{div_round_nearest_u64, Helpers};
2use crate::NanosDurationU64;
3use crate::Rate;
4use crate::SecsDurationU64;
5use core::cmp::Ordering;
6use core::convert;
7use core::ops;
8
9/// Represents a duration of time.
10///
11/// The generic `T` can either be `u32` or `u64`, and the const generics represent the ratio of the
12/// ticks contained within the duration: `duration in seconds = NOM / DENOM * ticks`
13#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
14#[cfg_attr(
15    feature = "postcard_max_size",
16    derive(postcard::experimental::max_size::MaxSize)
17)]
18#[derive(Clone, Copy, Debug)]
19pub struct Duration<T, const NOM: u64, const DENOM: u64> {
20    pub(crate) ticks: T,
21}
22
23// Unwrap a const-time `Option` or panic with the given static message. Lets the
24// shorthand methods turn `checked_mul` failures into a clear panic at the user's
25// call site instead of silently wrapping in release builds.
26macro_rules! const_checked {
27    ($e:expr, $msg:expr) => {
28        match $e {
29            Some(v) => v,
30            None => panic!("{}", $msg),
31        }
32    };
33}
34
35macro_rules! shorthand {
36    ($i:ty, $nom:literal, $denum:literal, $from_unit:ident, $as_unit:ident, $from_unital:ident, $unitstr:literal) => {
37        #[doc = concat!("Convert the Duration to an integer number of ", $unitstr, ".")]
38        #[doc = ""]
39        #[doc = concat!("**Compile-time error** if the conversion constants don't fit in `", stringify!($i), "`. **Panics** if the multiplication overflows `", stringify!($i), "`.")]
40        #[inline]
41        #[track_caller]
42        pub const fn $as_unit(&self) -> $i {
43            const {
44                assert!(
45                    Helpers::<$nom, $denum, NOM, DENOM>::RD_TIMES_LN <= <$i>::MAX as u64,
46                    concat!("Conversion constant RD_TIMES_LN doesn't fit in ", stringify!($i), " for this Duration type")
47                );
48                assert!(
49                    Helpers::<$nom, $denum, NOM, DENOM>::LD_TIMES_RN <= <$i>::MAX as u64,
50                    concat!("Conversion constant LD_TIMES_RN doesn't fit in ", stringify!($i), " for this Duration type")
51                );
52            }
53
54            let prod = const_checked!(
55                (Helpers::<$nom, $denum, NOM, DENOM>::LD_TIMES_RN as $i).checked_mul(self.ticks),
56                concat!("Duration::", stringify!($as_unit), ": multiplication overflowed storage type")
57            );
58            prod / Helpers::<$nom, $denum, NOM, DENOM>::RD_TIMES_LN as $i
59        }
60
61        #[doc = concat!("Create a duration from a number of ", $unitstr, ".")]
62        #[doc = ""]
63        #[doc = concat!("**Compile-time error** if the conversion constants don't fit in `", stringify!($i), "`. **Panics** if the multiplication overflows `", stringify!($i), "`.")]
64        #[inline]
65        #[track_caller]
66        pub const fn $from_unit(val: $i) -> Self {
67            const {
68                assert!(
69                    Helpers::<$nom, $denum, NOM, DENOM>::RD_TIMES_LN <= <$i>::MAX as u64,
70                    concat!("Conversion constant RD_TIMES_LN doesn't fit in ", stringify!($i), " for this Duration type")
71                );
72                assert!(
73                    Helpers::<$nom, $denum, NOM, DENOM>::LD_TIMES_RN <= <$i>::MAX as u64,
74                    concat!("Conversion constant LD_TIMES_RN doesn't fit in ", stringify!($i), " for this Duration type")
75                );
76            }
77
78            let prod = const_checked!(
79                (Helpers::<$nom, $denum, NOM, DENOM>::RD_TIMES_LN as $i).checked_mul(val),
80                concat!("Duration::", stringify!($from_unit), ": multiplication overflowed storage type")
81            );
82            Self::from_ticks(prod / Helpers::<$nom, $denum, NOM, DENOM>::LD_TIMES_RN as $i)
83        }
84
85        #[doc = concat!("Create a duration from a number of ", $unitstr, " (ceil rounded).")]
86        #[doc = ""]
87        #[doc = concat!("**Compile-time error** if the conversion constants don't fit in `", stringify!($i), "`. **Panics** if the multiplication overflows `", stringify!($i), "`.")]
88        #[inline]
89        #[track_caller]
90        pub const fn $from_unital(val: $i) -> Self {
91            const {
92                assert!(
93                    Helpers::<$nom, $denum, NOM, DENOM>::RD_TIMES_LN <= <$i>::MAX as u64,
94                    concat!("Conversion constant RD_TIMES_LN doesn't fit in ", stringify!($i), " for this Duration type")
95                );
96                assert!(
97                    Helpers::<$nom, $denum, NOM, DENOM>::LD_TIMES_RN <= <$i>::MAX as u64,
98                    concat!("Conversion constant LD_TIMES_RN doesn't fit in ", stringify!($i), " for this Duration type")
99                );
100            }
101
102            let mul = const_checked!(
103                (Helpers::<$nom, $denum, NOM, DENOM>::RD_TIMES_LN as $i).checked_mul(val),
104                concat!("Duration::", stringify!($from_unital), ": multiplication overflowed storage type")
105            );
106            let ld_times_rn = Helpers::<$nom, $denum, NOM, DENOM>::LD_TIMES_RN as $i;
107            Self::from_ticks(mul.div_ceil(ld_times_rn))
108        }
109    };
110}
111
112macro_rules! impl_duration_for_integer {
113    ($i:ty) => {
114        impl<const NOM: u64, const DENOM: u64> Duration<$i, NOM, DENOM> {
115            /// Create a `Duration` from a ticks value.
116            ///
117            /// ```
118            /// # use fugit::*;
119            #[doc = concat!("let _d = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(1);")]
120            /// ```
121            #[inline]
122            pub const fn from_ticks(ticks: $i) -> Self {
123                const { assert!(NOM > 0) };
124                const { assert!(DENOM > 0) };
125
126                Duration { ticks }
127            }
128
129            /// Extract the ticks from a `Duration`.
130            ///
131            /// ```
132            /// # use fugit::*;
133            #[doc = concat!("let d = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(234);")]
134            ///
135            /// assert_eq!(d.as_ticks(), 234);
136            /// ```
137            #[inline]
138            pub const fn as_ticks(&self) -> $i {
139                self.ticks
140            }
141
142            /// A duration of zero time.
143            ///
144            /// ```
145            /// # use fugit::*;
146            #[doc = concat!("let d = Duration::<", stringify!($i), ", 1, 1_000>::ZERO;")]
147            ///
148            /// assert_eq!(d.as_ticks(), 0);
149            /// assert!(d.is_zero());
150            /// ```
151            pub const ZERO: Self = Self::from_ticks(0);
152
153            /// The maximum duration.
154            ///
155            /// ```
156            /// # use fugit::*;
157            #[doc = concat!("let d = Duration::<", stringify!($i), ", 1, 1_000>::MAX;")]
158            ///
159            #[doc = concat!("assert_eq!(d.as_ticks(), ", stringify!($i), "::MAX);")]
160            /// ```
161            pub const MAX: Self = Self::from_ticks(<$i>::MAX);
162
163            /// Returns true if this `Duration` spans no time
164            ///
165            /// ```
166            /// # use fugit::*;
167            #[doc = concat!("let zero = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(0);")]
168            #[doc = concat!("let one = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(1);")]
169            ///
170            /// assert_eq!(zero.is_zero(), true);
171            /// assert_eq!(one.is_zero(), false);
172            /// ```
173            #[inline]
174            pub const fn is_zero(&self) -> bool {
175                self.ticks == 0
176            }
177
178            /// Add two durations.
179            ///
180            /// Returns `None` on tick overflow or cross-base conversion overflow.
181            ///
182            /// ```
183            /// # use fugit::*;
184            #[doc = concat!("let d1 = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(1);")]
185            #[doc = concat!("let d2 = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(2);")]
186            #[doc = concat!("let d3 = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(", stringify!($i), "::MAX);")]
187            ///
188            /// assert_eq!(d1.checked_add(d2).unwrap().as_ticks(), 3);
189            /// assert_eq!(d1.checked_add(d3), None);
190            /// ```
191            pub const fn checked_add<const O_NOM: u64, const O_DENOM: u64>(
192                self,
193                other: Duration<$i, O_NOM, O_DENOM>,
194            ) -> Option<Self> {
195                if Helpers::<NOM, DENOM, O_NOM, O_DENOM>::SAME_BASE {
196                    if let Some(ticks) = self.ticks.checked_add(other.ticks) {
197                        Some(Self::from_ticks(ticks))
198                    } else {
199                        None
200                    }
201                } else {
202                    if let Some(lh) = other
203                        .ticks
204                        .checked_mul(Helpers::<NOM, DENOM, O_NOM, O_DENOM>::LD_TIMES_RN as $i)
205                    {
206                        let ticks = lh / Helpers::<NOM, DENOM, O_NOM, O_DENOM>::RD_TIMES_LN as $i;
207
208                        if let Some(ticks) = self.ticks.checked_add(ticks) {
209                            Some(Self::from_ticks(ticks))
210                        } else {
211                            None
212                        }
213                    } else {
214                        None
215                    }
216                }
217            }
218
219            /// Subtract two durations.
220            ///
221            /// Returns `None` on tick underflow or cross-base conversion overflow.
222            ///
223            /// ```
224            /// # use fugit::*;
225            #[doc = concat!("let d1 = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(1);")]
226            #[doc = concat!("let d2 = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(2);")]
227            #[doc = concat!("let d3 = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(", stringify!($i), "::MAX);")]
228            ///
229            /// assert_eq!(d2.checked_sub(d1).unwrap().as_ticks(), 1);
230            /// assert_eq!(d1.checked_sub(d3), None);
231            /// ```
232            pub const fn checked_sub<const O_NOM: u64, const O_DENOM: u64>(
233                self,
234                other: Duration<$i, O_NOM, O_DENOM>,
235            ) -> Option<Self> {
236                if Helpers::<NOM, DENOM, O_NOM, O_DENOM>::SAME_BASE {
237                    if let Some(ticks) = self.ticks.checked_sub(other.ticks) {
238                        Some(Self::from_ticks(ticks))
239                    } else {
240                        None
241                    }
242                } else {
243                    if let Some(lh) = other
244                        .ticks
245                        .checked_mul(Helpers::<NOM, DENOM, O_NOM, O_DENOM>::LD_TIMES_RN as $i)
246                    {
247                        let ticks = lh / Helpers::<NOM, DENOM, O_NOM, O_DENOM>::RD_TIMES_LN as $i;
248
249                        if let Some(ticks) = self.ticks.checked_sub(ticks) {
250                            Some(Self::from_ticks(ticks))
251                        } else {
252                            None
253                        }
254                    } else {
255                        None
256                    }
257                }
258            }
259
260            /// Multiply this duration by an integer while checking for overflow.
261            ///
262            /// ```
263            /// # use fugit::*;
264            #[doc = concat!("let d = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(10);")]
265            ///
266            /// assert_eq!(d.checked_mul(3).unwrap().as_ticks(), 30);
267            #[doc = concat!("assert_eq!(Duration::<", stringify!($i), ", 1, 1_000>::MAX.checked_mul(2), None);")]
268            /// ```
269            #[inline]
270            pub const fn checked_mul(self, rhs: $i) -> Option<Self> {
271                if let Some(ticks) = self.ticks.checked_mul(rhs) {
272                    Some(Self::from_ticks(ticks))
273                } else {
274                    None
275                }
276            }
277
278            /// Divide this duration by an integer while checking for division by zero.
279            ///
280            /// ```
281            /// # use fugit::*;
282            #[doc = concat!("let d = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(30);")]
283            ///
284            /// assert_eq!(d.checked_div(3).unwrap().as_ticks(), 10);
285            #[doc = concat!("assert_eq!(Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(10).checked_div(0), None);")]
286            /// ```
287            #[inline]
288            pub const fn checked_div(self, rhs: $i) -> Option<Self> {
289                if rhs == 0 {
290                    None
291                } else {
292                    Some(Self::from_ticks(self.ticks / rhs))
293                }
294            }
295
296            /// Remainder of dividing two durations.
297            ///
298            /// Returns `None` if `other` is zero or the cross-base conversion overflows.
299            ///
300            /// ```
301            /// # use fugit::*;
302            #[doc = concat!("let d1 = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(10);")]
303            #[doc = concat!("let d2 = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(3);")]
304            ///
305            /// assert_eq!(d1.checked_rem(d2).unwrap().as_ticks(), 1);
306            /// ```
307            pub const fn checked_rem<const O_NOM: u64, const O_DENOM: u64>(
308                self,
309                other: Duration<$i, O_NOM, O_DENOM>,
310            ) -> Option<Self> {
311                if other.ticks == 0 {
312                    None
313                } else if Helpers::<NOM, DENOM, O_NOM, O_DENOM>::SAME_BASE {
314                    Some(Self::from_ticks(self.ticks % other.ticks))
315                } else {
316                    if let Some(lh) = other
317                        .ticks
318                        .checked_mul(Helpers::<NOM, DENOM, O_NOM, O_DENOM>::LD_TIMES_RN as $i)
319                    {
320                        let ticks = lh / Helpers::<NOM, DENOM, O_NOM, O_DENOM>::RD_TIMES_LN as $i;
321
322                        if ticks > 0 {
323                            Some(Self::from_ticks(self.ticks % ticks))
324                        } else {
325                            None
326                        }
327                    } else {
328                        None
329                    }
330                }
331            }
332
333            /// Divide this duration by an integer, rounding up (ceiling division).
334            ///
335            /// ```
336            /// # use fugit::*;
337            #[doc = concat!("let d = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(31);")]
338            ///
339            /// assert_eq!(d.div_ceil(3).as_ticks(), 11);
340            #[doc = concat!("let d = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(30);")]
341            /// assert_eq!(d.div_ceil(3).as_ticks(), 10);
342            /// ```
343            ///
344            /// # Panics
345            ///
346            /// This function will panic if `rhs` is zero.
347            #[inline]
348            #[track_caller]
349            pub const fn div_ceil(self, rhs: $i) -> Self {
350                Self::from_ticks(self.ticks.div_ceil(rhs))
351            }
352
353            /// Saturating duration addition. Computes `self + other`, saturating at the maximum value.
354            ///
355            /// ```
356            /// # use fugit::*;
357            #[doc = concat!("let d1 = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(1);")]
358            #[doc = concat!("let d2 = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(2);")]
359            ///
360            /// assert_eq!(d1.saturating_add(d2).as_ticks(), 3);
361            #[doc = concat!("assert_eq!(Duration::<", stringify!($i), ", 1, 1_000>::MAX.saturating_add(d1).as_ticks(), ", stringify!($i), "::MAX);")]
362            /// ```
363            pub const fn saturating_add<const O_NOM: u64, const O_DENOM: u64>(
364                self,
365                other: Duration<$i, O_NOM, O_DENOM>,
366            ) -> Self {
367                if let Some(result) = self.checked_add(other) {
368                    result
369                } else {
370                    Self::MAX
371                }
372            }
373
374            /// Saturating duration subtraction. Computes `self - other`, saturating at zero.
375            ///
376            /// ```
377            /// # use fugit::*;
378            #[doc = concat!("let d1 = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(10);")]
379            #[doc = concat!("let d2 = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(2);")]
380            ///
381            /// assert_eq!(d1.saturating_sub(d2).as_ticks(), 8);
382            /// assert_eq!(d2.saturating_sub(d1).as_ticks(), 0);
383            /// ```
384            pub const fn saturating_sub<const O_NOM: u64, const O_DENOM: u64>(
385                self,
386                other: Duration<$i, O_NOM, O_DENOM>,
387            ) -> Self {
388                if let Some(result) = self.checked_sub(other) {
389                    result
390                } else {
391                    Self::ZERO
392                }
393            }
394
395            /// Saturating duration multiplication. Computes `self * rhs`, saturating at the maximum value.
396            ///
397            /// ```
398            /// # use fugit::*;
399            #[doc = concat!("let d = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(10);")]
400            ///
401            /// assert_eq!(d.saturating_mul(3).as_ticks(), 30);
402            #[doc = concat!("assert_eq!(Duration::<", stringify!($i), ", 1, 1_000>::MAX.saturating_mul(2).as_ticks(), ", stringify!($i), "::MAX);")]
403            /// ```
404            #[inline]
405            pub const fn saturating_mul(self, rhs: $i) -> Self {
406                if let Some(result) = self.checked_mul(rhs) {
407                    result
408                } else {
409                    Self::MAX
410                }
411            }
412
413            #[doc = concat!("Const `cmp` for ", stringify!($i))]
414            #[inline(always)]
415            const fn _const_cmp(a: $i, b: $i) -> Ordering {
416                if a < b {
417                    Ordering::Less
418                } else if a > b {
419                    Ordering::Greater
420                } else {
421                    Ordering::Equal
422                }
423            }
424
425            /// Const partial comparison.
426            ///
427            /// Returns `None` if either side's tick value cannot be expressed in
428            /// the common base without overflowing the storage type.
429            ///
430            /// ```
431            /// # use fugit::*;
432            #[doc = concat!("let d1 = Duration::<", stringify!($i), ", 1, 100>::from_ticks(1);")]
433            #[doc = concat!("let d2 = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(1);")]
434            ///
435            /// assert_eq!(d1.const_partial_cmp(d2), Some(core::cmp::Ordering::Greater));
436            /// ```
437            #[inline]
438            pub const fn const_partial_cmp<const R_NOM: u64, const R_DENOM: u64>(
439                self,
440                other: Duration<$i, R_NOM, R_DENOM>
441            ) -> Option<Ordering> {
442                //
443                // We want to check:
444                //
445                // n_lh / d_lh * lh_ticks {cmp} n_rh / d_rh * rh_ticks
446                //
447                // simplify to
448                //
449                // n_lh * d_rh * lh_ticks {cmp} n_rh * d_lh * rh_ticks
450                //
451                // find gdc(n_lh * d_rh, n_rh * d_lh) and use that to make the constants minimal (done
452                // with the `helpers::Helpers` struct)
453                //
454                // then perform the comparison in a comparable basis
455                //
456
457                if Helpers::<NOM, DENOM, R_NOM, R_DENOM>::SAME_BASE {
458                    // If we are in the same base, comparison in trivial
459                    Some(Self::_const_cmp(self.ticks, other.ticks))
460                } else {
461                    let lh = self
462                        .ticks
463                        .checked_mul(Helpers::<NOM, DENOM, R_NOM, R_DENOM>::RD_TIMES_LN as $i);
464                    let rh = other
465                        .ticks
466                        .checked_mul(Helpers::<NOM, DENOM, R_NOM, R_DENOM>::LD_TIMES_RN as $i);
467
468                    if let (Some(lh), Some(rh)) = (lh, rh) {
469                        Some(Self::_const_cmp(lh, rh))
470                    } else {
471                        None
472                    }
473                }
474            }
475
476            /// Const equality check.
477            ///
478            /// Returns `false` (rather than panicking) if the cross-base
479            /// conversion overflows the storage type.
480            ///
481            /// ```
482            /// # use fugit::*;
483            #[doc = concat!("let d1 = Duration::<", stringify!($i), ", 1, 1_00>::from_ticks(1);")]
484            #[doc = concat!("let d2 = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(10);")]
485            ///
486            /// assert!(d1.const_eq(d2));
487            /// ```
488            #[inline]
489            pub const fn const_eq<const R_NOM: u64, const R_DENOM: u64>(
490                self,
491                other: Duration<$i, R_NOM, R_DENOM>
492            ) -> bool {
493                if Helpers::<NOM, DENOM, R_NOM, R_DENOM>::SAME_BASE {
494                    // If we are in the same base, comparison in trivial
495                    self.ticks == other.ticks
496                } else {
497                    let lh = self
498                        .ticks
499                        .checked_mul(Helpers::<NOM, DENOM, R_NOM, R_DENOM>::RD_TIMES_LN as $i);
500                    let rh = other
501                        .ticks
502                        .checked_mul(Helpers::<NOM, DENOM, R_NOM, R_DENOM>::LD_TIMES_RN as $i);
503
504                    if let (Some(lh), Some(rh)) = (lh, rh) {
505                        lh == rh
506                    } else {
507                        false
508                    }
509                }
510            }
511
512            /// Const try from, checking for overflow.
513            ///
514            /// ```
515            /// # use fugit::*;
516            #[doc = concat!("let d1 = Duration::<", stringify!($i), ", 1, 1_00>::from_ticks(1);")]
517            #[doc = concat!("let d2 = Duration::<", stringify!($i), ", 1, 1_000>::const_try_from(d1);")]
518            ///
519            /// assert_eq!(d2.unwrap().as_ticks(), 10);
520            /// ```
521            pub const fn const_try_from<const I_NOM: u64, const I_DENOM: u64>(
522                duration: Duration<$i, I_NOM, I_DENOM>,
523            ) -> Option<Self> {
524                if Helpers::<I_NOM, I_DENOM, NOM, DENOM>::SAME_BASE {
525                    Some(Self::from_ticks(duration.ticks))
526                } else {
527                    if let Some(lh) = (duration.ticks as u64)
528                        .checked_mul(Helpers::<I_NOM, I_DENOM, NOM, DENOM>::RD_TIMES_LN)
529                    {
530                        let ticks = div_round_nearest_u64(
531                            lh,
532                            Helpers::<I_NOM, I_DENOM, NOM, DENOM>::LD_TIMES_RN,
533                        );
534
535                        if ticks <= <$i>::MAX as u64 {
536                            Some(Self::from_ticks(ticks as $i))
537                        } else {
538                            None
539                        }
540                    } else {
541                        None
542                    }
543                }
544            }
545
546            /// Const try into, checking for overflow.
547            ///
548            /// ```
549            /// # use fugit::*;
550            #[doc = concat!("let d1 = Duration::<", stringify!($i), ", 1, 1_00>::from_ticks(1);")]
551            #[doc = concat!("let d2: Option<Duration::<", stringify!($i), ", 1, 1_000>> = d1.const_try_into();")]
552            ///
553            /// assert_eq!(d2.unwrap().as_ticks(), 10);
554            /// ```
555            #[inline]
556            pub const fn const_try_into<const O_NOM: u64, const O_DENOM: u64>(
557                self,
558            ) -> Option<Duration<$i, O_NOM, O_DENOM>> {
559                Duration::<$i, O_NOM, O_DENOM>::const_try_from(self)
560            }
561
562            /// Convert to a rate. Returns `None` if this duration is zero.
563            ///
564            /// ```
565            /// # use fugit::*;
566            #[doc = concat!("let d1 = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(2);")]
567            #[doc = concat!("let r1: Option<Rate::<", stringify!($i), ", 1, 1>> = d1.try_to_rate();")]
568            ///
569            /// assert_eq!(r1.unwrap().to_raw(), 500);
570            /// ```
571            #[inline]
572            pub const fn try_to_rate<const O_NOM: u64, const O_DENOM: u64>(
573                self,
574            ) -> Option<Rate<$i, O_NOM, O_DENOM>> {
575                Rate::<$i, O_NOM, O_DENOM>::try_from_duration(self)
576            }
577
578            /// Convert to a rate. Panics if this duration is zero.
579            #[inline]
580            #[track_caller]
581            pub const fn to_rate<const O_NOM: u64, const O_DENOM: u64>(
582                self,
583            ) -> Rate<$i, O_NOM, O_DENOM> {
584                if let Some(v) = self.try_to_rate() {
585                    v
586                } else {
587                    panic!("Into rate failed, divide-by-zero!");
588                }
589            }
590
591            /// Convert from a rate. Returns `None` if the rate is zero.
592            ///
593            /// ```
594            /// # use fugit::*;
595            #[doc = concat!("let r1 = Rate::<", stringify!($i), ", 1, 1>::from_raw(1);")]
596            #[doc = concat!("let d1 = Duration::<", stringify!($i), ", 1, 1_000>::try_from_rate(r1);")]
597            ///
598            /// assert_eq!(d1.unwrap().as_ticks(), 1_000);
599            /// ```
600            #[inline]
601            pub const fn try_from_rate<const I_NOM: u64, const I_DENOM: u64>(
602                rate: Rate<$i, I_NOM, I_DENOM>,
603            ) -> Option<Self> {
604                const {
605                    assert!(
606                        Helpers::<I_NOM, I_DENOM, NOM, DENOM>::RATE_TO_DURATION_NUMERATOR <= <$i>::MAX as u64,
607                        concat!("RATE_TO_DURATION_NUMERATOR doesn't fit in ", stringify!($i), " for this Rate/Duration combination")
608                    );
609                }
610                if rate.raw > 0 {
611                    Some(Self::from_ticks(
612                        Helpers::<I_NOM, I_DENOM, NOM, DENOM>::RATE_TO_DURATION_NUMERATOR as $i
613                        / rate.raw
614                    ))
615                } else {
616                    None
617                }
618            }
619
620            /// Convert from a rate. Panics if the rate is zero.
621            #[inline]
622            #[track_caller]
623            pub const fn from_rate<const I_NOM: u64, const I_DENOM: u64>(
624                rate: Rate<$i, I_NOM, I_DENOM>,
625            ) -> Self {
626                if let Some(v) = Self::try_from_rate(rate) {
627                    v
628                } else {
629                    panic!("From rate failed, divide-by-zero!");
630                }
631            }
632
633            /// Convert between bases for a duration, rounds to nearest.
634            ///
635            /// Unfortunately not a `From` impl due to collision with the std lib.
636            ///
637            /// ```
638            /// # use fugit::*;
639            #[doc = concat!("let d1 = Duration::<", stringify!($i), ", 1, 100>::from_ticks(1);")]
640            #[doc = concat!("let d2: Duration::<", stringify!($i), ", 1, 1_000> = d1.convert();")]
641            ///
642            /// assert_eq!(d2.as_ticks(), 10);
643            /// ```
644            /// Can be used in const contexts. Compilation will fail if the conversion causes overflow
645            /// ```compile_fail
646            /// # use fugit::*;
647            #[doc = concat!("const TICKS: ", stringify!($i), "= ", stringify!($i), "::MAX - 10;")]
648            #[doc = concat!("const D1: Duration::<", stringify!($i), ", 1, 100> = Duration::<", stringify!($i), ", 1, 100>::from_ticks(TICKS);")]
649            /// // Fails conversion due to tick overflow
650            #[doc = concat!("const D2: Duration::<", stringify!($i), ", 1, 200> = D1.convert();")]
651            #[inline]
652            #[track_caller]
653            pub const fn convert<const O_NOM: u64, const O_DENOM: u64>(
654                self,
655            ) -> Duration<$i, O_NOM, O_DENOM> {
656                if let Some(v) = self.const_try_into() {
657                    v
658                } else {
659                    panic!("Convert failed!");
660                }
661            }
662
663            shorthand!($i, 1, 1_000_000_000_000, from_picos, as_picos, from_picos_at_least, "picoseconds");
664            shorthand!($i, 1, 1_000_000_000, from_nanos, as_nanos, from_nanos_at_least, "nanoseconds");
665            shorthand!($i, 1, 1_000_000, from_micros, as_micros, from_micros_at_least, "microseconds");
666            shorthand!($i, 1, 1_000, from_millis, as_millis, from_millis_at_least, "milliseconds");
667            shorthand!($i, 1, 1, from_secs, as_secs, from_secs_at_least, "seconds");
668            shorthand!($i, 60, 1, from_minutes, as_minutes, from_minutes_at_least, "minutes");
669            shorthand!($i, 3600, 1, from_hours, as_hours, from_hours_at_least, "hours");
670
671            /// Convert the Duration to a floating point number of seconds.
672            #[inline]
673            pub const fn as_secs_f32(&self) -> f32 {
674                let factor = const { NOM as f32 / DENOM as f32 };
675                factor * self.ticks as f32
676            }
677
678            /// Convert the Duration to a floating point number of seconds.
679            #[inline]
680            pub const fn as_secs_f64(&self) -> f64 {
681                let factor = const { NOM as f64 / DENOM as f64 };
682                factor * self.ticks as f64
683            }
684
685            /// Create a duration from a floating point number of seconds.
686            ///
687            /// The value is rounded to the nearest tick.
688            ///
689            /// ```
690            /// # use fugit::*;
691            #[doc = concat!("let d = Duration::<", stringify!($i), ", 1, 1_000>::from_secs_f32(1.5);")]
692            ///
693            /// assert_eq!(d.as_ticks(), 1_500);
694            ///
695            #[doc = concat!("let d = Duration::<", stringify!($i), ", 1, 1_000>::from_secs_f32(1.5005);")]
696            /// assert_eq!(d.as_ticks(), 1_501);
697            /// ```
698            #[inline]
699            pub const fn from_secs_f32(secs: f32) -> Self {
700                let factor = const { DENOM as f32 / NOM as f32 };
701                Self::from_ticks((secs * factor + 0.5) as $i)
702            }
703
704            /// Create a duration from a floating point number of seconds.
705            ///
706            /// The value is rounded to the nearest tick.
707            ///
708            /// ```
709            /// # use fugit::*;
710            #[doc = concat!("let d = Duration::<", stringify!($i), ", 1, 1_000>::from_secs_f64(1.5);")]
711            ///
712            /// assert_eq!(d.as_ticks(), 1_500);
713            ///
714            #[doc = concat!("let d = Duration::<", stringify!($i), ", 1, 1_000>::from_secs_f64(1.5005);")]
715            /// assert_eq!(d.as_ticks(), 1_501);
716            /// ```
717            #[inline]
718            pub const fn from_secs_f64(secs: f64) -> Self {
719                let factor = const { DENOM as f64 / NOM as f64 };
720                Self::from_ticks((secs * factor + 0.5) as $i)
721            }
722
723            /// Period of a hertz rate. Panics if `val` is zero.
724            #[inline]
725            #[track_caller]
726            #[allow(non_snake_case)]
727            pub const fn Hz(val: $i) -> Self {
728                Self::from_rate(crate::Hertz::<$i>::from_raw(val))
729            }
730
731            /// Period of a kilohertz rate. Panics if `val` is zero.
732            #[inline]
733            #[track_caller]
734            #[allow(non_snake_case)]
735            pub const fn kHz(val: $i) -> Self {
736                Self::from_rate(crate::Kilohertz::<$i>::from_raw(val))
737            }
738
739            /// Period of a megahertz rate. Panics if `val` is zero.
740            #[inline]
741            #[track_caller]
742            #[allow(non_snake_case)]
743            pub const fn MHz(val: $i) -> Self {
744                Self::from_rate(crate::Megahertz::<$i>::from_raw(val))
745            }
746        }
747
748        impl<const L_NOM: u64, const L_DENOM: u64, const R_NOM: u64, const R_DENOM: u64>
749            PartialOrd<Duration<$i, R_NOM, R_DENOM>> for Duration<$i, L_NOM, L_DENOM>
750        {
751            #[inline]
752            fn partial_cmp(&self, other: &Duration<$i, R_NOM, R_DENOM>) -> Option<Ordering> {
753                self.const_partial_cmp(*other)
754            }
755        }
756
757        impl<const NOM: u64, const DENOM: u64> Ord for Duration<$i, NOM, DENOM> {
758            #[inline]
759            fn cmp(&self, other: &Self) -> Ordering {
760                Self::_const_cmp(self.ticks, other.ticks)
761            }
762        }
763
764        impl<const L_NOM: u64, const L_DENOM: u64, const R_NOM: u64, const R_DENOM: u64>
765            PartialEq<Duration<$i, R_NOM, R_DENOM>> for Duration<$i, L_NOM, L_DENOM>
766        {
767            #[inline]
768            fn eq(&self, other: &Duration<$i, R_NOM, R_DENOM>) -> bool {
769                self.const_eq(*other)
770            }
771        }
772
773        impl<const NOM: u64, const DENOM: u64> Eq for Duration<$i, NOM, DENOM> {}
774
775        // Duration - Duration = Duration (only same base until const_generics_defaults is
776        // stabilized)
777        impl<const NOM: u64, const DENOM: u64> ops::Sub for Duration<$i, NOM, DENOM>
778        {
779            type Output = Self;
780
781            #[inline]
782            #[track_caller]
783            fn sub(self, other: Self) -> Self::Output {
784                if let Some(v) = self.checked_sub(other) {
785                    v
786                } else {
787                    panic!("Sub failed!");
788                }
789            }
790        }
791
792        // Duration -= Duration
793        impl<const NOM: u64, const DENOM: u64> ops::SubAssign for Duration<$i, NOM, DENOM>
794        {
795            #[inline]
796            #[track_caller]
797            fn sub_assign(&mut self, other: Self) {
798                *self = *self - other;
799            }
800        }
801
802        // Duration + Duration = Duration (only same base until const_generics_defaults is
803        // stabilized)
804        impl<const NOM: u64, const DENOM: u64> ops::Add for Duration<$i, NOM, DENOM>
805        {
806            type Output = Self;
807
808            #[inline]
809            #[track_caller]
810            fn add(self, other: Self) -> Self::Output {
811                if let Some(v) = self.checked_add(other) {
812                    v
813                } else {
814                    panic!("Add failed!");
815                }
816            }
817        }
818
819        // Duration += Duration
820        impl<const NOM: u64, const DENOM: u64> ops::AddAssign for Duration<$i, NOM, DENOM>
821        {
822            #[inline]
823            #[track_caller]
824            fn add_assign(&mut self, other: Self) {
825                *self = *self + other;
826            }
827        }
828
829        // integer * Duration = Duration
830        impl<const NOM: u64, const DENOM: u64> ops::Mul<Duration<$i, NOM, DENOM>> for u32 {
831            type Output = Duration<$i, NOM, DENOM>;
832
833            #[inline]
834            #[track_caller]
835            fn mul(self, mut other: Duration<$i, NOM, DENOM>) -> Self::Output {
836                other.ticks *= self as $i;
837                other
838            }
839        }
840
841        // Duration * integer = Duration
842        impl<const NOM: u64, const DENOM: u64> ops::Mul<u32> for Duration<$i, NOM, DENOM> {
843            type Output = Self;
844
845            #[inline]
846            #[track_caller]
847            fn mul(mut self, other: u32) -> Self::Output {
848                self.ticks *= other as $i;
849                self
850            }
851        }
852
853        // Duration *= integer
854        impl<const NOM: u64, const DENOM: u64> ops::MulAssign<u32>
855            for Duration<$i, NOM, DENOM>
856        {
857            #[inline]
858            #[track_caller]
859            fn mul_assign(&mut self, other: u32) {
860                *self = *self * other;
861            }
862        }
863
864        // Duration / integer = Duration
865        impl<const NOM: u64, const DENOM: u64> ops::Div<u32> for Duration<$i, NOM, DENOM> {
866            type Output = Self;
867
868            #[inline]
869            #[track_caller]
870            fn div(mut self, other: u32) -> Self::Output {
871                self.ticks /= other as $i;
872                self
873            }
874        }
875
876        // Duration /= integer
877        impl<const NOM: u64, const DENOM: u64> ops::DivAssign<u32>
878            for Duration<$i, NOM, DENOM>
879        {
880            #[inline]
881            #[track_caller]
882            fn div_assign(&mut self, other: u32) {
883                *self = *self / other;
884            }
885        }
886
887        // Duration % Duration = Duration (only same base until const_generics_defaults is
888        // stabilized)
889        impl<const NOM: u64, const DENOM: u64> ops::Rem for Duration<$i, NOM, DENOM>
890        {
891            type Output = Self;
892
893            #[inline]
894            #[track_caller]
895            fn rem(self, other: Self) -> Self::Output {
896                if let Some(v) = self.checked_rem(other) {
897                    v
898                } else {
899                    panic!("Rem failed!");
900                }
901            }
902        }
903
904        // Duration %= Duration
905        impl<const NOM: u64, const DENOM: u64> ops::RemAssign for Duration<$i, NOM, DENOM>
906        {
907            #[inline]
908            #[track_caller]
909            fn rem_assign(&mut self, other: Self) {
910                *self = *self % other;
911            }
912        }
913
914        // Duration / Duration = integer
915        impl<const L_NOM: u64, const L_DENOM: u64, const R_NOM: u64, const R_DENOM: u64> ops::Div<Duration<$i, R_NOM, R_DENOM>>
916            for Duration<$i, L_NOM, L_DENOM>
917        {
918            type Output = $i;
919
920            #[inline]
921            #[track_caller]
922            fn div(self, other: Duration<$i, R_NOM, R_DENOM>) -> Self::Output {
923                let conv: Duration<$i, R_NOM, R_DENOM> = self.convert();
924                conv.ticks / other.ticks
925            }
926        }
927
928        #[cfg(feature = "defmt")]
929        impl<const NOM: u64, const DENOM: u64> defmt::Format for Duration<$i, NOM, DENOM>
930        {
931            fn format(&self, f: defmt::Formatter) {
932                if NOM == 3_600 && DENOM == 1 {
933                    defmt::write!(f, "{} h", self.ticks)
934                } else if NOM == 60 && DENOM == 1 {
935                    defmt::write!(f, "{} min", self.ticks)
936                } else if NOM == 1 && DENOM == 1 {
937                    defmt::write!(f, "{} s", self.ticks)
938                } else if NOM == 1 && DENOM == 1_000 {
939                    defmt::write!(f, "{} ms", self.ticks)
940                } else if NOM == 1 && DENOM == 1_000_000 {
941                    defmt::write!(f, "{} us", self.ticks)
942                } else if NOM == 1 && DENOM == 1_000_000_000 {
943                    defmt::write!(f, "{} ns", self.ticks)
944                } else {
945                    defmt::write!(f, "{} ticks @ ({}/{})", self.ticks, NOM, DENOM)
946                }
947            }
948        }
949
950        impl<const NOM: u64, const DENOM: u64> core::fmt::Display for Duration<$i, NOM, DENOM> {
951            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
952                if NOM == 3_600 && DENOM == 1 {
953                    write!(f, "{} h", self.ticks)
954                } else if NOM == 60 && DENOM == 1 {
955                    write!(f, "{} min", self.ticks)
956                } else if NOM == 1 && DENOM == 1 {
957                    write!(f, "{} s", self.ticks)
958                } else if NOM == 1 && DENOM == 1_000 {
959                    write!(f, "{} ms", self.ticks)
960                } else if NOM == 1 && DENOM == 1_000_000 {
961                    write!(f, "{} us", self.ticks)
962                } else if NOM == 1 && DENOM == 1_000_000_000 {
963                    write!(f, "{} ns", self.ticks)
964                } else {
965                    write!(f, "{} ticks @ ({}/{})", self.ticks, NOM, DENOM)
966                }
967            }
968        }
969    };
970}
971
972impl_duration_for_integer!(u32);
973impl_duration_for_integer!(u64);
974
975//
976// Conversion from core::time::Duration
977//
978
979impl<const NOM: u64, const DENOM: u64> convert::TryFrom<core::time::Duration>
980    for Duration<u32, NOM, DENOM>
981{
982    type Error = ();
983
984    #[inline]
985    fn try_from(val: core::time::Duration) -> Result<Self, Self::Error> {
986        Duration::<u64, NOM, DENOM>::try_from(val)?.try_into()
987    }
988}
989
990impl<const NOM: u64, const DENOM: u64> convert::TryFrom<core::time::Duration>
991    for Duration<u64, NOM, DENOM>
992{
993    type Error = ();
994
995    #[inline]
996    fn try_from(val: core::time::Duration) -> Result<Self, Self::Error> {
997        let secs_duration = SecsDurationU64::from_ticks(val.as_secs());
998        let nanos_duration = NanosDurationU64::from_ticks(val.subsec_nanos() as u64);
999
1000        let secs_converted: Self = secs_duration.const_try_into().ok_or(())?;
1001        let nanos_converted: Self = nanos_duration.const_try_into().ok_or(())?;
1002
1003        secs_converted.checked_add(nanos_converted).ok_or(())
1004    }
1005}
1006
1007//
1008// Conversion to core::time::Duration
1009//
1010
1011impl<const NOM: u64, const DENOM: u64> From<Duration<u32, NOM, DENOM>> for core::time::Duration {
1012    #[inline]
1013    fn from(val: Duration<u32, NOM, DENOM>) -> Self {
1014        let val_u64: Duration<u64, NOM, DENOM> = val.into();
1015        core::time::Duration::from(val_u64)
1016    }
1017}
1018
1019impl<const NOM: u64, const DENOM: u64> From<Duration<u64, NOM, DENOM>> for core::time::Duration {
1020    #[inline]
1021    fn from(val: Duration<u64, NOM, DENOM>) -> Self {
1022        let secs = val.as_secs();
1023        let secs_duration = Duration::<u64, NOM, DENOM>::from_secs(secs);
1024        let remainder = val.saturating_sub(secs_duration);
1025        let nanos = remainder.as_nanos() as u32;
1026
1027        core::time::Duration::new(secs, nanos)
1028    }
1029}
1030
1031//
1032// Operations between u32 and u64 Durations
1033//
1034
1035impl<const NOM: u64, const DENOM: u64> From<Duration<u32, NOM, DENOM>>
1036    for Duration<u64, NOM, DENOM>
1037{
1038    #[inline]
1039    fn from(val: Duration<u32, NOM, DENOM>) -> Self {
1040        Duration::<u64, NOM, DENOM>::from_ticks(val.as_ticks() as u64)
1041    }
1042}
1043
1044impl<const NOM: u64, const DENOM: u64> convert::TryFrom<Duration<u64, NOM, DENOM>>
1045    for Duration<u32, NOM, DENOM>
1046{
1047    type Error = ();
1048
1049    #[inline]
1050    fn try_from(val: Duration<u64, NOM, DENOM>) -> Result<Self, ()> {
1051        Ok(Duration::<u32, NOM, DENOM>::from_ticks(
1052            val.as_ticks().try_into().map_err(|_| ())?,
1053        ))
1054    }
1055}
1056
1057// Duration - Duration = Duration (to make shorthands work, until const_generics_defaults is
1058// stabilized)
1059impl<const NOM: u64, const DENOM: u64> ops::Sub<Duration<u32, NOM, DENOM>>
1060    for Duration<u64, NOM, DENOM>
1061{
1062    type Output = Self;
1063
1064    #[inline]
1065    #[track_caller]
1066    fn sub(self, other: Duration<u32, NOM, DENOM>) -> Self::Output {
1067        if let Some(v) = self.checked_sub(Self::from_ticks(other.as_ticks() as u64)) {
1068            v
1069        } else {
1070            panic!("Sub failed!");
1071        }
1072    }
1073}
1074
1075// Duration -= Duration (to make shorthands work, until const_generics_defaults is stabilized)
1076impl<const NOM: u64, const DENOM: u64> ops::SubAssign<Duration<u32, NOM, DENOM>>
1077    for Duration<u64, NOM, DENOM>
1078{
1079    #[inline]
1080    #[track_caller]
1081    fn sub_assign(&mut self, other: Duration<u32, NOM, DENOM>) {
1082        *self = *self - other;
1083    }
1084}
1085
1086// Duration + Duration = Duration (to make shorthands work, until const_generics_defaults is
1087// stabilized)
1088impl<const NOM: u64, const DENOM: u64> ops::Add<Duration<u32, NOM, DENOM>>
1089    for Duration<u64, NOM, DENOM>
1090{
1091    type Output = Self;
1092
1093    #[inline]
1094    #[track_caller]
1095    fn add(self, other: Duration<u32, NOM, DENOM>) -> Self::Output {
1096        if let Some(v) = self.checked_add(Self::from_ticks(other.as_ticks() as u64)) {
1097            v
1098        } else {
1099            panic!("Add failed!");
1100        }
1101    }
1102}
1103
1104// Duration += Duration (to make shorthands work, until const_generics_defaults is stabilized)
1105impl<const NOM: u64, const DENOM: u64> ops::AddAssign<Duration<u32, NOM, DENOM>>
1106    for Duration<u64, NOM, DENOM>
1107{
1108    #[inline]
1109    #[track_caller]
1110    fn add_assign(&mut self, other: Duration<u32, NOM, DENOM>) {
1111        *self = *self + other;
1112    }
1113}
1114
1115impl<const L_NOM: u64, const L_DENOM: u64, const R_NOM: u64, const R_DENOM: u64>
1116    PartialOrd<Duration<u32, R_NOM, R_DENOM>> for Duration<u64, L_NOM, L_DENOM>
1117{
1118    #[inline]
1119    fn partial_cmp(&self, other: &Duration<u32, R_NOM, R_DENOM>) -> Option<Ordering> {
1120        self.partial_cmp(&Duration::<u64, R_NOM, R_DENOM>::from_ticks(
1121            other.as_ticks() as u64,
1122        ))
1123    }
1124}
1125
1126impl<const L_NOM: u64, const L_DENOM: u64, const R_NOM: u64, const R_DENOM: u64>
1127    PartialEq<Duration<u32, R_NOM, R_DENOM>> for Duration<u64, L_NOM, L_DENOM>
1128{
1129    #[inline]
1130    fn eq(&self, other: &Duration<u32, R_NOM, R_DENOM>) -> bool {
1131        self.eq(&Duration::<u64, R_NOM, R_DENOM>::from_ticks(
1132            other.as_ticks() as u64,
1133        ))
1134    }
1135}
1136
1137impl<const L_NOM: u64, const L_DENOM: u64, const R_NOM: u64, const R_DENOM: u64>
1138    PartialOrd<Duration<u64, R_NOM, R_DENOM>> for Duration<u32, L_NOM, L_DENOM>
1139{
1140    #[inline]
1141    fn partial_cmp(&self, other: &Duration<u64, R_NOM, R_DENOM>) -> Option<Ordering> {
1142        Duration::<u64, L_NOM, L_DENOM>::from_ticks(self.ticks as u64).partial_cmp(other)
1143    }
1144}
1145
1146impl<const L_NOM: u64, const L_DENOM: u64, const R_NOM: u64, const R_DENOM: u64>
1147    PartialEq<Duration<u64, R_NOM, R_DENOM>> for Duration<u32, L_NOM, L_DENOM>
1148{
1149    #[inline]
1150    fn eq(&self, other: &Duration<u64, R_NOM, R_DENOM>) -> bool {
1151        Duration::<u64, L_NOM, L_DENOM>::from_ticks(self.ticks as u64).eq(other)
1152    }
1153}
1154
1155/// Extension trait for simple short-hands for u32 Durations
1156pub trait ExtU32 {
1157    /// Shorthand for creating a duration which represents picoseconds.
1158    fn picos<const NOM: u64, const DENOM: u64>(self) -> Duration<u32, NOM, DENOM>;
1159
1160    /// Shorthand for creating a duration which represents nanoseconds.
1161    fn nanos<const NOM: u64, const DENOM: u64>(self) -> Duration<u32, NOM, DENOM>;
1162
1163    /// Shorthand for creating a duration which represents microseconds.
1164    fn micros<const NOM: u64, const DENOM: u64>(self) -> Duration<u32, NOM, DENOM>;
1165
1166    /// Shorthand for creating a duration which represents milliseconds.
1167    fn millis<const NOM: u64, const DENOM: u64>(self) -> Duration<u32, NOM, DENOM>;
1168
1169    /// Shorthand for creating a duration which represents seconds.
1170    fn secs<const NOM: u64, const DENOM: u64>(self) -> Duration<u32, NOM, DENOM>;
1171
1172    /// Shorthand for creating a duration which represents minutes.
1173    fn minutes<const NOM: u64, const DENOM: u64>(self) -> Duration<u32, NOM, DENOM>;
1174
1175    /// Shorthand for creating a duration which represents hours.
1176    fn hours<const NOM: u64, const DENOM: u64>(self) -> Duration<u32, NOM, DENOM>;
1177}
1178
1179impl ExtU32 for u32 {
1180    #[inline]
1181    fn picos<const NOM: u64, const DENOM: u64>(self) -> Duration<u32, NOM, DENOM> {
1182        Duration::<u32, NOM, DENOM>::from_picos(self)
1183    }
1184
1185    #[inline]
1186    fn nanos<const NOM: u64, const DENOM: u64>(self) -> Duration<u32, NOM, DENOM> {
1187        Duration::<u32, NOM, DENOM>::from_nanos(self)
1188    }
1189
1190    #[inline]
1191    fn micros<const NOM: u64, const DENOM: u64>(self) -> Duration<u32, NOM, DENOM> {
1192        Duration::<u32, NOM, DENOM>::from_micros(self)
1193    }
1194
1195    #[inline]
1196    fn millis<const NOM: u64, const DENOM: u64>(self) -> Duration<u32, NOM, DENOM> {
1197        Duration::<u32, NOM, DENOM>::from_millis(self)
1198    }
1199
1200    #[inline]
1201    fn secs<const NOM: u64, const DENOM: u64>(self) -> Duration<u32, NOM, DENOM> {
1202        Duration::<u32, NOM, DENOM>::from_secs(self)
1203    }
1204
1205    #[inline]
1206    fn minutes<const NOM: u64, const DENOM: u64>(self) -> Duration<u32, NOM, DENOM> {
1207        Duration::<u32, NOM, DENOM>::from_minutes(self)
1208    }
1209
1210    #[inline]
1211    fn hours<const NOM: u64, const DENOM: u64>(self) -> Duration<u32, NOM, DENOM> {
1212        Duration::<u32, NOM, DENOM>::from_hours(self)
1213    }
1214}
1215
1216/// Extension trait for simple short-hands for u32 Durations (ceil rounded)
1217pub trait ExtU32Ceil {
1218    /// Shorthand for creating a duration which represents picoseconds.
1219    fn picos_at_least<const NOM: u64, const DENOM: u64>(self) -> Duration<u32, NOM, DENOM>;
1220
1221    /// Shorthand for creating a duration which represents nanoseconds.
1222    fn nanos_at_least<const NOM: u64, const DENOM: u64>(self) -> Duration<u32, NOM, DENOM>;
1223
1224    /// Shorthand for creating a duration which represents microseconds.
1225    fn micros_at_least<const NOM: u64, const DENOM: u64>(self) -> Duration<u32, NOM, DENOM>;
1226
1227    /// Shorthand for creating a duration which represents milliseconds.
1228    fn millis_at_least<const NOM: u64, const DENOM: u64>(self) -> Duration<u32, NOM, DENOM>;
1229
1230    /// Shorthand for creating a duration which represents seconds.
1231    fn secs_at_least<const NOM: u64, const DENOM: u64>(self) -> Duration<u32, NOM, DENOM>;
1232
1233    /// Shorthand for creating a duration which represents minutes.
1234    fn minutes_at_least<const NOM: u64, const DENOM: u64>(self) -> Duration<u32, NOM, DENOM>;
1235
1236    /// Shorthand for creating a duration which represents hours.
1237    fn hours_at_least<const NOM: u64, const DENOM: u64>(self) -> Duration<u32, NOM, DENOM>;
1238}
1239
1240impl ExtU32Ceil for u32 {
1241    #[inline]
1242    fn picos_at_least<const NOM: u64, const DENOM: u64>(self) -> Duration<u32, NOM, DENOM> {
1243        Duration::<u32, NOM, DENOM>::from_picos_at_least(self)
1244    }
1245
1246    #[inline]
1247    fn nanos_at_least<const NOM: u64, const DENOM: u64>(self) -> Duration<u32, NOM, DENOM> {
1248        Duration::<u32, NOM, DENOM>::from_nanos_at_least(self)
1249    }
1250
1251    #[inline]
1252    fn micros_at_least<const NOM: u64, const DENOM: u64>(self) -> Duration<u32, NOM, DENOM> {
1253        Duration::<u32, NOM, DENOM>::from_micros_at_least(self)
1254    }
1255
1256    #[inline]
1257    fn millis_at_least<const NOM: u64, const DENOM: u64>(self) -> Duration<u32, NOM, DENOM> {
1258        Duration::<u32, NOM, DENOM>::from_millis_at_least(self)
1259    }
1260
1261    #[inline]
1262    fn secs_at_least<const NOM: u64, const DENOM: u64>(self) -> Duration<u32, NOM, DENOM> {
1263        Duration::<u32, NOM, DENOM>::from_secs_at_least(self)
1264    }
1265
1266    #[inline]
1267    fn minutes_at_least<const NOM: u64, const DENOM: u64>(self) -> Duration<u32, NOM, DENOM> {
1268        Duration::<u32, NOM, DENOM>::from_minutes_at_least(self)
1269    }
1270
1271    #[inline]
1272    fn hours_at_least<const NOM: u64, const DENOM: u64>(self) -> Duration<u32, NOM, DENOM> {
1273        Duration::<u32, NOM, DENOM>::from_hours_at_least(self)
1274    }
1275}
1276
1277/// Extension trait for simple short-hands for u64 Durations
1278pub trait ExtU64 {
1279    /// Shorthand for creating a duration which represents picoseconds.
1280    fn picos<const NOM: u64, const DENOM: u64>(self) -> Duration<u64, NOM, DENOM>;
1281
1282    /// Shorthand for creating a duration which represents nanoseconds.
1283    fn nanos<const NOM: u64, const DENOM: u64>(self) -> Duration<u64, NOM, DENOM>;
1284
1285    /// Shorthand for creating a duration which represents microseconds.
1286    fn micros<const NOM: u64, const DENOM: u64>(self) -> Duration<u64, NOM, DENOM>;
1287
1288    /// Shorthand for creating a duration which represents milliseconds.
1289    fn millis<const NOM: u64, const DENOM: u64>(self) -> Duration<u64, NOM, DENOM>;
1290
1291    /// Shorthand for creating a duration which represents seconds.
1292    fn secs<const NOM: u64, const DENOM: u64>(self) -> Duration<u64, NOM, DENOM>;
1293
1294    /// Shorthand for creating a duration which represents minutes.
1295    fn minutes<const NOM: u64, const DENOM: u64>(self) -> Duration<u64, NOM, DENOM>;
1296
1297    /// Shorthand for creating a duration which represents hours.
1298    fn hours<const NOM: u64, const DENOM: u64>(self) -> Duration<u64, NOM, DENOM>;
1299}
1300
1301impl ExtU64 for u64 {
1302    #[inline]
1303    fn picos<const NOM: u64, const DENOM: u64>(self) -> Duration<u64, NOM, DENOM> {
1304        Duration::<u64, NOM, DENOM>::from_picos(self)
1305    }
1306
1307    #[inline]
1308    fn nanos<const NOM: u64, const DENOM: u64>(self) -> Duration<u64, NOM, DENOM> {
1309        Duration::<u64, NOM, DENOM>::from_nanos(self)
1310    }
1311
1312    #[inline]
1313    fn micros<const NOM: u64, const DENOM: u64>(self) -> Duration<u64, NOM, DENOM> {
1314        Duration::<u64, NOM, DENOM>::from_micros(self)
1315    }
1316
1317    #[inline]
1318    fn millis<const NOM: u64, const DENOM: u64>(self) -> Duration<u64, NOM, DENOM> {
1319        Duration::<u64, NOM, DENOM>::from_millis(self)
1320    }
1321
1322    #[inline]
1323    fn secs<const NOM: u64, const DENOM: u64>(self) -> Duration<u64, NOM, DENOM> {
1324        Duration::<u64, NOM, DENOM>::from_secs(self)
1325    }
1326
1327    #[inline]
1328    fn minutes<const NOM: u64, const DENOM: u64>(self) -> Duration<u64, NOM, DENOM> {
1329        Duration::<u64, NOM, DENOM>::from_minutes(self)
1330    }
1331
1332    #[inline]
1333    fn hours<const NOM: u64, const DENOM: u64>(self) -> Duration<u64, NOM, DENOM> {
1334        Duration::<u64, NOM, DENOM>::from_hours(self)
1335    }
1336}
1337
1338/// Extension trait for simple short-hands for u64 Durations (ceil rounded)
1339pub trait ExtU64Ceil {
1340    /// Shorthand for creating a duration which represents picoseconds.
1341    fn picos_at_least<const NOM: u64, const DENOM: u64>(self) -> Duration<u64, NOM, DENOM>;
1342
1343    /// Shorthand for creating a duration which represents nanoseconds.
1344    fn nanos_at_least<const NOM: u64, const DENOM: u64>(self) -> Duration<u64, NOM, DENOM>;
1345
1346    /// Shorthand for creating a duration which represents microseconds.
1347    fn micros_at_least<const NOM: u64, const DENOM: u64>(self) -> Duration<u64, NOM, DENOM>;
1348
1349    /// Shorthand for creating a duration which represents milliseconds.
1350    fn millis_at_least<const NOM: u64, const DENOM: u64>(self) -> Duration<u64, NOM, DENOM>;
1351
1352    /// Shorthand for creating a duration which represents seconds.
1353    fn secs_at_least<const NOM: u64, const DENOM: u64>(self) -> Duration<u64, NOM, DENOM>;
1354
1355    /// Shorthand for creating a duration which represents minutes.
1356    fn minutes_at_least<const NOM: u64, const DENOM: u64>(self) -> Duration<u64, NOM, DENOM>;
1357
1358    /// Shorthand for creating a duration which represents hours.
1359    fn hours_at_least<const NOM: u64, const DENOM: u64>(self) -> Duration<u64, NOM, DENOM>;
1360}
1361
1362impl ExtU64Ceil for u64 {
1363    #[inline]
1364    fn picos_at_least<const NOM: u64, const DENOM: u64>(self) -> Duration<u64, NOM, DENOM> {
1365        Duration::<u64, NOM, DENOM>::from_picos_at_least(self)
1366    }
1367
1368    #[inline]
1369    fn nanos_at_least<const NOM: u64, const DENOM: u64>(self) -> Duration<u64, NOM, DENOM> {
1370        Duration::<u64, NOM, DENOM>::from_nanos_at_least(self)
1371    }
1372
1373    #[inline]
1374    fn micros_at_least<const NOM: u64, const DENOM: u64>(self) -> Duration<u64, NOM, DENOM> {
1375        Duration::<u64, NOM, DENOM>::from_micros_at_least(self)
1376    }
1377
1378    #[inline]
1379    fn millis_at_least<const NOM: u64, const DENOM: u64>(self) -> Duration<u64, NOM, DENOM> {
1380        Duration::<u64, NOM, DENOM>::from_millis_at_least(self)
1381    }
1382
1383    #[inline]
1384    fn secs_at_least<const NOM: u64, const DENOM: u64>(self) -> Duration<u64, NOM, DENOM> {
1385        Duration::<u64, NOM, DENOM>::from_secs_at_least(self)
1386    }
1387
1388    #[inline]
1389    fn minutes_at_least<const NOM: u64, const DENOM: u64>(self) -> Duration<u64, NOM, DENOM> {
1390        Duration::<u64, NOM, DENOM>::from_minutes_at_least(self)
1391    }
1392
1393    #[inline]
1394    fn hours_at_least<const NOM: u64, const DENOM: u64>(self) -> Duration<u64, NOM, DENOM> {
1395        Duration::<u64, NOM, DENOM>::from_hours_at_least(self)
1396    }
1397}