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}