diff --git a/time/src/ext/digit_count.rs b/time/src/ext/digit_count.rs new file mode 100644 index 000000000..fb42ce9e0 --- /dev/null +++ b/time/src/ext/digit_count.rs @@ -0,0 +1,26 @@ +use num_conv::prelude::*; + +/// 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.truncate::() + 1, + None => 1, + } + } + })* + }; +} + +impl_digit_count!(u8, u16, u32); diff --git a/time/src/ext/mod.rs b/time/src/ext/mod.rs new file mode 100644 index 000000000..18f089822 --- /dev/null +++ b/time/src/ext/mod.rs @@ -0,0 +1,9 @@ +//! Extension traits. + +mod digit_count; +mod numerical_duration; +mod numerical_std_duration; + +pub(crate) use self::digit_count::DigitCount; +pub use self::numerical_duration::NumericalDuration; +pub use self::numerical_std_duration::NumericalStdDuration; diff --git a/time/src/ext/numerical_duration.rs b/time/src/ext/numerical_duration.rs new file mode 100644 index 000000000..fb9209d23 --- /dev/null +++ b/time/src/ext/numerical_duration.rs @@ -0,0 +1,140 @@ +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 f64 {} +} + +/// 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 _) + } +} diff --git a/time/src/ext.rs b/time/src/ext/numerical_std_duration.rs similarity index 53% rename from time/src/ext.rs rename to time/src/ext/numerical_std_duration.rs index 00089a0d5..062b33f76 100644 --- a/time/src/ext.rs +++ b/time/src/ext/numerical_std_duration.rs @@ -1,154 +1,17 @@ -//! Extension traits. - use core::time::Duration as StdDuration; use num_conv::prelude::*; 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 @@ -183,8 +46,8 @@ impl NumericalDuration for f64 { /// ``` /// /// 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. +/// 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; @@ -327,31 +190,3 @@ impl NumericalStdDuration for f64 { 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.truncate::() + 1, - None => 1, - } - } - })* - }; -} - -impl_digit_count!(u8, u16, u32); -// endregion DigitCount