//! Extension traits. use core::time::Duration as StdDuration; use crate::convert::*; use crate::Duration; /// Sealed trait to prevent downstream implementations. mod sealed { /// A trait that cannot be implemented by downstream users. pub trait Sealed {} impl Sealed for i64 {} impl Sealed for u64 {} impl Sealed for f64 {} } // region: NumericalDuration /// Create [`Duration`]s from numeric literals. /// /// # Examples /// /// Basic construction of [`Duration`]s. /// /// ```rust /// # use time::{Duration, ext::NumericalDuration}; /// assert_eq!(5.nanoseconds(), Duration::nanoseconds(5)); /// assert_eq!(5.microseconds(), Duration::microseconds(5)); /// assert_eq!(5.milliseconds(), Duration::milliseconds(5)); /// assert_eq!(5.seconds(), Duration::seconds(5)); /// assert_eq!(5.minutes(), Duration::minutes(5)); /// assert_eq!(5.hours(), Duration::hours(5)); /// assert_eq!(5.days(), Duration::days(5)); /// assert_eq!(5.weeks(), Duration::weeks(5)); /// ``` /// /// Signed integers work as well! /// /// ```rust /// # use time::{Duration, ext::NumericalDuration}; /// assert_eq!((-5).nanoseconds(), Duration::nanoseconds(-5)); /// assert_eq!((-5).microseconds(), Duration::microseconds(-5)); /// assert_eq!((-5).milliseconds(), Duration::milliseconds(-5)); /// assert_eq!((-5).seconds(), Duration::seconds(-5)); /// assert_eq!((-5).minutes(), Duration::minutes(-5)); /// assert_eq!((-5).hours(), Duration::hours(-5)); /// assert_eq!((-5).days(), Duration::days(-5)); /// assert_eq!((-5).weeks(), Duration::weeks(-5)); /// ``` /// /// Just like any other [`Duration`], they can be added, subtracted, etc. /// /// ```rust /// # use time::ext::NumericalDuration; /// assert_eq!(2.seconds() + 500.milliseconds(), 2_500.milliseconds()); /// assert_eq!(2.seconds() - 500.milliseconds(), 1_500.milliseconds()); /// ``` /// /// When called on floating point values, any remainder of the floating point value will be /// truncated. Keep in mind that floating point numbers are inherently imprecise and have limited /// capacity. pub trait NumericalDuration: sealed::Sealed { /// Create a [`Duration`] from the number of nanoseconds. fn nanoseconds(self) -> Duration; /// Create a [`Duration`] from the number of microseconds. fn microseconds(self) -> Duration; /// Create a [`Duration`] from the number of milliseconds. fn milliseconds(self) -> Duration; /// Create a [`Duration`] from the number of seconds. fn seconds(self) -> Duration; /// Create a [`Duration`] from the number of minutes. fn minutes(self) -> Duration; /// Create a [`Duration`] from the number of hours. fn hours(self) -> Duration; /// Create a [`Duration`] from the number of days. fn days(self) -> Duration; /// Create a [`Duration`] from the number of weeks. fn weeks(self) -> Duration; } impl NumericalDuration for i64 { fn nanoseconds(self) -> Duration { Duration::nanoseconds(self) } fn microseconds(self) -> Duration { Duration::microseconds(self) } fn milliseconds(self) -> Duration { Duration::milliseconds(self) } fn seconds(self) -> Duration { Duration::seconds(self) } fn minutes(self) -> Duration { Duration::minutes(self) } fn hours(self) -> Duration { Duration::hours(self) } fn days(self) -> Duration { Duration::days(self) } fn weeks(self) -> Duration { Duration::weeks(self) } } impl NumericalDuration for f64 { fn nanoseconds(self) -> Duration { Duration::nanoseconds(self as _) } fn microseconds(self) -> Duration { Duration::nanoseconds((self * Nanosecond::per(Microsecond) as Self) as _) } fn milliseconds(self) -> Duration { Duration::nanoseconds((self * Nanosecond::per(Millisecond) as Self) as _) } fn seconds(self) -> Duration { Duration::nanoseconds((self * Nanosecond::per(Second) as Self) as _) } fn minutes(self) -> Duration { Duration::nanoseconds((self * Nanosecond::per(Minute) as Self) as _) } fn hours(self) -> Duration { Duration::nanoseconds((self * Nanosecond::per(Hour) as Self) as _) } fn days(self) -> Duration { Duration::nanoseconds((self * Nanosecond::per(Day) as Self) as _) } fn weeks(self) -> Duration { Duration::nanoseconds((self * Nanosecond::per(Week) as Self) as _) } } // endregion NumericalDuration // region: NumericalStdDuration /// Create [`std::time::Duration`]s from numeric literals. /// /// # Examples /// /// Basic construction of [`std::time::Duration`]s. /// /// ```rust /// # use time::ext::NumericalStdDuration; /// # use core::time::Duration; /// assert_eq!(5.std_nanoseconds(), Duration::from_nanos(5)); /// assert_eq!(5.std_microseconds(), Duration::from_micros(5)); /// assert_eq!(5.std_milliseconds(), Duration::from_millis(5)); /// assert_eq!(5.std_seconds(), Duration::from_secs(5)); /// assert_eq!(5.std_minutes(), Duration::from_secs(5 * 60)); /// assert_eq!(5.std_hours(), Duration::from_secs(5 * 3_600)); /// assert_eq!(5.std_days(), Duration::from_secs(5 * 86_400)); /// assert_eq!(5.std_weeks(), Duration::from_secs(5 * 604_800)); /// ``` /// /// Just like any other [`std::time::Duration`], they can be added, subtracted, etc. /// /// ```rust /// # use time::ext::NumericalStdDuration; /// assert_eq!( /// 2.std_seconds() + 500.std_milliseconds(), /// 2_500.std_milliseconds() /// ); /// assert_eq!( /// 2.std_seconds() - 500.std_milliseconds(), /// 1_500.std_milliseconds() /// ); /// ``` /// /// When called on floating point values, any remainder of the floating point value will be /// truncated. Keep in mind that floating point numbers are inherently imprecise and have limited /// capacity. pub trait NumericalStdDuration: sealed::Sealed { /// Create a [`std::time::Duration`] from the number of nanoseconds. fn std_nanoseconds(self) -> StdDuration; /// Create a [`std::time::Duration`] from the number of microseconds. fn std_microseconds(self) -> StdDuration; /// Create a [`std::time::Duration`] from the number of milliseconds. fn std_milliseconds(self) -> StdDuration; /// Create a [`std::time::Duration`] from the number of seconds. fn std_seconds(self) -> StdDuration; /// Create a [`std::time::Duration`] from the number of minutes. fn std_minutes(self) -> StdDuration; /// Create a [`std::time::Duration`] from the number of hours. fn std_hours(self) -> StdDuration; /// Create a [`std::time::Duration`] from the number of days. fn std_days(self) -> StdDuration; /// Create a [`std::time::Duration`] from the number of weeks. fn std_weeks(self) -> StdDuration; } impl NumericalStdDuration for u64 { fn std_nanoseconds(self) -> StdDuration { StdDuration::from_nanos(self) } fn std_microseconds(self) -> StdDuration { StdDuration::from_micros(self) } fn std_milliseconds(self) -> StdDuration { StdDuration::from_millis(self) } fn std_seconds(self) -> StdDuration { StdDuration::from_secs(self) } fn std_minutes(self) -> StdDuration { StdDuration::from_secs( self.checked_mul(Second::per(Minute) as Self) .expect("overflow constructing `time::Duration`"), ) } fn std_hours(self) -> StdDuration { StdDuration::from_secs( self.checked_mul(Second::per(Hour) as Self) .expect("overflow constructing `time::Duration`"), ) } fn std_days(self) -> StdDuration { StdDuration::from_secs( self.checked_mul(Second::per(Day) as Self) .expect("overflow constructing `time::Duration`"), ) } fn std_weeks(self) -> StdDuration { StdDuration::from_secs( self.checked_mul(Second::per(Week) as Self) .expect("overflow constructing `time::Duration`"), ) } } impl NumericalStdDuration for f64 { fn std_nanoseconds(self) -> StdDuration { assert!(self >= 0.); StdDuration::from_nanos(self as _) } fn std_microseconds(self) -> StdDuration { assert!(self >= 0.); StdDuration::from_nanos((self * Nanosecond::per(Microsecond) as Self) as _) } fn std_milliseconds(self) -> StdDuration { assert!(self >= 0.); StdDuration::from_nanos((self * Nanosecond::per(Millisecond) as Self) as _) } fn std_seconds(self) -> StdDuration { assert!(self >= 0.); StdDuration::from_nanos((self * Nanosecond::per(Second) as Self) as _) } fn std_minutes(self) -> StdDuration { assert!(self >= 0.); StdDuration::from_nanos((self * Nanosecond::per(Minute) as Self) as _) } fn std_hours(self) -> StdDuration { assert!(self >= 0.); StdDuration::from_nanos((self * Nanosecond::per(Hour) as Self) as _) } fn std_days(self) -> StdDuration { assert!(self >= 0.); StdDuration::from_nanos((self * Nanosecond::per(Day) as Self) as _) } fn std_weeks(self) -> StdDuration { assert!(self >= 0.); StdDuration::from_nanos((self * Nanosecond::per(Week) as Self) as _) } } // endregion NumericalStdDuration // region: DigitCount /// A trait that indicates the formatted width of the value can be determined. /// /// Note that this should not be implemented for any signed integers. This forces the caller to /// write the sign if desired. pub(crate) trait DigitCount { /// The number of digits in the stringified value. fn num_digits(self) -> u8; } /// A macro to generate implementations of `DigitCount` for unsigned integers. macro_rules! impl_digit_count { ($($t:ty),* $(,)?) => { $(impl DigitCount for $t { fn num_digits(self) -> u8 { match self.checked_ilog10() { Some(n) => (n as u8) + 1, None => 1, } } })* }; } impl_digit_count!(u8, u16, u32); // endregion DigitCount