summaryrefslogtreecommitdiffstats
path: root/vendor/time/src/utc_offset.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/time/src/utc_offset.rs')
-rw-r--r--vendor/time/src/utc_offset.rs198
1 files changed, 134 insertions, 64 deletions
diff --git a/vendor/time/src/utc_offset.rs b/vendor/time/src/utc_offset.rs
index af7fd1bf7..86a937d7a 100644
--- a/vendor/time/src/utc_offset.rs
+++ b/vendor/time/src/utc_offset.rs
@@ -5,10 +5,13 @@ use core::ops::Neg;
#[cfg(feature = "formatting")]
use std::io;
+use deranged::{RangedI32, RangedI8};
+
use crate::convert::*;
use crate::error;
#[cfg(feature = "formatting")]
use crate::formatting::Formattable;
+use crate::internal_macros::ensure_ranged;
#[cfg(feature = "parsing")]
use crate::parsing::Parsable;
#[cfg(feature = "local-offset")]
@@ -16,6 +19,13 @@ use crate::sys::local_offset_at;
#[cfg(feature = "local-offset")]
use crate::OffsetDateTime;
+/// The type of the `hours` field of `UtcOffset`.
+type Hours = RangedI8<{ -(Hour::per(Day) as i8 - 1) }, { Hour::per(Day) as i8 - 1 }>;
+/// The type of the `minutes` field of `UtcOffset`.
+type Minutes = RangedI8<{ -(Minute::per(Hour) as i8 - 1) }, { Minute::per(Hour) as i8 - 1 }>;
+/// The type of the `seconds` field of `UtcOffset`.
+type Seconds = RangedI8<{ -(Second::per(Minute) as i8 - 1) }, { Second::per(Minute) as i8 - 1 }>;
+
/// An offset from UTC.
///
/// This struct can store values up to ±23:59:59. If you need support outside this range, please
@@ -24,11 +34,11 @@ use crate::OffsetDateTime;
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct UtcOffset {
#[allow(clippy::missing_docs_in_private_items)]
- hours: i8,
+ hours: Hours,
#[allow(clippy::missing_docs_in_private_items)]
- minutes: i8,
+ minutes: Minutes,
#[allow(clippy::missing_docs_in_private_items)]
- seconds: i8,
+ seconds: Seconds,
}
impl UtcOffset {
@@ -39,34 +49,32 @@ impl UtcOffset {
/// # use time_macros::offset;
/// assert_eq!(UtcOffset::UTC, offset!(UTC));
/// ```
- pub const UTC: Self = Self::__from_hms_unchecked(0, 0, 0);
+ #[allow(clippy::undocumented_unsafe_blocks)] // rust-lang/rust-clippy#11246
+ // Safety: All values are in range.
+ pub const UTC: Self = unsafe { Self::__from_hms_unchecked(0, 0, 0) };
// region: constructors
/// Create a `UtcOffset` representing an offset of the hours, minutes, and seconds provided, the
/// validity of which must be guaranteed by the caller. All three parameters must have the same
/// sign.
+ ///
+ /// # Safety
+ ///
+ /// - Hours must be in the range `-23..=23`.
+ /// - Minutes must be in the range `-59..=59`.
+ /// - Seconds must be in the range `-59..=59`.
+ ///
+ /// While the signs of the parameters are required to match to avoid bugs, this is not a safety
+ /// invariant.
#[doc(hidden)]
- pub const fn __from_hms_unchecked(hours: i8, minutes: i8, seconds: i8) -> Self {
- if hours < 0 {
- debug_assert!(minutes <= 0);
- debug_assert!(seconds <= 0);
- } else if hours > 0 {
- debug_assert!(minutes >= 0);
- debug_assert!(seconds >= 0);
- }
- if minutes < 0 {
- debug_assert!(seconds <= 0);
- } else if minutes > 0 {
- debug_assert!(seconds >= 0);
- }
- debug_assert!(hours.unsigned_abs() < 24);
- debug_assert!(minutes.unsigned_abs() < Minute.per(Hour));
- debug_assert!(seconds.unsigned_abs() < Second.per(Minute));
-
- Self {
- hours,
- minutes,
- seconds,
+ pub const unsafe fn __from_hms_unchecked(hours: i8, minutes: i8, seconds: i8) -> Self {
+ // Safety: The caller must uphold the safety invariants.
+ unsafe {
+ Self::from_hms_ranged_unchecked(
+ Hours::new_unchecked(hours),
+ Minutes::new_unchecked(minutes),
+ Seconds::new_unchecked(seconds),
+ )
}
}
@@ -84,29 +92,71 @@ impl UtcOffset {
/// ```
pub const fn from_hms(
hours: i8,
- mut minutes: i8,
- mut seconds: i8,
+ minutes: i8,
+ seconds: i8,
) -> Result<Self, error::ComponentRange> {
- ensure_value_in_range!(hours in -23 => 23);
- ensure_value_in_range!(
- minutes in -(Minute.per(Hour) as i8 - 1) => Minute.per(Hour) as i8 - 1
- );
- ensure_value_in_range!(
- seconds in -(Second.per(Minute) as i8 - 1) => Second.per(Minute) as i8 - 1
- );
-
- if (hours > 0 && minutes < 0) || (hours < 0 && minutes > 0) {
- minutes *= -1;
+ Ok(Self::from_hms_ranged(
+ ensure_ranged!(Hours: hours),
+ ensure_ranged!(Minutes: minutes),
+ ensure_ranged!(Seconds: seconds),
+ ))
+ }
+
+ /// Create a `UtcOffset` representing an offset of the hours, minutes, and seconds provided. All
+ /// three parameters must have the same sign.
+ ///
+ /// While the signs of the parameters are required to match, this is not a safety invariant.
+ pub(crate) const fn from_hms_ranged_unchecked(
+ hours: Hours,
+ minutes: Minutes,
+ seconds: Seconds,
+ ) -> Self {
+ if hours.get() < 0 {
+ debug_assert!(minutes.get() <= 0);
+ debug_assert!(seconds.get() <= 0);
+ } else if hours.get() > 0 {
+ debug_assert!(minutes.get() >= 0);
+ debug_assert!(seconds.get() >= 0);
+ }
+ if minutes.get() < 0 {
+ debug_assert!(seconds.get() <= 0);
+ } else if minutes.get() > 0 {
+ debug_assert!(seconds.get() >= 0);
+ }
+
+ Self {
+ hours,
+ minutes,
+ seconds,
}
- if (hours > 0 && seconds < 0)
- || (hours < 0 && seconds > 0)
- || (minutes > 0 && seconds < 0)
- || (minutes < 0 && seconds > 0)
+ }
+
+ /// Create a `UtcOffset` representing an offset by the number of hours, minutes, and seconds
+ /// provided.
+ ///
+ /// The sign of all three components should match. If they do not, all smaller components will
+ /// have their signs flipped.
+ pub(crate) const fn from_hms_ranged(
+ hours: Hours,
+ mut minutes: Minutes,
+ mut seconds: Seconds,
+ ) -> Self {
+ if (hours.get() > 0 && minutes.get() < 0) || (hours.get() < 0 && minutes.get() > 0) {
+ minutes = minutes.neg();
+ }
+ if (hours.get() > 0 && seconds.get() < 0)
+ || (hours.get() < 0 && seconds.get() > 0)
+ || (minutes.get() > 0 && seconds.get() < 0)
+ || (minutes.get() < 0 && seconds.get() > 0)
{
- seconds *= -1;
+ seconds = seconds.neg();
}
- Ok(Self::__from_hms_unchecked(hours, minutes, seconds))
+ Self {
+ hours,
+ minutes,
+ seconds,
+ }
}
/// Create a `UtcOffset` representing an offset by the number of seconds provided.
@@ -117,15 +167,28 @@ impl UtcOffset {
/// # Ok::<_, time::Error>(())
/// ```
pub const fn from_whole_seconds(seconds: i32) -> Result<Self, error::ComponentRange> {
- ensure_value_in_range!(
- seconds in -24 * Second.per(Hour) as i32 - 1 => 24 * Second.per(Hour) as i32 - 1
- );
-
- Ok(Self::__from_hms_unchecked(
- (seconds / Second.per(Hour) as i32) as _,
- ((seconds % Second.per(Hour) as i32) / Minute.per(Hour) as i32) as _,
- (seconds % Second.per(Minute) as i32) as _,
- ))
+ type WholeSeconds = RangedI32<
+ {
+ Hours::MIN.get() as i32 * Second::per(Hour) as i32
+ + Minutes::MIN.get() as i32 * Second::per(Minute) as i32
+ + Seconds::MIN.get() as i32
+ },
+ {
+ Hours::MAX.get() as i32 * Second::per(Hour) as i32
+ + Minutes::MAX.get() as i32 * Second::per(Minute) as i32
+ + Seconds::MAX.get() as i32
+ },
+ >;
+ ensure_ranged!(WholeSeconds: seconds);
+
+ // Safety: The value was checked to be in range.
+ Ok(unsafe {
+ Self::__from_hms_unchecked(
+ (seconds / Second::per(Hour) as i32) as _,
+ ((seconds % Second::per(Hour) as i32) / Minute::per(Hour) as i32) as _,
+ (seconds % Second::per(Minute) as i32) as _,
+ )
+ })
}
// endregion constructors
@@ -139,6 +202,13 @@ impl UtcOffset {
/// assert_eq!(offset!(-1:02:03).as_hms(), (-1, -2, -3));
/// ```
pub const fn as_hms(self) -> (i8, i8, i8) {
+ (self.hours.get(), self.minutes.get(), self.seconds.get())
+ }
+
+ /// Obtain the UTC offset as its hours, minutes, and seconds. The sign of all three components
+ /// will always match. A positive value indicates an offset to the east; a negative to the west.
+ #[cfg(feature = "quickcheck")]
+ pub(crate) const fn as_hms_ranged(self) -> (Hours, Minutes, Seconds) {
(self.hours, self.minutes, self.seconds)
}
@@ -151,7 +221,7 @@ impl UtcOffset {
/// assert_eq!(offset!(-1:02:03).whole_hours(), -1);
/// ```
pub const fn whole_hours(self) -> i8 {
- self.hours
+ self.hours.get()
}
/// Obtain the number of whole minutes the offset is from UTC. A positive value indicates an
@@ -163,7 +233,7 @@ impl UtcOffset {
/// assert_eq!(offset!(-1:02:03).whole_minutes(), -62);
/// ```
pub const fn whole_minutes(self) -> i16 {
- self.hours as i16 * Minute.per(Hour) as i16 + self.minutes as i16
+ self.hours.get() as i16 * Minute::per(Hour) as i16 + self.minutes.get() as i16
}
/// Obtain the number of minutes past the hour the offset is from UTC. A positive value
@@ -175,7 +245,7 @@ impl UtcOffset {
/// assert_eq!(offset!(-1:02:03).minutes_past_hour(), -2);
/// ```
pub const fn minutes_past_hour(self) -> i8 {
- self.minutes
+ self.minutes.get()
}
/// Obtain the number of whole seconds the offset is from UTC. A positive value indicates an
@@ -189,9 +259,9 @@ impl UtcOffset {
// This may be useful for anyone manually implementing arithmetic, as it
// would let them construct a `Duration` directly.
pub const fn whole_seconds(self) -> i32 {
- self.hours as i32 * Second.per(Hour) as i32
- + self.minutes as i32 * Second.per(Minute) as i32
- + self.seconds as i32
+ self.hours.get() as i32 * Second::per(Hour) as i32
+ + self.minutes.get() as i32 * Second::per(Minute) as i32
+ + self.seconds.get() as i32
}
/// Obtain the number of seconds past the minute the offset is from UTC. A positive value
@@ -203,7 +273,7 @@ impl UtcOffset {
/// assert_eq!(offset!(-1:02:03).seconds_past_minute(), -3);
/// ```
pub const fn seconds_past_minute(self) -> i8 {
- self.seconds
+ self.seconds.get()
}
// endregion getters
@@ -218,7 +288,7 @@ impl UtcOffset {
/// assert!(offset!(UTC).is_utc());
/// ```
pub const fn is_utc(self) -> bool {
- self.hours == 0 && self.minutes == 0 && self.seconds == 0
+ self.hours.get() == 0 && self.minutes.get() == 0 && self.seconds.get() == 0
}
/// Check if the offset is positive, or east of UTC.
@@ -230,7 +300,7 @@ impl UtcOffset {
/// assert!(!offset!(UTC).is_positive());
/// ```
pub const fn is_positive(self) -> bool {
- self.hours > 0 || self.minutes > 0 || self.seconds > 0
+ self.hours.get() > 0 || self.minutes.get() > 0 || self.seconds.get() > 0
}
/// Check if the offset is negative, or west of UTC.
@@ -242,7 +312,7 @@ impl UtcOffset {
/// assert!(!offset!(UTC).is_negative());
/// ```
pub const fn is_negative(self) -> bool {
- self.hours < 0 || self.minutes < 0 || self.seconds < 0
+ self.hours.get() < 0 || self.minutes.get() < 0 || self.seconds.get() < 0
}
// endregion is_{sign}
@@ -334,7 +404,7 @@ impl fmt::Display for UtcOffset {
if self.is_negative() { '-' } else { '+' },
self.hours.abs(),
self.minutes.abs(),
- self.seconds.abs()
+ self.seconds.abs(),
)
}
}
@@ -350,6 +420,6 @@ impl Neg for UtcOffset {
type Output = Self;
fn neg(self) -> Self::Output {
- Self::__from_hms_unchecked(-self.hours, -self.minutes, -self.seconds)
+ Self::from_hms_ranged(self.hours.neg(), self.minutes.neg(), self.seconds.neg())
}
}