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