gametime/
span.rs

1//! This module contains `TimeSpan` type that represents durations.
2//! The name `Duration` is not used to avoid confusion with std type.
3//!
4//!
5//! Contains traits and functions to work with `TimeSpan`s.
6//!
7
8use core::{
9    convert::TryFrom,
10    fmt::{self, Debug, Display},
11    num::{NonZeroU64, TryFromIntError},
12    ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Range, Rem, RemAssign, Sub, SubAssign},
13    str::FromStr,
14    time::Duration,
15};
16
17/// An interval in between time stamps.
18/// This type is used to represent durations with nanosecond precision.
19#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
20#[repr(transparent)]
21pub struct TimeSpan {
22    nanos: u64,
23}
24
25impl TimeSpan {
26    fn fmt(self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
27        if self == Self::ZERO {
28            f.write_str("0")
29        } else {
30            let mut span = self;
31            if span >= Self::DAY {
32                let days = span / Self::DAY;
33                span %= Self::DAY;
34
35                let hours = span / Self::HOUR;
36                span %= Self::HOUR;
37
38                let minutes = span / Self::MINUTE;
39                span %= Self::MINUTE;
40
41                let seconds = span / Self::SECOND;
42                span %= Self::SECOND;
43
44                let millis = span / Self::MILLISECOND;
45
46                if millis > 0 {
47                    write!(f, "{days}d{hours:02}:{minutes:02}:{seconds:02}.{millis:03}")
48                } else if seconds > 0 {
49                    write!(f, "{days}d{hours:02}:{minutes:02}:{seconds:02}")
50                } else {
51                    write!(f, "{days}d{hours:02}:{minutes:02}")
52                }
53            } else if span >= Self::HOUR {
54                let hours = span / Self::HOUR;
55                span %= Self::HOUR;
56
57                let minutes = span / Self::MINUTE;
58                span %= Self::MINUTE;
59
60                let seconds = span / Self::SECOND;
61                span %= Self::SECOND;
62
63                let millis = span / Self::MILLISECOND;
64                if millis > 0 {
65                    write!(f, "{hours}:{minutes:02}:{seconds:02}.{millis:03}")
66                } else {
67                    write!(f, "{hours}:{minutes:02}:{seconds:02}")
68                }
69            } else if span >= Self::MINUTE {
70                let minutes = span / Self::MINUTE;
71                span %= Self::MINUTE;
72
73                let seconds = span / Self::SECOND;
74                span %= Self::SECOND;
75
76                let millis = span / Self::MILLISECOND;
77                if millis > 0 {
78                    write!(f, "{minutes}:{seconds:02}.{millis:03}")
79                } else {
80                    write!(f, "{minutes}:{seconds:02}")
81                }
82            } else if span >= Self::SECOND {
83                let seconds = span / Self::SECOND;
84                span %= Self::SECOND;
85
86                let millis = span / Self::MILLISECOND;
87                if millis > 0 {
88                    write!(f, "{seconds}.{millis:03}s")
89                } else {
90                    write!(f, "{seconds}s")
91                }
92            } else if span >= Self::MILLISECOND {
93                let millis = span / Self::MILLISECOND;
94                span %= Self::MILLISECOND;
95
96                let micros = span / Self::MICROSECOND;
97                if micros > 0 {
98                    write!(f, "{millis}.{micros:03}ms")
99                } else {
100                    write!(f, "{millis}ms")
101                }
102            } else if span >= Self::MICROSECOND {
103                let micros = span / Self::MICROSECOND;
104                span %= Self::MICROSECOND;
105
106                let nanos = span / Self::NANOSECOND;
107                if nanos > 0 {
108                    write!(f, "{micros}.{nanos:03}us")
109                } else {
110                    write!(f, "{micros}us")
111                }
112            } else {
113                let nanos = span / Self::NANOSECOND;
114                write!(f, "{nanos}ns")
115            }
116        }
117    }
118
119    fn fmt_full(self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
120        let mut span = self;
121        let days = span / Self::DAY;
122        span %= Self::DAY;
123        let hours = span / Self::HOUR;
124        span %= Self::HOUR;
125        let minutes = span / Self::MINUTE;
126        span %= Self::MINUTE;
127        let seconds = span / Self::SECOND;
128        span %= Self::SECOND;
129        let nanos = span / Self::NANOSECOND;
130
131        write!(
132            f,
133            "{days:01}d{hours:02}:{minutes:02}:{seconds:02}.{nanos:09}"
134        )
135    }
136
137    fn fmt_nanos(self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
138        write!(f, "{}ns", self.nanos)
139    }
140}
141
142impl Debug for TimeSpan {
143    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
144        if f.alternate() {
145            self.fmt_nanos(f)
146        } else {
147            (*self).fmt(f)
148        }
149    }
150}
151
152impl Display for TimeSpan {
153    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
154        if f.alternate() {
155            self.fmt_full(f)
156        } else {
157            (*self).fmt(f)
158        }
159    }
160}
161
162#[derive(Debug)]
163pub enum TimeSpanParseErr {
164    NonASCII,
165    StringTooLarge { len: usize },
166    IntParseError { source: core::num::ParseIntError },
167    UnexpectedDelimiter { delim: char, pos: usize },
168    UnexpectedEndOfString,
169    UnexpectedSuffix,
170    HoursOutOfBound { hours: u64 },
171    MinutesOutOfBound { minutes: u64 },
172    SecondsOutOfBound { seconds: u64 },
173}
174
175impl fmt::Display for TimeSpanParseErr {
176    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
177        match self {
178            Self::NonASCII => f.write_str("Time spans encoded in strings are always ASCII"),
179            Self::StringTooLarge { len } => {
180                write!(
181                    f,
182                    "Valid time span string may never exceed {MAX_TIME_SPAN_STRING} bytes. String is {len}"
183                )
184            }
185            Self::IntParseError { .. } => f.write_str("Failed to parse integer"),
186            Self::UnexpectedDelimiter { delim, pos } => {
187                write!(f, "Unexpected delimiter '{delim}' at {pos}")
188            }
189            Self::UnexpectedEndOfString => f.write_str("Unexpected end of string"),
190            Self::UnexpectedSuffix => {
191                f.write_str("Unexpected suffix. Only `s`, `ms` and `us` suffixes are supported")
192            }
193            Self::HoursOutOfBound { hours } => {
194                write!(f, "Hours must be in range 0-23 when days are specified. Value at hours position is '{hours}'")
195            }
196            Self::MinutesOutOfBound { minutes } => {
197                write!(f, "Minutes must be in range 0-59 when hours are specified. Value at minutes position is '{minutes}'")
198            }
199            Self::SecondsOutOfBound { seconds } => {
200                write!(
201                    f,
202                    "Seconds must be in range 0-59 when minutes are specified. Value at seconds position is '{seconds}'"
203                )
204            }
205        }
206    }
207}
208
209#[cfg(feature = "std")]
210impl std::error::Error for TimeSpanParseErr {
211    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
212        match self {
213            Self::IntParseError { source } => Some(source),
214            _ => None,
215        }
216    }
217}
218
219const MAX_TIME_SPAN_STRING: usize = 48;
220
221struct Ranges {
222    days: Option<Range<usize>>,
223    hours: Option<Range<usize>>,
224    minutes: Option<Range<usize>>,
225    seconds: Option<Range<usize>>,
226    fract: Option<Range<usize>>,
227    denom: u32,
228}
229
230impl Ranges {
231    fn parse(self, s: &str) -> Result<TimeSpan, TimeSpanParseErr> {
232        let seconds: u64 = self
233            .seconds
234            .map_or(Ok(0), |r| s[r].trim().parse())
235            .map_err(|source| TimeSpanParseErr::IntParseError { source })?;
236
237        if self.minutes.is_some() && seconds > 59 {
238            return Err(TimeSpanParseErr::SecondsOutOfBound { seconds });
239        }
240
241        let minutes: u64 = self
242            .minutes
243            .map_or(Ok(0), |r| s[r].trim().parse())
244            .map_err(|source| TimeSpanParseErr::IntParseError { source })?;
245
246        if self.hours.is_some() && minutes > 59 {
247            return Err(TimeSpanParseErr::MinutesOutOfBound { minutes });
248        }
249
250        let hours: u64 = self
251            .hours
252            .map_or(Ok(0), |r| s[r].trim().parse())
253            .map_err(|source| TimeSpanParseErr::IntParseError { source })?;
254
255        if self.days.is_some() && hours > 23 {
256            return Err(TimeSpanParseErr::HoursOutOfBound { hours });
257        }
258
259        let days: u64 = self
260            .days
261            .map_or(Ok(0), |r| s[r].trim().parse())
262            .map_err(|source| TimeSpanParseErr::IntParseError { source })?;
263
264        let fract: u64 = self
265            .fract
266            .map_or(Ok(0), |r| s[r].trim().parse())
267            .map_err(|source| TimeSpanParseErr::IntParseError { source })?;
268
269        let nanos = if self.denom > 9 {
270            fract / 10u64.pow(self.denom - 9)
271        } else {
272            fract * 10u64.pow(9 - self.denom)
273        };
274
275        Ok(days * TimeSpan::DAY
276            + hours * TimeSpan::HOUR
277            + minutes * TimeSpan::MINUTE
278            + seconds * TimeSpan::SECOND
279            + nanos * TimeSpan::NANOSECOND)
280    }
281}
282
283impl FromStr for TimeSpan {
284    type Err = TimeSpanParseErr;
285
286    #[allow(clippy::too_many_lines)]
287    fn from_str(s: &str) -> Result<Self, Self::Err> {
288        #![allow(clippy::cast_possible_truncation)]
289
290        if !s.is_ascii() {
291            return Err(TimeSpanParseErr::NonASCII);
292        }
293
294        if s.len() > MAX_TIME_SPAN_STRING {
295            return Err(TimeSpanParseErr::StringTooLarge { len: s.len() });
296        }
297
298        let mut seps = s.match_indices(|c: char| !c.is_ascii_digit() && !c.is_ascii_whitespace());
299
300        match seps.next() {
301            Some((dh, "d" | "D" | "t" | "T")) => match seps.next() {
302                Some((hm, ":")) => match seps.next() {
303                    None => Ranges {
304                        days: Some(0..dh),
305                        hours: Some(dh + 1..hm),
306                        minutes: Some(hm + 1..s.len()),
307                        seconds: None,
308                        fract: None,
309                        denom: 0,
310                    },
311                    Some((ms, ":")) => match seps.next() {
312                        None => Ranges {
313                            days: Some(0..dh),
314                            hours: Some(dh + 1..hm),
315                            minutes: Some(hm + 1..ms),
316                            seconds: Some(ms + 1..s.len()),
317                            fract: None,
318                            denom: 0,
319                        },
320                        Some((sf, ".")) => {
321                            if let Some((pos, delim)) = seps.next() {
322                                return Err(TimeSpanParseErr::UnexpectedDelimiter {
323                                    delim: delim.chars().next().unwrap(),
324                                    pos,
325                                });
326                            }
327                            Ranges {
328                                days: Some(0..dh),
329                                hours: Some(dh + 1..hm),
330                                minutes: Some(hm + 1..ms),
331                                seconds: Some(ms + 1..sf),
332                                fract: Some(sf + 1..s.len().min(sf + 21)),
333                                denom: (s.len() - sf - 1).min(20) as u32,
334                            }
335                        }
336
337                        Some((pos, delim)) => {
338                            return Err(TimeSpanParseErr::UnexpectedDelimiter {
339                                delim: delim.chars().next().unwrap(),
340                                pos,
341                            });
342                        }
343                    },
344                    Some((pos, delim)) => {
345                        return Err(TimeSpanParseErr::UnexpectedDelimiter {
346                            delim: delim.chars().next().unwrap(),
347                            pos,
348                        });
349                    }
350                },
351                Some((pos, delim)) => {
352                    return Err(TimeSpanParseErr::UnexpectedDelimiter {
353                        delim: delim.chars().next().unwrap(),
354                        pos,
355                    });
356                }
357                None => {
358                    return Err(TimeSpanParseErr::UnexpectedEndOfString);
359                }
360            },
361            Some((hms, ":")) => match seps.next() {
362                Some((ms, ":")) => match seps.next() {
363                    Some((sf, ".")) => {
364                        if let Some((pos, delim)) = seps.next() {
365                            return Err(TimeSpanParseErr::UnexpectedDelimiter {
366                                delim: delim.chars().next().unwrap(),
367                                pos,
368                            });
369                        }
370                        Ranges {
371                            days: None,
372                            hours: Some(0..hms),
373                            minutes: Some(hms + 1..ms),
374                            seconds: Some(ms + 1..sf),
375                            fract: Some(sf + 1..s.len().min(sf + 21)),
376                            denom: (s.len() - sf - 1).min(20) as u32,
377                        }
378                    }
379                    None => Ranges {
380                        days: None,
381                        hours: Some(0..hms),
382                        minutes: Some(hms + 1..ms),
383                        seconds: Some(ms + 1..s.len()),
384                        fract: None,
385                        denom: 0,
386                    },
387                    Some((pos, delim)) => {
388                        return Err(TimeSpanParseErr::UnexpectedDelimiter {
389                            delim: delim.chars().next().unwrap(),
390                            pos,
391                        });
392                    }
393                },
394                Some((sf, ".")) => {
395                    if let Some((pos, delim)) = seps.next() {
396                        return Err(TimeSpanParseErr::UnexpectedDelimiter {
397                            delim: delim.chars().next().unwrap(),
398                            pos,
399                        });
400                    }
401                    Ranges {
402                        days: None,
403                        hours: None,
404                        minutes: Some(0..hms),
405                        seconds: Some(hms + 1..sf),
406                        fract: Some(sf + 1..s.len()),
407                        denom: (s.len() - sf - 1).min(20) as u32,
408                    }
409                }
410                None => Ranges {
411                    days: None,
412                    hours: None,
413                    minutes: Some(0..hms),
414                    seconds: Some(hms + 1..s.len()),
415                    fract: None,
416                    denom: 0,
417                },
418                Some((pos, delim)) => {
419                    return Err(TimeSpanParseErr::UnexpectedDelimiter {
420                        delim: delim.chars().next().unwrap(),
421                        pos,
422                    });
423                }
424            },
425
426            Some((sf, ".")) => {
427                if let Some((pos, delim)) = seps.next() {
428                    return Err(TimeSpanParseErr::UnexpectedDelimiter {
429                        delim: delim.chars().next().unwrap(),
430                        pos,
431                    });
432                }
433                Ranges {
434                    days: None,
435                    hours: None,
436                    minutes: None,
437                    seconds: Some(0..sf),
438                    fract: Some(sf + 1..s.len()),
439                    denom: (s.len() - sf - 1).min(20) as u32,
440                }
441            }
442
443            Some((suffix, "s")) => {
444                if s[suffix..].trim() != "s" {
445                    return Err(TimeSpanParseErr::UnexpectedSuffix);
446                }
447
448                let seconds: u64 = s[..suffix]
449                    .trim()
450                    .parse()
451                    .map_err(|source| TimeSpanParseErr::IntParseError { source })?;
452                return Ok(seconds * Self::SECOND);
453            }
454
455            Some((suffix, "m")) => {
456                if s[suffix..].trim() != "ms" {
457                    return Err(TimeSpanParseErr::UnexpectedSuffix);
458                }
459
460                let millis: u64 = s[..suffix]
461                    .trim()
462                    .parse()
463                    .map_err(|source| TimeSpanParseErr::IntParseError { source })?;
464                return Ok(millis * Self::MILLISECOND);
465            }
466
467            Some((suffix, "u")) => {
468                if s[suffix..].trim() != "us" {
469                    return Err(TimeSpanParseErr::UnexpectedSuffix);
470                }
471
472                let micros: u64 = s[..suffix]
473                    .trim()
474                    .parse()
475                    .map_err(|source| TimeSpanParseErr::IntParseError { source })?;
476                return Ok(micros * Self::MICROSECOND);
477            }
478
479            None => {
480                let seconds: u64 = s
481                    .trim()
482                    .parse()
483                    .map_err(|source| TimeSpanParseErr::IntParseError { source })?;
484                return Ok(seconds * Self::SECOND);
485            }
486
487            Some((pos, delim)) => {
488                return Err(TimeSpanParseErr::UnexpectedDelimiter {
489                    delim: delim.chars().next().unwrap(),
490                    pos,
491                });
492            }
493        }
494        .parse(s)
495    }
496}
497
498#[cfg(feature = "serde")]
499impl serde::Serialize for TimeSpan {
500    #[inline]
501    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
502    where
503        S: serde::Serializer,
504    {
505        // Serialize in pretty format for human readable serializer
506        if serializer.is_human_readable() {
507            serializer.serialize_str(&self.to_string())
508        } else {
509            serializer.serialize_u64(self.nanos)
510        }
511    }
512}
513
514#[cfg(feature = "serde")]
515impl<'de> serde::Deserialize<'de> for TimeSpan {
516    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
517    where
518        D: serde::Deserializer<'de>,
519    {
520        struct Visitor;
521
522        impl<'de> serde::de::Visitor<'de> for Visitor {
523            type Value = TimeSpan;
524
525            fn expecting(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
526                fmt.write_str("String with encoded time span or integer representing nanoseconds")
527            }
528
529            fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E> {
530                Ok(TimeSpan { nanos: v })
531            }
532
533            fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
534            where
535                E: serde::de::Error,
536            {
537                if v < 0 {
538                    Err(E::custom("TimeSpan cannot be negative"))
539                } else {
540                    Ok(TimeSpan { nanos: v as u64 })
541                }
542            }
543
544            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
545            where
546                E: serde::de::Error,
547            {
548                v.parse().map_err(|err| E::custom(err))
549            }
550        }
551
552        if deserializer.is_human_readable() {
553            deserializer.deserialize_str(Visitor)
554        } else {
555            deserializer.deserialize_u64(Visitor)
556        }
557    }
558}
559
560impl From<Duration> for TimeSpan {
561    #[inline]
562    fn from(duration: Duration) -> Self {
563        let nanos = duration.as_nanos();
564        let nanos = u64::try_from(nanos).expect("Duration is too large to fit in TimeSpan");
565
566        TimeSpan {
567            nanos,
568        }
569    }
570}
571
572impl From<TimeSpan> for Duration {
573    #[inline]
574    fn from(span: TimeSpan) -> Self {
575        Duration::new(span.as_seconds(), (span.as_nanos() % 1_000_000_000) as u32)
576    }
577}
578
579impl TimeSpan {
580    /// Zero time span.
581    ///
582    /// Represents duration between equal time points.
583    pub const ZERO: Self = TimeSpan { nanos: 0 };
584
585    /// One nanosecond span.
586    /// Minimal possible time span supported by this type.
587    pub const NANOSECOND: Self = TimeSpan { nanos: 1 };
588
589    /// One microsecond span.
590    pub const MICROSECOND: Self = TimeSpan { nanos: 1_000 };
591
592    /// One millisecond span.
593    pub const MILLISECOND: Self = TimeSpan { nanos: 1_000_000 };
594
595    /// One second span.
596    pub const SECOND: Self = TimeSpan {
597        nanos: 1_000_000_000,
598    };
599
600    /// One minute span.
601    pub const MINUTE: Self = TimeSpan {
602        nanos: 60_000_000_000,
603    };
604
605    /// One hour span.
606    pub const HOUR: Self = TimeSpan {
607        nanos: 3_600_000_000_000,
608    };
609
610    /// One day span.
611    pub const DAY: Self = TimeSpan {
612        nanos: 86_400_000_000_000,
613    };
614
615    /// One week.
616    /// Defined as 7 days.
617    pub const WEEK: Self = TimeSpan {
618        nanos: 604_800_000_000_000,
619    };
620
621    /// One Julian year.
622    /// Average year length in Julian calendar.
623    /// Defined as 365.25 days.
624    pub const JULIAN_YEAR: Self = TimeSpan {
625        nanos: 31_557_600_000_000_000,
626    };
627
628    /// One Gregorian year.
629    /// Average year length in Gregorian calendar.
630    /// Defined as 365.2425 days.
631    pub const GREGORIAN_YEAR: Self = TimeSpan {
632        nanos: 31_556_952_000_000,
633    };
634
635    /// One solar year (tropical year).
636    /// Defined as 365.24219 days.
637    pub const SOLAR_YEAR: Self = TimeSpan {
638        nanos: 31_556_925_216_000_000,
639    };
640
641    /// One year.
642    /// Closest value to the average length of a year on Earth.
643    pub const YEAR: Self = Self::SOLAR_YEAR;
644
645    /// Constructs time span from number of nanoseconds.
646    #[inline]
647    #[must_use]
648    pub const fn new(nanos: u64) -> TimeSpan {
649        TimeSpan { nanos }
650    }
651
652    /// Returns number of nanoseconds in this time span.
653    #[inline]
654    #[must_use]
655    pub const fn as_nanos(self) -> u64 {
656        self.nanos
657    }
658
659    /// Returns number of microseconds this value represents.
660    #[inline]
661    #[must_use]
662    pub const fn as_micros(&self) -> u64 {
663        self.nanos / Self::MICROSECOND.nanos
664    }
665
666    /// Returns number of whole milliseconds this value represents.
667    #[inline]
668    #[must_use]
669    pub const fn as_millis(&self) -> u64 {
670        self.nanos / Self::MILLISECOND.nanos
671    }
672
673    /// Returns number of whole seconds this value represents.
674    #[inline]
675    #[must_use]
676    pub const fn as_seconds(&self) -> u64 {
677        self.nanos / Self::SECOND.nanos
678    }
679
680    /// Returns number of whole minutes this value represents.
681    #[inline]
682    #[must_use]
683    pub const fn as_minutes(&self) -> u64 {
684        self.nanos / Self::MINUTE.nanos
685    }
686
687    /// Returns number of whole hours this value represents.
688    #[inline]
689    #[must_use]
690    pub const fn as_hours(&self) -> u64 {
691        self.nanos / Self::HOUR.nanos
692    }
693
694    /// Returns number of whole days this value represents.
695    #[inline]
696    #[must_use]
697    pub const fn as_days(&self) -> u64 {
698        self.nanos / Self::DAY.nanos
699    }
700
701    /// Returns number of whole weeks this value represents.
702    #[inline]
703    #[must_use]
704    pub const fn as_weeks(&self) -> u64 {
705        self.nanos / Self::WEEK.nanos
706    }
707
708    /// Returns number of seconds as floating point value.
709    /// This function should be used for small-ish spans when high precision is not required.
710    #[inline]
711    #[must_use]
712    pub fn as_secs_f32(&self) -> f32 {
713        #![allow(clippy::cast_precision_loss)] // Precision loss is acceptable here.
714
715        self.nanos as f32 / Self::SECOND.nanos as f32
716    }
717
718    /// Returns number of seconds as high precision floating point value.
719    #[inline]
720    #[must_use]
721    pub fn as_secs_f64(&self) -> f64 {
722        #![allow(clippy::cast_precision_loss)] // Precision loss is acceptable here.
723
724        self.nanos as f64 / Self::SECOND.nanos as f64
725    }
726
727    /// Returns checked sum of two time spans.
728    #[inline]
729    #[must_use]
730    pub const fn checked_add(self, span: TimeSpan) -> Option<TimeSpan> {
731        match self.nanos.checked_add(span.nanos) {
732            None => None,
733            Some(nanos) => Some(TimeSpan { nanos }),
734        }
735    }
736
737    /// Returns checked difference of two time spans.
738    #[inline]
739    #[must_use]
740    pub const fn checked_sub(self, span: TimeSpan) -> Option<TimeSpan> {
741        match self.nanos.checked_sub(span.nanos) {
742            None => None,
743            Some(nanos) => Some(TimeSpan { nanos }),
744        }
745    }
746
747    /// Returns checked multiplication of time span by a number.
748    #[inline]
749    #[must_use]
750    pub const fn checked_mul(self, value: u64) -> Option<TimeSpan> {
751        match self.nanos.checked_mul(value) {
752            None => None,
753            Some(nanos) => Some(TimeSpan { nanos }),
754        }
755    }
756
757    /// Returns checked division of time span by a number.
758    #[inline]
759    #[must_use]
760    pub const fn checked_div(self, value: u64) -> Option<TimeSpan> {
761        match self.nanos.checked_div(value) {
762            None => None,
763            Some(nanos) => Some(TimeSpan { nanos }),
764        }
765    }
766
767    /// Returns the result of dividing this time span by a non-zero value.
768    #[inline]
769    #[must_use]
770    pub const fn div(self, value: NonZeroU64) -> TimeSpan {
771        let nanos = self.nanos / value.get();
772        TimeSpan { nanos }
773    }
774
775    /// Returns the result of dividing this time span by a non-zero time span.
776    #[inline]
777    #[must_use]
778    pub const fn checked_div_span(self, span: TimeSpan) -> Option<u64> {
779        match self.nanos.checked_div(span.nanos) {
780            None => None,
781            Some(value) => Some(value),
782        }
783    }
784
785    /// Returns the result of dividing this time span by a non-zero time span.
786    #[inline]
787    #[must_use]
788    pub const fn div_span(self, span: NonZeroTimeSpan) -> u64 {
789        self.nanos / span.nanos.get()
790    }
791
792    /// Returns checked remainder of time span divided by a number.
793    #[inline]
794    #[must_use]
795    pub const fn checked_rem(self, value: u64) -> Option<TimeSpan> {
796        match self.nanos.checked_rem(value) {
797            None => None,
798            Some(nanos) => Some(TimeSpan { nanos }),
799        }
800    }
801
802    /// Returns the remainder of time span divided by a non-zero value.
803    #[inline]
804    #[must_use]
805    pub const fn rem(self, value: NonZeroU64) -> TimeSpan {
806        let nanos = self.nanos % value.get();
807        TimeSpan { nanos }
808    }
809
810    /// Returns checked remainder of time span divided by a non-zero time span.
811    #[inline]
812    #[must_use]
813    pub const fn checked_rem_span(self, span: TimeSpan) -> Option<TimeSpan> {
814        match self.nanos.checked_rem(span.nanos) {
815            None => None,
816            Some(nanos) => Some(TimeSpan { nanos }),
817        }
818    }
819
820    /// Returns the remainder of time span divided by a non-zero time span.
821    #[inline]
822    #[must_use]
823    pub const fn rem_span(self, span: NonZeroTimeSpan) -> TimeSpan {
824        let nanos = self.nanos % span.nanos.get();
825        TimeSpan { nanos }
826    }
827
828    /// Constructs time span from number of days, hours, minutes and seconds.
829    #[inline]
830    #[must_use]
831    pub const fn hms(hours: u64, minutes: u64, seconds: u64) -> TimeSpan {
832        TimeSpan {
833            nanos: hours * Self::HOUR.nanos
834                + minutes * Self::MINUTE.nanos
835                + seconds * Self::SECOND.nanos,
836        }
837    }
838
839    /// Constructs time span from number of days, hours, minutes and seconds.
840    #[inline]
841    #[must_use]
842    pub const fn dhms(days: u64, hours: u64, minutes: u64, seconds: u64) -> TimeSpan {
843        TimeSpan {
844            nanos: days * Self::DAY.nanos
845                + hours * Self::HOUR.nanos
846                + minutes * Self::MINUTE.nanos
847                + seconds * Self::SECOND.nanos,
848        }
849    }
850}
851
852/// An interval in between different time stamps.
853#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
854#[repr(transparent)]
855pub struct NonZeroTimeSpan {
856    nanos: NonZeroU64,
857}
858
859impl From<NonZeroTimeSpan> for TimeSpan {
860    #[inline]
861    fn from(span: NonZeroTimeSpan) -> Self {
862        TimeSpan {
863            nanos: span.nanos.get(),
864        }
865    }
866}
867
868impl TryFrom<TimeSpan> for NonZeroTimeSpan {
869    type Error = TryFromIntError;
870
871    #[inline]
872    fn try_from(span: TimeSpan) -> Result<Self, TryFromIntError> {
873        match NonZeroU64::try_from(span.nanos) {
874            Err(err) => Err(err),
875            Ok(nanos) => Ok(NonZeroTimeSpan { nanos }),
876        }
877    }
878}
879
880impl NonZeroTimeSpan {
881    /// One nanosecond span.
882    /// Minimal possible time span supported by this type.
883    pub const NANOSECOND: Self = NonZeroTimeSpan {
884        nanos: const { NonZeroU64::new(1).unwrap() },
885    };
886
887    /// One microsecond span.
888    pub const MICROSECOND: Self = NonZeroTimeSpan {
889        nanos: const { NonZeroU64::new(1_000).unwrap() },
890    };
891
892    /// One millisecond span.
893    pub const MILLISECOND: Self = NonZeroTimeSpan {
894        nanos: const { NonZeroU64::new(1_000_000).unwrap() },
895    };
896
897    /// One second span.
898    pub const SECOND: Self = NonZeroTimeSpan {
899        nanos: const { NonZeroU64::new(1_000_000_000).unwrap() },
900    };
901
902    /// One minute span.
903    pub const MINUTE: Self = NonZeroTimeSpan {
904        nanos: const { NonZeroU64::new(60_000_000_000).unwrap() },
905    };
906
907    /// One hour span.
908    pub const HOUR: Self = NonZeroTimeSpan {
909        nanos: const { NonZeroU64::new(3_600_000_000_000).unwrap() },
910    };
911
912    /// One day span.
913    pub const DAY: Self = NonZeroTimeSpan {
914        nanos: const { NonZeroU64::new(86_400_000_000_000).unwrap() },
915    };
916
917    /// One week.
918    /// Defined as 7 days.
919    pub const WEEK: Self = NonZeroTimeSpan {
920        nanos: const { NonZeroU64::new(604_800_000_000_000).unwrap() },
921    };
922
923    /// One Julian year.
924    /// Average year length in Julian calendar.
925    /// Defined as 365.25 days.
926    pub const JULIAN_YEAR: Self = NonZeroTimeSpan {
927        nanos: const { NonZeroU64::new(31_557_600_000_000_000).unwrap() },
928    };
929
930    /// One Gregorian year.
931    /// Average year length in Gregorian calendar.
932    /// 3 days per 400 years shorter than Julian year.
933    /// Defined as 365.2425 days.
934    pub const GREGORIAN_YEAR: Self = NonZeroTimeSpan {
935        nanos: const { NonZeroU64::new(31_556_952_000_000).unwrap() },
936    };
937
938    /// One solar year (tropical year).
939    /// Defined as 365.24219 days.
940    pub const SOLAR_YEAR: Self = NonZeroTimeSpan {
941        nanos: const { NonZeroU64::new(31_556_925_216_000_000).unwrap() },
942    };
943
944    /// One year.
945    /// Closest value to the average length of a year on Earth.
946    pub const YEAR: Self = Self::SOLAR_YEAR;
947
948    /// Constructs time span from number of nanoseconds.
949    #[inline]
950    #[must_use]
951    pub const fn new(nanos: NonZeroU64) -> NonZeroTimeSpan {
952        NonZeroTimeSpan { nanos }
953    }
954    /// Returns number of nanoseconds in this time span.
955    #[inline]
956    #[must_use]
957    pub const fn as_nanos(self) -> NonZeroU64 {
958        self.nanos
959    }
960
961    /// Returns number of microseconds this value represents.
962    #[inline]
963    #[must_use]
964    pub const fn as_micros(&self) -> u64 {
965        self.nanos.get() / Self::MICROSECOND.nanos.get()
966    }
967
968    /// Returns number of whole milliseconds this value represents.
969    #[inline]
970    #[must_use]
971    pub const fn as_millis(&self) -> u64 {
972        self.nanos.get() / Self::MILLISECOND.nanos.get()
973    }
974
975    /// Returns number of whole seconds this value represents.
976    #[inline]
977    #[must_use]
978    pub const fn as_seconds(&self) -> u64 {
979        self.nanos.get() / Self::SECOND.nanos.get()
980    }
981
982    /// Returns number of whole minutes this value represents.
983    #[inline]
984    #[must_use]
985    pub const fn as_minutes(&self) -> u64 {
986        self.nanos.get() / Self::MINUTE.nanos.get()
987    }
988
989    /// Returns number of whole hours this value represents.
990    #[inline]
991    #[must_use]
992    pub const fn as_hours(&self) -> u64 {
993        self.nanos.get() / Self::HOUR.nanos.get()
994    }
995
996    /// Returns number of whole days this value represents.
997    #[inline]
998    #[must_use]
999    pub const fn as_days(&self) -> u64 {
1000        self.nanos.get() / Self::DAY.nanos.get()
1001    }
1002
1003    /// Returns number of whole weeks this value represents.
1004    #[inline]
1005    #[must_use]
1006    pub const fn as_weeks(&self) -> u64 {
1007        self.nanos.get() / Self::WEEK.nanos.get()
1008    }
1009
1010    /// Returns number of seconds as floating point value.
1011    /// This function should be used for small-ish spans when high precision is not required.
1012    #[inline]
1013    #[must_use]
1014    pub fn as_secs_f32(&self) -> f32 {
1015        #![allow(clippy::cast_precision_loss)] // Precision loss is acceptable here.
1016
1017        self.nanos.get() as f32 / Self::SECOND.nanos.get() as f32
1018    }
1019
1020    /// Returns number of seconds as high precision floating point value.
1021    #[inline]
1022    #[must_use]
1023    pub fn as_secs_f64(&self) -> f64 {
1024        #![allow(clippy::cast_precision_loss)] // Precision loss is acceptable here.
1025
1026        self.nanos.get() as f64 / Self::SECOND.nanos.get() as f64
1027    }
1028
1029    /// Returns checked sum of two time spans.
1030    #[inline]
1031    #[must_use]
1032    pub const fn checked_add(self, span: TimeSpan) -> Option<NonZeroTimeSpan> {
1033        match self.nanos.get().checked_add(span.nanos) {
1034            None => None,
1035            Some(nanos) => Some(NonZeroTimeSpan {
1036                nanos: unsafe {
1037                    // # Safety
1038                    // Sum of non-zero and non-negative is non-zero
1039                    NonZeroU64::new_unchecked(nanos)
1040                },
1041            }),
1042        }
1043    }
1044
1045    /// Returns checked difference of two time spans.
1046    #[inline]
1047    #[must_use]
1048    pub const fn checked_sub(self, span: TimeSpan) -> Option<TimeSpan> {
1049        match self.nanos.get().checked_sub(span.nanos) {
1050            None => None,
1051            Some(nanos) => Some(TimeSpan { nanos }),
1052        }
1053    }
1054
1055    /// Returns checked multiplication of time span by a number.
1056    #[inline]
1057    #[must_use]
1058    pub const fn checked_mul(self, value: u64) -> Option<TimeSpan> {
1059        match self.nanos.get().checked_mul(value) {
1060            None => None,
1061            Some(nanos) => Some(TimeSpan { nanos }),
1062        }
1063    }
1064
1065    /// Returns checked multiplication of time span by a non-zero number.
1066    #[inline]
1067    #[must_use]
1068    pub const fn checked_mul_non_zero(self, value: NonZeroU64) -> Option<NonZeroTimeSpan> {
1069        match self.nanos.get().checked_mul(value.get()) {
1070            None => None,
1071            Some(nanos) => Some(NonZeroTimeSpan {
1072                nanos: unsafe {
1073                    // # Safety
1074                    // a > 0, b > 0 hence a * b > 0
1075                    NonZeroU64::new_unchecked(nanos)
1076                },
1077            }),
1078        }
1079    }
1080
1081    /// Returns checked division of time span by a number.
1082    #[inline]
1083    #[must_use]
1084    pub const fn checked_div(self, value: u64) -> Option<TimeSpan> {
1085        match self.nanos.get().checked_div(value) {
1086            None => None,
1087            Some(nanos) => Some(TimeSpan { nanos }),
1088        }
1089    }
1090
1091    /// Returns the result of dividing this time span by a non-zero value.
1092    #[inline]
1093    #[must_use]
1094    pub const fn div(self, value: NonZeroU64) -> TimeSpan {
1095        let nanos = self.nanos.get() / value.get();
1096        TimeSpan { nanos }
1097    }
1098
1099    /// Returns the result of dividing this time span by a non-zero time span.
1100    #[inline]
1101    #[must_use]
1102    pub const fn checked_div_span(self, span: TimeSpan) -> Option<u64> {
1103        match self.nanos.get().checked_div(span.nanos) {
1104            None => None,
1105            Some(value) => Some(value),
1106        }
1107    }
1108
1109    /// Returns the result of dividing this time span by a non-zero time span.
1110    #[inline]
1111    #[must_use]
1112    pub const fn div_span(self, span: NonZeroTimeSpan) -> u64 {
1113        self.nanos.get() / span.nanos.get()
1114    }
1115
1116    /// Returns checked remainder of time span divided by a number.
1117    #[inline]
1118    #[must_use]
1119    pub const fn checked_rem(self, value: u64) -> Option<TimeSpan> {
1120        match self.nanos.get().checked_rem(value) {
1121            None => None,
1122            Some(nanos) => Some(TimeSpan { nanos }),
1123        }
1124    }
1125
1126    /// Returns the remainder of time span divided by a non-zero value.
1127    #[inline]
1128    #[must_use]
1129    pub const fn rem(self, value: NonZeroU64) -> TimeSpan {
1130        let nanos = self.nanos.get() % value.get();
1131        TimeSpan { nanos }
1132    }
1133
1134    /// Returns checked remainder of time span divided by a non-zero time span.
1135    #[inline]
1136    #[must_use]
1137    pub const fn checked_rem_span(self, span: TimeSpan) -> Option<TimeSpan> {
1138        match self.nanos.get().checked_rem(span.nanos) {
1139            None => None,
1140            Some(nanos) => Some(TimeSpan { nanos }),
1141        }
1142    }
1143
1144    /// Returns the remainder of time span divided by a non-zero time span.
1145    #[inline]
1146    #[must_use]
1147    pub const fn rem_span(self, span: NonZeroTimeSpan) -> TimeSpan {
1148        let nanos = self.nanos.get() % span.nanos.get();
1149        TimeSpan { nanos }
1150    }
1151}
1152
1153impl Add<TimeSpan> for TimeSpan {
1154    type Output = Self;
1155
1156    #[inline]
1157    fn add(self, rhs: TimeSpan) -> Self {
1158        self.checked_add(rhs).expect("overflow when adding spans")
1159    }
1160}
1161
1162impl Add<TimeSpan> for NonZeroTimeSpan {
1163    type Output = Self;
1164
1165    #[inline]
1166    fn add(self, rhs: TimeSpan) -> Self {
1167        self.checked_add(rhs).expect("overflow when adding spans")
1168    }
1169}
1170
1171impl Add<NonZeroTimeSpan> for TimeSpan {
1172    type Output = NonZeroTimeSpan;
1173
1174    #[inline]
1175    fn add(self, rhs: NonZeroTimeSpan) -> NonZeroTimeSpan {
1176        rhs.checked_add(self).expect("overflow when adding spans")
1177    }
1178}
1179
1180impl Add<NonZeroTimeSpan> for NonZeroTimeSpan {
1181    type Output = NonZeroTimeSpan;
1182
1183    #[inline]
1184    fn add(self, rhs: NonZeroTimeSpan) -> Self {
1185        self.checked_add(rhs.into())
1186            .expect("overflow when adding spans")
1187    }
1188}
1189
1190impl AddAssign<TimeSpan> for TimeSpan {
1191    fn add_assign(&mut self, rhs: TimeSpan) {
1192        *self = *self + rhs;
1193    }
1194}
1195
1196impl AddAssign<NonZeroTimeSpan> for TimeSpan {
1197    fn add_assign(&mut self, rhs: NonZeroTimeSpan) {
1198        *self = (*self + rhs).into();
1199    }
1200}
1201
1202impl AddAssign<TimeSpan> for NonZeroTimeSpan {
1203    fn add_assign(&mut self, rhs: TimeSpan) {
1204        *self = *self + rhs;
1205    }
1206}
1207
1208impl AddAssign<NonZeroTimeSpan> for NonZeroTimeSpan {
1209    fn add_assign(&mut self, rhs: Self) {
1210        *self = *self + rhs;
1211    }
1212}
1213
1214impl Sub<TimeSpan> for TimeSpan {
1215    type Output = TimeSpan;
1216
1217    #[inline]
1218    fn sub(self, rhs: TimeSpan) -> Self {
1219        self.checked_sub(rhs)
1220            .expect("overflow when subtracting spans")
1221    }
1222}
1223
1224impl Sub<TimeSpan> for NonZeroTimeSpan {
1225    type Output = TimeSpan;
1226
1227    #[inline]
1228    fn sub(self, rhs: TimeSpan) -> TimeSpan {
1229        self.checked_sub(rhs)
1230            .expect("overflow when subtracting spans")
1231    }
1232}
1233
1234impl Sub<NonZeroTimeSpan> for TimeSpan {
1235    type Output = TimeSpan;
1236
1237    #[inline]
1238    fn sub(self, rhs: NonZeroTimeSpan) -> TimeSpan {
1239        rhs.checked_sub(self)
1240            .expect("overflow when subtracting spans")
1241    }
1242}
1243
1244impl Sub<NonZeroTimeSpan> for NonZeroTimeSpan {
1245    type Output = TimeSpan;
1246
1247    #[inline]
1248    fn sub(self, rhs: NonZeroTimeSpan) -> TimeSpan {
1249        self.checked_sub(rhs.into())
1250            .expect("overflow when subtracting spans")
1251    }
1252}
1253
1254impl SubAssign<TimeSpan> for TimeSpan {
1255    fn sub_assign(&mut self, rhs: TimeSpan) {
1256        *self = *self - rhs;
1257    }
1258}
1259
1260impl SubAssign<NonZeroTimeSpan> for TimeSpan {
1261    fn sub_assign(&mut self, rhs: NonZeroTimeSpan) {
1262        *self = *self - rhs;
1263    }
1264}
1265
1266impl Div<TimeSpan> for TimeSpan {
1267    type Output = u64;
1268
1269    #[inline]
1270    fn div(self, rhs: TimeSpan) -> u64 {
1271        self.checked_div_span(rhs)
1272            .expect("divide by zero error when dividing span by span")
1273    }
1274}
1275
1276impl Div<NonZeroTimeSpan> for TimeSpan {
1277    type Output = u64;
1278
1279    #[inline]
1280    fn div(self, rhs: NonZeroTimeSpan) -> u64 {
1281        self.div_span(rhs)
1282    }
1283}
1284
1285impl Div<TimeSpan> for NonZeroTimeSpan {
1286    type Output = u64;
1287
1288    #[inline]
1289    fn div(self, rhs: TimeSpan) -> u64 {
1290        self.checked_div_span(rhs)
1291            .expect("divide by zero error when dividing span by span")
1292    }
1293}
1294
1295impl Div<NonZeroTimeSpan> for NonZeroTimeSpan {
1296    type Output = u64;
1297
1298    #[inline]
1299    fn div(self, rhs: NonZeroTimeSpan) -> u64 {
1300        self.div_span(rhs)
1301    }
1302}
1303
1304impl Rem<TimeSpan> for TimeSpan {
1305    type Output = TimeSpan;
1306
1307    #[inline]
1308    fn rem(self, rhs: TimeSpan) -> TimeSpan {
1309        self.checked_rem_span(rhs)
1310            .expect("divide by zero error when dividing span by span")
1311    }
1312}
1313
1314impl RemAssign<TimeSpan> for TimeSpan {
1315    #[inline]
1316    fn rem_assign(&mut self, rhs: TimeSpan) {
1317        *self = *self % rhs;
1318    }
1319}
1320
1321impl Rem<NonZeroTimeSpan> for TimeSpan {
1322    type Output = TimeSpan;
1323
1324    #[inline]
1325    fn rem(self, rhs: NonZeroTimeSpan) -> TimeSpan {
1326        self.rem_span(rhs)
1327    }
1328}
1329
1330impl RemAssign<NonZeroTimeSpan> for TimeSpan {
1331    #[inline]
1332    fn rem_assign(&mut self, rhs: NonZeroTimeSpan) {
1333        *self = *self % rhs;
1334    }
1335}
1336
1337impl Rem<TimeSpan> for NonZeroTimeSpan {
1338    type Output = TimeSpan;
1339
1340    #[inline]
1341    fn rem(self, rhs: TimeSpan) -> TimeSpan {
1342        self.checked_rem_span(rhs)
1343            .expect("divide by zero error when dividing span by span")
1344    }
1345}
1346
1347impl Rem<NonZeroTimeSpan> for NonZeroTimeSpan {
1348    type Output = TimeSpan;
1349
1350    #[inline]
1351    fn rem(self, rhs: NonZeroTimeSpan) -> TimeSpan {
1352        self.rem_span(rhs)
1353    }
1354}
1355
1356impl Mul<u64> for TimeSpan {
1357    type Output = Self;
1358
1359    #[inline]
1360    fn mul(self, rhs: u64) -> Self {
1361        self.checked_mul(rhs)
1362            .expect("overflow when multiplying span by scalar")
1363    }
1364}
1365
1366impl Mul<TimeSpan> for u64 {
1367    type Output = TimeSpan;
1368
1369    #[inline]
1370    fn mul(self, rhs: TimeSpan) -> TimeSpan {
1371        rhs * self
1372    }
1373}
1374
1375impl MulAssign<u64> for TimeSpan {
1376    #[inline]
1377    fn mul_assign(&mut self, rhs: u64) {
1378        *self = *self * rhs;
1379    }
1380}
1381
1382impl Div<u64> for TimeSpan {
1383    type Output = TimeSpan;
1384
1385    #[inline]
1386    fn div(self, rhs: u64) -> Self {
1387        self.checked_div(rhs)
1388            .expect("divide by zero error when dividing span by scalar")
1389    }
1390}
1391
1392impl DivAssign<u64> for TimeSpan {
1393    #[inline]
1394    fn div_assign(&mut self, rhs: u64) {
1395        *self = *self / rhs;
1396    }
1397}
1398
1399impl Rem<u64> for TimeSpan {
1400    type Output = TimeSpan;
1401
1402    #[inline]
1403    fn rem(self, rhs: u64) -> Self {
1404        self.checked_rem(rhs)
1405            .expect("divide by zero error when dividing span by scalar")
1406    }
1407}
1408
1409impl RemAssign<u64> for TimeSpan {
1410    #[inline]
1411    fn rem_assign(&mut self, rhs: u64) {
1412        *self = *self % rhs;
1413    }
1414}
1415
1416impl Mul<u64> for NonZeroTimeSpan {
1417    type Output = TimeSpan;
1418
1419    #[inline]
1420    fn mul(self, rhs: u64) -> TimeSpan {
1421        self.checked_mul(rhs)
1422            .expect("overflow when multiplying span by scalar")
1423    }
1424}
1425
1426impl Mul<NonZeroTimeSpan> for u64 {
1427    type Output = TimeSpan;
1428
1429    #[inline]
1430    fn mul(self, rhs: NonZeroTimeSpan) -> TimeSpan {
1431        rhs * self
1432    }
1433}
1434
1435impl Div<u64> for NonZeroTimeSpan {
1436    type Output = TimeSpan;
1437
1438    #[inline]
1439    fn div(self, rhs: u64) -> TimeSpan {
1440        self.checked_div(rhs)
1441            .expect("divide by zero error when dividing span by scalar")
1442    }
1443}
1444
1445impl Rem<u64> for NonZeroTimeSpan {
1446    type Output = TimeSpan;
1447
1448    #[inline]
1449    fn rem(self, rhs: u64) -> TimeSpan {
1450        self.checked_rem(rhs)
1451            .expect("divide by zero error when dividing span by scalar")
1452    }
1453}
1454
1455impl Mul<NonZeroU64> for TimeSpan {
1456    type Output = Self;
1457
1458    #[inline]
1459    fn mul(self, rhs: NonZeroU64) -> Self {
1460        self.checked_mul(rhs.get())
1461            .expect("overflow when multiplying span by scalar")
1462    }
1463}
1464
1465impl Mul<TimeSpan> for NonZeroU64 {
1466    type Output = TimeSpan;
1467
1468    #[inline]
1469    fn mul(self, rhs: TimeSpan) -> TimeSpan {
1470        rhs * self
1471    }
1472}
1473
1474impl MulAssign<NonZeroU64> for TimeSpan {
1475    #[inline]
1476    fn mul_assign(&mut self, rhs: NonZeroU64) {
1477        *self = *self * rhs;
1478    }
1479}
1480
1481impl Div<NonZeroU64> for TimeSpan {
1482    type Output = TimeSpan;
1483
1484    #[inline]
1485    fn div(self, rhs: NonZeroU64) -> Self {
1486        self.div(rhs)
1487    }
1488}
1489
1490impl DivAssign<NonZeroU64> for TimeSpan {
1491    #[inline]
1492    fn div_assign(&mut self, rhs: NonZeroU64) {
1493        *self = *self / rhs;
1494    }
1495}
1496
1497impl Rem<NonZeroU64> for TimeSpan {
1498    type Output = TimeSpan;
1499
1500    #[inline]
1501    fn rem(self, rhs: NonZeroU64) -> Self {
1502        self.rem(rhs)
1503    }
1504}
1505
1506impl RemAssign<NonZeroU64> for TimeSpan {
1507    #[inline]
1508    fn rem_assign(&mut self, rhs: NonZeroU64) {
1509        *self = *self % rhs;
1510    }
1511}
1512
1513impl Mul<NonZeroU64> for NonZeroTimeSpan {
1514    type Output = NonZeroTimeSpan;
1515
1516    #[inline]
1517    fn mul(self, rhs: NonZeroU64) -> NonZeroTimeSpan {
1518        self.checked_mul_non_zero(rhs)
1519            .expect("overflow when multiplying span by scalar")
1520    }
1521}
1522
1523impl Mul<NonZeroTimeSpan> for NonZeroU64 {
1524    type Output = NonZeroTimeSpan;
1525
1526    #[inline]
1527    fn mul(self, rhs: NonZeroTimeSpan) -> NonZeroTimeSpan {
1528        rhs * self
1529    }
1530}
1531
1532impl Div<NonZeroU64> for NonZeroTimeSpan {
1533    type Output = TimeSpan;
1534
1535    #[inline]
1536    fn div(self, rhs: NonZeroU64) -> TimeSpan {
1537        self.div(rhs)
1538    }
1539}
1540
1541impl Rem<NonZeroU64> for NonZeroTimeSpan {
1542    type Output = TimeSpan;
1543
1544    #[inline]
1545    fn rem(self, rhs: NonZeroU64) -> TimeSpan {
1546        self.rem(rhs)
1547    }
1548}
1549
1550/// This trait adds methods to integers to convert values into `TimeSpan`s.
1551pub trait TimeSpanNumExt {
1552    /// Convert integer value into `TimeSpan` with that amount of nanoseconds.
1553    fn nanoseconds(self) -> TimeSpan;
1554
1555    /// Convert integer value into `TimeSpan` with that amount of microseconds.
1556    fn microseconds(self) -> TimeSpan;
1557
1558    /// Convert integer value into `TimeSpan` with that amount of milliseconds.
1559    fn milliseconds(self) -> TimeSpan;
1560
1561    /// Convert integer value into `TimeSpan` with that amount of seconds.
1562    fn seconds(self) -> TimeSpan;
1563
1564    /// Convert integer value into `TimeSpan` with that amount of minutes.
1565    fn minutes(self) -> TimeSpan;
1566
1567    /// Convert integer value into `TimeSpan` with that amount of hours.
1568    fn hours(self) -> TimeSpan;
1569
1570    /// Convert integer value into `TimeSpan` with that amount of days.
1571    fn days(self) -> TimeSpan;
1572}
1573
1574/// This trait adds methods to non-zero integers to convert values into `NonZeroTimeSpan`s.
1575pub trait NonZeroTimeSpanNumExt {
1576    /// Convert integer value into `NonZeroTimeSpan` with that amount of nanoseconds.
1577    fn nanoseconds(self) -> NonZeroTimeSpan;
1578
1579    /// Convert integer value into `NonZeroTimeSpan` with that amount of microseconds.
1580    fn microseconds(self) -> NonZeroTimeSpan;
1581
1582    /// Convert integer value into `NonZeroTimeSpan` with that amount of milliseconds.
1583    fn milliseconds(self) -> NonZeroTimeSpan;
1584
1585    /// Convert integer value into `NonZeroTimeSpan` with that amount of seconds.
1586    fn seconds(self) -> NonZeroTimeSpan;
1587
1588    /// Convert integer value into `NonZeroTimeSpan` with that amount of minutes.
1589    fn minutes(self) -> NonZeroTimeSpan;
1590
1591    /// Convert integer value into `NonZeroTimeSpan` with that amount of hours.
1592    fn hours(self) -> NonZeroTimeSpan;
1593
1594    /// Convert integer value into `NonZeroTimeSpan` with that amount of days.
1595    fn days(self) -> NonZeroTimeSpan;
1596}
1597
1598macro_rules! impl_for_int {
1599    ($($int:ty)*) => {
1600        $(
1601            impl_for_int!(@ $int);
1602        )*
1603    };
1604
1605    (@ $int:ty) => {
1606        impl TimeSpanNumExt for $int {
1607            #[inline]
1608            fn nanoseconds(self) -> TimeSpan {
1609                TimeSpan::NANOSECOND * u64::from(self)
1610            }
1611            #[inline]
1612            fn microseconds(self) -> TimeSpan {
1613                TimeSpan::MICROSECOND * u64::from(self)
1614            }
1615            #[inline]
1616            fn milliseconds(self) -> TimeSpan {
1617                TimeSpan::MILLISECOND * u64::from(self)
1618            }
1619            #[inline]
1620            fn seconds(self) -> TimeSpan {
1621                TimeSpan::SECOND * u64::from(self)
1622            }
1623            #[inline]
1624            fn minutes(self) -> TimeSpan {
1625                TimeSpan::MINUTE * u64::from(self)
1626            }
1627            #[inline]
1628            fn hours(self) -> TimeSpan {
1629                TimeSpan::HOUR * u64::from(self)
1630            }
1631            #[inline]
1632            fn days(self) -> TimeSpan {
1633                TimeSpan::DAY * u64::from(self)
1634            }
1635        }
1636    };
1637}
1638
1639impl_for_int!(u64);
1640
1641macro_rules! impl_for_nonzero_int {
1642($($int:ty)*) => {
1643        $(
1644            impl_for_nonzero_int!(@ $int);
1645        )*
1646    };
1647
1648    (@ $int:ty) => {
1649
1650        impl NonZeroTimeSpanNumExt for $int {
1651            #[inline]
1652            fn nanoseconds(self) -> NonZeroTimeSpan {
1653                NonZeroTimeSpan::NANOSECOND * NonZeroU64::from(self)
1654            }
1655            #[inline]
1656            fn microseconds(self) -> NonZeroTimeSpan {
1657                NonZeroTimeSpan::MICROSECOND * NonZeroU64::from(self)
1658            }
1659            #[inline]
1660            fn milliseconds(self) -> NonZeroTimeSpan {
1661                NonZeroTimeSpan::MILLISECOND * NonZeroU64::from(self)
1662            }
1663            #[inline]
1664            fn seconds(self) -> NonZeroTimeSpan {
1665                NonZeroTimeSpan::SECOND * NonZeroU64::from(self)
1666            }
1667            #[inline]
1668            fn minutes(self) -> NonZeroTimeSpan {
1669                NonZeroTimeSpan::MINUTE * NonZeroU64::from(self)
1670            }
1671            #[inline]
1672            fn hours(self) -> NonZeroTimeSpan {
1673                NonZeroTimeSpan::HOUR * NonZeroU64::from(self)
1674            }
1675            #[inline]
1676            fn days(self) -> NonZeroTimeSpan {
1677                NonZeroTimeSpan::DAY * NonZeroU64::from(self)
1678            }
1679        }
1680    };
1681}
1682
1683impl_for_nonzero_int!(NonZeroU64);
1684
1685#[test]
1686fn test_span_print() {
1687    assert_eq!("1d00:00", TimeSpan::DAY.to_string());
1688    assert_eq!("1:00:00", TimeSpan::HOUR.to_string());
1689    assert_eq!("1:00", TimeSpan::MINUTE.to_string());
1690    assert_eq!("1s", TimeSpan::SECOND.to_string());
1691
1692    assert_eq!(
1693        "1:02:11",
1694        (TimeSpan::HOUR + 2 * TimeSpan::MINUTE + 11 * TimeSpan::SECOND).to_string()
1695    );
1696
1697    assert_eq!(
1698        "2:11.011",
1699        (2 * TimeSpan::MINUTE + 11 * TimeSpan::SECOND + 11 * TimeSpan::MILLISECOND).to_string()
1700    );
1701
1702    assert_eq!(
1703        "2:11.011",
1704        (2 * TimeSpan::MINUTE + 11 * TimeSpan::SECOND + 11 * TimeSpan::MILLISECOND).to_string()
1705    );
1706}
1707
1708#[test]
1709fn test_span_parse() {
1710    assert_eq!("1d00:00".parse::<TimeSpan>().unwrap(), TimeSpan::DAY);
1711    assert_eq!("1:00:00".parse::<TimeSpan>().unwrap(), TimeSpan::HOUR);
1712    assert_eq!("1:00".parse::<TimeSpan>().unwrap(), TimeSpan::MINUTE);
1713    assert_eq!("1s".parse::<TimeSpan>().unwrap(), TimeSpan::SECOND);
1714
1715    assert_eq!(
1716        "1:02:11".parse::<TimeSpan>().unwrap(),
1717        TimeSpan::HOUR + 2 * TimeSpan::MINUTE + 11 * TimeSpan::SECOND
1718    );
1719
1720    assert_eq!(
1721        "2:11.011".parse::<TimeSpan>().unwrap(),
1722        2 * TimeSpan::MINUTE + 11 * TimeSpan::SECOND + 11 * TimeSpan::MILLISECOND
1723    );
1724
1725    assert_eq!(
1726        "2:11.011".parse::<TimeSpan>().unwrap(),
1727        2 * TimeSpan::MINUTE + 11 * TimeSpan::SECOND + 11 * TimeSpan::MILLISECOND
1728    );
1729}