diff options
Diffstat (limited to 'vendor/time/src/time.rs')
-rw-r--r-- | vendor/time/src/time.rs | 471 |
1 files changed, 296 insertions, 175 deletions
diff --git a/vendor/time/src/time.rs b/vendor/time/src/time.rs index 87b465bb9..74ab2a5ed 100644 --- a/vendor/time/src/time.rs +++ b/vendor/time/src/time.rs @@ -6,9 +6,12 @@ use core::time::Duration as StdDuration; #[cfg(feature = "formatting")] use std::io; +use deranged::{RangedU32, RangedU8}; + use crate::convert::*; #[cfg(feature = "formatting")] use crate::formatting::Formattable; +use crate::internal_macros::{cascade, ensure_ranged, impl_add_assign, impl_sub_assign}; #[cfg(feature = "parsing")] use crate::parsing::Parsable; use crate::util::DateAdjustment; @@ -23,27 +26,118 @@ pub(crate) enum Padding { Optimize, } +/// The type of the `hour` field of `Time`. +type Hours = RangedU8<0, { Hour::per(Day) - 1 }>; +/// The type of the `minute` field of `Time`. +type Minutes = RangedU8<0, { Minute::per(Hour) - 1 }>; +/// The type of the `second` field of `Time`. +type Seconds = RangedU8<0, { Second::per(Minute) - 1 }>; +/// The type of the `nanosecond` field of `Time`. +type Nanoseconds = RangedU32<0, { Nanosecond::per(Second) - 1 }>; + /// The clock time within a given date. Nanosecond precision. /// /// All minutes are assumed to have exactly 60 seconds; no attempt is made to handle leap seconds /// (either positive or negative). /// /// When comparing two `Time`s, they are assumed to be in the same calendar date. -#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[derive(Clone, Copy, Eq)] +#[repr(C)] pub struct Time { + // The order of this struct's fields matter! + // Do not change them. + + // Little endian version + #[cfg(target_endian = "little")] #[allow(clippy::missing_docs_in_private_items)] - hour: u8, + nanosecond: Nanoseconds, + #[cfg(target_endian = "little")] #[allow(clippy::missing_docs_in_private_items)] - minute: u8, + second: Seconds, + #[cfg(target_endian = "little")] #[allow(clippy::missing_docs_in_private_items)] - second: u8, + minute: Minutes, + #[cfg(target_endian = "little")] #[allow(clippy::missing_docs_in_private_items)] - nanosecond: u32, + hour: Hours, + #[cfg(target_endian = "little")] #[allow(clippy::missing_docs_in_private_items)] padding: Padding, + + // Big endian version + #[cfg(target_endian = "big")] + #[allow(clippy::missing_docs_in_private_items)] + padding: Padding, + #[cfg(target_endian = "big")] + #[allow(clippy::missing_docs_in_private_items)] + hour: Hours, + #[cfg(target_endian = "big")] + #[allow(clippy::missing_docs_in_private_items)] + minute: Minutes, + #[cfg(target_endian = "big")] + #[allow(clippy::missing_docs_in_private_items)] + second: Seconds, + #[cfg(target_endian = "big")] + #[allow(clippy::missing_docs_in_private_items)] + nanosecond: Nanoseconds, +} + +impl core::hash::Hash for Time { + fn hash<H: core::hash::Hasher>(&self, state: &mut H) { + self.as_u64().hash(state) + } +} + +impl PartialEq for Time { + fn eq(&self, other: &Self) -> bool { + self.as_u64().eq(&other.as_u64()) + } +} + +impl PartialOrd for Time { + fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> { + self.as_u64().partial_cmp(&other.as_u64()) + } +} + +impl Ord for Time { + fn cmp(&self, other: &Self) -> core::cmp::Ordering { + self.as_u64().cmp(&other.as_u64()) + } } impl Time { + /// Provides an u64 based representation **of the correct endianness** + /// + /// This representation can be used to do comparisons equality testing or hashing. + const fn as_u64(self) -> u64 { + let nano_bytes = self.nanosecond.get().to_ne_bytes(); + + #[cfg(target_endian = "big")] + return u64::from_be_bytes([ + self.padding as u8, + self.hour.get(), + self.minute.get(), + self.second.get(), + nano_bytes[0], + nano_bytes[1], + nano_bytes[2], + nano_bytes[3], + ]); + + #[cfg(target_endian = "little")] + return u64::from_le_bytes([ + nano_bytes[0], + nano_bytes[1], + nano_bytes[2], + nano_bytes[3], + self.second.get(), + self.minute.get(), + self.hour.get(), + self.padding as u8, + ]); + } + /// Create a `Time` that is exactly midnight. /// /// ```rust @@ -51,38 +145,44 @@ impl Time { /// # use time_macros::time; /// assert_eq!(Time::MIDNIGHT, time!(0:00)); /// ``` - pub const MIDNIGHT: Self = Self::__from_hms_nanos_unchecked(0, 0, 0, 0); + pub const MIDNIGHT: Self = Self::MIN; /// The smallest value that can be represented by `Time`. /// /// `00:00:00.0` - pub(crate) const MIN: Self = Self::__from_hms_nanos_unchecked(0, 0, 0, 0); + pub(crate) const MIN: Self = + Self::from_hms_nanos_ranged(Hours::MIN, Minutes::MIN, Seconds::MIN, Nanoseconds::MIN); /// The largest value that can be represented by `Time`. /// /// `23:59:59.999_999_999` - pub(crate) const MAX: Self = Self::__from_hms_nanos_unchecked(23, 59, 59, 999_999_999); + pub(crate) const MAX: Self = + Self::from_hms_nanos_ranged(Hours::MAX, Minutes::MAX, Seconds::MAX, Nanoseconds::MAX); // region: constructors /// Create a `Time` from its components. + /// + /// # Safety + /// + /// - `hours` must be in the range `0..=23`. + /// - `minutes` must be in the range `0..=59`. + /// - `seconds` must be in the range `0..=59`. + /// - `nanoseconds` must be in the range `0..=999_999_999`. #[doc(hidden)] - pub const fn __from_hms_nanos_unchecked( + pub const unsafe fn __from_hms_nanos_unchecked( hour: u8, minute: u8, second: u8, nanosecond: u32, ) -> Self { - debug_assert!(hour < Hour.per(Day)); - debug_assert!(minute < Minute.per(Hour)); - debug_assert!(second < Second.per(Minute)); - debug_assert!(nanosecond < Nanosecond.per(Second)); - - Self { - hour, - minute, - second, - nanosecond, - padding: Padding::Optimize, + // Safety: The caller must uphold the safety invariants. + unsafe { + Self::from_hms_nanos_ranged( + Hours::new_unchecked(hour), + Minutes::new_unchecked(minute), + Seconds::new_unchecked(second), + Nanoseconds::new_unchecked(nanosecond), + ) } } @@ -100,10 +200,28 @@ impl Time { /// assert!(Time::from_hms(0, 0, 60).is_err()); // 60 isn't a valid second. /// ``` pub const fn from_hms(hour: u8, minute: u8, second: u8) -> Result<Self, error::ComponentRange> { - ensure_value_in_range!(hour in 0 => Hour.per(Day) - 1); - ensure_value_in_range!(minute in 0 => Minute.per(Hour) - 1); - ensure_value_in_range!(second in 0 => Second.per(Minute) - 1); - Ok(Self::__from_hms_nanos_unchecked(hour, minute, second, 0)) + Ok(Self::from_hms_nanos_ranged( + ensure_ranged!(Hours: hour), + ensure_ranged!(Minutes: minute), + ensure_ranged!(Seconds: second), + Nanoseconds::MIN, + )) + } + + /// Create a `Time` from the hour, minute, second, and nanosecond. + pub(crate) const fn from_hms_nanos_ranged( + hour: Hours, + minute: Minutes, + second: Seconds, + nanosecond: Nanoseconds, + ) -> Self { + Self { + hour, + minute, + second, + nanosecond, + padding: Padding::Optimize, + } } /// Attempt to create a `Time` from the hour, minute, second, and millisecond. @@ -126,15 +244,11 @@ impl Time { second: u8, millisecond: u16, ) -> Result<Self, error::ComponentRange> { - ensure_value_in_range!(hour in 0 => Hour.per(Day) - 1); - ensure_value_in_range!(minute in 0 => Minute.per(Hour) - 1); - ensure_value_in_range!(second in 0 => Second.per(Minute) - 1); - ensure_value_in_range!(millisecond in 0 => Millisecond.per(Second) - 1); - Ok(Self::__from_hms_nanos_unchecked( - hour, - minute, - second, - millisecond as u32 * Nanosecond.per(Millisecond), + Ok(Self::from_hms_nanos_ranged( + ensure_ranged!(Hours: hour), + ensure_ranged!(Minutes: minute), + ensure_ranged!(Seconds: second), + ensure_ranged!(Nanoseconds: millisecond as u32 * Nanosecond::per(Millisecond)), )) } @@ -158,15 +272,11 @@ impl Time { second: u8, microsecond: u32, ) -> Result<Self, error::ComponentRange> { - ensure_value_in_range!(hour in 0 => Hour.per(Day) - 1); - ensure_value_in_range!(minute in 0 => Minute.per(Hour) - 1); - ensure_value_in_range!(second in 0 => Second.per(Minute) - 1); - ensure_value_in_range!(microsecond in 0 => Microsecond.per(Second) - 1); - Ok(Self::__from_hms_nanos_unchecked( - hour, - minute, - second, - microsecond * Nanosecond.per(Microsecond) as u32, + Ok(Self::from_hms_nanos_ranged( + ensure_ranged!(Hours: hour), + ensure_ranged!(Minutes: minute), + ensure_ranged!(Seconds: second), + ensure_ranged!(Nanoseconds: microsecond * Nanosecond::per(Microsecond) as u32), )) } @@ -190,12 +300,11 @@ impl Time { second: u8, nanosecond: u32, ) -> Result<Self, error::ComponentRange> { - ensure_value_in_range!(hour in 0 => Hour.per(Day) - 1); - ensure_value_in_range!(minute in 0 => Minute.per(Hour) - 1); - ensure_value_in_range!(second in 0 => Second.per(Minute) - 1); - ensure_value_in_range!(nanosecond in 0 => Nanosecond.per(Second) - 1); - Ok(Self::__from_hms_nanos_unchecked( - hour, minute, second, nanosecond, + Ok(Self::from_hms_nanos_ranged( + ensure_ranged!(Hours: hour), + ensure_ranged!(Minutes: minute), + ensure_ranged!(Seconds: second), + ensure_ranged!(Nanoseconds: nanosecond), )) } // endregion constructors @@ -209,7 +318,7 @@ impl Time { /// assert_eq!(time!(23:59:59).as_hms(), (23, 59, 59)); /// ``` pub const fn as_hms(self) -> (u8, u8, u8) { - (self.hour, self.minute, self.second) + (self.hour.get(), self.minute.get(), self.second.get()) } /// Get the clock hour, minute, second, and millisecond. @@ -221,10 +330,10 @@ impl Time { /// ``` pub const fn as_hms_milli(self) -> (u8, u8, u8, u16) { ( - self.hour, - self.minute, - self.second, - (self.nanosecond / Nanosecond.per(Millisecond)) as u16, + self.hour.get(), + self.minute.get(), + self.second.get(), + (self.nanosecond.get() / Nanosecond::per(Millisecond)) as u16, ) } @@ -240,10 +349,10 @@ impl Time { /// ``` pub const fn as_hms_micro(self) -> (u8, u8, u8, u32) { ( - self.hour, - self.minute, - self.second, - self.nanosecond / Nanosecond.per(Microsecond) as u32, + self.hour.get(), + self.minute.get(), + self.second.get(), + self.nanosecond.get() / Nanosecond::per(Microsecond) as u32, ) } @@ -258,6 +367,17 @@ impl Time { /// ); /// ``` pub const fn as_hms_nano(self) -> (u8, u8, u8, u32) { + ( + self.hour.get(), + self.minute.get(), + self.second.get(), + self.nanosecond.get(), + ) + } + + /// Get the clock hour, minute, second, and nanosecond. + #[cfg(feature = "quickcheck")] + pub(crate) const fn as_hms_nano_ranged(self) -> (Hours, Minutes, Seconds, Nanoseconds) { (self.hour, self.minute, self.second, self.nanosecond) } @@ -271,7 +391,7 @@ impl Time { /// assert_eq!(time!(23:59:59).hour(), 23); /// ``` pub const fn hour(self) -> u8 { - self.hour + self.hour.get() } /// Get the minute within the hour. @@ -284,7 +404,7 @@ impl Time { /// assert_eq!(time!(23:59:59).minute(), 59); /// ``` pub const fn minute(self) -> u8 { - self.minute + self.minute.get() } /// Get the second within the minute. @@ -297,7 +417,7 @@ impl Time { /// assert_eq!(time!(23:59:59).second(), 59); /// ``` pub const fn second(self) -> u8 { - self.second + self.second.get() } /// Get the milliseconds within the second. @@ -310,7 +430,7 @@ impl Time { /// assert_eq!(time!(23:59:59.999).millisecond(), 999); /// ``` pub const fn millisecond(self) -> u16 { - (self.nanosecond / Nanosecond.per(Millisecond)) as _ + (self.nanosecond.get() / Nanosecond::per(Millisecond)) as _ } /// Get the microseconds within the second. @@ -323,7 +443,7 @@ impl Time { /// assert_eq!(time!(23:59:59.999_999).microsecond(), 999_999); /// ``` pub const fn microsecond(self) -> u32 { - self.nanosecond / Nanosecond.per(Microsecond) as u32 + self.nanosecond.get() / Nanosecond::per(Microsecond) as u32 } /// Get the nanoseconds within the second. @@ -336,7 +456,7 @@ impl Time { /// assert_eq!(time!(23:59:59.999_999_999).nanosecond(), 999_999_999); /// ``` pub const fn nanosecond(self) -> u32 { - self.nanosecond + self.nanosecond.get() } // endregion getters @@ -344,116 +464,135 @@ impl Time { /// Add the sub-day time of the [`Duration`] to the `Time`. Wraps on overflow, returning whether /// the date is different. pub(crate) const fn adjusting_add(self, duration: Duration) -> (DateAdjustment, Self) { - let mut nanoseconds = self.nanosecond as i32 + duration.subsec_nanoseconds(); + let mut nanoseconds = self.nanosecond.get() as i32 + duration.subsec_nanoseconds(); let mut seconds = - self.second as i8 + (duration.whole_seconds() % Second.per(Minute) as i64) as i8; + self.second.get() as i8 + (duration.whole_seconds() % Second::per(Minute) as i64) as i8; let mut minutes = - self.minute as i8 + (duration.whole_minutes() % Minute.per(Hour) as i64) as i8; - let mut hours = self.hour as i8 + (duration.whole_hours() % Hour.per(Day) as i64) as i8; + self.minute.get() as i8 + (duration.whole_minutes() % Minute::per(Hour) as i64) as i8; + let mut hours = + self.hour.get() as i8 + (duration.whole_hours() % Hour::per(Day) as i64) as i8; let mut date_adjustment = DateAdjustment::None; - cascade!(nanoseconds in 0..Nanosecond.per(Second) as _ => seconds); - cascade!(seconds in 0..Second.per(Minute) as _ => minutes); - cascade!(minutes in 0..Minute.per(Hour) as _ => hours); - if hours >= Hour.per(Day) as _ { - hours -= Hour.per(Day) as i8; + cascade!(nanoseconds in 0..Nanosecond::per(Second) as _ => seconds); + cascade!(seconds in 0..Second::per(Minute) as _ => minutes); + cascade!(minutes in 0..Minute::per(Hour) as _ => hours); + if hours >= Hour::per(Day) as _ { + hours -= Hour::per(Day) as i8; date_adjustment = DateAdjustment::Next; } else if hours < 0 { - hours += Hour.per(Day) as i8; + hours += Hour::per(Day) as i8; date_adjustment = DateAdjustment::Previous; } ( date_adjustment, - Self::__from_hms_nanos_unchecked( - hours as _, - minutes as _, - seconds as _, - nanoseconds as _, - ), + // Safety: The cascades above ensure the values are in range. + unsafe { + Self::__from_hms_nanos_unchecked( + hours as _, + minutes as _, + seconds as _, + nanoseconds as _, + ) + }, ) } /// Subtract the sub-day time of the [`Duration`] to the `Time`. Wraps on overflow, returning /// whether the date is different. pub(crate) const fn adjusting_sub(self, duration: Duration) -> (DateAdjustment, Self) { - let mut nanoseconds = self.nanosecond as i32 - duration.subsec_nanoseconds(); + let mut nanoseconds = self.nanosecond.get() as i32 - duration.subsec_nanoseconds(); let mut seconds = - self.second as i8 - (duration.whole_seconds() % Second.per(Minute) as i64) as i8; + self.second.get() as i8 - (duration.whole_seconds() % Second::per(Minute) as i64) as i8; let mut minutes = - self.minute as i8 - (duration.whole_minutes() % Minute.per(Hour) as i64) as i8; - let mut hours = self.hour as i8 - (duration.whole_hours() % Hour.per(Day) as i64) as i8; + self.minute.get() as i8 - (duration.whole_minutes() % Minute::per(Hour) as i64) as i8; + let mut hours = + self.hour.get() as i8 - (duration.whole_hours() % Hour::per(Day) as i64) as i8; let mut date_adjustment = DateAdjustment::None; - cascade!(nanoseconds in 0..Nanosecond.per(Second) as _ => seconds); - cascade!(seconds in 0..Second.per(Minute) as _ => minutes); - cascade!(minutes in 0..Minute.per(Hour) as _ => hours); - if hours >= Hour.per(Day) as _ { - hours -= Hour.per(Day) as i8; + cascade!(nanoseconds in 0..Nanosecond::per(Second) as _ => seconds); + cascade!(seconds in 0..Second::per(Minute) as _ => minutes); + cascade!(minutes in 0..Minute::per(Hour) as _ => hours); + if hours >= Hour::per(Day) as _ { + hours -= Hour::per(Day) as i8; date_adjustment = DateAdjustment::Next; } else if hours < 0 { - hours += Hour.per(Day) as i8; + hours += Hour::per(Day) as i8; date_adjustment = DateAdjustment::Previous; } ( date_adjustment, - Self::__from_hms_nanos_unchecked( - hours as _, - minutes as _, - seconds as _, - nanoseconds as _, - ), + // Safety: The cascades above ensure the values are in range. + unsafe { + Self::__from_hms_nanos_unchecked( + hours as _, + minutes as _, + seconds as _, + nanoseconds as _, + ) + }, ) } /// Add the sub-day time of the [`std::time::Duration`] to the `Time`. Wraps on overflow, /// returning whether the date is the previous date as the first element of the tuple. pub(crate) const fn adjusting_add_std(self, duration: StdDuration) -> (bool, Self) { - let mut nanosecond = self.nanosecond + duration.subsec_nanos(); - let mut second = self.second + (duration.as_secs() % Second.per(Minute) as u64) as u8; - let mut minute = self.minute - + ((duration.as_secs() / Second.per(Minute) as u64) % Minute.per(Hour) as u64) as u8; - let mut hour = self.hour - + ((duration.as_secs() / Second.per(Hour) as u64) % Hour.per(Day) as u64) as u8; + let mut nanosecond = self.nanosecond.get() + duration.subsec_nanos(); + let mut second = + self.second.get() + (duration.as_secs() % Second::per(Minute) as u64) as u8; + let mut minute = self.minute.get() + + ((duration.as_secs() / Second::per(Minute) as u64) % Minute::per(Hour) as u64) as u8; + let mut hour = self.hour.get() + + ((duration.as_secs() / Second::per(Hour) as u64) % Hour::per(Day) as u64) as u8; let mut is_next_day = false; - cascade!(nanosecond in 0..Nanosecond.per(Second) => second); - cascade!(second in 0..Second.per(Minute) => minute); - cascade!(minute in 0..Minute.per(Hour) => hour); - if hour >= Hour.per(Day) { - hour -= Hour.per(Day); + cascade!(nanosecond in 0..Nanosecond::per(Second) => second); + cascade!(second in 0..Second::per(Minute) => minute); + cascade!(minute in 0..Minute::per(Hour) => hour); + if hour >= Hour::per(Day) { + hour -= Hour::per(Day); is_next_day = true; } ( is_next_day, - Self::__from_hms_nanos_unchecked(hour, minute, second, nanosecond), + // Safety: The cascades above ensure the values are in range. + unsafe { Self::__from_hms_nanos_unchecked(hour, minute, second, nanosecond) }, ) } /// Subtract the sub-day time of the [`std::time::Duration`] to the `Time`. Wraps on overflow, /// returning whether the date is the previous date as the first element of the tuple. pub(crate) const fn adjusting_sub_std(self, duration: StdDuration) -> (bool, Self) { - let mut nanosecond = self.nanosecond as i32 - duration.subsec_nanos() as i32; - let mut second = self.second as i8 - (duration.as_secs() % Second.per(Minute) as u64) as i8; - let mut minute = self.minute as i8 - - ((duration.as_secs() / Second.per(Minute) as u64) % Minute.per(Hour) as u64) as i8; - let mut hour = self.hour as i8 - - ((duration.as_secs() / Second.per(Hour) as u64) % Hour.per(Day) as u64) as i8; + let mut nanosecond = self.nanosecond.get() as i32 - duration.subsec_nanos() as i32; + let mut second = + self.second.get() as i8 - (duration.as_secs() % Second::per(Minute) as u64) as i8; + let mut minute = self.minute.get() as i8 + - ((duration.as_secs() / Second::per(Minute) as u64) % Minute::per(Hour) as u64) as i8; + let mut hour = self.hour.get() as i8 + - ((duration.as_secs() / Second::per(Hour) as u64) % Hour::per(Day) as u64) as i8; let mut is_previous_day = false; - cascade!(nanosecond in 0..Nanosecond.per(Second) as _ => second); - cascade!(second in 0..Second.per(Minute) as _ => minute); - cascade!(minute in 0..Minute.per(Hour) as _ => hour); + cascade!(nanosecond in 0..Nanosecond::per(Second) as _ => second); + cascade!(second in 0..Second::per(Minute) as _ => minute); + cascade!(minute in 0..Minute::per(Hour) as _ => hour); if hour < 0 { - hour += Hour.per(Day) as i8; + hour += Hour::per(Day) as i8; is_previous_day = true; } ( is_previous_day, - Self::__from_hms_nanos_unchecked(hour as _, minute as _, second as _, nanosecond as _), + // Safety: The cascades above ensure the values are in range. + unsafe { + Self::__from_hms_nanos_unchecked( + hour as _, + minute as _, + second as _, + nanosecond as _, + ) + }, ) } // endregion arithmetic helpers @@ -470,14 +609,9 @@ impl Time { /// assert!(time!(01:02:03.004_005_006).replace_hour(24).is_err()); // 24 isn't a valid hour /// ``` #[must_use = "This method does not mutate the original `Time`."] - pub const fn replace_hour(self, hour: u8) -> Result<Self, error::ComponentRange> { - ensure_value_in_range!(hour in 0 => Hour.per(Day) - 1); - Ok(Self::__from_hms_nanos_unchecked( - hour, - self.minute, - self.second, - self.nanosecond, - )) + pub const fn replace_hour(mut self, hour: u8) -> Result<Self, error::ComponentRange> { + self.hour = ensure_ranged!(Hours: hour); + Ok(self) } /// Replace the minutes within the hour. @@ -491,14 +625,9 @@ impl Time { /// assert!(time!(01:02:03.004_005_006).replace_minute(60).is_err()); // 60 isn't a valid minute /// ``` #[must_use = "This method does not mutate the original `Time`."] - pub const fn replace_minute(self, minute: u8) -> Result<Self, error::ComponentRange> { - ensure_value_in_range!(minute in 0 => Minute.per(Hour) - 1); - Ok(Self::__from_hms_nanos_unchecked( - self.hour, - minute, - self.second, - self.nanosecond, - )) + pub const fn replace_minute(mut self, minute: u8) -> Result<Self, error::ComponentRange> { + self.minute = ensure_ranged!(Minutes: minute); + Ok(self) } /// Replace the seconds within the minute. @@ -512,14 +641,9 @@ impl Time { /// assert!(time!(01:02:03.004_005_006).replace_second(60).is_err()); // 60 isn't a valid second /// ``` #[must_use = "This method does not mutate the original `Time`."] - pub const fn replace_second(self, second: u8) -> Result<Self, error::ComponentRange> { - ensure_value_in_range!(second in 0 => Second.per(Minute) - 1); - Ok(Self::__from_hms_nanos_unchecked( - self.hour, - self.minute, - second, - self.nanosecond, - )) + pub const fn replace_second(mut self, second: u8) -> Result<Self, error::ComponentRange> { + self.second = ensure_ranged!(Seconds: second); + Ok(self) } /// Replace the milliseconds within the second. @@ -534,16 +658,12 @@ impl Time { /// ``` #[must_use = "This method does not mutate the original `Time`."] pub const fn replace_millisecond( - self, + mut self, millisecond: u16, ) -> Result<Self, error::ComponentRange> { - ensure_value_in_range!(millisecond in 0 => Millisecond.per(Second) - 1); - Ok(Self::__from_hms_nanos_unchecked( - self.hour, - self.minute, - self.second, - millisecond as u32 * Nanosecond.per(Millisecond), - )) + self.nanosecond = + ensure_ranged!(Nanoseconds: millisecond as u32 * Nanosecond::per(Millisecond)); + Ok(self) } /// Replace the microseconds within the second. @@ -558,16 +678,12 @@ impl Time { /// ``` #[must_use = "This method does not mutate the original `Time`."] pub const fn replace_microsecond( - self, + mut self, microsecond: u32, ) -> Result<Self, error::ComponentRange> { - ensure_value_in_range!(microsecond in 0 => Microsecond.per(Second) - 1); - Ok(Self::__from_hms_nanos_unchecked( - self.hour, - self.minute, - self.second, - microsecond * Nanosecond.per(Microsecond) as u32, - )) + self.nanosecond = + ensure_ranged!(Nanoseconds: microsecond * Nanosecond::per(Microsecond) as u32); + Ok(self) } /// Replace the nanoseconds within the second. @@ -581,14 +697,12 @@ impl Time { /// assert!(time!(01:02:03.004_005_006).replace_nanosecond(1_000_000_000).is_err()); // 1_000_000_000 isn't a valid nanosecond /// ``` #[must_use = "This method does not mutate the original `Time`."] - pub const fn replace_nanosecond(self, nanosecond: u32) -> Result<Self, error::ComponentRange> { - ensure_value_in_range!(nanosecond in 0 => Nanosecond.per(Second) - 1); - Ok(Self::__from_hms_nanos_unchecked( - self.hour, - self.minute, - self.second, - nanosecond, - )) + pub const fn replace_nanosecond( + mut self, + nanosecond: u32, + ) -> Result<Self, error::ComponentRange> { + self.nanosecond = ensure_ranged!(Nanoseconds: nanosecond); + Ok(self) } // endregion replacement } @@ -754,24 +868,31 @@ impl Sub for Time { /// assert_eq!(time!(0:00) - time!(23:00), (-23).hours()); /// ``` fn sub(self, rhs: Self) -> Self::Output { - let hour_diff = (self.hour as i8) - (rhs.hour as i8); - let minute_diff = (self.minute as i8) - (rhs.minute as i8); - let second_diff = (self.second as i8) - (rhs.second as i8); - let nanosecond_diff = (self.nanosecond as i32) - (rhs.nanosecond as i32); + let hour_diff = (self.hour.get() as i8) - (rhs.hour.get() as i8); + let minute_diff = (self.minute.get() as i8) - (rhs.minute.get() as i8); + let second_diff = (self.second.get() as i8) - (rhs.second.get() as i8); + let nanosecond_diff = (self.nanosecond.get() as i32) - (rhs.nanosecond.get() as i32); - let seconds = hour_diff as i64 * Second.per(Hour) as i64 - + minute_diff as i64 * Second.per(Minute) as i64 + let seconds = hour_diff as i64 * Second::per(Hour) as i64 + + minute_diff as i64 * Second::per(Minute) as i64 + second_diff as i64; let (seconds, nanoseconds) = if seconds > 0 && nanosecond_diff < 0 { - (seconds - 1, nanosecond_diff + Nanosecond.per(Second) as i32) + ( + seconds - 1, + nanosecond_diff + Nanosecond::per(Second) as i32, + ) } else if seconds < 0 && nanosecond_diff > 0 { - (seconds + 1, nanosecond_diff - Nanosecond.per(Second) as i32) + ( + seconds + 1, + nanosecond_diff - Nanosecond::per(Second) as i32, + ) } else { (seconds, nanosecond_diff) }; - Duration::new_unchecked(seconds, nanoseconds) + // Safety: `nanoseconds` is in range due to the overflow handling. + unsafe { Duration::new_unchecked(seconds, nanoseconds) } } } // endregion trait impls |