/// Sealed to prevent downstream implementations. mod sealed { usesuper::*;
/// A trait to allow `parse_item` to be generic. pubtrait AnyFormatItem { /// Parse a single item, returning the remaining input on success. fn parse_item<'a>(
&self,
parsed: &mut Parsed,
input: &'a [u8],
) -> Result<&'a [u8], error::ParseFromDescription>;
}
}
for item in items.iter() { match parsed.parse_item(input, item) {
Ok(remaining_input) => return Ok(remaining_input),
Err(err) if first_err.is_none() => first_err = Some(err),
Err(_) => {}
}
}
match first_err {
Some(err) => Err(err), // This location will be reached if the slice is empty, skipping the `for` loop. // As this case is expected to be uncommon, there's no need to check up front.
None => Ok(input),
}
}
}
}
}
for item in items.iter() { match parsed.parse_item(input, item) {
Ok(remaining_input) => return Ok(remaining_input),
Err(err) if first_err.is_none() => first_err = Some(err),
Err(_) => {}
}
}
match first_err {
Some(err) => Err(err), // This location will be reached if the slice is empty, skipping the `for` loop. // As this case is expected to be uncommon, there's no need to check up front.
None => Ok(input),
}
}
}
}
}
/// All information parsed. /// /// This information is directly used to construct the final values. /// /// Most users will not need think about this struct in any way. It is public to allow for manual /// control over values, in the instance that the default parser is insufficient. #[derive(Debug, Clone, Copy)] pubstruct Parsed { /// Calendar year.
year: OptionRangedI32<{ MIN_YEAR }, { MAX_YEAR }>, /// The last two digits of the calendar year.
year_last_two: OptionRangedU8<0, 99>, /// Year of the [ISO week date](https://en.wikipedia.org/wiki/ISO_week_date).
iso_year: OptionRangedI32<{ MIN_YEAR }, { MAX_YEAR }>, /// The last two digits of the ISO week year.
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: OptionRangedU8<0, 53>, /// Week of the year, where week one begins on the first Monday of the calendar year.
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: OptionRangedU8<1, 53>, /// Day of the week.
weekday: Option<Weekday>, /// Day of the year.
ordinal: OptionRangedU16<1, 366>, /// Day of the month.
day: OptionRangedU8<1, 31>, /// Hour within the day.
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: 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: OptionRangedU8<0, { Minute::per(Hour) - 1 }>, /// Second within the minute. // do not subtract one, as leap seconds may be allowed
second: OptionRangedU8<0, { Second::per(Minute) }>, /// Nanosecond within the second.
subsecond: OptionRangedU32<0, { Nanosecond::per(Second) - 1 }>, /// Whole hours of the UTC offset.
offset_hour: OptionRangedI8<-23, 23>, /// Minutes within the hour of the UTC offset.
offset_minute:
OptionRangedI8<{ -((Minute::per(Hour) - 1) as i8) }, { (Minute::per(Hour) - 1) as _ }>, /// Seconds within the minute of the UTC offset.
offset_second:
OptionRangedI8<{ -((Second::per(Minute) - 1) as i8) }, { (Second::per(Minute) - 1) as _ }>, /// The Unix timestamp in nanoseconds.
unix_timestamp_nanos: OptionRangedI128<
{
OffsetDateTime::new_in_offset(Date::MIN, Time::MIDNIGHT, UtcOffset::UTC)
.unix_timestamp_nanos()
},
{
OffsetDateTime::new_in_offset(Date::MAX, Time::MAX, UtcOffset::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) leap_second_allowed: bool,
}
/// Parse a single [`BorrowedFormatItem`] or [`OwnedFormatItem`], mutating the struct. The /// remaining input is returned as the `Ok` value. /// /// If a [`BorrowedFormatItem::Optional`] or [`OwnedFormatItem::Optional`] is passed, parsing /// will not fail; the input will be returned as-is if the expected format is not present. pubfn parse_item<'a>(
&mutself,
input: &'a [u8],
item: &impl sealed::AnyFormatItem,
) -> Result<&'a [u8], error::ParseFromDescription> {
item.parse_item(self, input)
}
/// Parse a sequence of [`BorrowedFormatItem`]s or [`OwnedFormatItem`]s, mutating the struct. /// The remaining input is returned as the `Ok` value. /// /// This method will fail if any of the contained [`BorrowedFormatItem`]s or /// [`OwnedFormatItem`]s fail to parse. `self` will not be mutated in this instance. pubfn parse_items<'a>(
&mutself, mut input: &'a [u8],
items: &[impl sealed::AnyFormatItem],
) -> Result<&'a [u8], error::ParseFromDescription> { // Make a copy that we can mutate. It will only be set to the user's copy if everything // succeeds. letmut this = *self; for item in items {
input = this.parse_item(input, item)?;
}
*self = this;
Ok(input)
}
/// Parse a literal byte sequence. The remaining input is returned as the `Ok` value. pubfn parse_literal<'a>(
input: &'a [u8],
literal: &[u8],
) -> Result<&'a [u8], error::ParseFromDescription> {
input
.strip_prefix(literal)
.ok_or(error::ParseFromDescription::InvalidLiteral)
}
/// Parse a single component, mutating the struct. The remaining input is returned as the `Ok` /// value. pubfn parse_component<'a>(
&mutself,
input: &'a [u8],
component: Component,
) -> Result<&'a [u8], error::ParseFromDescription> { use error::ParseFromDescription::InvalidComponent;
/// Generate setters based on the builders.
macro_rules! setters {
($($name:ident $setter:ident $builder:ident $type:ty;)*) => {$( #[doc = concat!("Set the `", stringify!($setter), "` component.")] pubfn $setter(&mutself, value: $type) -> Option<()> {
*self = self.$builder(value)?;
Some(())
}
)*};
}
/// Setter methods /// /// All setters return `Option<()>`, which is `Some` if the value was set, and `None` if not. The /// setters _may_ fail if the value is invalid, though behavior is not guaranteed. impl Parsed {
setters! {
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",
note = "use `parsed.set_offset_minute_signed()` instead"
)] pubfn set_offset_minute(&mutself, value: u8) -> Option<()> { if value > i8::MAX.cast_unsigned() {
None
} else { self.set_offset_minute_signed(value.cast_signed())
}
}
/// Set the `offset_minute` component. #[doc(hidden)] #[deprecated(
since = "0.3.8",
note = "use `parsed.set_offset_second_signed()` instead"
)] pubfn set_offset_second(&mutself, value: u8) -> Option<()> { if value > i8::MAX.cast_unsigned() {
None
} else { self.set_offset_second_signed(value.cast_signed())
}
}
}
/// Builder methods /// /// 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 { /// Set the `year` component and return `self`. pubconstfn with_year(mutself, 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`. pubconstfn with_year_last_two(mutself, 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`. pubconstfn with_iso_year(mutself, 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`. pubconstfn with_iso_year_last_two(mutself, 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`. pubconstfn with_month(mutself, value: Month) -> Option<Self> { self.month = Some(value);
Some(self)
}
/// Set the `sunday_week_number` component and return `self`. pubconstfn with_sunday_week_number(mutself, 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`. pubconstfn with_monday_week_number(mutself, 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`. pubconstfn with_iso_week_number(mutself, 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`. pubconstfn with_weekday(mutself, value: Weekday) -> Option<Self> { self.weekday = Some(value);
Some(self)
}
/// Set the `ordinal` component and return `self`. pubconstfn with_ordinal(mutself, value: NonZeroU16) -> Option<Self> { self.ordinal = OptionRangedU16::Some(const_try_opt!(RangedU16::new(value.get())));
Some(self)
}
/// Set the `day` component and return `self`. pubconstfn with_day(mutself, 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`. pubconstfn with_hour_24(mutself, 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`. pubconstfn with_hour_12(mutself, 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`. pubconstfn with_hour_12_is_pm(mutself, value: bool) -> Option<Self> { self.hour_12_is_pm = Some(value);
Some(self)
}
/// Set the `minute` component and return `self`. pubconstfn with_minute(mutself, value: u8) -> Option<Self> { self.minute = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value)));
Some(self)
}
/// Set the `second` component and return `self`. pubconstfn with_second(mutself, value: u8) -> Option<Self> { self.second = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value)));
Some(self)
}
/// Set the `subsecond` component and return `self`. pubconstfn with_subsecond(mutself, value: u32) -> Option<Self> { self.subsecond = OptionRangedU32::Some(const_try_opt!(RangedU32::new(value)));
Some(self)
}
/// Set the `offset_hour` component and return `self`. pubconstfn with_offset_hour(mutself, 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",
note = "use `parsed.with_offset_minute_signed()` instead"
)] pubconstfn with_offset_minute(self, value: u8) -> Option<Self> { if value > i8::MAX as u8 {
None
} else { self.with_offset_minute_signed(value as _)
}
}
/// Set the `offset_minute` component and return `self`. pubconstfn with_offset_minute_signed(mutself, value: i8) -> Option<Self> { self.offset_minute = 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",
note = "use `parsed.with_offset_second_signed()` instead"
)] pubconstfn with_offset_second(self, value: u8) -> Option<Self> { if value > i8::MAX as u8 {
None
} else { self.with_offset_second_signed(value as _)
}
}
/// Set the `offset_second` component and return `self`. pubconstfn with_offset_second_signed(mutself, value: i8) -> Option<Self> { self.offset_second = OptionRangedI8::Some(const_try_opt!(RangedI8::new(value)));
Some(self)
}
/// Set the `unix_timestamp_nanos` component and return `self`. pubconstfn with_unix_timestamp_nanos(mutself, value: i128) -> Option<Self> { self.unix_timestamp_nanos = OptionRangedI128::Some(const_try_opt!(RangedI128::new(value)));
Some(self)
}
}
impl TryFrom<Parsed> for Date { type Error = error::TryFromParsed;
fn try_from(parsed: Parsed) -> Result<Self, Self::Error> { /// Match on the components that need to be present.
macro_rules! match_ {
(_ => $catch_all:expr $(,)?) => {
$catch_all
};
(($($name:ident),* $(,)?) => $arm:expr, $($rest:tt)*) => { iflet ($(Some($name)),*) = ($(parsed.$name()),*) {
$arm
} else {
match_!($($rest)*)
}
};
}
/// Get the value needed to adjust the ordinal day for Sunday and Monday-based week /// numbering. constfn adjustment(year: i32) -> i16 { // Safety: `ordinal` is not zero. matchunsafe { Date::__from_ordinal_date_unchecked(year, 1) }.weekday() {
Weekday::Monday => 7,
Weekday::Tuesday => 1,
Weekday::Wednesday => 2,
Weekday::Thursday => 3,
Weekday::Friday => 4,
Weekday::Saturday => 5,
Weekday::Sunday => 6,
}
}
// TODO Only the basics have been covered. There are many other valid values that are not // currently constructed from the information known.
impl TryFrom<Parsed> for UtcOffset { type Error = error::TryFromParsed;
fn try_from(parsed: Parsed) -> Result<Self, Self::Error> { let hour = parsed.offset_hour().ok_or(InsufficientInformation)?; let minute = parsed.offset_minute_signed().unwrap_or(0); let second = parsed.offset_second_signed().unwrap_or(0);
Self::from_hms(hour, minute, second).map_err(|mut err| { // Provide the user a more accurate error. if err.name == "hours" {
err.name = "offset hour";
} elseif err.name == "minutes" {
err.name = "offset minute";
} elseif err.name == "seconds" {
err.name = "offset second";
}
err.into()
})
}
}
impl TryFrom<Parsed> for PrimitiveDateTime { type Error = error::TryFromParsed;
// 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.leap_second_allowed && parsed.second() == Some(60) { if parsed.set_second(59).is_none() {
bug!("59 is a valid second");
} if parsed.set_subsecond(999_999_999).is_none() {
bug!("999_999_999 is a valid subsecond");
} true
} else { false
};
let dt = Self::new_in_offset(
Date::try_from(parsed)?,
Time::try_from(parsed)?,
UtcOffset::try_from(parsed)?,
);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.