embedded_time/
duration.rs

1//! Duration types/units
2
3pub use crate::fraction::Fraction;
4use crate::{
5    fixed_point::{self, FixedPoint},
6    rate,
7    time_int::TimeInt,
8    ConversionError,
9};
10use core::{
11    convert::TryFrom,
12    hash::{Hash, Hasher},
13    mem::size_of,
14    prelude::v1::*,
15};
16#[doc(hidden)]
17pub use fixed_point::FixedPoint as _;
18use num::{CheckedDiv, CheckedMul};
19#[doc(inline)]
20pub use units::*;
21
22/// An unsigned, fixed-point duration type
23///
24/// Each implementation defines an _integer_ type and a _scaling factor_ [`Fraction`].
25///
26/// # Constructing a duration
27///
28/// ```rust
29/// use embedded_time::duration::*;
30///
31/// let millis = <Milliseconds>::new(5);
32/// let millis = Milliseconds(5_u32);
33/// let millis = 5_u32.milliseconds();
34/// ```
35///
36/// # Get the integer part
37///
38/// ```rust
39/// use embedded_time::duration::*;
40///
41/// let millis = Milliseconds(23_u32).integer();
42///
43/// assert_eq!(millis, 23_u32);
44/// ```
45///
46/// # Formatting
47///
48/// Just forwards the underlying integer to [`core::fmt::Display::fmt()`]
49///
50/// ```rust
51/// use embedded_time::duration::*;
52///
53/// assert_eq!(format!("{}", Seconds(123_u32)), "123");
54/// ```
55///
56/// # Getting H:M:S.MS... Components
57///
58/// ```rust
59/// use embedded_time::duration::*;
60///
61/// // (the default duration _integer_ type is `u32`)
62/// let duration = 38_238_479_u32.microseconds();
63/// let hours: Hours = duration.into();
64/// let minutes = <Minutes>::from(duration) % Hours(1_u32);
65/// let seconds = <Seconds>::from(duration) % Minutes(1_u32);
66/// let milliseconds = <Milliseconds>::from(duration) % Seconds(1_u32);
67/// // ...
68/// ```
69///
70/// # Converting between `Duration`s
71///
72/// Many intra-duration conversions can be done using `From`/`Into`:
73///
74/// ```rust
75/// use embedded_time::duration::*;
76///
77/// let seconds = Seconds::<u32>::from(23_000_u32.milliseconds());
78/// assert_eq!(seconds.integer(), 23_u32);
79///
80/// let seconds: Seconds<u32> = 23_000_u32.milliseconds().into();
81/// assert_eq!(seconds.integer(), 23_u32);
82/// ```
83///
84/// Others require the use of `TryFrom`/`TryInto`:
85///
86/// ```rust
87/// use embedded_time::duration::*;
88/// use std::convert::{TryInto, TryFrom};
89///
90/// let millis = Milliseconds::<u32>::try_from(23_u32.seconds()).unwrap();
91/// assert_eq!(millis.integer(), 23_000_u32);
92///
93/// let millis: Milliseconds<u32> = 23_u32.seconds().try_into().unwrap();
94/// assert_eq!(millis.integer(), 23_000_u32);
95/// ```
96///
97/// # Converting to `core` types
98///
99/// ([`core::time::Duration`])
100///
101/// **Note**: Due to the inner types used by `core::time::Duration`, a lot of code bloat occurs when
102/// it is used.
103///
104/// ## Examples
105///
106/// ```rust
107/// use embedded_time::duration::*;
108/// use core::convert::TryFrom;
109///
110/// let core_duration = core::time::Duration::try_from(2_569_u32.milliseconds()).unwrap();
111///
112/// assert_eq!(core_duration.as_secs(), 2);
113/// assert_eq!(core_duration.subsec_nanos(), 569_000_000);
114/// ```
115///
116/// ```rust
117/// use embedded_time::duration::*;
118/// use core::convert::TryInto;
119///
120/// let core_duration: core::time::Duration = 2_569_u32.milliseconds().try_into().unwrap();
121///
122/// assert_eq!(core_duration.as_secs(), 2);
123/// assert_eq!(core_duration.subsec_nanos(), 569_000_000);
124/// ```
125///
126/// # Converting from `core` types
127///
128/// ([`core::time::Duration`])
129///
130/// **Note**: Due to the inner types used by `core::time::Duration`, a lot of code bloat occurs when
131/// it is used.
132///
133/// ## Examples
134///
135/// ```rust
136/// use embedded_time::duration::*;
137/// use core::convert::TryFrom;
138///
139/// let core_duration = core::time::Duration::new(5, 730_023_852);
140///
141/// assert_eq!(Milliseconds::<u32>::try_from(core_duration), Ok(5_730.milliseconds()));
142/// ```
143///
144/// ```rust
145/// use embedded_time::duration::*;
146/// # use core::convert::TryInto;
147///
148/// let duration: Result<Milliseconds<u32>, _> = core::time::Duration::new(5, 730023852).try_into();
149///
150/// assert_eq!(duration, Ok(5_730.milliseconds()));
151/// ```
152///
153/// ## Errors
154///
155/// [`ConversionError::ConversionFailure`] : The duration doesn't fit in the type specified
156///
157/// ```rust
158/// use embedded_time::{duration::*, ConversionError};
159/// # use core::convert::{TryFrom, TryInto};
160///
161/// assert_eq!(
162///     Milliseconds::<u32>::try_from(
163///         core::time::Duration::from_millis((u32::MAX as u64) + 1)
164///     ),
165///     Err(ConversionError::ConversionFailure)
166/// );
167///
168/// let duration: Result<Milliseconds<u32>, _> =
169///     core::time::Duration::from_millis((u32::MAX as u64) + 1).try_into();
170/// assert_eq!(duration, Err(ConversionError::ConversionFailure));
171/// ```
172///
173/// # Converting from a [`Generic`] `Duration`
174///
175/// ## Examples
176///
177/// ```rust
178/// use embedded_time::duration::*;
179/// # use core::convert::{TryFrom, TryInto};
180///
181/// // A generic duration of 2 seconds
182/// let generic_duration = Generic::new(2_000_u32, Fraction::new(1, 1_000));
183///
184/// let secs = Seconds::<u64>::try_from(generic_duration).unwrap();
185/// assert_eq!(secs.integer(), 2_u64);
186///
187/// let secs: Seconds<u64> = generic_duration.try_into().unwrap();
188/// assert_eq!(secs.integer(), 2_u64);
189/// ```
190///
191/// ## Errors
192///
193/// Failure will only occur if the provided value does not fit in the selected destination type.
194///
195/// ---
196///
197/// [`ConversionError::Unspecified`]
198///
199/// ```rust
200/// use embedded_time::{duration::*, ConversionError};
201/// # use core::convert::TryFrom;
202///
203/// assert_eq!(
204///     Seconds::<u32>::try_from(Generic::new(u32::MAX, Fraction::new(10,1))),
205///     Err(ConversionError::Unspecified)
206/// );
207/// ```
208///
209/// ---
210///
211/// [`ConversionError::ConversionFailure`] : The _integer_ conversion to that of the
212/// destination type fails.
213///
214/// ```rust
215/// use embedded_time::{duration::*, ConversionError};
216/// # use core::convert::TryFrom;
217///
218/// assert_eq!(
219///     Seconds::<u32>::try_from(Generic::new(u32::MAX as u64 + 1, Fraction::new(1,1))),
220///     Err(ConversionError::ConversionFailure)
221/// );
222/// ```
223///
224/// # Converting to a [`Generic`] `Duration` with the same _scaling factor_
225///
226/// ```rust
227/// use embedded_time::duration::*;
228///
229/// let generic_duration = Generic::<u32>::from(5_u32.seconds());
230/// let generic_duration: Generic<u32> = 5_u32.seconds().into();
231///
232/// assert_eq!(generic_duration.integer(), 5_u32);
233/// ```
234///
235/// # Converting to a [`Generic`] `Duration` with a different _scaling factor_
236///
237/// See [`Duration::to_generic()`]
238///
239/// # Converting to a _named_ `Rate`
240///
241/// See [`Duration::to_rate()`]
242///
243/// # Add/Sub
244///
245/// The result of the operation is the LHS type
246///
247/// ## Examples
248///
249/// ```rust
250/// use embedded_time::duration::*;
251///
252/// assert_eq!((Milliseconds(1_u32) + Seconds(1_u32)),
253///     Milliseconds(1_001_u32));
254///
255/// assert_eq!((Milliseconds(2_001_u32) - Seconds(1_u32)),
256///     Milliseconds(1_001_u32));
257/// ```
258///
259/// ## Panics
260///
261/// The same reason the integer operation would panic. Namely, if the result overflows the type.
262///
263/// ```rust,should_panic
264/// use embedded_time::duration::*;
265///
266/// let _ = Seconds(u32::MAX) + Seconds(1_u32);
267/// ```
268///
269/// # Mul/Div
270///
271/// Durations may also be multiplied and divided by integers. The result is of the LHS type. Both
272/// _panicky_ and _checked_ operations are available.
273///
274/// # Comparisons
275///
276/// ```rust
277/// use embedded_time::duration::*;
278///
279/// assert_eq!(Seconds(2_u32), Milliseconds(2_000_u32));
280/// assert_ne!(Seconds(2_u32), Milliseconds(2_001_u32));
281///
282/// assert!(Seconds(2_u32) < Milliseconds(2_001_u32));
283/// assert!(Seconds(2_u32) > Milliseconds(1_999_u32));
284/// ```
285///
286/// # Remainder
287///
288/// ```rust
289/// use embedded_time::duration::*;
290///
291/// assert_eq!(Minutes(62_u32) % Hours(1_u32), Minutes(2_u32));
292/// ```
293pub trait Duration: Sized + Copy {
294    /// Construct a `Generic` `Duration` from a _named_ `Duration` (eg.
295    /// [`Milliseconds`])
296    ///
297    /// # Examples
298    ///
299    /// ```rust
300    /// use embedded_time::duration::*;
301    ///
302    /// let millis = Milliseconds(20_u32);
303    ///
304    /// // convert into a generic duration with a different _scaling factor_
305    /// let generic = millis.to_generic::<u32>(Fraction::new(1, 2_000)).unwrap();
306    ///
307    /// assert_eq!(generic.integer(), 40_u32);
308    /// ```
309    ///
310    /// # Errors
311    ///
312    /// Failure will only occur if the provided value does not fit in the selected destination type.
313    ///
314    /// ---
315    ///
316    /// [`ConversionError::Unspecified`]
317    ///
318    /// ```rust
319    /// use embedded_time::{duration::*, ConversionError};
320    ///
321    /// assert_eq!(
322    ///     Seconds(u32::MAX).to_generic::<u32>(Fraction::new(1, 2)),
323    ///     Err(ConversionError::Unspecified)
324    /// );
325    /// ```
326    ///
327    /// ---
328    ///
329    /// [`ConversionError::ConversionFailure`] : The integer conversion to that of the destination
330    /// type fails.
331    ///
332    /// ```rust
333    /// use embedded_time::{duration::*, ConversionError};
334    ///
335    /// assert_eq!(Seconds(u32::MAX as u64 + 1).to_generic::<u32>(Fraction::new(1, 1)),
336    ///     Err(ConversionError::ConversionFailure));
337    /// ```
338    fn to_generic<DestInt: TimeInt>(
339        self,
340        scaling_factor: Fraction,
341    ) -> Result<Generic<DestInt>, ConversionError>
342    where
343        Self: FixedPoint,
344        DestInt: TryFrom<Self::T>,
345    {
346        Ok(Generic::<DestInt>::new(
347            self.into_ticks(scaling_factor)?,
348            scaling_factor,
349        ))
350    }
351
352    /// Convert to _named_ [`Rate`](rate::Rate)
353    ///
354    /// (the duration is equal to the reciprocal of the rate)
355    ///
356    /// # Examples
357    ///
358    /// ```rust
359    /// use embedded_time::{duration::*, rate::*};
360    ///
361    /// assert_eq!(
362    ///     Microseconds(500_u32).to_rate(),
363    ///     Ok(Kilohertz(2_u32))
364    /// );
365    /// ```
366    ///
367    /// # Errors
368    ///
369    /// Failure will only occur if the provided value does not fit in the selected destination type.
370    ///
371    /// ---
372    ///
373    /// [`ConversionError::Overflow`] : The conversion of the _scaling factor_ causes an overflow.
374    ///
375    /// ```rust
376    /// use embedded_time::{duration::*, rate::*, ConversionError};
377    ///
378    /// assert_eq!(
379    ///     Hours(u32::MAX).to_rate::<Megahertz<u32>>(),
380    ///     Err(ConversionError::Overflow)
381    /// );
382    /// ```
383    ///
384    /// ---
385    ///
386    /// [`ConversionError::DivByZero`] : The rate is `0`, therefore the reciprocal is undefined.
387    ///
388    /// ```rust
389    /// use embedded_time::{duration::*, rate::*, ConversionError};
390    ///
391    /// assert_eq!(
392    ///     Seconds(0_u32).to_rate::<Hertz<u32>>(),
393    ///     Err(ConversionError::DivByZero)
394    /// );
395    /// ```
396    fn to_rate<Rate: rate::Rate>(&self) -> Result<Rate, ConversionError>
397    where
398        Rate: FixedPoint,
399        Self: FixedPoint,
400        Rate::T: TryFrom<Self::T>,
401    {
402        let conversion_factor = Self::SCALING_FACTOR
403            .checked_mul(&Rate::SCALING_FACTOR)
404            .ok_or(ConversionError::Unspecified)?
405            .recip();
406
407        if size_of::<Self::T>() >= size_of::<Rate::T>() {
408            fixed_point::FixedPoint::from_ticks(
409                Self::T::from(*conversion_factor.numerator())
410                    .checked_div(
411                        &self
412                            .integer()
413                            .checked_mul(&Self::T::from(*conversion_factor.denominator()))
414                            .ok_or(ConversionError::Overflow)?,
415                    )
416                    .ok_or(ConversionError::DivByZero)?,
417                Rate::SCALING_FACTOR,
418            )
419        } else {
420            fixed_point::FixedPoint::from_ticks(
421                Rate::T::from(*conversion_factor.numerator())
422                    .checked_div(
423                        &Rate::T::try_from(self.integer())
424                            .map_err(|_| ConversionError::Overflow)?
425                            .checked_mul(&Rate::T::from(*conversion_factor.denominator()))
426                            .ok_or(ConversionError::Overflow)?,
427                    )
428                    .ok_or(ConversionError::DivByZero)?,
429                Rate::SCALING_FACTOR,
430            )
431        }
432    }
433}
434
435/// The `Generic` `Duration` type allows an arbitrary _scaling factor_ to be used without having to
436/// impl `FixedPoint`.
437///
438/// The purpose of this type is to allow a simple `Duration` object that can be defined at run-time.
439/// It does this by replacing the `const` _scaling factor_ with a struct field.
440#[derive(Copy, Clone, Debug, Default)]
441pub struct Generic<T> {
442    integer: T,
443    scaling_factor: Fraction,
444}
445
446impl<T: TimeInt> PartialOrd<Generic<T>> for Generic<T> {
447    /// See [Comparisons](trait.Duration.html#comparisons)
448    fn partial_cmp(&self, rhs: &Generic<T>) -> Option<core::cmp::Ordering> {
449        Some(
450            self.integer
451                .checked_mul_fraction(&self.scaling_factor)?
452                .cmp(&rhs.integer.checked_mul_fraction(&rhs.scaling_factor)?),
453        )
454    }
455}
456
457impl<T: TimeInt> Ord for Generic<T> {
458    fn cmp(&self, rhs: &Generic<T>) -> core::cmp::Ordering {
459        if let Some(v) = self.partial_cmp(rhs) {
460            v
461        } else {
462            panic!("Cmp failed")
463        }
464    }
465}
466
467impl<T: TimeInt> PartialEq<Generic<T>> for Generic<T> {
468    /// See [Comparisons](trait.Duration.html#comparisons)
469    fn eq(&self, rhs: &Generic<T>) -> bool {
470        self.partial_cmp(rhs) == Some(core::cmp::Ordering::Equal)
471    }
472}
473
474impl<T: TimeInt> Eq for Generic<T> {}
475
476impl<T: TimeInt + Hash> Hash for Generic<T> {
477    fn hash<H: Hasher>(&self, state: &mut H) {
478        if let Some(v) = self.integer.checked_mul_fraction(&self.scaling_factor) {
479            v.hash(state);
480        }
481    }
482}
483
484impl<T: TimeInt> Generic<T> {
485    /// Constructs a new fixed-point `Generic` `Duration` value
486    pub fn new(integer: T, scaling_factor: Fraction) -> Self {
487        Self {
488            integer,
489            scaling_factor,
490        }
491    }
492
493    /// Returns the _integer_ part
494    pub fn integer(&self) -> T {
495        self.integer
496    }
497
498    /// Returns the _scaling factor_ [`Fraction`] part
499    pub fn scaling_factor(&self) -> &Fraction {
500        &self.scaling_factor
501    }
502}
503
504impl<T: TimeInt> Duration for Generic<T> {}
505
506/// Duration units
507#[doc(hidden)]
508pub mod units {
509    use super::*;
510    use crate::{
511        fixed_point::{self, FixedPoint},
512        fraction::Fraction,
513        time_int::TimeInt,
514        ConversionError,
515    };
516    use core::{
517        cmp,
518        convert::{TryFrom, TryInto},
519        fmt::{self, Formatter},
520        ops,
521    };
522    #[doc(hidden)]
523    pub use Extensions as _;
524
525    macro_rules! impl_duration {
526        ( $name:ident, ($numer:expr, $denom:expr) ) => {
527            /// A duration unit type
528            #[derive(Copy, Clone, Eq, Ord, Hash, Debug, Default)]
529            #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
530            pub struct $name<T: TimeInt = u32>(pub T);
531
532            impl<T: TimeInt> $name<T> {
533                /// See [Constructing a duration](trait.Duration.html#constructing-a-duration)
534                pub fn new(value: T) -> Self {
535                    Self(value)
536                }
537            }
538
539            impl<T: TimeInt> Duration for $name<T> {}
540
541            impl<T: TimeInt> FixedPoint for $name<T> {
542                type T = T;
543                const SCALING_FACTOR: Fraction = Fraction::new($numer, $denom);
544
545                /// See [Constructing a duration](trait.Duration.html#constructing-a-duration)
546                fn new(value: Self::T) -> Self {
547                    Self(value)
548                }
549
550                /// See [Get the integer part](trait.Duration.html#get-the-integer-part)
551                fn integer(&self) -> Self::T {
552                    self.0
553                }
554            }
555
556            impl<T: TimeInt> fmt::Display for $name<T> {
557                /// See [Formatting](trait.Duration.html#formatting)
558                fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
559                    fmt::Display::fmt(&self.0, f)
560                }
561            }
562
563            impl<T: TimeInt, Rhs: Duration> ops::Add<Rhs> for $name<T>
564            where
565                Rhs: FixedPoint,
566                Self: TryFrom<Rhs>,
567            {
568                type Output = Self;
569
570                /// See [Add/Sub](trait.Duration.html#addsub)
571                fn add(self, rhs: Rhs) -> Self::Output {
572                    <Self as FixedPoint>::add(self, rhs)
573                }
574            }
575
576            impl<T: TimeInt, Rhs: Duration> ops::Sub<Rhs> for $name<T>
577            where
578                Self: TryFrom<Rhs>,
579                Rhs: FixedPoint,
580            {
581                type Output = Self;
582
583                /// See [Add/Sub](trait.Duration.html#addsub)
584                fn sub(self, rhs: Rhs) -> Self::Output {
585                    <Self as FixedPoint>::sub(self, rhs)
586                }
587            }
588
589            impl<T: TimeInt, Clock: crate::Clock> ops::Add<crate::Instant<Clock>> for $name<T>
590            where
591                Clock::T: TryFrom<T>,
592            {
593                type Output = crate::Instant<Clock>;
594
595                // Symmetric version of Instant + Duration
596                fn add(self, rhs: crate::Instant<Clock>) -> Self::Output {
597                    if let Some(v) = rhs.checked_add(self) {
598                        v
599                    } else {
600                        panic!("Add failed")
601                    }
602                }
603            }
604
605            impl<T: TimeInt> ops::Mul<T> for $name<T> {
606                type Output = Self;
607
608                /// See [Mul/Div](trait.Duration.html#muldiv)
609                fn mul(self, rhs: T) -> Self::Output {
610                    <Self as FixedPoint>::mul(self, rhs)
611                }
612            }
613
614            impl<T: TimeInt> ops::Div<T> for $name<T> {
615                type Output = Self;
616
617                /// See [Mul/Div](trait.Duration.html#muldiv)
618                fn div(self, rhs: T) -> Self::Output {
619                    <Self as FixedPoint>::div(self, rhs)
620                }
621            }
622
623            impl<T: TimeInt, Rhs: Duration> ops::Rem<Rhs> for $name<T>
624            where
625                Self: TryFrom<Rhs>,
626                Rhs: FixedPoint,
627            {
628                type Output = Self;
629
630                /// See [Remainder](trait.Duration.html#remainder)
631                fn rem(self, rhs: Rhs) -> Self::Output {
632                    <Self as FixedPoint>::rem(self, rhs)
633                }
634            }
635
636            impl<SourceInt: TimeInt, DestInt: TimeInt> TryFrom<Generic<SourceInt>>
637                for $name<DestInt>
638            where
639                DestInt: TryFrom<SourceInt>,
640            {
641                type Error = ConversionError;
642
643                /// See [Converting from a `Generic`
644                /// `Duration`](trait.Duration.html#converting-from-a-generic-duration)
645                fn try_from(generic_duration: Generic<SourceInt>) -> Result<Self, Self::Error> {
646                    fixed_point::FixedPoint::from_ticks(
647                        generic_duration.integer,
648                        generic_duration.scaling_factor,
649                    )
650                }
651            }
652
653            impl<T: TimeInt> From<$name<T>> for Generic<T> {
654                /// See [Converting to a `Generic`
655                /// `Duration`](trait.Duration.html#converting-to-a-generic-duration)
656                fn from(duration: $name<T>) -> Self {
657                    Self::new(duration.integer(), $name::<T>::SCALING_FACTOR)
658                }
659            }
660        };
661
662        ( $name:ident, ($numer:expr, $denom:expr), ge_secs ) => {
663            impl_duration![$name, ($numer, $denom)];
664
665            // TODO: Make this more custom (seconds and higher<u32> can be `From`) and comprehensive
666            // (allow u64 durations)
667            impl TryFrom<$name<u32>> for core::time::Duration {
668                type Error = ConversionError;
669
670                /// See [Converting to `core`
671                /// types](trait.Duration.html#converting-to-core-types)
672                fn try_from(duration: $name<u32>) -> Result<Self, Self::Error> {
673                    let seconds: Seconds<u64> = duration.into();
674                    Ok(Self::from_secs(seconds.integer()))
675                }
676            }
677
678            impl TryFrom<core::time::Duration> for $name<u32> {
679                type Error = ConversionError;
680
681                /// See [Converting from `core`
682                /// types](trait.Duration.html#converting-from-core-types)
683                fn try_from(core_duration: core::time::Duration) -> Result<Self, Self::Error> {
684                    let seconds = Seconds(core_duration.as_secs());
685                    seconds.try_into()
686                }
687            }
688
689            impl From<core::time::Duration> for $name<u64> {
690                /// See [Converting from `core`
691                /// types](trait.Duration.html#converting-from-core-types)
692                fn from(core_duration: core::time::Duration) -> Self {
693                    let seconds = Seconds(core_duration.as_secs());
694                    seconds.into()
695                }
696            }
697        };
698        ( $name:ident, ($numer:expr, $denom:expr), $from_core_dur:ident, $as_core_dur:ident ) => {
699            impl_duration![$name, ($numer, $denom)];
700
701            impl<T: TimeInt> TryFrom<$name<T>> for core::time::Duration
702            where
703                u64: From<T>,
704            {
705                type Error = ConversionError;
706
707                /// See [Converting to `core` types](trait.Duration.html#converting-to-core-types)
708                fn try_from(duration: $name<T>) -> Result<Self, Self::Error> {
709                    Ok(Self::$from_core_dur(duration.integer().into()))
710                }
711            }
712
713            impl<T: TimeInt> TryFrom<core::time::Duration> for $name<T>
714            where
715                T: TryFrom<u128>,
716            {
717                type Error = ConversionError;
718
719                /// See [Converting from `core`
720                /// types](trait.Duration.html#converting-from-core-types)
721                fn try_from(core_duration: core::time::Duration) -> Result<Self, Self::Error> {
722                    Ok(Self(
723                        core_duration
724                            .$as_core_dur()
725                            .try_into()
726                            .map_err(|_| ConversionError::ConversionFailure)?,
727                    ))
728                }
729            }
730        };
731    }
732    impl_duration![Hours, (3600, 1), ge_secs];
733    impl_duration![Minutes, (60, 1), ge_secs];
734    impl_duration![Seconds, (1, 1), ge_secs];
735    impl_duration![Milliseconds, (1, 1_000), from_millis, as_millis];
736    impl_duration![Microseconds, (1, 1_000_000), from_micros, as_micros];
737    impl_duration![Nanoseconds, (1, 1_000_000_000), from_nanos, as_nanos];
738
739    macro_rules! impl_partial_eq {
740        ($name:ident) => {
741            impl<T: TimeInt, RhsInt: TimeInt> cmp::PartialEq<$name<RhsInt>> for $name<T>
742            where
743                T: TryFrom<RhsInt>,
744            {
745                /// See [Comparisons](trait.Duration.html#comparisons)
746                fn eq(&self, rhs: &$name<RhsInt>) -> bool {
747                    match T::try_from(rhs.integer()) {
748                        Ok(rhs_integer) => self.integer() == rhs_integer,
749                        Err(_) => false,
750                    }
751                }
752            }
753        };
754    }
755    impl_partial_eq![Hours];
756    impl_partial_eq![Minutes];
757    impl_partial_eq![Seconds];
758    impl_partial_eq![Milliseconds];
759    impl_partial_eq![Microseconds];
760    impl_partial_eq![Nanoseconds];
761
762    macro_rules! impl_big_partial_eq_small {
763        ($big:ident) => {};
764        ($big:ident, $($small:ident),+) => {
765            $(
766                impl<T: TimeInt, RhsInt: TimeInt> cmp::PartialEq<$small<RhsInt>> for $big<T>
767                where
768                    $small<RhsInt>: TryFrom<Self>,
769                {
770                    /// See [Comparisons](trait.Duration.html#comparisons)
771                    fn eq(&self, rhs: &$small<RhsInt>) -> bool {
772                        match $small::<RhsInt>::try_from(*self) {
773                            Ok(lhs) => lhs.integer() == rhs.integer(),
774                            Err(_) => false,
775                        }
776                    }
777                }
778            )+
779
780            impl_big_partial_eq_small![$($small),+];
781        };
782    }
783    impl_big_partial_eq_small![
784        Hours,
785        Minutes,
786        Seconds,
787        Milliseconds,
788        Microseconds,
789        Nanoseconds
790    ];
791
792    macro_rules! impl_small_partial_eq_big {
793        ($small:ident) => {};
794        ($small:ident, $($big:ident),+) => {
795            $(
796                impl<T: TimeInt, RhsInt: TimeInt> cmp::PartialEq<$big<RhsInt>> for $small<T>
797                where
798                    Self: TryFrom<$big<RhsInt>>,
799                {
800                    /// See [Comparisons](trait.Duration.html#comparisons)
801                    fn eq(&self, rhs: &$big<RhsInt>) -> bool {
802                        match Self::try_from(*rhs) {
803                            Ok(rhs) => self.integer() == rhs.integer(),
804                            Err(_) => false,
805                        }
806                    }
807                }
808            )+
809
810            impl_small_partial_eq_big![$($big),+];
811        };
812
813    }
814    impl_small_partial_eq_big![
815        Nanoseconds,
816        Microseconds,
817        Milliseconds,
818        Seconds,
819        Minutes,
820        Hours
821    ];
822
823    macro_rules! impl_partial_ord {
824        ($name:ident) => {
825            impl<T: TimeInt, RhsInt: TimeInt> PartialOrd<$name<RhsInt>> for $name<T>
826            where
827                T: TryFrom<RhsInt>,
828            {
829                /// See [Comparisons](trait.Duration.html#comparisons)
830                fn partial_cmp(&self, rhs: &$name<RhsInt>) -> Option<core::cmp::Ordering> {
831                    match T::try_from(rhs.integer()) {
832                        Ok(rhs_integer) => Some(self.integer().cmp(&rhs_integer)),
833                        Err(_) => Some(core::cmp::Ordering::Less),
834                    }
835                }
836            }
837        };
838    }
839    impl_partial_ord![Hours];
840    impl_partial_ord![Minutes];
841    impl_partial_ord![Seconds];
842    impl_partial_ord![Milliseconds];
843    impl_partial_ord![Microseconds];
844    impl_partial_ord![Nanoseconds];
845
846    macro_rules! impl_big_partial_ord_small {
847        ($big:ident) => {};
848        ($big:ident, $($small:ident),+) => {
849            $(
850                impl<T: TimeInt, RhsInt: TimeInt> PartialOrd<$small<RhsInt>> for $big<T>
851                where
852                    $small<RhsInt>: TryFrom<Self>,
853                {
854                    /// See [Comparisons](trait.Duration.html#comparisons)
855                    fn partial_cmp(&self, rhs: &$small<RhsInt>) -> Option<core::cmp::Ordering> {
856                        match $small::<RhsInt>::try_from(*self) {
857                            Ok(lhs) => Some(lhs.integer().cmp(&rhs.integer())),
858                            Err(_) => Some(core::cmp::Ordering::Greater),
859                        }
860                    }
861                }
862            )+
863
864            impl_big_partial_ord_small![$($small),+];
865        };
866    }
867    impl_big_partial_ord_small![
868        Hours,
869        Minutes,
870        Seconds,
871        Milliseconds,
872        Microseconds,
873        Nanoseconds
874    ];
875
876    macro_rules! impl_small_partial_ord_big {
877        ($small:ident) => {};
878        ($small:ident, $($big:ident),+) => {
879            $(
880                impl<T: TimeInt, RhsInt: TimeInt> PartialOrd<$big<RhsInt>> for $small<T>
881                where
882                    Self: TryFrom<$big<RhsInt>>,
883                {
884                    /// See [Comparisons](trait.Duration.html#comparisons)
885                    fn partial_cmp(&self, rhs: &$big<RhsInt>) -> Option<core::cmp::Ordering> {
886                        match Self::try_from(*rhs) {
887                        Ok(rhs) => Some(self.integer().cmp(&rhs.integer())),
888                        Err(_) => Some(core::cmp::Ordering::Less),
889                    }
890                    }
891                }
892            )+
893
894            impl_small_partial_ord_big![$($big),+];
895        };
896
897    }
898    impl_small_partial_ord_big![
899        Nanoseconds,
900        Microseconds,
901        Milliseconds,
902        Seconds,
903        Minutes,
904        Hours
905    ];
906
907    macro_rules! impl_from {
908        ($name:ident) => {
909            impl From<$name<u32>> for $name<u64> {
910                /// See [Converting between
911                /// `Duration`s](trait.Duration.html#converting-between-durations)
912                fn from(source: $name<u32>) -> Self {
913                    Self::new(u64::from(source.integer()))
914                }
915            }
916
917            impl TryFrom<$name<u64>> for $name<u32> {
918                type Error = ConversionError;
919
920                /// See [Converting between
921                /// `Duration`s](trait.Duration.html#converting-between-durations)
922                fn try_from(source: $name<u64>) -> Result<Self, Self::Error> {
923                    fixed_point::FixedPoint::from_ticks(
924                        source.integer(),
925                        $name::<u64>::SCALING_FACTOR,
926                    )
927                }
928            }
929        };
930    }
931    impl_from![Hours];
932    impl_from![Minutes];
933    impl_from![Seconds];
934    impl_from![Milliseconds];
935    impl_from![Microseconds];
936    impl_from![Nanoseconds];
937
938    macro_rules! impl_from_smaller {
939        ($name:ident) => {};
940        ($big:ident, $($small:ident),+) => {
941            $(
942                impl<T: TimeInt> From<$small<T>> for $big<T>
943                {
944                    /// See [Converting between `Duration`s](trait.Duration.html#converting-between-durations)
945                    fn from(small: $small<T>) -> Self {
946                        if let Ok(v) = fixed_point::FixedPoint::from_ticks(small.integer(), $small::<T>::SCALING_FACTOR) {
947                            v
948                        } else {
949                            panic!("From failed")
950                        }
951                    }
952                }
953
954                impl From<$small<u32>> for $big<u64>
955                {
956                    /// See [Converting between `Duration`s](trait.Duration.html#converting-between-durations)
957                    fn from(small: $small<u32>) -> Self {
958                        if let Ok(v) = fixed_point::FixedPoint::from_ticks(small.integer(), $small::<u32>::SCALING_FACTOR) {
959                            v
960                        } else {
961                            panic!("From failed")
962                        }
963                    }
964                }
965
966                impl TryFrom<$small<u64>> for $big<u32>
967                {
968                    type Error = ConversionError;
969
970                    /// See [Converting between `Duration`s](trait.Duration.html#converting-between-durations)
971                    fn try_from(small: $small<u64>) -> Result<Self, Self::Error> {
972                        fixed_point::FixedPoint::from_ticks(
973                            small.integer(),
974                            $small::<u64>::SCALING_FACTOR,
975                        )
976                    }
977                }
978            )+
979
980            impl_from_smaller![$($small),+];
981        };
982
983    }
984    impl_from_smaller![
985        Hours,
986        Minutes,
987        Seconds,
988        Milliseconds,
989        Microseconds,
990        Nanoseconds
991    ];
992
993    macro_rules! impl_from_bigger {
994        ($small:ident) => {};
995        ($small:ident, $($big:ident),+) => {
996            $(
997                impl From<$big<u32>> for $small<u64>
998                {
999                    /// See [Converting between `Duration`s](trait.Duration.html#converting-between-durations)
1000                    fn from(big: $big<u32>) -> Self {
1001                        if let Ok(v) = fixed_point::FixedPoint::from_ticks(big.integer(), $big::<u32>::SCALING_FACTOR) {
1002                            v
1003                        } else {
1004                            panic!("From failed")
1005                        }
1006                    }
1007                }
1008
1009                impl<T: TimeInt> TryFrom<$big<T>> for $small<T>
1010                {
1011                    type Error = ConversionError;
1012
1013                    /// See [Converting between `Duration`s](trait.Duration.html#converting-between-durations)
1014                    fn try_from(big: $big<T>) -> Result<Self, Self::Error> {
1015                        fixed_point::FixedPoint::from_ticks(
1016                            big.integer(),
1017                            $big::<T>::SCALING_FACTOR,
1018                        )
1019                    }
1020                }
1021
1022                impl TryFrom<$big<u64>> for $small<u32>
1023                {
1024                    type Error = ConversionError;
1025
1026                    /// See [Converting between `Duration`s](trait.Duration.html#converting-between-durations)
1027                    fn try_from(big: $big<u64>) -> Result<Self, Self::Error> {
1028                        fixed_point::FixedPoint::from_ticks(
1029                            big.integer(),
1030                            $big::<u64>::SCALING_FACTOR,
1031                        )
1032                    }
1033                }
1034            )+
1035
1036            impl_from_bigger![$($big),+];
1037        };
1038    }
1039
1040    impl_from_bigger![
1041        Nanoseconds,
1042        Microseconds,
1043        Milliseconds,
1044        Seconds,
1045        Minutes,
1046        Hours
1047    ];
1048
1049    /// Create duration-based extensions from primitive numeric types.
1050    ///
1051    /// ```rust
1052    /// use embedded_time::duration::*;
1053    ///
1054    /// assert_eq!(5.nanoseconds(), Nanoseconds(5_u32));
1055    /// assert_eq!(5.microseconds(), Microseconds(5_u32));
1056    /// assert_eq!(5.milliseconds(), Milliseconds(5_u32));
1057    /// assert_eq!(5.seconds(), Seconds(5_u32));
1058    /// assert_eq!(5.minutes(), Minutes(5_u32));
1059    /// assert_eq!(5.hours(), Hours(5_u32));
1060    /// ```
1061    pub trait Extensions: TimeInt {
1062        /// nanoseconds
1063        fn nanoseconds(self) -> Nanoseconds<Self> {
1064            Nanoseconds::new(self)
1065        }
1066        /// microseconds
1067        fn microseconds(self) -> Microseconds<Self> {
1068            Microseconds::new(self)
1069        }
1070        /// milliseconds
1071        fn milliseconds(self) -> Milliseconds<Self> {
1072            Milliseconds::new(self)
1073        }
1074        /// seconds
1075        fn seconds(self) -> Seconds<Self> {
1076            Seconds::new(self)
1077        }
1078        /// minutes
1079        fn minutes(self) -> Minutes<Self> {
1080            Minutes::new(self)
1081        }
1082        /// hours
1083        fn hours(self) -> Hours<Self> {
1084            Hours::new(self)
1085        }
1086    }
1087
1088    impl Extensions for u32 {}
1089}
1090
1091#[cfg(test)]
1092mod tests {
1093    use super::*;
1094}