1 //! The [`Duration`] struct and its associated `impl`s.
2 
3 use core::cmp::Ordering;
4 use core::convert::{TryFrom, TryInto};
5 use core::fmt;
6 use core::iter::Sum;
7 use core::ops::{Add, Div, Mul, Neg, Sub, SubAssign};
8 use core::time::Duration as StdDuration;
9 
10 use crate::error;
11 #[cfg(feature = "std")]
12 use crate::Instant;
13 
14 /// By explicitly inserting this enum where padding is expected, the compiler is able to better
15 /// perform niche value optimization.
16 #[repr(u32)]
17 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
18 pub(crate) enum Padding {
19     #[allow(clippy::missing_docs_in_private_items)]
20     Optimize,
21 }
22 
23 impl Default for Padding {
24     fn default() -> Self {
25         Self::Optimize
26     }
27 }
28 
29 /// A span of time with nanosecond precision.
30 ///
31 /// Each `Duration` is composed of a whole number of seconds and a fractional part represented in
32 /// nanoseconds.
altera_uart_setbrg(struct udevice * dev,int baudrate)33 ///
34 /// This implementation allows for negative durations, unlike [`core::time::Duration`].
35 #[derive(Clone, Copy, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
36 pub struct Duration {
37     /// Number of whole seconds.
38     seconds: i64,
39     /// Number of nanoseconds within the second. The sign always matches the `seconds` field.
40     nanoseconds: i32, // always -10^9 < nanoseconds < 10^9
41     #[allow(clippy::missing_docs_in_private_items)]
42     padding: Padding,
43 }
44 
altera_uart_putc(struct udevice * dev,const char ch)45 impl fmt::Debug for Duration {
46     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
47         f.debug_struct("Duration")
48             .field("seconds", &self.seconds)
49             .field("nanoseconds", &self.nanoseconds)
50             .finish()
51     }
52 }
53 
54 impl Duration {
55     // region: constants
56     /// Equivalent to `0.seconds()`.
57     ///
altera_uart_pending(struct udevice * dev,bool input)58     /// ```rust
59     /// # use time::{Duration, ext::NumericalDuration};
60     /// assert_eq!(Duration::ZERO, 0.seconds());
61     /// ```
62     pub const ZERO: Self = Self::seconds(0);
63 
64     /// Equivalent to `1.nanoseconds()`.
65     ///
66     /// ```rust
67     /// # use time::{Duration, ext::NumericalDuration};
68     /// assert_eq!(Duration::NANOSECOND, 1.nanoseconds());
69     /// ```
altera_uart_getc(struct udevice * dev)70     pub const NANOSECOND: Self = Self::nanoseconds(1);
71 
72     /// Equivalent to `1.microseconds()`.
73     ///
74     /// ```rust
75     /// # use time::{Duration, ext::NumericalDuration};
76     /// assert_eq!(Duration::MICROSECOND, 1.microseconds());
77     /// ```
78     pub const MICROSECOND: Self = Self::microseconds(1);
79 
80     /// Equivalent to `1.milliseconds()`.
altera_uart_probe(struct udevice * dev)81     ///
82     /// ```rust
83     /// # use time::{Duration, ext::NumericalDuration};
84     /// assert_eq!(Duration::MILLISECOND, 1.milliseconds());
85     /// ```
86     pub const MILLISECOND: Self = Self::milliseconds(1);
87 
88     /// Equivalent to `1.seconds()`.
89     ///
90     /// ```rust
91     /// # use time::{Duration, ext::NumericalDuration};
92     /// assert_eq!(Duration::SECOND, 1.seconds());
93     /// ```
94     pub const SECOND: Self = Self::seconds(1);
95 
96     /// Equivalent to `1.minutes()`.
97     ///
98     /// ```rust
99     /// # use time::{Duration, ext::NumericalDuration};
100     /// assert_eq!(Duration::MINUTE, 1.minutes());
101     /// ```
102     pub const MINUTE: Self = Self::minutes(1);
103 
104     /// Equivalent to `1.hours()`.
105     ///
106     /// ```rust
107     /// # use time::{Duration, ext::NumericalDuration};
108     /// assert_eq!(Duration::HOUR, 1.hours());
109     /// ```
110     pub const HOUR: Self = Self::hours(1);
111 
112     /// Equivalent to `1.days()`.
113     ///
114     /// ```rust
115     /// # use time::{Duration, ext::NumericalDuration};
116     /// assert_eq!(Duration::DAY, 1.days());
117     /// ```
118     pub const DAY: Self = Self::days(1);
119 
120     /// Equivalent to `1.weeks()`.
121     ///
122     /// ```rust
123     /// # use time::{Duration, ext::NumericalDuration};
_debug_uart_init(void)124     /// assert_eq!(Duration::WEEK, 1.weeks());
125     /// ```
126     pub const WEEK: Self = Self::weeks(1);
127 
128     /// The minimum possible duration. Adding any negative duration to this will cause an overflow.
129     pub const MIN: Self = Self::new_unchecked(i64::MIN, -999_999_999);
130 
131     /// The maximum possible duration. Adding any positive duration to this will cause an overflow.
132     pub const MAX: Self = Self::new_unchecked(i64::MAX, 999_999_999);
_debug_uart_putc(int ch)133     // endregion constants
134 
135     // region: is_{sign}
136     /// Check if a duration is exactly zero.
137     ///
138     /// ```rust
139     /// # use time::ext::NumericalDuration;
140     /// assert!(0.seconds().is_zero());
141     /// assert!(!1.nanoseconds().is_zero());
142     /// ```
143     pub const fn is_zero(self) -> bool {
144         self.seconds == 0 && self.nanoseconds == 0
145     }
146 
147     /// Check if a duration is negative.
148     ///
149     /// ```rust
150     /// # use time::ext::NumericalDuration;
151     /// assert!((-1).seconds().is_negative());
152     /// assert!(!0.seconds().is_negative());
153     /// assert!(!1.seconds().is_negative());
154     /// ```
155     pub const fn is_negative(self) -> bool {
156         self.seconds < 0 || self.nanoseconds < 0
157     }
158 
159     /// Check if a duration is positive.
160     ///
161     /// ```rust
162     /// # use time::ext::NumericalDuration;
163     /// assert!(1.seconds().is_positive());
164     /// assert!(!0.seconds().is_positive());
165     /// assert!(!(-1).seconds().is_positive());
166     /// ```
167     pub const fn is_positive(self) -> bool {
168         self.seconds > 0 || self.nanoseconds > 0
169     }
170     // endregion is_{sign}
171 
172     // region: abs
173     /// Get the absolute value of the duration.
174     ///
175     /// This method saturates the returned value if it would otherwise overflow.
176     ///
177     /// ```rust
178     /// # use time::ext::NumericalDuration;
179     /// assert_eq!(1.seconds().abs(), 1.seconds());
180     /// assert_eq!(0.seconds().abs(), 0.seconds());
181     /// assert_eq!((-1).seconds().abs(), 1.seconds());
182     /// ```
183     pub const fn abs(self) -> Self {
184         Self::new_unchecked(self.seconds.saturating_abs(), self.nanoseconds.abs())
185     }
186 
187     /// Convert the existing `Duration` to a `std::time::Duration` and its sign. This doesn't
188     /// actually require the standard library, but is currently only used when it's enabled.
189     #[allow(clippy::missing_const_for_fn)] // false positive
190     #[cfg(feature = "std")]
191     pub(crate) fn abs_std(self) -> StdDuration {
192         StdDuration::new(self.seconds.unsigned_abs(), self.nanoseconds.unsigned_abs())
193     }
194     // endregion abs
195 
196     // region: constructors
197     /// Create a new `Duration` without checking the validity of the components.
198     pub(crate) const fn new_unchecked(seconds: i64, nanoseconds: i32) -> Self {
199         Self {
200             seconds,
201             nanoseconds,
202             padding: Padding::Optimize,
203         }
204     }
205 
206     /// Create a new `Duration` with the provided seconds and nanoseconds. If nanoseconds is at
207     /// least ±10<sup>9</sup>, it will wrap to the number of seconds.
208     ///
209     /// ```rust
210     /// # use time::{Duration, ext::NumericalDuration};
211     /// assert_eq!(Duration::new(1, 0), 1.seconds());
212     /// assert_eq!(Duration::new(-1, 0), (-1).seconds());
213     /// assert_eq!(Duration::new(1, 2_000_000_000), 3.seconds());
214     /// ```
215     pub const fn new(mut seconds: i64, mut nanoseconds: i32) -> Self {
216         seconds += nanoseconds as i64 / 1_000_000_000;
217         nanoseconds %= 1_000_000_000;
218 
219         if seconds > 0 && nanoseconds < 0 {
220             seconds -= 1;
221             nanoseconds += 1_000_000_000;
222         } else if seconds < 0 && nanoseconds > 0 {
223             seconds += 1;
224             nanoseconds -= 1_000_000_000;
225         }
226 
227         Self::new_unchecked(seconds, nanoseconds)
228     }
229 
230     /// Create a new `Duration` with the given number of weeks. Equivalent to
231     /// `Duration::seconds(weeks * 604_800)`.
232     ///
233     /// ```rust
234     /// # use time::{Duration, ext::NumericalDuration};
235     /// assert_eq!(Duration::weeks(1), 604_800.seconds());
236     /// ```
237     pub const fn weeks(weeks: i64) -> Self {
238         Self::seconds(weeks * 604_800)
239     }
240 
241     /// Create a new `Duration` with the given number of days. Equivalent to
242     /// `Duration::seconds(days * 86_400)`.
243     ///
244     /// ```rust
245     /// # use time::{Duration, ext::NumericalDuration};
246     /// assert_eq!(Duration::days(1), 86_400.seconds());
247     /// ```
248     pub const fn days(days: i64) -> Self {
249         Self::seconds(days * 86_400)
250     }
251 
252     /// Create a new `Duration` with the given number of hours. Equivalent to
253     /// `Duration::seconds(hours * 3_600)`.
254     ///
255     /// ```rust
256     /// # use time::{Duration, ext::NumericalDuration};
257     /// assert_eq!(Duration::hours(1), 3_600.seconds());
258     /// ```
259     pub const fn hours(hours: i64) -> Self {
260         Self::seconds(hours * 3_600)
261     }
262 
263     /// Create a new `Duration` with the given number of minutes. Equivalent to
264     /// `Duration::seconds(minutes * 60)`.
265     ///
266     /// ```rust
267     /// # use time::{Duration, ext::NumericalDuration};
268     /// assert_eq!(Duration::minutes(1), 60.seconds());
269     /// ```
270     pub const fn minutes(minutes: i64) -> Self {
271         Self::seconds(minutes * 60)
272     }
273 
274     /// Create a new `Duration` with the given number of seconds.
275     ///
276     /// ```rust
277     /// # use time::{Duration, ext::NumericalDuration};
278     /// assert_eq!(Duration::seconds(1), 1_000.milliseconds());
279     /// ```
280     pub const fn seconds(seconds: i64) -> Self {
281         Self::new_unchecked(seconds, 0)
282     }
283 
284     /// Creates a new `Duration` from the specified number of seconds represented as `f64`.
285     ///
286     /// ```rust
287     /// # use time::{Duration, ext::NumericalDuration};
288     /// assert_eq!(Duration::seconds_f64(0.5), 0.5.seconds());
289     /// assert_eq!(Duration::seconds_f64(-0.5), -0.5.seconds());
290     /// ```
291     pub fn seconds_f64(seconds: f64) -> Self {
292         Self::new_unchecked(seconds as _, ((seconds % 1.) * 1_000_000_000.) as _)
293     }
294 
295     /// Creates a new `Duration` from the specified number of seconds represented as `f32`.
296     ///
297     /// ```rust
298     /// # use time::{Duration, ext::NumericalDuration};
299     /// assert_eq!(Duration::seconds_f32(0.5), 0.5.seconds());
300     /// assert_eq!(Duration::seconds_f32(-0.5), (-0.5).seconds());
301     /// ```
302     pub fn seconds_f32(seconds: f32) -> Self {
303         Self::new_unchecked(seconds as _, ((seconds % 1.) * 1_000_000_000.) as _)
304     }
305 
306     /// Create a new `Duration` with the given number of milliseconds.
307     ///
308     /// ```rust
309     /// # use time::{Duration, ext::NumericalDuration};
310     /// assert_eq!(Duration::milliseconds(1), 1_000.microseconds());
311     /// assert_eq!(Duration::milliseconds(-1), (-1_000).microseconds());
312     /// ```
313     pub const fn milliseconds(milliseconds: i64) -> Self {
314         Self::new_unchecked(
315             milliseconds / 1_000,
316             ((milliseconds % 1_000) * 1_000_000) as _,
317         )
318     }
319 
320     /// Create a new `Duration` with the given number of microseconds.
321     ///
322     /// ```rust
323     /// # use time::{Duration, ext::NumericalDuration};
324     /// assert_eq!(Duration::microseconds(1), 1_000.nanoseconds());
325     /// assert_eq!(Duration::microseconds(-1), (-1_000).nanoseconds());
326     /// ```
327     pub const fn microseconds(microseconds: i64) -> Self {
328         Self::new_unchecked(
329             microseconds / 1_000_000,
330             ((microseconds % 1_000_000) * 1_000) as _,
331         )
332     }
333 
334     /// Create a new `Duration` with the given number of nanoseconds.
335     ///
336     /// ```rust
337     /// # use time::{Duration, ext::NumericalDuration};
338     /// assert_eq!(Duration::nanoseconds(1), 1.microseconds() / 1_000);
339     /// assert_eq!(Duration::nanoseconds(-1), (-1).microseconds() / 1_000);
340     /// ```
341     pub const fn nanoseconds(nanoseconds: i64) -> Self {
342         Self::new_unchecked(
343             nanoseconds / 1_000_000_000,
344             (nanoseconds % 1_000_000_000) as _,
345         )
346     }
347 
348     /// Create a new `Duration` with the given number of nanoseconds.
349     ///
350     /// As the input range cannot be fully mapped to the output, this should only be used where it's
351     /// known to result in a valid value.
352     pub(crate) const fn nanoseconds_i128(nanoseconds: i128) -> Self {
353         Self::new_unchecked(
354             (nanoseconds / 1_000_000_000) as _,
355             (nanoseconds % 1_000_000_000) as _,
356         )
357     }
358     // endregion constructors
359 
360     // region: getters
361     /// Get the number of whole weeks in the duration.
362     ///
363     /// ```rust
364     /// # use time::ext::NumericalDuration;
365     /// assert_eq!(1.weeks().whole_weeks(), 1);
366     /// assert_eq!((-1).weeks().whole_weeks(), -1);
367     /// assert_eq!(6.days().whole_weeks(), 0);
368     /// assert_eq!((-6).days().whole_weeks(), 0);
369     /// ```
370     pub const fn whole_weeks(self) -> i64 {
371         self.whole_seconds() / 604_800
372     }
373 
374     /// Get the number of whole days in the duration.
375     ///
376     /// ```rust
377     /// # use time::ext::NumericalDuration;
378     /// assert_eq!(1.days().whole_days(), 1);
379     /// assert_eq!((-1).days().whole_days(), -1);
380     /// assert_eq!(23.hours().whole_days(), 0);
381     /// assert_eq!((-23).hours().whole_days(), 0);
382     /// ```
383     pub const fn whole_days(self) -> i64 {
384         self.whole_seconds() / 86_400
385     }
386 
387     /// Get the number of whole hours in the duration.
388     ///
389     /// ```rust
390     /// # use time::ext::NumericalDuration;
391     /// assert_eq!(1.hours().whole_hours(), 1);
392     /// assert_eq!((-1).hours().whole_hours(), -1);
393     /// assert_eq!(59.minutes().whole_hours(), 0);
394     /// assert_eq!((-59).minutes().whole_hours(), 0);
395     /// ```
396     pub const fn whole_hours(self) -> i64 {
397         self.whole_seconds() / 3_600
398     }
399 
400     /// Get the number of whole minutes in the duration.
401     ///
402     /// ```rust
403     /// # use time::ext::NumericalDuration;
404     /// assert_eq!(1.minutes().whole_minutes(), 1);
405     /// assert_eq!((-1).minutes().whole_minutes(), -1);
406     /// assert_eq!(59.seconds().whole_minutes(), 0);
407     /// assert_eq!((-59).seconds().whole_minutes(), 0);
408     /// ```
409     pub const fn whole_minutes(self) -> i64 {
410         self.whole_seconds() / 60
411     }
412 
413     /// Get the number of whole seconds in the duration.
414     ///
415     /// ```rust
416     /// # use time::ext::NumericalDuration;
417     /// assert_eq!(1.seconds().whole_seconds(), 1);
418     /// assert_eq!((-1).seconds().whole_seconds(), -1);
419     /// assert_eq!(1.minutes().whole_seconds(), 60);
420     /// assert_eq!((-1).minutes().whole_seconds(), -60);
421     /// ```
422     pub const fn whole_seconds(self) -> i64 {
423         self.seconds
424     }
425 
426     /// Get the number of fractional seconds in the duration.
427     ///
428     /// ```rust
429     /// # use time::ext::NumericalDuration;
430     /// assert_eq!(1.5.seconds().as_seconds_f64(), 1.5);
431     /// assert_eq!((-1.5).seconds().as_seconds_f64(), -1.5);
432     /// ```
433     pub fn as_seconds_f64(self) -> f64 {
434         self.seconds as f64 + self.nanoseconds as f64 / 1_000_000_000.
435     }
436 
437     /// Get the number of fractional seconds in the duration.
438     ///
439     /// ```rust
440     /// # use time::ext::NumericalDuration;
441     /// assert_eq!(1.5.seconds().as_seconds_f32(), 1.5);
442     /// assert_eq!((-1.5).seconds().as_seconds_f32(), -1.5);
443     /// ```
444     pub fn as_seconds_f32(self) -> f32 {
445         self.seconds as f32 + self.nanoseconds as f32 / 1_000_000_000.
446     }
447 
448     /// Get the number of whole milliseconds in the duration.
449     ///
450     /// ```rust
451     /// # use time::ext::NumericalDuration;
452     /// assert_eq!(1.seconds().whole_milliseconds(), 1_000);
453     /// assert_eq!((-1).seconds().whole_milliseconds(), -1_000);
454     /// assert_eq!(1.milliseconds().whole_milliseconds(), 1);
455     /// assert_eq!((-1).milliseconds().whole_milliseconds(), -1);
456     /// ```
457     pub const fn whole_milliseconds(self) -> i128 {
458         self.seconds as i128 * 1_000 + self.nanoseconds as i128 / 1_000_000
459     }
460 
461     /// Get the number of milliseconds past the number of whole seconds.
462     ///
463     /// Always in the range `-1_000..1_000`.
464     ///
465     /// ```rust
466     /// # use time::ext::NumericalDuration;
467     /// assert_eq!(1.4.seconds().subsec_milliseconds(), 400);
468     /// assert_eq!((-1.4).seconds().subsec_milliseconds(), -400);
469     /// ```
470     // Allow the lint, as the value is guaranteed to be less than 1000.
471     pub const fn subsec_milliseconds(self) -> i16 {
472         (self.nanoseconds / 1_000_000) as _
473     }
474 
475     /// Get the number of whole microseconds in the duration.
476     ///
477     /// ```rust
478     /// # use time::ext::NumericalDuration;
479     /// assert_eq!(1.milliseconds().whole_microseconds(), 1_000);
480     /// assert_eq!((-1).milliseconds().whole_microseconds(), -1_000);
481     /// assert_eq!(1.microseconds().whole_microseconds(), 1);
482     /// assert_eq!((-1).microseconds().whole_microseconds(), -1);
483     /// ```
484     pub const fn whole_microseconds(self) -> i128 {
485         self.seconds as i128 * 1_000_000 + self.nanoseconds as i128 / 1_000
486     }
487 
488     /// Get the number of microseconds past the number of whole seconds.
489     ///
490     /// Always in the range `-1_000_000..1_000_000`.
491     ///
492     /// ```rust
493     /// # use time::ext::NumericalDuration;
494     /// assert_eq!(1.0004.seconds().subsec_microseconds(), 400);
495     /// assert_eq!((-1.0004).seconds().subsec_microseconds(), -400);
496     /// ```
497     pub const fn subsec_microseconds(self) -> i32 {
498         self.nanoseconds / 1_000
499     }
500 
501     /// Get the number of nanoseconds in the duration.
502     ///
503     /// ```rust
504     /// # use time::ext::NumericalDuration;
505     /// assert_eq!(1.microseconds().whole_nanoseconds(), 1_000);
506     /// assert_eq!((-1).microseconds().whole_nanoseconds(), -1_000);
507     /// assert_eq!(1.nanoseconds().whole_nanoseconds(), 1);
508     /// assert_eq!((-1).nanoseconds().whole_nanoseconds(), -1);
509     /// ```
510     pub const fn whole_nanoseconds(self) -> i128 {
511         self.seconds as i128 * 1_000_000_000 + self.nanoseconds as i128
512     }
513 
514     /// Get the number of nanoseconds past the number of whole seconds.
515     ///
516     /// The returned value will always be in the range `-1_000_000_000..1_000_000_000`.
517     ///
518     /// ```rust
519     /// # use time::ext::NumericalDuration;
520     /// assert_eq!(1.000_000_400.seconds().subsec_nanoseconds(), 400);
521     /// assert_eq!((-1.000_000_400).seconds().subsec_nanoseconds(), -400);
522     /// ```
523     pub const fn subsec_nanoseconds(self) -> i32 {
524         self.nanoseconds
525     }
526     // endregion getters
527 
528     // region: checked arithmetic
529     /// Computes `self + rhs`, returning `None` if an overflow occurred.
530     ///
531     /// ```rust
532     /// # use time::{Duration, ext::NumericalDuration};
533     /// assert_eq!(5.seconds().checked_add(5.seconds()), Some(10.seconds()));
534     /// assert_eq!(Duration::MAX.checked_add(1.nanoseconds()), None);
535     /// assert_eq!((-5).seconds().checked_add(5.seconds()), Some(0.seconds()));
536     /// ```
537     pub const fn checked_add(self, rhs: Self) -> Option<Self> {
538         let mut seconds = const_try_opt!(self.seconds.checked_add(rhs.seconds));
539         let mut nanoseconds = self.nanoseconds + rhs.nanoseconds;
540 
541         if nanoseconds >= 1_000_000_000 || seconds < 0 && nanoseconds > 0 {
542             nanoseconds -= 1_000_000_000;
543             seconds = const_try_opt!(seconds.checked_add(1));
544         } else if nanoseconds <= -1_000_000_000 || seconds > 0 && nanoseconds < 0 {
545             nanoseconds += 1_000_000_000;
546             seconds = const_try_opt!(seconds.checked_sub(1));
547         }
548 
549         Some(Self::new_unchecked(seconds, nanoseconds))
550     }
551 
552     /// Computes `self - rhs`, returning `None` if an overflow occurred.
553     ///
554     /// ```rust
555     /// # use time::{Duration, ext::NumericalDuration};
556     /// assert_eq!(5.seconds().checked_sub(5.seconds()), Some(Duration::ZERO));
557     /// assert_eq!(Duration::MIN.checked_sub(1.nanoseconds()), None);
558     /// assert_eq!(5.seconds().checked_sub(10.seconds()), Some((-5).seconds()));
559     /// ```
560     pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
561         let mut seconds = const_try_opt!(self.seconds.checked_sub(rhs.seconds));
562         let mut nanoseconds = self.nanoseconds - rhs.nanoseconds;
563 
564         if nanoseconds >= 1_000_000_000 || seconds < 0 && nanoseconds > 0 {
565             nanoseconds -= 1_000_000_000;
566             seconds = const_try_opt!(seconds.checked_add(1));
567         } else if nanoseconds <= -1_000_000_000 || seconds > 0 && nanoseconds < 0 {
568             nanoseconds += 1_000_000_000;
569             seconds = const_try_opt!(seconds.checked_sub(1));
570         }
571 
572         Some(Self::new_unchecked(seconds, nanoseconds))
573     }
574 
575     /// Computes `self * rhs`, returning `None` if an overflow occurred.
576     ///
577     /// ```rust
578     /// # use time::{Duration, ext::NumericalDuration};
579     /// assert_eq!(5.seconds().checked_mul(2), Some(10.seconds()));
580     /// assert_eq!(5.seconds().checked_mul(-2), Some((-10).seconds()));
581     /// assert_eq!(5.seconds().checked_mul(0), Some(0.seconds()));
582     /// assert_eq!(Duration::MAX.checked_mul(2), None);
583     /// assert_eq!(Duration::MIN.checked_mul(2), None);
584     /// ```
585     pub const fn checked_mul(self, rhs: i32) -> Option<Self> {
586         // Multiply nanoseconds as i64, because it cannot overflow that way.
587         let total_nanos = self.nanoseconds as i64 * rhs as i64;
588         let extra_secs = total_nanos / 1_000_000_000;
589         let nanoseconds = (total_nanos % 1_000_000_000) as _;
590         let seconds = const_try_opt!(
591             const_try_opt!(self.seconds.checked_mul(rhs as _)).checked_add(extra_secs)
592         );
593 
594         Some(Self::new_unchecked(seconds, nanoseconds))
595     }
596 
597     /// Computes `self / rhs`, returning `None` if `rhs == 0` or if the result would overflow.
598     ///
599     /// ```rust
600     /// # use time::ext::NumericalDuration;
601     /// assert_eq!(10.seconds().checked_div(2), Some(5.seconds()));
602     /// assert_eq!(10.seconds().checked_div(-2), Some((-5).seconds()));
603     /// assert_eq!(1.seconds().checked_div(0), None);
604     /// ```
605     #[allow(clippy::missing_const_for_fn)] // requires Rust 1.52
606     pub fn checked_div(self, rhs: i32) -> Option<Self> {
607         let seconds = const_try_opt!(self.seconds.checked_div(rhs as i64));
608         let carry = self.seconds - seconds * (rhs as i64);
609         let extra_nanos = const_try_opt!((carry * 1_000_000_000).checked_div(rhs as i64));
610         let nanoseconds = const_try_opt!(self.nanoseconds.checked_div(rhs)) + (extra_nanos as i32);
611 
612         Some(Self::new_unchecked(seconds, nanoseconds))
613     }
614     // endregion checked arithmetic
615 
616     // region: saturating arithmetic
617     /// Computes `self + rhs`, saturating if an overflow occurred.
618     ///
619     /// ```rust
620     /// # use time::{Duration, ext::NumericalDuration};
621     /// assert_eq!(5.seconds().saturating_add(5.seconds()), 10.seconds());
622     /// assert_eq!(Duration::MAX.saturating_add(1.nanoseconds()), Duration::MAX);
623     /// assert_eq!(
624     ///     Duration::MIN.saturating_add((-1).nanoseconds()),
625     ///     Duration::MIN
626     /// );
627     /// assert_eq!((-5).seconds().saturating_add(5.seconds()), Duration::ZERO);
628     /// ```
629     pub const fn saturating_add(self, rhs: Self) -> Self {
630         let (mut seconds, overflow) = self.seconds.overflowing_add(rhs.seconds);
631         if overflow {
632             if self.seconds > 0 {
633                 return Self::MAX;
634             }
635             return Self::MIN;
636         }
637         let mut nanoseconds = self.nanoseconds + rhs.nanoseconds;
638 
639         if nanoseconds >= 1_000_000_000 || seconds < 0 && nanoseconds > 0 {
640             nanoseconds -= 1_000_000_000;
641             seconds = match seconds.checked_add(1) {
642                 Some(seconds) => seconds,
643                 None => return Self::MAX,
644             };
645         } else if nanoseconds <= -1_000_000_000 || seconds > 0 && nanoseconds < 0 {
646             nanoseconds += 1_000_000_000;
647             seconds = match seconds.checked_sub(1) {
648                 Some(seconds) => seconds,
649                 None => return Self::MIN,
650             };
651         }
652 
653         Self::new_unchecked(seconds, nanoseconds)
654     }
655 
656     /// Computes `self - rhs`, saturating if an overflow occurred.
657     ///
658     /// ```rust
659     /// # use time::{Duration, ext::NumericalDuration};
660     /// assert_eq!(5.seconds().saturating_sub(5.seconds()), Duration::ZERO);
661     /// assert_eq!(Duration::MIN.saturating_sub(1.nanoseconds()), Duration::MIN);
662     /// assert_eq!(
663     ///     Duration::MAX.saturating_sub((-1).nanoseconds()),
664     ///     Duration::MAX
665     /// );
666     /// assert_eq!(5.seconds().saturating_sub(10.seconds()), (-5).seconds());
667     /// ```
668     pub const fn saturating_sub(self, rhs: Self) -> Self {
669         let (mut seconds, overflow) = self.seconds.overflowing_sub(rhs.seconds);
670         if overflow {
671             if self.seconds > 0 {
672                 return Self::MAX;
673             }
674             return Self::MIN;
675         }
676         let mut nanoseconds = self.nanoseconds - rhs.nanoseconds;
677 
678         if nanoseconds >= 1_000_000_000 || seconds < 0 && nanoseconds > 0 {
679             nanoseconds -= 1_000_000_000;
680             seconds = match seconds.checked_add(1) {
681                 Some(seconds) => seconds,
682                 None => return Self::MAX,
683             };
684         } else if nanoseconds <= -1_000_000_000 || seconds > 0 && nanoseconds < 0 {
685             nanoseconds += 1_000_000_000;
686             seconds = match seconds.checked_sub(1) {
687                 Some(seconds) => seconds,
688                 None => return Self::MIN,
689             };
690         }
691 
692         Self::new_unchecked(seconds, nanoseconds)
693     }
694 
695     /// Computes `self * rhs`, saturating if an overflow occurred.
696     ///
697     /// ```rust
698     /// # use time::{Duration, ext::NumericalDuration};
699     /// assert_eq!(5.seconds().saturating_mul(2), 10.seconds());
700     /// assert_eq!(5.seconds().saturating_mul(-2), (-10).seconds());
701     /// assert_eq!(5.seconds().saturating_mul(0), Duration::ZERO);
702     /// assert_eq!(Duration::MAX.saturating_mul(2), Duration::MAX);
703     /// assert_eq!(Duration::MIN.saturating_mul(2), Duration::MIN);
704     /// assert_eq!(Duration::MAX.saturating_mul(-2), Duration::MIN);
705     /// assert_eq!(Duration::MIN.saturating_mul(-2), Duration::MAX);
706     /// ```
707     pub const fn saturating_mul(self, rhs: i32) -> Self {
708         // Multiply nanoseconds as i64, because it cannot overflow that way.
709         let total_nanos = self.nanoseconds as i64 * rhs as i64;
710         let extra_secs = total_nanos / 1_000_000_000;
711         let nanoseconds = (total_nanos % 1_000_000_000) as _;
712         let (seconds, overflow1) = self.seconds.overflowing_mul(rhs as _);
713         if overflow1 {
714             if self.seconds > 0 && rhs > 0 || self.seconds < 0 && rhs < 0 {
715                 return Self::MAX;
716             }
717             return Self::MIN;
718         }
719         let (seconds, overflow2) = seconds.overflowing_add(extra_secs);
720         if overflow2 {
721             if self.seconds > 0 && rhs > 0 {
722                 return Self::MAX;
723             }
724             return Self::MIN;
725         }
726 
727         Self::new_unchecked(seconds, nanoseconds)
728     }
729     // endregion saturating arithmetic
730 
731     /// Runs a closure, returning the duration of time it took to run. The return value of the
732     /// closure is provided in the second part of the tuple.
733     #[cfg(feature = "std")]
734     pub fn time_fn<T>(f: impl FnOnce() -> T) -> (Self, T) {
735         let start = Instant::now();
736         let return_value = f();
737         let end = Instant::now();
738 
739         (end - start, return_value)
740     }
741 }
742 
743 // region: trait impls
744 impl TryFrom<StdDuration> for Duration {
745     type Error = error::ConversionRange;
746 
747     fn try_from(original: StdDuration) -> Result<Self, error::ConversionRange> {
748         Ok(Self::new(
749             original
750                 .as_secs()
751                 .try_into()
752                 .map_err(|_| error::ConversionRange)?,
753             original.subsec_nanos() as _,
754         ))
755     }
756 }
757 
758 impl TryFrom<Duration> for StdDuration {
759     type Error = error::ConversionRange;
760 
761     fn try_from(duration: Duration) -> Result<Self, error::ConversionRange> {
762         Ok(Self::new(
763             duration
764                 .seconds
765                 .try_into()
766                 .map_err(|_| error::ConversionRange)?,
767             duration
768                 .nanoseconds
769                 .try_into()
770                 .map_err(|_| error::ConversionRange)?,
771         ))
772     }
773 }
774 
775 impl Add for Duration {
776     type Output = Self;
777 
778     fn add(self, rhs: Self) -> Self::Output {
779         self.checked_add(rhs)
780             .expect("overflow when adding durations")
781     }
782 }
783 
784 impl Add<StdDuration> for Duration {
785     type Output = Self;
786 
787     fn add(self, std_duration: StdDuration) -> Self::Output {
788         self + Self::try_from(std_duration)
789             .expect("overflow converting `std::time::Duration` to `time::Duration`")
790     }
791 }
792 
793 impl Add<Duration> for StdDuration {
794     type Output = Duration;
795 
796     fn add(self, rhs: Duration) -> Self::Output {
797         rhs + self
798     }
799 }
800 
801 impl_add_assign!(Duration: Duration, StdDuration);
802 
803 impl Neg for Duration {
804     type Output = Self;
805 
806     fn neg(self) -> Self::Output {
807         Self::new_unchecked(-self.seconds, -self.nanoseconds)
808     }
809 }
810 
811 impl Sub for Duration {
812     type Output = Self;
813 
814     fn sub(self, rhs: Self) -> Self::Output {
815         self.checked_sub(rhs)
816             .expect("overflow when subtracting durations")
817     }
818 }
819 
820 impl Sub<StdDuration> for Duration {
821     type Output = Self;
822 
823     fn sub(self, rhs: StdDuration) -> Self::Output {
824         self - Self::try_from(rhs)
825             .expect("overflow converting `std::time::Duration` to `time::Duration`")
826     }
827 }
828 
829 impl Sub<Duration> for StdDuration {
830     type Output = Duration;
831 
832     fn sub(self, rhs: Duration) -> Self::Output {
833         Duration::try_from(self)
834             .expect("overflow converting `std::time::Duration` to `time::Duration`")
835             - rhs
836     }
837 }
838 
839 impl_sub_assign!(Duration: Duration, StdDuration);
840 
841 impl SubAssign<Duration> for StdDuration {
842     fn sub_assign(&mut self, rhs: Duration) {
843         *self = (*self - rhs).try_into().expect(
844             "Cannot represent a resulting duration in std. Try `let x = x - rhs;`, which will \
845              change the type.",
846         );
847     }
848 }
849 
850 /// Implement `Mul` (reflexively) and `Div` for `Duration` for various types.
851 macro_rules! duration_mul_div_int {
852     ($($type:ty),+) => {$(
853         impl Mul<$type> for Duration {
854             type Output = Self;
855 
856             fn mul(self, rhs: $type) -> Self::Output {
857                 Self::nanoseconds_i128(
858                     self.whole_nanoseconds()
859                         .checked_mul(rhs as _)
860                         .expect("overflow when multiplying duration")
861                 )
862             }
863         }
864 
865         impl Mul<Duration> for $type {
866             type Output = Duration;
867 
868             fn mul(self, rhs: Duration) -> Self::Output {
869                 rhs * self
870             }
871         }
872 
873         impl Div<$type> for Duration {
874             type Output = Self;
875 
876             fn div(self, rhs: $type) -> Self::Output {
877                 Self::nanoseconds_i128(self.whole_nanoseconds() / rhs as i128)
878             }
879         }
880     )+};
881 }
882 duration_mul_div_int![i8, i16, i32, u8, u16, u32];
883 
884 impl Mul<f32> for Duration {
885     type Output = Self;
886 
887     fn mul(self, rhs: f32) -> Self::Output {
888         Self::seconds_f32(self.as_seconds_f32() * rhs)
889     }
890 }
891 
892 impl Mul<Duration> for f32 {
893     type Output = Duration;
894 
895     fn mul(self, rhs: Duration) -> Self::Output {
896         rhs * self
897     }
898 }
899 
900 impl Mul<f64> for Duration {
901     type Output = Self;
902 
903     fn mul(self, rhs: f64) -> Self::Output {
904         Self::seconds_f64(self.as_seconds_f64() * rhs)
905     }
906 }
907 
908 impl Mul<Duration> for f64 {
909     type Output = Duration;
910 
911     fn mul(self, rhs: Duration) -> Self::Output {
912         rhs * self
913     }
914 }
915 
916 impl_mul_assign!(Duration: i8, i16, i32, u8, u16, u32, f32, f64);
917 
918 impl Div<f32> for Duration {
919     type Output = Self;
920 
921     fn div(self, rhs: f32) -> Self::Output {
922         Self::seconds_f32(self.as_seconds_f32() / rhs)
923     }
924 }
925 
926 impl Div<f64> for Duration {
927     type Output = Self;
928 
929     fn div(self, rhs: f64) -> Self::Output {
930         Self::seconds_f64(self.as_seconds_f64() / rhs)
931     }
932 }
933 
934 impl_div_assign!(Duration: i8, i16, i32, u8, u16, u32, f32, f64);
935 
936 impl Div for Duration {
937     type Output = f64;
938 
939     fn div(self, rhs: Self) -> Self::Output {
940         self.as_seconds_f64() / rhs.as_seconds_f64()
941     }
942 }
943 
944 impl Div<StdDuration> for Duration {
945     type Output = f64;
946 
947     fn div(self, rhs: StdDuration) -> Self::Output {
948         self.as_seconds_f64() / rhs.as_secs_f64()
949     }
950 }
951 
952 impl Div<Duration> for StdDuration {
953     type Output = f64;
954 
955     fn div(self, rhs: Duration) -> Self::Output {
956         self.as_secs_f64() / rhs.as_seconds_f64()
957     }
958 }
959 
960 impl PartialEq<StdDuration> for Duration {
961     fn eq(&self, rhs: &StdDuration) -> bool {
962         Ok(*self) == Self::try_from(*rhs)
963     }
964 }
965 
966 impl PartialEq<Duration> for StdDuration {
967     fn eq(&self, rhs: &Duration) -> bool {
968         rhs == self
969     }
970 }
971 
972 impl PartialOrd<StdDuration> for Duration {
973     fn partial_cmp(&self, rhs: &StdDuration) -> Option<Ordering> {
974         if rhs.as_secs() > i64::MAX as _ {
975             return Some(Ordering::Less);
976         }
977 
978         Some(
979             self.seconds
980                 .cmp(&(rhs.as_secs() as _))
981                 .then_with(|| self.nanoseconds.cmp(&(rhs.subsec_nanos() as _))),
982         )
983     }
984 }
985 
986 impl PartialOrd<Duration> for StdDuration {
987     fn partial_cmp(&self, rhs: &Duration) -> Option<Ordering> {
988         rhs.partial_cmp(self).map(Ordering::reverse)
989     }
990 }
991 
992 impl Sum for Duration {
993     fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
994         iter.reduce(|a, b| a + b).unwrap_or_default()
995     }
996 }
997 
998 impl<'a> Sum<&'a Self> for Duration {
999     fn sum<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
1000         iter.copied().sum()
1001     }
1002 }
1003 // endregion trait impls
1004