summaryrefslogtreecommitdiffstats
path: root/vendor/time/src/parsing/parsed.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/time/src/parsing/parsed.rs')
-rw-r--r--vendor/time/src/parsing/parsed.rs655
1 files changed, 361 insertions, 294 deletions
diff --git a/vendor/time/src/parsing/parsed.rs b/vendor/time/src/parsing/parsed.rs
index 04c74a720..f31087fe2 100644
--- a/vendor/time/src/parsing/parsed.rs
+++ b/vendor/time/src/parsing/parsed.rs
@@ -1,16 +1,22 @@
//! Information parsed from an input and format description.
-use core::mem::MaybeUninit;
use core::num::{NonZeroU16, NonZeroU8};
+use deranged::{
+ OptionRangedI128, OptionRangedI32, OptionRangedI8, OptionRangedU16, OptionRangedU32,
+ OptionRangedU8, RangedI128, RangedI32, RangedI8, RangedU16, RangedU32, RangedU8,
+};
+
+use crate::convert::{Day, Hour, Minute, Nanosecond, Second};
+use crate::date::{MAX_YEAR, MIN_YEAR};
use crate::date_time::{maybe_offset_from_offset, offset_kind, DateTime, MaybeOffset};
use crate::error::TryFromParsed::InsufficientInformation;
-use crate::format_description::modifier::{WeekNumberRepr, YearRepr};
#[cfg(feature = "alloc")]
use crate::format_description::OwnedFormatItem;
-use crate::format_description::{Component, FormatItem};
+use crate::format_description::{modifier, Component, FormatItem};
+use crate::internal_macros::const_try_opt;
use crate::parsing::component::{
- parse_day, parse_hour, parse_ignore, parse_minute, parse_month, parse_offset_hour,
+ parse_day, parse_end, parse_hour, parse_ignore, parse_minute, parse_month, parse_offset_hour,
parse_offset_minute, parse_offset_second, parse_ordinal, parse_period, parse_second,
parse_subsecond, parse_unix_timestamp, parse_week_number, parse_weekday, parse_year, Period,
};
@@ -99,10 +105,6 @@ impl sealed::AnyFormatItem for OwnedFormatItem {
}
}
-/// The type of the `flags` field in [`Parsed`]. Allows for changing a single location and having it
-/// effect all uses.
-type Flag = u32;
-
/// All information parsed.
///
/// This information is directly used to construct the final values.
@@ -111,106 +113,97 @@ type Flag = u32;
/// control over values, in the instance that the default parser is insufficient.
#[derive(Debug, Clone, Copy)]
pub struct Parsed {
- /// Bitflags indicating whether a particular field is present.
- flags: Flag,
/// Calendar year.
- year: MaybeUninit<i32>,
+ year: OptionRangedI32<{ MIN_YEAR }, { MAX_YEAR }>,
/// The last two digits of the calendar year.
- year_last_two: MaybeUninit<u8>,
+ year_last_two: OptionRangedU8<0, 99>,
/// Year of the [ISO week date](https://en.wikipedia.org/wiki/ISO_week_date).
- iso_year: MaybeUninit<i32>,
+ iso_year: OptionRangedI32<{ MIN_YEAR }, { MAX_YEAR }>,
/// The last two digits of the ISO week year.
- iso_year_last_two: MaybeUninit<u8>,
+ iso_year_last_two: OptionRangedU8<0, 99>,
/// Month of the year.
month: Option<Month>,
/// Week of the year, where week one begins on the first Sunday of the calendar year.
- sunday_week_number: MaybeUninit<u8>,
+ sunday_week_number: OptionRangedU8<0, 53>,
/// Week of the year, where week one begins on the first Monday of the calendar year.
- monday_week_number: MaybeUninit<u8>,
+ monday_week_number: OptionRangedU8<0, 53>,
/// Week of the year, where week one is the Monday-to-Sunday period containing January 4.
- iso_week_number: Option<NonZeroU8>,
+ iso_week_number: OptionRangedU8<1, 53>,
/// Day of the week.
weekday: Option<Weekday>,
/// Day of the year.
- ordinal: Option<NonZeroU16>,
+ ordinal: OptionRangedU16<1, 366>,
/// Day of the month.
- day: Option<NonZeroU8>,
+ day: OptionRangedU8<1, 31>,
/// Hour within the day.
- hour_24: MaybeUninit<u8>,
+ hour_24: OptionRangedU8<0, { Hour::per(Day) - 1 }>,
/// Hour within the 12-hour period (midnight to noon or vice versa). This is typically used in
/// conjunction with AM/PM, which is indicated by the `hour_12_is_pm` field.
- hour_12: Option<NonZeroU8>,
+ hour_12: OptionRangedU8<1, 12>,
/// Whether the `hour_12` field indicates a time that "PM".
hour_12_is_pm: Option<bool>,
/// Minute within the hour.
- minute: MaybeUninit<u8>,
+ // minute: MaybeUninit<u8>,
+ minute: OptionRangedU8<0, { Minute::per(Hour) - 1 }>,
/// Second within the minute.
- second: MaybeUninit<u8>,
+ // do not subtract one, as leap seconds may be allowed
+ second: OptionRangedU8<0, { Second::per(Minute) }>,
/// Nanosecond within the second.
- subsecond: MaybeUninit<u32>,
+ subsecond: OptionRangedU32<0, { Nanosecond::per(Second) - 1 }>,
/// Whole hours of the UTC offset.
- offset_hour: MaybeUninit<i8>,
+ offset_hour: OptionRangedI8<-23, 23>,
/// Minutes within the hour of the UTC offset.
- offset_minute: MaybeUninit<i8>,
+ offset_minute:
+ OptionRangedI8<{ -((Minute::per(Hour) - 1) as i8) }, { (Minute::per(Hour) - 1) as _ }>,
/// Seconds within the minute of the UTC offset.
- offset_second: MaybeUninit<i8>,
+ offset_second:
+ OptionRangedI8<{ -((Second::per(Minute) - 1) as i8) }, { (Second::per(Minute) - 1) as _ }>,
/// The Unix timestamp in nanoseconds.
- unix_timestamp_nanos: MaybeUninit<i128>,
-}
-
-#[allow(clippy::missing_docs_in_private_items)]
-impl Parsed {
- const YEAR_FLAG: Flag = 1 << 0;
- const YEAR_LAST_TWO_FLAG: Flag = 1 << 1;
- const ISO_YEAR_FLAG: Flag = 1 << 2;
- const ISO_YEAR_LAST_TWO_FLAG: Flag = 1 << 3;
- const SUNDAY_WEEK_NUMBER_FLAG: Flag = 1 << 4;
- const MONDAY_WEEK_NUMBER_FLAG: Flag = 1 << 5;
- const HOUR_24_FLAG: Flag = 1 << 6;
- const MINUTE_FLAG: Flag = 1 << 7;
- const SECOND_FLAG: Flag = 1 << 8;
- const SUBSECOND_FLAG: Flag = 1 << 9;
- const OFFSET_HOUR_FLAG: Flag = 1 << 10;
- const OFFSET_MINUTE_FLAG: Flag = 1 << 11;
- const OFFSET_SECOND_FLAG: Flag = 1 << 12;
+ // unix_timestamp_nanos: MaybeUninit<i128>,
+ unix_timestamp_nanos: OptionRangedI128<
+ { Date::MIN.midnight().assume_utc().unix_timestamp_nanos() },
+ {
+ Date::MAX
+ .with_time(Time::MAX)
+ .assume_utc()
+ .unix_timestamp_nanos()
+ },
+ >,
+ /// Indicates whether the [`UtcOffset`] is negative. This information is obtained when parsing
+ /// the offset hour, but may not otherwise be stored due to "-0" being equivalent to "0".
+ offset_is_negative: Option<bool>,
/// Indicates whether a leap second is permitted to be parsed. This is required by some
/// well-known formats.
- pub(super) const LEAP_SECOND_ALLOWED_FLAG: Flag = 1 << 13;
- /// Indicates whether the `UtcOffset` is negative. This information is obtained when parsing the
- /// offset hour, but may not otherwise be stored due to "-0" being equivalent to "0".
- const OFFSET_IS_NEGATIVE_FLAG: Flag = 1 << 14;
- /// Does the value at `OFFSET_IS_NEGATIVE_FLAG` have any semantic meaning, or is it just the
- /// default value? If the latter, the value should be considered to have no meaning.
- const OFFSET_IS_NEGATIVE_FLAG_IS_INITIALIZED: Flag = 1 << 15;
- const UNIX_TIMESTAMP_NANOS_FLAG: Flag = 1 << 16;
+ pub(super) leap_second_allowed: bool,
}
impl Parsed {
/// Create a new instance of `Parsed` with no information known.
pub const fn new() -> Self {
Self {
- flags: 0,
- year: MaybeUninit::uninit(),
- year_last_two: MaybeUninit::uninit(),
- iso_year: MaybeUninit::uninit(),
- iso_year_last_two: MaybeUninit::uninit(),
+ year: OptionRangedI32::None,
+ year_last_two: OptionRangedU8::None,
+ iso_year: OptionRangedI32::None,
+ iso_year_last_two: OptionRangedU8::None,
month: None,
- sunday_week_number: MaybeUninit::uninit(),
- monday_week_number: MaybeUninit::uninit(),
- iso_week_number: None,
+ sunday_week_number: OptionRangedU8::None,
+ monday_week_number: OptionRangedU8::None,
+ iso_week_number: OptionRangedU8::None,
weekday: None,
- ordinal: None,
- day: None,
- hour_24: MaybeUninit::uninit(),
- hour_12: None,
+ ordinal: OptionRangedU16::None,
+ day: OptionRangedU8::None,
+ hour_24: OptionRangedU8::None,
+ hour_12: OptionRangedU8::None,
hour_12_is_pm: None,
- minute: MaybeUninit::uninit(),
- second: MaybeUninit::uninit(),
- subsecond: MaybeUninit::uninit(),
- offset_hour: MaybeUninit::uninit(),
- offset_minute: MaybeUninit::uninit(),
- offset_second: MaybeUninit::uninit(),
- unix_timestamp_nanos: MaybeUninit::uninit(),
+ minute: OptionRangedU8::None,
+ second: OptionRangedU8::None,
+ subsecond: OptionRangedU32::None,
+ offset_hour: OptionRangedI8::None,
+ offset_minute: OptionRangedI8::None,
+ offset_second: OptionRangedI8::None,
+ unix_timestamp_nanos: OptionRangedI128::None,
+ offset_is_negative: None,
+ leap_second_allowed: false,
}
}
@@ -283,11 +276,11 @@ impl Parsed {
let ParsedItem(remaining, value) =
parse_week_number(input, modifiers).ok_or(InvalidComponent("week number"))?;
match modifiers.repr {
- WeekNumberRepr::Iso => {
+ modifier::WeekNumberRepr::Iso => {
NonZeroU8::new(value).and_then(|value| self.set_iso_week_number(value))
}
- WeekNumberRepr::Sunday => self.set_sunday_week_number(value),
- WeekNumberRepr::Monday => self.set_monday_week_number(value),
+ modifier::WeekNumberRepr::Sunday => self.set_sunday_week_number(value),
+ modifier::WeekNumberRepr::Monday => self.set_monday_week_number(value),
}
.ok_or(InvalidComponent("week number"))?;
Ok(remaining)
@@ -296,10 +289,10 @@ impl Parsed {
let ParsedItem(remaining, value) =
parse_year(input, modifiers).ok_or(InvalidComponent("year"))?;
match (modifiers.iso_week_based, modifiers.repr) {
- (false, YearRepr::Full) => self.set_year(value),
- (false, YearRepr::LastTwo) => self.set_year_last_two(value as _),
- (true, YearRepr::Full) => self.set_iso_year(value),
- (true, YearRepr::LastTwo) => self.set_iso_year_last_two(value as _),
+ (false, modifier::YearRepr::Full) => self.set_year(value),
+ (false, modifier::YearRepr::LastTwo) => self.set_year_last_two(value as _),
+ (true, modifier::YearRepr::Full) => self.set_iso_year(value),
+ (true, modifier::YearRepr::LastTwo) => self.set_iso_year_last_two(value as _),
}
.ok_or(InvalidComponent("year"))?;
Ok(remaining)
@@ -332,9 +325,9 @@ impl Parsed {
Component::OffsetHour(modifiers) => parse_offset_hour(input, modifiers)
.and_then(|parsed| {
parsed.consume_value(|(value, is_negative)| {
- self.set_flag(Self::OFFSET_IS_NEGATIVE_FLAG_IS_INITIALIZED, true);
- self.set_flag(Self::OFFSET_IS_NEGATIVE_FLAG, is_negative);
- self.set_offset_hour(value)
+ self.set_offset_hour(value)?;
+ self.offset_is_negative = Some(is_negative);
+ Some(())
})
})
.ok_or(InvalidComponent("offset hour")),
@@ -356,145 +349,152 @@ impl Parsed {
parsed.consume_value(|value| self.set_unix_timestamp_nanos(value))
})
.ok_or(InvalidComponent("unix_timestamp")),
+ Component::End(modifiers) => parse_end(input, modifiers)
+ .map(ParsedItem::<()>::into_inner)
+ .ok_or(error::ParseFromDescription::UnexpectedTrailingCharacters),
}
}
+}
- /// Get the value of the provided flag.
- const fn get_flag(&self, flag: Flag) -> bool {
- self.flags & flag == flag
+/// Getter methods
+impl Parsed {
+ /// Obtain the `year` component.
+ pub const fn year(&self) -> Option<i32> {
+ self.year.get_primitive()
}
- /// Set the value of the provided flag.
- pub(super) fn set_flag(&mut self, flag: Flag, value: bool) {
- if value {
- self.flags |= flag;
- } else {
- self.flags &= !flag;
- }
+ /// Obtain the `year_last_two` component.
+ pub const fn year_last_two(&self) -> Option<u8> {
+ self.year_last_two.get_primitive()
}
-}
-/// Generate getters for each of the fields.
-macro_rules! getters {
- ($($(@$flag:ident)? $name:ident: $ty:ty),+ $(,)?) => {$(
- getters!(! $(@$flag)? $name: $ty);
- )*};
- (! $name:ident : $ty:ty) => {
- /// Obtain the named component.
- pub const fn $name(&self) -> Option<$ty> {
- self.$name
- }
- };
- (! @$flag:ident $name:ident : $ty:ty) => {
- /// Obtain the named component.
- pub const fn $name(&self) -> Option<$ty> {
- if !self.get_flag(Self::$flag) {
- None
- } else {
- // SAFETY: We just checked if the field is present.
- Some(unsafe { self.$name.assume_init() })
- }
- }
- };
-}
+ /// Obtain the `iso_year` component.
+ pub const fn iso_year(&self) -> Option<i32> {
+ self.iso_year.get_primitive()
+ }
-/// Getter methods
-impl Parsed {
- getters! {
- @YEAR_FLAG year: i32,
- @YEAR_LAST_TWO_FLAG year_last_two: u8,
- @ISO_YEAR_FLAG iso_year: i32,
- @ISO_YEAR_LAST_TWO_FLAG iso_year_last_two: u8,
- month: Month,
- @SUNDAY_WEEK_NUMBER_FLAG sunday_week_number: u8,
- @MONDAY_WEEK_NUMBER_FLAG monday_week_number: u8,
- iso_week_number: NonZeroU8,
- weekday: Weekday,
- ordinal: NonZeroU16,
- day: NonZeroU8,
- @HOUR_24_FLAG hour_24: u8,
- hour_12: NonZeroU8,
- hour_12_is_pm: bool,
- @MINUTE_FLAG minute: u8,
- @SECOND_FLAG second: u8,
- @SUBSECOND_FLAG subsecond: u32,
- @OFFSET_HOUR_FLAG offset_hour: i8,
- @UNIX_TIMESTAMP_NANOS_FLAG unix_timestamp_nanos: i128,
- }
-
- /// Obtain the absolute value of the offset minute.
+ /// Obtain the `iso_year_last_two` component.
+ pub const fn iso_year_last_two(&self) -> Option<u8> {
+ self.iso_year_last_two.get_primitive()
+ }
+
+ /// Obtain the `month` component.
+ pub const fn month(&self) -> Option<Month> {
+ self.month
+ }
+
+ /// Obtain the `sunday_week_number` component.
+ pub const fn sunday_week_number(&self) -> Option<u8> {
+ self.sunday_week_number.get_primitive()
+ }
+
+ /// Obtain the `monday_week_number` component.
+ pub const fn monday_week_number(&self) -> Option<u8> {
+ self.monday_week_number.get_primitive()
+ }
+
+ /// Obtain the `iso_week_number` component.
+ pub const fn iso_week_number(&self) -> Option<NonZeroU8> {
+ NonZeroU8::new(const_try_opt!(self.iso_week_number.get_primitive()))
+ }
+
+ /// Obtain the `weekday` component.
+ pub const fn weekday(&self) -> Option<Weekday> {
+ self.weekday
+ }
+
+ /// Obtain the `ordinal` component.
+ pub const fn ordinal(&self) -> Option<NonZeroU16> {
+ NonZeroU16::new(const_try_opt!(self.ordinal.get_primitive()))
+ }
+
+ /// Obtain the `day` component.
+ pub const fn day(&self) -> Option<NonZeroU8> {
+ NonZeroU8::new(const_try_opt!(self.day.get_primitive()))
+ }
+
+ /// Obtain the `hour_24` component.
+ pub const fn hour_24(&self) -> Option<u8> {
+ self.hour_24.get_primitive()
+ }
+
+ /// Obtain the `hour_12` component.
+ pub const fn hour_12(&self) -> Option<NonZeroU8> {
+ NonZeroU8::new(const_try_opt!(self.hour_12.get_primitive()))
+ }
+
+ /// Obtain the `hour_12_is_pm` component.
+ pub const fn hour_12_is_pm(&self) -> Option<bool> {
+ self.hour_12_is_pm
+ }
+
+ /// Obtain the `minute` component.
+ pub const fn minute(&self) -> Option<u8> {
+ self.minute.get_primitive()
+ }
+
+ /// Obtain the `second` component.
+ pub const fn second(&self) -> Option<u8> {
+ self.second.get_primitive()
+ }
+
+ /// Obtain the `subsecond` component.
+ pub const fn subsecond(&self) -> Option<u32> {
+ self.subsecond.get_primitive()
+ }
+
+ /// Obtain the `offset_hour` component.
+ pub const fn offset_hour(&self) -> Option<i8> {
+ self.offset_hour.get_primitive()
+ }
+
+ /// Obtain the absolute value of the `offset_minute` component.
#[doc(hidden)]
#[deprecated(since = "0.3.8", note = "use `parsed.offset_minute_signed()` instead")]
pub const fn offset_minute(&self) -> Option<u8> {
Some(const_try_opt!(self.offset_minute_signed()).unsigned_abs())
}
- /// Obtain the offset minute as an `i8`.
+ /// Obtain the `offset_minute` component.
pub const fn offset_minute_signed(&self) -> Option<i8> {
- if !self.get_flag(Self::OFFSET_MINUTE_FLAG) {
- None
- } else {
- // SAFETY: We just checked if the field is present.
- let value = unsafe { self.offset_minute.assume_init() };
-
- if self.get_flag(Self::OFFSET_IS_NEGATIVE_FLAG_IS_INITIALIZED)
- && (value.is_negative() != self.get_flag(Self::OFFSET_IS_NEGATIVE_FLAG))
- {
- Some(-value)
- } else {
- Some(value)
- }
+ match (self.offset_minute.get_primitive(), self.offset_is_negative) {
+ (Some(offset_minute), Some(true)) => Some(-offset_minute),
+ (Some(offset_minute), _) => Some(offset_minute),
+ (None, _) => None,
}
}
- /// Obtain the absolute value of the offset second.
+ /// Obtain the absolute value of the `offset_second` component.
#[doc(hidden)]
#[deprecated(since = "0.3.8", note = "use `parsed.offset_second_signed()` instead")]
pub const fn offset_second(&self) -> Option<u8> {
Some(const_try_opt!(self.offset_second_signed()).unsigned_abs())
}
- /// Obtain the offset second as an `i8`.
+ /// Obtain the `offset_second` component.
pub const fn offset_second_signed(&self) -> Option<i8> {
- if !self.get_flag(Self::OFFSET_SECOND_FLAG) {
- None
- } else {
- // SAFETY: We just checked if the field is present.
- let value = unsafe { self.offset_second.assume_init() };
-
- if self.get_flag(Self::OFFSET_IS_NEGATIVE_FLAG_IS_INITIALIZED)
- && (value.is_negative() != self.get_flag(Self::OFFSET_IS_NEGATIVE_FLAG))
- {
- Some(-value)
- } else {
- Some(value)
- }
+ match (self.offset_second.get_primitive(), self.offset_is_negative) {
+ (Some(offset_second), Some(true)) => Some(-offset_second),
+ (Some(offset_second), _) => Some(offset_second),
+ (None, _) => None,
}
}
+
+ /// Obtain the `unix_timestamp_nanos` component.
+ pub const fn unix_timestamp_nanos(&self) -> Option<i128> {
+ self.unix_timestamp_nanos.get_primitive()
+ }
}
-/// Generate setters for each of the fields.
-///
-/// This macro should only be used for fields where the value is not validated beyond its type.
+/// Generate setters based on the builders.
macro_rules! setters {
- ($($(@$flag:ident)? $setter_name:ident $name:ident: $ty:ty),+ $(,)?) => {$(
- setters!(! $(@$flag)? $setter_name $name: $ty);
- )*};
- (! $setter_name:ident $name:ident : $ty:ty) => {
- /// Set the named component.
- pub fn $setter_name(&mut self, value: $ty) -> Option<()> {
- self.$name = Some(value);
- Some(())
- }
- };
- (! @$flag:ident $setter_name:ident $name:ident : $ty:ty) => {
- /// Set the named component.
- pub fn $setter_name(&mut self, value: $ty) -> Option<()> {
- self.$name = MaybeUninit::new(value);
- self.set_flag(Self::$flag, true);
+ ($($name:ident $setter:ident $builder:ident $type:ty;)*) => {$(
+ #[doc = concat!("Set the `", stringify!($setter), "` component.")]
+ pub fn $setter(&mut self, value: $type) -> Option<()> {
+ *self = self.$builder(value)?;
Some(())
}
- };
+ )*};
}
/// Setter methods
@@ -503,28 +503,30 @@ macro_rules! setters {
/// setters _may_ fail if the value is invalid, though behavior is not guaranteed.
impl Parsed {
setters! {
- @YEAR_FLAG set_year year: i32,
- @YEAR_LAST_TWO_FLAG set_year_last_two year_last_two: u8,
- @ISO_YEAR_FLAG set_iso_year iso_year: i32,
- @ISO_YEAR_LAST_TWO_FLAG set_iso_year_last_two iso_year_last_two: u8,
- set_month month: Month,
- @SUNDAY_WEEK_NUMBER_FLAG set_sunday_week_number sunday_week_number: u8,
- @MONDAY_WEEK_NUMBER_FLAG set_monday_week_number monday_week_number: u8,
- set_iso_week_number iso_week_number: NonZeroU8,
- set_weekday weekday: Weekday,
- set_ordinal ordinal: NonZeroU16,
- set_day day: NonZeroU8,
- @HOUR_24_FLAG set_hour_24 hour_24: u8,
- set_hour_12 hour_12: NonZeroU8,
- set_hour_12_is_pm hour_12_is_pm: bool,
- @MINUTE_FLAG set_minute minute: u8,
- @SECOND_FLAG set_second second: u8,
- @SUBSECOND_FLAG set_subsecond subsecond: u32,
- @OFFSET_HOUR_FLAG set_offset_hour offset_hour: i8,
- @UNIX_TIMESTAMP_NANOS_FLAG set_unix_timestamp_nanos unix_timestamp_nanos: i128,
- }
-
- /// Set the named component.
+ year set_year with_year i32;
+ year_last_two set_year_last_two with_year_last_two u8;
+ iso_year set_iso_year with_iso_year i32;
+ iso_year_last_two set_iso_year_last_two with_iso_year_last_two u8;
+ month set_month with_month Month;
+ sunday_week_number set_sunday_week_number with_sunday_week_number u8;
+ monday_week_number set_monday_week_number with_monday_week_number u8;
+ iso_week_number set_iso_week_number with_iso_week_number NonZeroU8;
+ weekday set_weekday with_weekday Weekday;
+ ordinal set_ordinal with_ordinal NonZeroU16;
+ day set_day with_day NonZeroU8;
+ hour_24 set_hour_24 with_hour_24 u8;
+ hour_12 set_hour_12 with_hour_12 NonZeroU8;
+ hour_12_is_pm set_hour_12_is_pm with_hour_12_is_pm bool;
+ minute set_minute with_minute u8;
+ second set_second with_second u8;
+ subsecond set_subsecond with_subsecond u32;
+ offset_hour set_offset_hour with_offset_hour i8;
+ offset_minute set_offset_minute_signed with_offset_minute_signed i8;
+ offset_second set_offset_second_signed with_offset_second_signed i8;
+ unix_timestamp_nanos set_unix_timestamp_nanos with_unix_timestamp_nanos i128;
+ }
+
+ /// Set the `offset_minute` component.
#[doc(hidden)]
#[deprecated(
since = "0.3.8",
@@ -539,13 +541,6 @@ impl Parsed {
}
/// Set the `offset_minute` component.
- pub fn set_offset_minute_signed(&mut self, value: i8) -> Option<()> {
- self.offset_minute = MaybeUninit::new(value);
- self.set_flag(Self::OFFSET_MINUTE_FLAG, true);
- Some(())
- }
-
- /// Set the named component.
#[doc(hidden)]
#[deprecated(
since = "0.3.8",
@@ -558,37 +553,6 @@ impl Parsed {
self.set_offset_second_signed(value as _)
}
}
-
- /// Set the `offset_second` component.
- pub fn set_offset_second_signed(&mut self, value: i8) -> Option<()> {
- self.offset_second = MaybeUninit::new(value);
- self.set_flag(Self::OFFSET_SECOND_FLAG, true);
- Some(())
- }
-}
-
-/// Generate build methods for each of the fields.
-///
-/// This macro should only be used for fields where the value is not validated beyond its type.
-macro_rules! builders {
- ($($(@$flag:ident)? $builder_name:ident $name:ident: $ty:ty),+ $(,)?) => {$(
- builders!(! $(@$flag)? $builder_name $name: $ty);
- )*};
- (! $builder_name:ident $name:ident : $ty:ty) => {
- /// Set the named component and return `self`.
- pub const fn $builder_name(mut self, value: $ty) -> Option<Self> {
- self.$name = Some(value);
- Some(self)
- }
- };
- (! @$flag:ident $builder_name:ident $name:ident : $ty:ty) => {
- /// Set the named component and return `self`.
- pub const fn $builder_name(mut self, value: $ty) -> Option<Self> {
- self.$name = MaybeUninit::new(value);
- self.flags |= Self::$flag;
- Some(self)
- }
- };
}
/// Builder methods
@@ -596,29 +560,115 @@ macro_rules! builders {
/// All builder methods return `Option<Self>`, which is `Some` if the value was set, and `None` if
/// not. The builder methods _may_ fail if the value is invalid, though behavior is not guaranteed.
impl Parsed {
- builders! {
- @YEAR_FLAG with_year year: i32,
- @YEAR_LAST_TWO_FLAG with_year_last_two year_last_two: u8,
- @ISO_YEAR_FLAG with_iso_year iso_year: i32,
- @ISO_YEAR_LAST_TWO_FLAG with_iso_year_last_two iso_year_last_two: u8,
- with_month month: Month,
- @SUNDAY_WEEK_NUMBER_FLAG with_sunday_week_number sunday_week_number: u8,
- @MONDAY_WEEK_NUMBER_FLAG with_monday_week_number monday_week_number: u8,
- with_iso_week_number iso_week_number: NonZeroU8,
- with_weekday weekday: Weekday,
- with_ordinal ordinal: NonZeroU16,
- with_day day: NonZeroU8,
- @HOUR_24_FLAG with_hour_24 hour_24: u8,
- with_hour_12 hour_12: NonZeroU8,
- with_hour_12_is_pm hour_12_is_pm: bool,
- @MINUTE_FLAG with_minute minute: u8,
- @SECOND_FLAG with_second second: u8,
- @SUBSECOND_FLAG with_subsecond subsecond: u32,
- @OFFSET_HOUR_FLAG with_offset_hour offset_hour: i8,
- @UNIX_TIMESTAMP_NANOS_FLAG with_unix_timestamp_nanos unix_timestamp_nanos: i128,
- }
-
- /// Set the named component and return `self`.
+ /// Set the `year` component and return `self`.
+ pub const fn with_year(mut self, value: i32) -> Option<Self> {
+ self.year = OptionRangedI32::Some(const_try_opt!(RangedI32::new(value)));
+ Some(self)
+ }
+
+ /// Set the `year_last_two` component and return `self`.
+ pub const fn with_year_last_two(mut self, value: u8) -> Option<Self> {
+ self.year_last_two = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value)));
+ Some(self)
+ }
+
+ /// Set the `iso_year` component and return `self`.
+ pub const fn with_iso_year(mut self, value: i32) -> Option<Self> {
+ self.iso_year = OptionRangedI32::Some(const_try_opt!(RangedI32::new(value)));
+ Some(self)
+ }
+
+ /// Set the `iso_year_last_two` component and return `self`.
+ pub const fn with_iso_year_last_two(mut self, value: u8) -> Option<Self> {
+ self.iso_year_last_two = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value)));
+ Some(self)
+ }
+
+ /// Set the `month` component and return `self`.
+ pub const fn with_month(mut self, value: Month) -> Option<Self> {
+ self.month = Some(value);
+ Some(self)
+ }
+
+ /// Set the `sunday_week_number` component and return `self`.
+ pub const fn with_sunday_week_number(mut self, value: u8) -> Option<Self> {
+ self.sunday_week_number = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value)));
+ Some(self)
+ }
+
+ /// Set the `monday_week_number` component and return `self`.
+ pub const fn with_monday_week_number(mut self, value: u8) -> Option<Self> {
+ self.monday_week_number = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value)));
+ Some(self)
+ }
+
+ /// Set the `iso_week_number` component and return `self`.
+ pub const fn with_iso_week_number(mut self, value: NonZeroU8) -> Option<Self> {
+ self.iso_week_number = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value.get())));
+ Some(self)
+ }
+
+ /// Set the `weekday` component and return `self`.
+ pub const fn with_weekday(mut self, value: Weekday) -> Option<Self> {
+ self.weekday = Some(value);
+ Some(self)
+ }
+
+ /// Set the `ordinal` component and return `self`.
+ pub const fn with_ordinal(mut self, value: NonZeroU16) -> Option<Self> {
+ self.ordinal = OptionRangedU16::Some(const_try_opt!(RangedU16::new(value.get())));
+ Some(self)
+ }
+
+ /// Set the `day` component and return `self`.
+ pub const fn with_day(mut self, value: NonZeroU8) -> Option<Self> {
+ self.day = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value.get())));
+ Some(self)
+ }
+
+ /// Set the `hour_24` component and return `self`.
+ pub const fn with_hour_24(mut self, value: u8) -> Option<Self> {
+ self.hour_24 = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value)));
+ Some(self)
+ }
+
+ /// Set the `hour_12` component and return `self`.
+ pub const fn with_hour_12(mut self, value: NonZeroU8) -> Option<Self> {
+ self.hour_12 = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value.get())));
+ Some(self)
+ }
+
+ /// Set the `hour_12_is_pm` component and return `self`.
+ pub const fn with_hour_12_is_pm(mut self, value: bool) -> Option<Self> {
+ self.hour_12_is_pm = Some(value);
+ Some(self)
+ }
+
+ /// Set the `minute` component and return `self`.
+ pub const fn with_minute(mut self, value: u8) -> Option<Self> {
+ self.minute = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value)));
+ Some(self)
+ }
+
+ /// Set the `second` component and return `self`.
+ pub const fn with_second(mut self, value: u8) -> Option<Self> {
+ self.second = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value)));
+ Some(self)
+ }
+
+ /// Set the `subsecond` component and return `self`.
+ pub const fn with_subsecond(mut self, value: u32) -> Option<Self> {
+ self.subsecond = OptionRangedU32::Some(const_try_opt!(RangedU32::new(value)));
+ Some(self)
+ }
+
+ /// Set the `offset_hour` component and return `self`.
+ pub const fn with_offset_hour(mut self, value: i8) -> Option<Self> {
+ self.offset_hour = OptionRangedI8::Some(const_try_opt!(RangedI8::new(value)));
+ Some(self)
+ }
+
+ /// Set the `offset_minute` component and return `self`.
#[doc(hidden)]
#[deprecated(
since = "0.3.8",
@@ -634,12 +684,11 @@ impl Parsed {
/// Set the `offset_minute` component and return `self`.
pub const fn with_offset_minute_signed(mut self, value: i8) -> Option<Self> {
- self.offset_minute = MaybeUninit::new(value);
- self.flags |= Self::OFFSET_MINUTE_FLAG;
+ self.offset_minute = OptionRangedI8::Some(const_try_opt!(RangedI8::new(value)));
Some(self)
}
- /// Set the named component and return `self`.
+ /// Set the `offset_minute` component and return `self`.
#[doc(hidden)]
#[deprecated(
since = "0.3.8",
@@ -655,8 +704,13 @@ impl Parsed {
/// Set the `offset_second` component and return `self`.
pub const fn with_offset_second_signed(mut self, value: i8) -> Option<Self> {
- self.offset_second = MaybeUninit::new(value);
- self.flags |= Self::OFFSET_SECOND_FLAG;
+ self.offset_second = OptionRangedI8::Some(const_try_opt!(RangedI8::new(value)));
+ Some(self)
+ }
+
+ /// Set the `unix_timestamp_nanos` component and return `self`.
+ pub const fn with_unix_timestamp_nanos(mut self, value: i128) -> Option<Self> {
+ self.unix_timestamp_nanos = OptionRangedI128::Some(const_try_opt!(RangedI128::new(value)));
Some(self)
}
}
@@ -682,7 +736,8 @@ impl TryFrom<Parsed> for Date {
/// Get the value needed to adjust the ordinal day for Sunday and Monday-based week
/// numbering.
const fn adjustment(year: i32) -> i16 {
- match Date::__from_ordinal_date_unchecked(year, 1).weekday() {
+ // Safety: `ordinal` is not zero.
+ match unsafe { Date::__from_ordinal_date_unchecked(year, 1) }.weekday() {
Weekday::Monday => 7,
Weekday::Tuesday => 1,
Weekday::Wednesday => 2,
@@ -733,6 +788,7 @@ impl TryFrom<Parsed> for Time {
(_, Some(hour), Some(true)) => hour.get() + 12,
_ => return Err(InsufficientInformation),
};
+
if parsed.hour_24().is_none()
&& parsed.hour_12().is_some()
&& parsed.hour_12_is_pm().is_some()
@@ -742,10 +798,17 @@ impl TryFrom<Parsed> for Time {
{
return Ok(Self::from_hms_nano(hour, 0, 0, 0)?);
}
- let minute = parsed.minute().ok_or(InsufficientInformation)?;
- let second = parsed.second().unwrap_or(0);
- let subsecond = parsed.subsecond().unwrap_or(0);
- Ok(Self::from_hms_nano(hour, minute, second, subsecond)?)
+
+ // Reject combinations such as hour-second with minute omitted.
+ match (parsed.minute(), parsed.second(), parsed.subsecond()) {
+ (None, None, None) => Ok(Self::from_hms_nano(hour, 0, 0, 0)?),
+ (Some(minute), None, None) => Ok(Self::from_hms_nano(hour, minute, 0, 0)?),
+ (Some(minute), Some(second), None) => Ok(Self::from_hms_nano(hour, minute, second, 0)?),
+ (Some(minute), Some(second), Some(subsecond)) => {
+ Ok(Self::from_hms_nano(hour, minute, second, subsecond)?)
+ }
+ _ => Err(InsufficientInformation),
+ }
}
}
@@ -796,27 +859,31 @@ impl<O: MaybeOffset> TryFrom<Parsed> for DateTime<O> {
if let Some(timestamp) = parsed.unix_timestamp_nanos() {
let DateTime { date, time, offset } =
DateTime::<offset_kind::Fixed>::from_unix_timestamp_nanos(timestamp)?;
- return Ok(Self {
+
+ let mut value = Self {
date,
time,
offset: maybe_offset_from_offset::<O>(offset),
- });
+ };
+ if let Some(subsecond) = parsed.subsecond() {
+ value = value.replace_nanosecond(subsecond)?;
+ }
+ return Ok(value);
}
}
// Some well-known formats explicitly allow leap seconds. We don't currently support them,
// so treat it as the nearest preceding moment that can be represented. Because leap seconds
// always fall at the end of a month UTC, reject any that are at other times.
- let leap_second_input =
- if parsed.get_flag(Parsed::LEAP_SECOND_ALLOWED_FLAG) && parsed.second() == Some(60) {
- parsed.set_second(59).expect("59 is a valid second");
- parsed
- .set_subsecond(999_999_999)
- .expect("999_999_999 is a valid subsecond");
- true
- } else {
- false
- };
+ let leap_second_input = if parsed.leap_second_allowed && parsed.second() == Some(60) {
+ parsed.set_second(59).expect("59 is a valid second");
+ parsed
+ .set_subsecond(999_999_999)
+ .expect("999_999_999 is a valid subsecond");
+ true
+ } else {
+ false
+ };
let dt = Self {
date: Date::try_from(parsed)?,