summaryrefslogtreecommitdiffstats
path: root/third_party/rust/time/src/parsing/component.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/time/src/parsing/component.rs')
-rw-r--r--third_party/rust/time/src/parsing/component.rs296
1 files changed, 296 insertions, 0 deletions
diff --git a/third_party/rust/time/src/parsing/component.rs b/third_party/rust/time/src/parsing/component.rs
new file mode 100644
index 0000000000..38d632a0da
--- /dev/null
+++ b/third_party/rust/time/src/parsing/component.rs
@@ -0,0 +1,296 @@
+//! Parsing implementations for all [`Component`](crate::format_description::Component)s.
+
+use core::num::{NonZeroU16, NonZeroU8};
+
+use crate::format_description::modifier;
+#[cfg(feature = "large-dates")]
+use crate::parsing::combinator::n_to_m_digits_padded;
+use crate::parsing::combinator::{
+ any_digit, exactly_n_digits, exactly_n_digits_padded, first_match, opt, sign,
+};
+use crate::parsing::ParsedItem;
+use crate::{Month, Weekday};
+
+// region: date components
+/// Parse the "year" component of a `Date`.
+pub(crate) fn parse_year(input: &[u8], modifiers: modifier::Year) -> Option<ParsedItem<'_, i32>> {
+ match modifiers.repr {
+ modifier::YearRepr::Full => {
+ let ParsedItem(input, sign) = opt(sign)(input);
+ #[cfg(not(feature = "large-dates"))]
+ let ParsedItem(input, year) =
+ exactly_n_digits_padded::<4, u32>(modifiers.padding)(input)?;
+ #[cfg(feature = "large-dates")]
+ let ParsedItem(input, year) =
+ n_to_m_digits_padded::<4, 6, u32>(modifiers.padding)(input)?;
+ match sign {
+ Some(b'-') => Some(ParsedItem(input, -(year as i32))),
+ None if modifiers.sign_is_mandatory || year >= 10_000 => None,
+ _ => Some(ParsedItem(input, year as i32)),
+ }
+ }
+ modifier::YearRepr::LastTwo => {
+ Some(exactly_n_digits_padded::<2, u32>(modifiers.padding)(input)?.map(|v| v as i32))
+ }
+ }
+}
+
+/// Parse the "month" component of a `Date`.
+pub(crate) fn parse_month(
+ input: &[u8],
+ modifiers: modifier::Month,
+) -> Option<ParsedItem<'_, Month>> {
+ use Month::*;
+ let ParsedItem(remaining, value) = first_match(
+ match modifiers.repr {
+ modifier::MonthRepr::Numerical => {
+ return exactly_n_digits_padded::<2, _>(modifiers.padding)(input)?
+ .flat_map(|n| Month::from_number(n).ok());
+ }
+ modifier::MonthRepr::Long => [
+ (b"January".as_slice(), January),
+ (b"February".as_slice(), February),
+ (b"March".as_slice(), March),
+ (b"April".as_slice(), April),
+ (b"May".as_slice(), May),
+ (b"June".as_slice(), June),
+ (b"July".as_slice(), July),
+ (b"August".as_slice(), August),
+ (b"September".as_slice(), September),
+ (b"October".as_slice(), October),
+ (b"November".as_slice(), November),
+ (b"December".as_slice(), December),
+ ],
+ modifier::MonthRepr::Short => [
+ (b"Jan".as_slice(), January),
+ (b"Feb".as_slice(), February),
+ (b"Mar".as_slice(), March),
+ (b"Apr".as_slice(), April),
+ (b"May".as_slice(), May),
+ (b"Jun".as_slice(), June),
+ (b"Jul".as_slice(), July),
+ (b"Aug".as_slice(), August),
+ (b"Sep".as_slice(), September),
+ (b"Oct".as_slice(), October),
+ (b"Nov".as_slice(), November),
+ (b"Dec".as_slice(), December),
+ ],
+ },
+ modifiers.case_sensitive,
+ )(input)?;
+ Some(ParsedItem(remaining, value))
+}
+
+/// Parse the "week number" component of a `Date`.
+pub(crate) fn parse_week_number(
+ input: &[u8],
+ modifiers: modifier::WeekNumber,
+) -> Option<ParsedItem<'_, u8>> {
+ exactly_n_digits_padded::<2, _>(modifiers.padding)(input)
+}
+
+/// Parse the "weekday" component of a `Date`.
+pub(crate) fn parse_weekday(
+ input: &[u8],
+ modifiers: modifier::Weekday,
+) -> Option<ParsedItem<'_, Weekday>> {
+ first_match(
+ match (modifiers.repr, modifiers.one_indexed) {
+ (modifier::WeekdayRepr::Short, _) => [
+ (b"Mon".as_slice(), Weekday::Monday),
+ (b"Tue".as_slice(), Weekday::Tuesday),
+ (b"Wed".as_slice(), Weekday::Wednesday),
+ (b"Thu".as_slice(), Weekday::Thursday),
+ (b"Fri".as_slice(), Weekday::Friday),
+ (b"Sat".as_slice(), Weekday::Saturday),
+ (b"Sun".as_slice(), Weekday::Sunday),
+ ],
+ (modifier::WeekdayRepr::Long, _) => [
+ (b"Monday".as_slice(), Weekday::Monday),
+ (b"Tuesday".as_slice(), Weekday::Tuesday),
+ (b"Wednesday".as_slice(), Weekday::Wednesday),
+ (b"Thursday".as_slice(), Weekday::Thursday),
+ (b"Friday".as_slice(), Weekday::Friday),
+ (b"Saturday".as_slice(), Weekday::Saturday),
+ (b"Sunday".as_slice(), Weekday::Sunday),
+ ],
+ (modifier::WeekdayRepr::Sunday, false) => [
+ (b"1".as_slice(), Weekday::Monday),
+ (b"2".as_slice(), Weekday::Tuesday),
+ (b"3".as_slice(), Weekday::Wednesday),
+ (b"4".as_slice(), Weekday::Thursday),
+ (b"5".as_slice(), Weekday::Friday),
+ (b"6".as_slice(), Weekday::Saturday),
+ (b"0".as_slice(), Weekday::Sunday),
+ ],
+ (modifier::WeekdayRepr::Sunday, true) => [
+ (b"2".as_slice(), Weekday::Monday),
+ (b"3".as_slice(), Weekday::Tuesday),
+ (b"4".as_slice(), Weekday::Wednesday),
+ (b"5".as_slice(), Weekday::Thursday),
+ (b"6".as_slice(), Weekday::Friday),
+ (b"7".as_slice(), Weekday::Saturday),
+ (b"1".as_slice(), Weekday::Sunday),
+ ],
+ (modifier::WeekdayRepr::Monday, false) => [
+ (b"0".as_slice(), Weekday::Monday),
+ (b"1".as_slice(), Weekday::Tuesday),
+ (b"2".as_slice(), Weekday::Wednesday),
+ (b"3".as_slice(), Weekday::Thursday),
+ (b"4".as_slice(), Weekday::Friday),
+ (b"5".as_slice(), Weekday::Saturday),
+ (b"6".as_slice(), Weekday::Sunday),
+ ],
+ (modifier::WeekdayRepr::Monday, true) => [
+ (b"1".as_slice(), Weekday::Monday),
+ (b"2".as_slice(), Weekday::Tuesday),
+ (b"3".as_slice(), Weekday::Wednesday),
+ (b"4".as_slice(), Weekday::Thursday),
+ (b"5".as_slice(), Weekday::Friday),
+ (b"6".as_slice(), Weekday::Saturday),
+ (b"7".as_slice(), Weekday::Sunday),
+ ],
+ },
+ modifiers.case_sensitive,
+ )(input)
+}
+
+/// Parse the "ordinal" component of a `Date`.
+pub(crate) fn parse_ordinal(
+ input: &[u8],
+ modifiers: modifier::Ordinal,
+) -> Option<ParsedItem<'_, NonZeroU16>> {
+ exactly_n_digits_padded::<3, _>(modifiers.padding)(input)
+}
+
+/// Parse the "day" component of a `Date`.
+pub(crate) fn parse_day(
+ input: &[u8],
+ modifiers: modifier::Day,
+) -> Option<ParsedItem<'_, NonZeroU8>> {
+ exactly_n_digits_padded::<2, _>(modifiers.padding)(input)
+}
+// endregion date components
+
+// region: time components
+/// Indicate whether the hour is "am" or "pm".
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub(crate) enum Period {
+ #[allow(clippy::missing_docs_in_private_items)]
+ Am,
+ #[allow(clippy::missing_docs_in_private_items)]
+ Pm,
+}
+
+/// Parse the "hour" component of a `Time`.
+pub(crate) fn parse_hour(input: &[u8], modifiers: modifier::Hour) -> Option<ParsedItem<'_, u8>> {
+ exactly_n_digits_padded::<2, _>(modifiers.padding)(input)
+}
+
+/// Parse the "minute" component of a `Time`.
+pub(crate) fn parse_minute(
+ input: &[u8],
+ modifiers: modifier::Minute,
+) -> Option<ParsedItem<'_, u8>> {
+ exactly_n_digits_padded::<2, _>(modifiers.padding)(input)
+}
+
+/// Parse the "second" component of a `Time`.
+pub(crate) fn parse_second(
+ input: &[u8],
+ modifiers: modifier::Second,
+) -> Option<ParsedItem<'_, u8>> {
+ exactly_n_digits_padded::<2, _>(modifiers.padding)(input)
+}
+
+/// Parse the "period" component of a `Time`. Required if the hour is on a 12-hour clock.
+pub(crate) fn parse_period(
+ input: &[u8],
+ modifiers: modifier::Period,
+) -> Option<ParsedItem<'_, Period>> {
+ first_match(
+ if modifiers.is_uppercase {
+ [
+ (b"AM".as_slice(), Period::Am),
+ (b"PM".as_slice(), Period::Pm),
+ ]
+ } else {
+ [
+ (b"am".as_slice(), Period::Am),
+ (b"pm".as_slice(), Period::Pm),
+ ]
+ },
+ modifiers.case_sensitive,
+ )(input)
+}
+
+/// Parse the "subsecond" component of a `Time`.
+pub(crate) fn parse_subsecond(
+ input: &[u8],
+ modifiers: modifier::Subsecond,
+) -> Option<ParsedItem<'_, u32>> {
+ use modifier::SubsecondDigits::*;
+ Some(match modifiers.digits {
+ One => exactly_n_digits::<1, u32>(input)?.map(|v| v * 100_000_000),
+ Two => exactly_n_digits::<2, u32>(input)?.map(|v| v * 10_000_000),
+ Three => exactly_n_digits::<3, u32>(input)?.map(|v| v * 1_000_000),
+ Four => exactly_n_digits::<4, u32>(input)?.map(|v| v * 100_000),
+ Five => exactly_n_digits::<5, u32>(input)?.map(|v| v * 10_000),
+ Six => exactly_n_digits::<6, u32>(input)?.map(|v| v * 1_000),
+ Seven => exactly_n_digits::<7, u32>(input)?.map(|v| v * 100),
+ Eight => exactly_n_digits::<8, u32>(input)?.map(|v| v * 10),
+ Nine => exactly_n_digits::<9, _>(input)?,
+ OneOrMore => {
+ let ParsedItem(mut input, mut value) =
+ any_digit(input)?.map(|v| (v - b'0') as u32 * 100_000_000);
+
+ let mut multiplier = 10_000_000;
+ while let Some(ParsedItem(new_input, digit)) = any_digit(input) {
+ value += (digit - b'0') as u32 * multiplier;
+ input = new_input;
+ multiplier /= 10;
+ }
+
+ ParsedItem(input, value)
+ }
+ })
+}
+// endregion time components
+
+// region: offset components
+/// Parse the "hour" component of a `UtcOffset`.
+pub(crate) fn parse_offset_hour(
+ input: &[u8],
+ modifiers: modifier::OffsetHour,
+) -> Option<ParsedItem<'_, i8>> {
+ let ParsedItem(input, sign) = opt(sign)(input);
+ let ParsedItem(input, hour) = exactly_n_digits_padded::<2, u8>(modifiers.padding)(input)?;
+ match sign {
+ Some(b'-') => Some(ParsedItem(input, -(hour as i8))),
+ None if modifiers.sign_is_mandatory => None,
+ _ => Some(ParsedItem(input, hour as i8)),
+ }
+}
+
+/// Parse the "minute" component of a `UtcOffset`.
+pub(crate) fn parse_offset_minute(
+ input: &[u8],
+ modifiers: modifier::OffsetMinute,
+) -> Option<ParsedItem<'_, i8>> {
+ Some(
+ exactly_n_digits_padded::<2, u8>(modifiers.padding)(input)?
+ .map(|offset_minute| offset_minute as _),
+ )
+}
+
+/// Parse the "second" component of a `UtcOffset`.
+pub(crate) fn parse_offset_second(
+ input: &[u8],
+ modifiers: modifier::OffsetSecond,
+) -> Option<ParsedItem<'_, i8>> {
+ Some(
+ exactly_n_digits_padded::<2, u8>(modifiers.padding)(input)?
+ .map(|offset_second| offset_second as _),
+ )
+}
+// endregion offset components