From 6d0b341fdcf613c15f22afbcfd4f0678ce7cff3e Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Sun, 24 Sep 2023 00:47:48 -0400 Subject: [PATCH] Rework, expose unit conversions --- time-core/src/convert.rs | 168 ++++++++++++------------ time-macros/src/offset.rs | 4 +- time-macros/src/time.rs | 8 +- time/src/date.rs | 4 +- time/src/date_time.rs | 38 +++--- time/src/duration.rs | 146 ++++++++++---------- time/src/ext.rs | 36 ++--- time/src/formatting/iso8601.rs | 12 +- time/src/formatting/mod.rs | 6 +- time/src/lib.rs | 3 +- time/src/parsing/component.rs | 6 +- time/src/parsing/iso8601.rs | 16 +-- time/src/parsing/parsed.rs | 12 +- time/src/sys/local_offset_at/wasm_js.rs | 2 +- time/src/sys/local_offset_at/windows.rs | 2 +- time/src/time.rs | 105 ++++++++------- time/src/utc_offset.rs | 26 ++-- 17 files changed, 300 insertions(+), 294 deletions(-) diff --git a/time-core/src/convert.rs b/time-core/src/convert.rs index c393675d7..9c28f0263 100644 --- a/time-core/src/convert.rs +++ b/time-core/src/convert.rs @@ -1,106 +1,104 @@ //! Conversion between units of time. -/// Declare the structs that represent a unit of time. -macro_rules! declare_structs { - ($($t:ident $str:expr)*) => {$( +use self::sealed::Per; + +mod sealed { + /// A trait for defining the ratio of two units of time. + /// + /// This trait is used to implement the `per` method on the various structs. + pub trait Per { + /// The smallest unsigned integer type that can represent [`VALUE`](Self::VALUE). + type Output; + + /// The number of one unit of time in the other. + const VALUE: Self::Output; + } +} + +/// Declare and implement `Per` for all relevant types. Identity implementations are automatic. +macro_rules! impl_per { + ($($t:ident ($str:literal) per {$( + $larger:ident : $output:ty = $value:expr + )*})*) => {$( #[doc = concat!("A unit of time representing exactly one ", $str, ".")] - #[derive(Debug, Copy, Clone)] + #[derive(Debug, Clone, Copy)] pub struct $t; impl $t { - /// Obtain the integer ratio between the two units of time. + #[doc = concat!("Obtain the number of times `", stringify!($t), "` can fit into `T`.")] + #[doc = concat!("If `T` is smaller than `", stringify!($t), "`, the code will fail to")] + /// compile. The return type is the smallest unsigned integer type that can represent + /// the value. + /// + /// Valid calls: /// - /// If the ratio is less than one, the call will fail to compile. - pub const fn per(self, _: T) -> <(Self, T) as Per>::Output + #[doc = concat!(" - `", stringify!($t), "::per(", stringify!($t), ")` (returns `u8`)")] + $(#[doc = concat!(" - `", stringify!($t), "::per(", stringify!($larger), ")` (returns `", stringify!($output), "`)")])* + pub const fn per(_larger: T) -> >::Output where - (Self, T): Per, + Self: Per, T: Copy, { - <(Self, T)>::VALUE + Self::VALUE } } - )*}; -} - -declare_structs! { - Nanosecond "nanosecond" - Microsecond "microsecond" - Millisecond "millisecond" - Second "second" - Minute "minute" - Hour "hour" - Day "day" - Week "week" -} - -mod sealed { - pub trait Sealed {} -} - -/// A trait for defining the ratio of two units of time. -/// -/// This trait is used to implement the `per` method on the various structs. -pub trait Per: sealed::Sealed { - /// The smallest unsigned integer type that can represent [`VALUE`](Self::VALUE). - type Output; - /// The number of one unit of time in the other. - const VALUE: Self::Output; -} + impl Per<$t> for $t { + type Output = u8; -/// Implement the `Per` trait for pairs of types. -macro_rules! impl_per { - ($($t:ty : $x:ident in $y:ident = $val:expr)*) => {$( - impl sealed::Sealed for ($x, $y) {} + const VALUE: u8 = 1; + } - impl Per for ($x, $y) { - type Output = $t; + $(impl Per<$larger> for $t { + type Output = $output; - const VALUE: $t = $val; - } + const VALUE: $output = $value; + })* )*}; } impl_per! { - u8: Nanosecond in Nanosecond = 1 - u16: Nanosecond in Microsecond = 1_000 - u32: Nanosecond in Millisecond = 1_000_000 - u32: Nanosecond in Second = 1_000_000_000 - u64: Nanosecond in Minute = 60_000_000_000 - u64: Nanosecond in Hour = 3_600_000_000_000 - u64: Nanosecond in Day = 86_400_000_000_000 - u64: Nanosecond in Week = 604_800_000_000_000 - - u8: Microsecond in Microsecond = 1 - u16: Microsecond in Millisecond = 1_000 - u32: Microsecond in Second = 1_000_000 - u32: Microsecond in Minute = 60_000_000 - u32: Microsecond in Hour = 3_600_000_000 - u64: Microsecond in Day = 86_400_000_000 - u64: Microsecond in Week = 604_800_000_000 - - u8: Millisecond in Millisecond = 1 - u16: Millisecond in Second = 1_000 - u16: Millisecond in Minute = 60_000 - u32: Millisecond in Hour = 3_600_000 - u32: Millisecond in Day = 86_400_000 - u32: Millisecond in Week = 604_800_000 - - u8: Second in Second = 1 - u8: Second in Minute = 60 - u16: Second in Hour = 3_600 - u32: Second in Day = 86_400 - u32: Second in Week = 604_800 - - u8: Minute in Minute = 1 - u8: Minute in Hour = 60 - u16: Minute in Day = 1_440 - u16: Minute in Week = 10_080 - - u8: Hour in Hour = 1 - u8: Hour in Day = 24 - u8: Hour in Week = 168 - - u8: Day in Day = 1 - u8: Day in Week = 7 + Nanosecond ("nanosecond") per { + Microsecond: u16 = 1_000 + Millisecond: u32 = 1_000_000 + Second: u32 = 1_000_000_000 + Minute: u64 = 60_000_000_000 + Hour: u64 = 3_600_000_000_000 + Day: u64 = 86_400_000_000_000 + Week: u64 = 604_800_000_000_000 + } + Microsecond ("microsecond") per { + Millisecond: u16 = 1_000 + Second: u32 = 1_000_000 + Minute: u32 = 60_000_000 + Hour: u32 = 3_600_000_000 + Day: u64 = 86_400_000_000 + Week: u64 = 604_800_000_000 + } + Millisecond ("millisecond") per { + Second: u16 = 1_000 + Minute: u16 = 60_000 + Hour: u32 = 3_600_000 + Day: u32 = 86_400_000 + Week: u32 = 604_800_000 + } + Second ("second") per { + Minute: u8 = 60 + Hour: u16 = 3_600 + Day: u32 = 86_400 + Week: u32 = 604_800 + } + Minute ("minute") per { + Hour: u8 = 60 + Day: u16 = 1_440 + Week: u16 = 10_080 + } + Hour ("hour") per { + Day: u8 = 24 + Week: u8 = 168 + } + Day ("day") per { + Week: u8 = 7 + } + Week ("week") per {} } diff --git a/time-macros/src/offset.rs b/time-macros/src/offset.rs index 9c330ca90..b9a3c610a 100644 --- a/time-macros/src/offset.rs +++ b/time-macros/src/offset.rs @@ -59,14 +59,14 @@ pub(crate) fn parse(chars: &mut Peekable) -> Result= Minute.per(Hour) as _ { + } else if minutes >= Minute::per(Hour) as _ { Err(Error::InvalidComponent { name: "minute", value: minutes.to_string(), span_start: Some(minutes_span), span_end: Some(minutes_span), }) - } else if seconds >= Second.per(Minute) as _ { + } else if seconds >= Second::per(Minute) as _ { Err(Error::InvalidComponent { name: "second", value: seconds.to_string(), diff --git a/time-macros/src/time.rs b/time-macros/src/time.rs index dc843cf31..4e565c1de 100644 --- a/time-macros/src/time.rs +++ b/time-macros/src/time.rs @@ -73,21 +73,21 @@ pub(crate) fn parse(chars: &mut Peekable) -> Result