diff options
Diffstat (limited to 'vendor/time/src/format_description/parse')
| -rw-r--r-- | vendor/time/src/format_description/parse/ast.rs | 384 | ||||
| -rw-r--r-- | vendor/time/src/format_description/parse/format_item.rs | 549 | ||||
| -rw-r--r-- | vendor/time/src/format_description/parse/lexer.rs | 284 | ||||
| -rw-r--r-- | vendor/time/src/format_description/parse/mod.rs | 262 | ||||
| -rw-r--r-- | vendor/time/src/format_description/parse/strftime.rs | 487 |
5 files changed, 0 insertions, 1966 deletions
diff --git a/vendor/time/src/format_description/parse/ast.rs b/vendor/time/src/format_description/parse/ast.rs deleted file mode 100644 index cf13de89..00000000 --- a/vendor/time/src/format_description/parse/ast.rs +++ /dev/null @@ -1,384 +0,0 @@ -//! AST for parsing format descriptions. - -use alloc::boxed::Box; -use alloc::string::String; -use alloc::vec::Vec; -use core::iter; - -use super::{lexer, unused, Error, Location, Spanned, SpannedValue, Unused}; -use crate::internal_macros::bug; - -/// One part of a complete format description. -pub(super) enum Item<'a> { - /// A literal string, formatted and parsed as-is. - /// - /// This should never be present inside a nested format description. - Literal(Spanned<&'a [u8]>), - /// A sequence of brackets. The first acts as the escape character. - /// - /// This should never be present if the lexer has `BACKSLASH_ESCAPE` set to `true`. - EscapedBracket { - /// The first bracket. - _first: Unused<Location>, - /// The second bracket. - _second: Unused<Location>, - }, - /// Part of a type, along with its modifiers. - Component { - /// Where the opening bracket was in the format string. - _opening_bracket: Unused<Location>, - /// Whitespace between the opening bracket and name. - _leading_whitespace: Unused<Option<Spanned<&'a [u8]>>>, - /// The name of the component. - name: Spanned<&'a [u8]>, - /// The modifiers for the component. - modifiers: Box<[Modifier<'a>]>, - /// Whitespace between the modifiers and closing bracket. - _trailing_whitespace: Unused<Option<Spanned<&'a [u8]>>>, - /// Where the closing bracket was in the format string. - _closing_bracket: Unused<Location>, - }, - /// An optional sequence of items. - Optional { - /// Where the opening bracket was in the format string. - opening_bracket: Location, - /// Whitespace between the opening bracket and "optional". - _leading_whitespace: Unused<Option<Spanned<&'a [u8]>>>, - /// The "optional" keyword. - _optional_kw: Unused<Spanned<&'a [u8]>>, - /// Whitespace between the "optional" keyword and the opening bracket. - _whitespace: Unused<Spanned<&'a [u8]>>, - /// The items within the optional sequence. - nested_format_description: NestedFormatDescription<'a>, - /// Where the closing bracket was in the format string. - closing_bracket: Location, - }, - /// The first matching parse of a sequence of items. - First { - /// Where the opening bracket was in the format string. - opening_bracket: Location, - /// Whitespace between the opening bracket and "first". - _leading_whitespace: Unused<Option<Spanned<&'a [u8]>>>, - /// The "first" keyword. - _first_kw: Unused<Spanned<&'a [u8]>>, - /// Whitespace between the "first" keyword and the opening bracket. - _whitespace: Unused<Spanned<&'a [u8]>>, - /// The sequences of items to try. - nested_format_descriptions: Box<[NestedFormatDescription<'a>]>, - /// Where the closing bracket was in the format string. - closing_bracket: Location, - }, -} - -/// A format description that is nested within another format description. -pub(super) struct NestedFormatDescription<'a> { - /// Where the opening bracket was in the format string. - pub(super) _opening_bracket: Unused<Location>, - /// The items within the nested format description. - pub(super) items: Box<[Item<'a>]>, - /// Where the closing bracket was in the format string. - pub(super) _closing_bracket: Unused<Location>, - /// Whitespace between the closing bracket and the next item. - pub(super) _trailing_whitespace: Unused<Option<Spanned<&'a [u8]>>>, -} - -/// A modifier for a component. -pub(super) struct Modifier<'a> { - /// Whitespace preceding the modifier. - pub(super) _leading_whitespace: Unused<Spanned<&'a [u8]>>, - /// The key of the modifier. - pub(super) key: Spanned<&'a [u8]>, - /// Where the colon of the modifier was in the format string. - pub(super) _colon: Unused<Location>, - /// The value of the modifier. - pub(super) value: Spanned<&'a [u8]>, -} - -/// Parse the provided tokens into an AST. -pub(super) fn parse< - 'item: 'iter, - 'iter, - I: Iterator<Item = Result<lexer::Token<'item>, Error>>, - const VERSION: usize, ->( - tokens: &'iter mut lexer::Lexed<I>, -) -> impl Iterator<Item = Result<Item<'item>, Error>> + 'iter { - validate_version!(VERSION); - parse_inner::<_, false, VERSION>(tokens) -} - -/// Parse the provided tokens into an AST. The const generic indicates whether the resulting -/// [`Item`] will be used directly or as part of a [`NestedFormatDescription`]. -fn parse_inner< - 'item, - I: Iterator<Item = Result<lexer::Token<'item>, Error>>, - const NESTED: bool, - const VERSION: usize, ->( - tokens: &mut lexer::Lexed<I>, -) -> impl Iterator<Item = Result<Item<'item>, Error>> + '_ { - validate_version!(VERSION); - iter::from_fn(move || { - if NESTED && tokens.peek_closing_bracket().is_some() { - return None; - } - - let next = match tokens.next()? { - Ok(token) => token, - Err(err) => return Some(Err(err)), - }; - - Some(match next { - lexer::Token::Literal(Spanned { value: _, span: _ }) if NESTED => { - bug!("literal should not be present in nested description") - } - lexer::Token::Literal(value) => Ok(Item::Literal(value)), - lexer::Token::Bracket { - kind: lexer::BracketKind::Opening, - location, - } => { - if version!(..=1) { - if let Some(second_location) = tokens.next_if_opening_bracket() { - Ok(Item::EscapedBracket { - _first: unused(location), - _second: unused(second_location), - }) - } else { - parse_component::<_, VERSION>(location, tokens) - } - } else { - parse_component::<_, VERSION>(location, tokens) - } - } - lexer::Token::Bracket { - kind: lexer::BracketKind::Closing, - location: _, - } if NESTED => { - bug!("closing bracket should be caught by the `if` statement") - } - lexer::Token::Bracket { - kind: lexer::BracketKind::Closing, - location: _, - } => { - bug!("closing bracket should have been consumed by `parse_component`") - } - lexer::Token::ComponentPart { - kind: _, // whitespace is significant in nested components - value, - } if NESTED => Ok(Item::Literal(value)), - lexer::Token::ComponentPart { kind: _, value: _ } => { - bug!("component part should have been consumed by `parse_component`") - } - }) - }) -} - -/// Parse a component. This assumes that the opening bracket has already been consumed. -fn parse_component< - 'a, - I: Iterator<Item = Result<lexer::Token<'a>, Error>>, - const VERSION: usize, ->( - opening_bracket: Location, - tokens: &mut lexer::Lexed<I>, -) -> Result<Item<'a>, Error> { - validate_version!(VERSION); - let leading_whitespace = tokens.next_if_whitespace(); - - let Some(name) = tokens.next_if_not_whitespace() else { - let span = match leading_whitespace { - Some(Spanned { value: _, span }) => span, - None => opening_bracket.to_self(), - }; - return Err(Error { - _inner: unused(span.error("expected component name")), - public: crate::error::InvalidFormatDescription::MissingComponentName { - index: span.start.byte as usize, - }, - }); - }; - - if *name == b"optional" { - let Some(whitespace) = tokens.next_if_whitespace() else { - return Err(Error { - _inner: unused(name.span.error("expected whitespace after `optional`")), - public: crate::error::InvalidFormatDescription::Expected { - what: "whitespace after `optional`", - index: name.span.end.byte as usize, - }, - }); - }; - - let nested = parse_nested::<_, VERSION>(whitespace.span.end, tokens)?; - - let Some(closing_bracket) = tokens.next_if_closing_bracket() else { - return Err(Error { - _inner: unused(opening_bracket.error("unclosed bracket")), - public: crate::error::InvalidFormatDescription::UnclosedOpeningBracket { - index: opening_bracket.byte as usize, - }, - }); - }; - - return Ok(Item::Optional { - opening_bracket, - _leading_whitespace: unused(leading_whitespace), - _optional_kw: unused(name), - _whitespace: unused(whitespace), - nested_format_description: nested, - closing_bracket, - }); - } - - if *name == b"first" { - let Some(whitespace) = tokens.next_if_whitespace() else { - return Err(Error { - _inner: unused(name.span.error("expected whitespace after `first`")), - public: crate::error::InvalidFormatDescription::Expected { - what: "whitespace after `first`", - index: name.span.end.byte as usize, - }, - }); - }; - - let mut nested_format_descriptions = Vec::new(); - while let Ok(description) = parse_nested::<_, VERSION>(whitespace.span.end, tokens) { - nested_format_descriptions.push(description); - } - - let Some(closing_bracket) = tokens.next_if_closing_bracket() else { - return Err(Error { - _inner: unused(opening_bracket.error("unclosed bracket")), - public: crate::error::InvalidFormatDescription::UnclosedOpeningBracket { - index: opening_bracket.byte as usize, - }, - }); - }; - - return Ok(Item::First { - opening_bracket, - _leading_whitespace: unused(leading_whitespace), - _first_kw: unused(name), - _whitespace: unused(whitespace), - nested_format_descriptions: nested_format_descriptions.into_boxed_slice(), - closing_bracket, - }); - } - - let mut modifiers = Vec::new(); - let trailing_whitespace = loop { - let Some(whitespace) = tokens.next_if_whitespace() else { - break None; - }; - - // This is not necessary for proper parsing, but provides a much better error when a nested - // description is used where it's not allowed. - if let Some(location) = tokens.next_if_opening_bracket() { - return Err(Error { - _inner: unused( - location - .to_self() - .error("modifier must be of the form `key:value`"), - ), - public: crate::error::InvalidFormatDescription::InvalidModifier { - value: String::from("["), - index: location.byte as usize, - }, - }); - } - - let Some(Spanned { value, span }) = tokens.next_if_not_whitespace() else { - break Some(whitespace); - }; - - let Some(colon_index) = value.iter().position(|&b| b == b':') else { - return Err(Error { - _inner: unused(span.error("modifier must be of the form `key:value`")), - public: crate::error::InvalidFormatDescription::InvalidModifier { - value: String::from_utf8_lossy(value).into_owned(), - index: span.start.byte as usize, - }, - }); - }; - let key = &value[..colon_index]; - let value = &value[colon_index + 1..]; - - if key.is_empty() { - return Err(Error { - _inner: unused(span.shrink_to_start().error("expected modifier key")), - public: crate::error::InvalidFormatDescription::InvalidModifier { - value: String::new(), - index: span.start.byte as usize, - }, - }); - } - if value.is_empty() { - return Err(Error { - _inner: unused(span.shrink_to_end().error("expected modifier value")), - public: crate::error::InvalidFormatDescription::InvalidModifier { - value: String::new(), - index: span.shrink_to_end().start.byte as usize, - }, - }); - } - - modifiers.push(Modifier { - _leading_whitespace: unused(whitespace), - key: key.spanned(span.shrink_to_before(colon_index as u32)), - _colon: unused(span.start.offset(colon_index as u32)), - value: value.spanned(span.shrink_to_after(colon_index as u32)), - }); - }; - - let Some(closing_bracket) = tokens.next_if_closing_bracket() else { - return Err(Error { - _inner: unused(opening_bracket.error("unclosed bracket")), - public: crate::error::InvalidFormatDescription::UnclosedOpeningBracket { - index: opening_bracket.byte as usize, - }, - }); - }; - - Ok(Item::Component { - _opening_bracket: unused(opening_bracket), - _leading_whitespace: unused(leading_whitespace), - name, - modifiers: modifiers.into_boxed_slice(), - _trailing_whitespace: unused(trailing_whitespace), - _closing_bracket: unused(closing_bracket), - }) -} - -/// Parse a nested format description. The location provided is the the most recent one consumed. -fn parse_nested<'a, I: Iterator<Item = Result<lexer::Token<'a>, Error>>, const VERSION: usize>( - last_location: Location, - tokens: &mut lexer::Lexed<I>, -) -> Result<NestedFormatDescription<'a>, Error> { - validate_version!(VERSION); - let Some(opening_bracket) = tokens.next_if_opening_bracket() else { - return Err(Error { - _inner: unused(last_location.error("expected opening bracket")), - public: crate::error::InvalidFormatDescription::Expected { - what: "opening bracket", - index: last_location.byte as usize, - }, - }); - }; - let items = parse_inner::<_, true, VERSION>(tokens).collect::<Result<_, _>>()?; - let Some(closing_bracket) = tokens.next_if_closing_bracket() else { - return Err(Error { - _inner: unused(opening_bracket.error("unclosed bracket")), - public: crate::error::InvalidFormatDescription::UnclosedOpeningBracket { - index: opening_bracket.byte as usize, - }, - }); - }; - let trailing_whitespace = tokens.next_if_whitespace(); - - Ok(NestedFormatDescription { - _opening_bracket: unused(opening_bracket), - items, - _closing_bracket: unused(closing_bracket), - _trailing_whitespace: unused(trailing_whitespace), - }) -} diff --git a/vendor/time/src/format_description/parse/format_item.rs b/vendor/time/src/format_description/parse/format_item.rs deleted file mode 100644 index d401daa5..00000000 --- a/vendor/time/src/format_description/parse/format_item.rs +++ /dev/null @@ -1,549 +0,0 @@ -//! Typed, validated representation of a parsed format description. - -use alloc::boxed::Box; -use alloc::string::String; -use core::num::NonZeroU16; -use core::str::{self, FromStr}; - -use super::{ast, unused, Error, Span, Spanned}; -use crate::internal_macros::bug; - -/// Parse an AST iterator into a sequence of format items. -pub(super) fn parse<'a>( - ast_items: impl Iterator<Item = Result<ast::Item<'a>, Error>>, -) -> impl Iterator<Item = Result<Item<'a>, Error>> { - ast_items.map(|ast_item| ast_item.and_then(Item::from_ast)) -} - -/// A description of how to format and parse one part of a type. -pub(super) enum Item<'a> { - /// A literal string. - Literal(&'a [u8]), - /// Part of a type, along with its modifiers. - Component(Component), - /// A sequence of optional items. - Optional { - /// The items themselves. - value: Box<[Self]>, - /// The span of the full sequence. - span: Span, - }, - /// The first matching parse of a sequence of format descriptions. - First { - /// The sequence of format descriptions. - value: Box<[Box<[Self]>]>, - /// The span of the full sequence. - span: Span, - }, -} - -impl Item<'_> { - /// Parse an AST item into a format item. - pub(super) fn from_ast(ast_item: ast::Item<'_>) -> Result<Item<'_>, Error> { - Ok(match ast_item { - ast::Item::Component { - _opening_bracket: _, - _leading_whitespace: _, - name, - modifiers, - _trailing_whitespace: _, - _closing_bracket: _, - } => Item::Component(component_from_ast(&name, &modifiers)?), - ast::Item::Literal(Spanned { value, span: _ }) => Item::Literal(value), - ast::Item::EscapedBracket { - _first: _, - _second: _, - } => Item::Literal(b"["), - ast::Item::Optional { - opening_bracket, - _leading_whitespace: _, - _optional_kw: _, - _whitespace: _, - nested_format_description, - closing_bracket, - } => { - let items = nested_format_description - .items - .into_vec() - .into_iter() - .map(Item::from_ast) - .collect::<Result<_, _>>()?; - Item::Optional { - value: items, - span: opening_bracket.to(closing_bracket), - } - } - ast::Item::First { - opening_bracket, - _leading_whitespace: _, - _first_kw: _, - _whitespace: _, - nested_format_descriptions, - closing_bracket, - } => { - let items = nested_format_descriptions - .into_vec() - .into_iter() - .map(|nested_format_description| { - nested_format_description - .items - .into_vec() - .into_iter() - .map(Item::from_ast) - .collect() - }) - .collect::<Result<_, _>>()?; - Item::First { - value: items, - span: opening_bracket.to(closing_bracket), - } - } - }) - } -} - -impl<'a> TryFrom<Item<'a>> for crate::format_description::BorrowedFormatItem<'a> { - type Error = Error; - - fn try_from(item: Item<'a>) -> Result<Self, Self::Error> { - match item { - Item::Literal(literal) => Ok(Self::Literal(literal)), - Item::Component(component) => Ok(Self::Component(component.into())), - Item::Optional { value: _, span } => Err(Error { - _inner: unused(span.error( - "optional items are not supported in runtime-parsed format descriptions", - )), - public: crate::error::InvalidFormatDescription::NotSupported { - what: "optional item", - context: "runtime-parsed format descriptions", - index: span.start.byte as usize, - }, - }), - Item::First { value: _, span } => Err(Error { - _inner: unused(span.error( - "'first' items are not supported in runtime-parsed format descriptions", - )), - public: crate::error::InvalidFormatDescription::NotSupported { - what: "'first' item", - context: "runtime-parsed format descriptions", - index: span.start.byte as usize, - }, - }), - } - } -} - -impl From<Item<'_>> for crate::format_description::OwnedFormatItem { - fn from(item: Item<'_>) -> Self { - match item { - Item::Literal(literal) => Self::Literal(literal.to_vec().into_boxed_slice()), - Item::Component(component) => Self::Component(component.into()), - Item::Optional { value, span: _ } => Self::Optional(Box::new(value.into())), - Item::First { value, span: _ } => { - Self::First(value.into_vec().into_iter().map(Into::into).collect()) - } - } - } -} - -impl<'a> From<Box<[Item<'a>]>> for crate::format_description::OwnedFormatItem { - fn from(items: Box<[Item<'a>]>) -> Self { - let items = items.into_vec(); - match <[_; 1]>::try_from(items) { - Ok([item]) => item.into(), - Err(vec) => Self::Compound(vec.into_iter().map(Into::into).collect()), - } - } -} - -/// Declare the `Component` struct. -macro_rules! component_definition { - (@if_required required then { $($then:tt)* } $(else { $($else:tt)* })?) => { $($then)* }; - (@if_required then { $($then:tt)* } $(else { $($else:tt)* })?) => { $($($else)*)? }; - (@if_from_str from_str then { $($then:tt)* } $(else { $($else:tt)* })?) => { $($then)* }; - (@if_from_str then { $($then:tt)* } $(else { $($else:tt)* })?) => { $($($else)*)? }; - - ($vis:vis enum $name:ident { - $($variant:ident = $parse_variant:literal {$( - $(#[$required:tt])? - $field:ident = $parse_field:literal: - Option<$(#[$from_str:tt])? $field_type:ty> - => $target_field:ident - ),* $(,)?}),* $(,)? - }) => { - $vis enum $name { - $($variant($variant),)* - } - - $($vis struct $variant { - $($field: Option<$field_type>),* - })* - - $(impl $variant { - /// Parse the component from the AST, given its modifiers. - fn with_modifiers( - modifiers: &[ast::Modifier<'_>], - _component_span: Span, - ) -> Result<Self, Error> - { - // rustc will complain if the modifier is empty. - #[allow(unused_mut)] - let mut this = Self { - $($field: None),* - }; - - for modifier in modifiers { - $(#[allow(clippy::string_lit_as_bytes)] - if modifier.key.eq_ignore_ascii_case($parse_field.as_bytes()) { - this.$field = component_definition!(@if_from_str $($from_str)? - then { - parse_from_modifier_value::<$field_type>(&modifier.value)? - } else { - <$field_type>::from_modifier_value(&modifier.value)? - }); - continue; - })* - return Err(Error { - _inner: unused(modifier.key.span.error("invalid modifier key")), - public: crate::error::InvalidFormatDescription::InvalidModifier { - value: String::from_utf8_lossy(*modifier.key).into_owned(), - index: modifier.key.span.start.byte as usize, - } - }); - } - - $(component_definition! { @if_required $($required)? then { - if this.$field.is_none() { - return Err(Error { - _inner: unused(_component_span.error("missing required modifier")), - public: - crate::error::InvalidFormatDescription::MissingRequiredModifier { - name: $parse_field, - index: _component_span.start.byte as usize, - } - }); - } - }})* - - Ok(this) - } - })* - - impl From<$name> for crate::format_description::Component { - fn from(component: $name) -> Self { - match component {$( - $name::$variant($variant { $($field),* }) => { - $crate::format_description::component::Component::$variant( - $crate::format_description::modifier::$variant {$( - $target_field: component_definition! { @if_required $($required)? - then { - match $field { - Some(value) => value.into(), - None => bug!("required modifier was not set"), - } - } else { - $field.unwrap_or_default().into() - } - } - ),*} - ) - } - )*} - } - } - - /// Parse a component from the AST, given its name and modifiers. - fn component_from_ast( - name: &Spanned<&[u8]>, - modifiers: &[ast::Modifier<'_>], - ) -> Result<Component, Error> { - $(#[allow(clippy::string_lit_as_bytes)] - if name.eq_ignore_ascii_case($parse_variant.as_bytes()) { - return Ok(Component::$variant($variant::with_modifiers(&modifiers, name.span)?)); - })* - Err(Error { - _inner: unused(name.span.error("invalid component")), - public: crate::error::InvalidFormatDescription::InvalidComponentName { - name: String::from_utf8_lossy(name).into_owned(), - index: name.span.start.byte as usize, - }, - }) - } - } -} - -// Keep in alphabetical order. -component_definition! { - pub(super) enum Component { - Day = "day" { - padding = "padding": Option<Padding> => padding, - }, - End = "end" {}, - Hour = "hour" { - padding = "padding": Option<Padding> => padding, - base = "repr": Option<HourBase> => is_12_hour_clock, - }, - Ignore = "ignore" { - #[required] - count = "count": Option<#[from_str] NonZeroU16> => count, - }, - Minute = "minute" { - padding = "padding": Option<Padding> => padding, - }, - Month = "month" { - padding = "padding": Option<Padding> => padding, - repr = "repr": Option<MonthRepr> => repr, - case_sensitive = "case_sensitive": Option<MonthCaseSensitive> => case_sensitive, - }, - OffsetHour = "offset_hour" { - sign_behavior = "sign": Option<SignBehavior> => sign_is_mandatory, - padding = "padding": Option<Padding> => padding, - }, - OffsetMinute = "offset_minute" { - padding = "padding": Option<Padding> => padding, - }, - OffsetSecond = "offset_second" { - padding = "padding": Option<Padding> => padding, - }, - Ordinal = "ordinal" { - padding = "padding": Option<Padding> => padding, - }, - Period = "period" { - case = "case": Option<PeriodCase> => is_uppercase, - case_sensitive = "case_sensitive": Option<PeriodCaseSensitive> => case_sensitive, - }, - Second = "second" { - padding = "padding": Option<Padding> => padding, - }, - Subsecond = "subsecond" { - digits = "digits": Option<SubsecondDigits> => digits, - }, - UnixTimestamp = "unix_timestamp" { - precision = "precision": Option<UnixTimestampPrecision> => precision, - sign_behavior = "sign": Option<SignBehavior> => sign_is_mandatory, - }, - Weekday = "weekday" { - repr = "repr": Option<WeekdayRepr> => repr, - one_indexed = "one_indexed": Option<WeekdayOneIndexed> => one_indexed, - case_sensitive = "case_sensitive": Option<WeekdayCaseSensitive> => case_sensitive, - }, - WeekNumber = "week_number" { - padding = "padding": Option<Padding> => padding, - repr = "repr": Option<WeekNumberRepr> => repr, - }, - Year = "year" { - padding = "padding": Option<Padding> => padding, - repr = "repr": Option<YearRepr> => repr, - range = "range": Option<YearRange> => range, - base = "base": Option<YearBase> => iso_week_based, - sign_behavior = "sign": Option<SignBehavior> => sign_is_mandatory, - }, - } -} - -/// Get the target type for a given enum. -macro_rules! target_ty { - ($name:ident $type:ty) => { - $type - }; - ($name:ident) => { - $crate::format_description::modifier::$name - }; -} - -/// Get the target value for a given enum. -macro_rules! target_value { - ($name:ident $variant:ident $value:expr) => { - $value - }; - ($name:ident $variant:ident) => { - $crate::format_description::modifier::$name::$variant - }; -} - -/// Declare the various modifiers. -/// -/// For the general case, ordinary syntax can be used. Note that you _must_ declare a default -/// variant. The only significant change is that the string representation of the variant must be -/// provided after the variant name. For example, `Numerical = b"numerical"` declares a variant -/// named `Numerical` with the string representation `b"numerical"`. This is the value that will be -/// used when parsing the modifier. The value is not case sensitive. -/// -/// If the type in the public API does not have the same name as the type in the internal -/// representation, then the former must be specified in parenthesis after the internal name. For -/// example, `HourBase(bool)` has an internal name "HourBase", but is represented as a boolean in -/// the public API. -/// -/// By default, the internal variant name is assumed to be the same as the public variant name. If -/// this is not the case, the qualified path to the variant must be specified in parenthesis after -/// the internal variant name. For example, `Twelve(true)` has an internal variant name "Twelve", -/// but is represented as `true` in the public API. -macro_rules! modifier { - ($( - enum $name:ident $(($target_ty:ty))? { - $( - $(#[$attr:meta])? - $variant:ident $(($target_value:expr))? = $parse_variant:literal - ),* $(,)? - } - )+) => {$( - #[derive(Default)] - enum $name { - $($(#[$attr])? $variant),* - } - - impl $name { - /// Parse the modifier from its string representation. - fn from_modifier_value(value: &Spanned<&[u8]>) -> Result<Option<Self>, Error> { - $(if value.eq_ignore_ascii_case($parse_variant) { - return Ok(Some(Self::$variant)); - })* - Err(Error { - _inner: unused(value.span.error("invalid modifier value")), - public: crate::error::InvalidFormatDescription::InvalidModifier { - value: String::from_utf8_lossy(value).into_owned(), - index: value.span.start.byte as usize, - }, - }) - } - } - - impl From<$name> for target_ty!($name $($target_ty)?) { - fn from(modifier: $name) -> Self { - match modifier { - $($name::$variant => target_value!($name $variant $($target_value)?)),* - } - } - } - )+}; -} - -// Keep in alphabetical order. -modifier! { - enum HourBase(bool) { - Twelve(true) = b"12", - #[default] - TwentyFour(false) = b"24", - } - - enum MonthCaseSensitive(bool) { - False(false) = b"false", - #[default] - True(true) = b"true", - } - - enum MonthRepr { - #[default] - Numerical = b"numerical", - Long = b"long", - Short = b"short", - } - - enum Padding { - Space = b"space", - #[default] - Zero = b"zero", - None = b"none", - } - - enum PeriodCase(bool) { - Lower(false) = b"lower", - #[default] - Upper(true) = b"upper", - } - - enum PeriodCaseSensitive(bool) { - False(false) = b"false", - #[default] - True(true) = b"true", - } - - enum SignBehavior(bool) { - #[default] - Automatic(false) = b"automatic", - Mandatory(true) = b"mandatory", - } - - enum SubsecondDigits { - One = b"1", - Two = b"2", - Three = b"3", - Four = b"4", - Five = b"5", - Six = b"6", - Seven = b"7", - Eight = b"8", - Nine = b"9", - #[default] - OneOrMore = b"1+", - } - - enum UnixTimestampPrecision { - #[default] - Second = b"second", - Millisecond = b"millisecond", - Microsecond = b"microsecond", - Nanosecond = b"nanosecond", - } - - enum WeekNumberRepr { - #[default] - Iso = b"iso", - Sunday = b"sunday", - Monday = b"monday", - } - - enum WeekdayCaseSensitive(bool) { - False(false) = b"false", - #[default] - True(true) = b"true", - } - - enum WeekdayOneIndexed(bool) { - False(false) = b"false", - #[default] - True(true) = b"true", - } - - enum WeekdayRepr { - Short = b"short", - #[default] - Long = b"long", - Sunday = b"sunday", - Monday = b"monday", - } - - enum YearBase(bool) { - #[default] - Calendar(false) = b"calendar", - IsoWeek(true) = b"iso_week", - } - - enum YearRepr { - #[default] - Full = b"full", - Century = b"century", - LastTwo = b"last_two", - } - - enum YearRange { - Standard = b"standard", - #[default] - Extended = b"extended", - } -} - -/// Parse a modifier value using `FromStr`. Requires the modifier value to be valid UTF-8. -fn parse_from_modifier_value<T: FromStr>(value: &Spanned<&[u8]>) -> Result<Option<T>, Error> { - str::from_utf8(value) - .ok() - .and_then(|val| val.parse::<T>().ok()) - .map(|val| Some(val)) - .ok_or_else(|| Error { - _inner: unused(value.span.error("invalid modifier value")), - public: crate::error::InvalidFormatDescription::InvalidModifier { - value: String::from_utf8_lossy(value).into_owned(), - index: value.span.start.byte as usize, - }, - }) -} diff --git a/vendor/time/src/format_description/parse/lexer.rs b/vendor/time/src/format_description/parse/lexer.rs deleted file mode 100644 index a63722e1..00000000 --- a/vendor/time/src/format_description/parse/lexer.rs +++ /dev/null @@ -1,284 +0,0 @@ -//! Lexer for parsing format descriptions. - -use core::iter; - -use super::{attach_location, unused, Error, Location, Spanned, SpannedValue}; - -/// An iterator over the lexed tokens. -pub(super) struct Lexed<I: Iterator> { - /// The internal iterator. - iter: iter::Peekable<I>, -} - -impl<I: Iterator> Iterator for Lexed<I> { - type Item = I::Item; - - fn next(&mut self) -> Option<Self::Item> { - self.iter.next() - } -} - -impl<'iter, 'token: 'iter, I: Iterator<Item = Result<Token<'token>, Error>> + 'iter> Lexed<I> { - /// Peek at the next item in the iterator. - pub(super) fn peek(&mut self) -> Option<&I::Item> { - self.iter.peek() - } - - /// Consume the next token if it is whitespace. - pub(super) fn next_if_whitespace(&mut self) -> Option<Spanned<&'token [u8]>> { - if let Some(&Ok(Token::ComponentPart { - kind: ComponentKind::Whitespace, - value, - })) = self.peek() - { - self.next(); // consume - Some(value) - } else { - None - } - } - - /// Consume the next token if it is a component item that is not whitespace. - pub(super) fn next_if_not_whitespace(&mut self) -> Option<Spanned<&'token [u8]>> { - if let Some(&Ok(Token::ComponentPart { - kind: ComponentKind::NotWhitespace, - value, - })) = self.peek() - { - self.next(); // consume - Some(value) - } else { - None - } - } - - /// Consume the next token if it is an opening bracket. - pub(super) fn next_if_opening_bracket(&mut self) -> Option<Location> { - if let Some(&Ok(Token::Bracket { - kind: BracketKind::Opening, - location, - })) = self.peek() - { - self.next(); // consume - Some(location) - } else { - None - } - } - - /// Peek at the next token if it is a closing bracket. - pub(super) fn peek_closing_bracket(&'iter mut self) -> Option<&'iter Location> { - if let Some(Ok(Token::Bracket { - kind: BracketKind::Closing, - location, - })) = self.peek() - { - Some(location) - } else { - None - } - } - - /// Consume the next token if it is a closing bracket. - pub(super) fn next_if_closing_bracket(&mut self) -> Option<Location> { - if let Some(&Ok(Token::Bracket { - kind: BracketKind::Closing, - location, - })) = self.peek() - { - self.next(); // consume - Some(location) - } else { - None - } - } -} - -/// A token emitted by the lexer. There is no semantic meaning at this stage. -pub(super) enum Token<'a> { - /// A literal string, formatted and parsed as-is. - Literal(Spanned<&'a [u8]>), - /// An opening or closing bracket. May or may not be the start or end of a component. - Bracket { - /// Whether the bracket is opening or closing. - kind: BracketKind, - /// Where the bracket was in the format string. - location: Location, - }, - /// One part of a component. This could be its name, a modifier, or whitespace. - ComponentPart { - /// Whether the part is whitespace or not. - kind: ComponentKind, - /// The part itself. - value: Spanned<&'a [u8]>, - }, -} - -/// What type of bracket is present. -pub(super) enum BracketKind { - /// An opening bracket: `[` - Opening, - /// A closing bracket: `]` - Closing, -} - -/// Indicates whether the component is whitespace or not. -pub(super) enum ComponentKind { - Whitespace, - NotWhitespace, -} - -/// Parse the string into a series of [`Token`]s. -/// -/// `VERSION` controls the version of the format description that is being parsed. Currently, this -/// must be 1 or 2. -/// -/// - When `VERSION` is 1, `[[` is the only escape sequence, resulting in a literal `[`. -/// - When `VERSION` is 2, all escape sequences begin with `\`. The only characters that may -/// currently follow are `\`, `[`, and `]`, all of which result in the literal character. All -/// other characters result in a lex error. -pub(super) fn lex<const VERSION: usize>( - mut input: &[u8], -) -> Lexed<impl Iterator<Item = Result<Token<'_>, Error>>> { - validate_version!(VERSION); - - let mut depth: u8 = 0; - let mut iter = attach_location(input.iter()).peekable(); - let mut second_bracket_location = None; - - let iter = iter::from_fn(move || { - // The flag is only set when version is zero. - if version!(..=1) { - // There is a flag set to emit the second half of an escaped bracket pair. - if let Some(location) = second_bracket_location.take() { - return Some(Ok(Token::Bracket { - kind: BracketKind::Opening, - location, - })); - } - } - - Some(Ok(match iter.next()? { - // possible escape sequence - (b'\\', backslash_loc) if version!(2..) => { - match iter.next() { - Some((b'\\' | b'[' | b']', char_loc)) => { - // The escaped character is emitted as-is. - let char = &input[1..2]; - input = &input[2..]; - if depth == 0 { - Token::Literal(char.spanned(backslash_loc.to(char_loc))) - } else { - Token::ComponentPart { - kind: ComponentKind::NotWhitespace, - value: char.spanned(backslash_loc.to(char_loc)), - } - } - } - Some((_, loc)) => { - return Some(Err(Error { - _inner: unused(loc.error("invalid escape sequence")), - public: crate::error::InvalidFormatDescription::Expected { - what: "valid escape sequence", - index: loc.byte as usize, - }, - })); - } - None => { - return Some(Err(Error { - _inner: unused(backslash_loc.error("unexpected end of input")), - public: crate::error::InvalidFormatDescription::Expected { - what: "valid escape sequence", - index: backslash_loc.byte as usize, - }, - })); - } - } - } - // potentially escaped opening bracket - (b'[', location) if version!(..=1) => { - if let Some((_, second_location)) = iter.next_if(|&(&byte, _)| byte == b'[') { - // Escaped bracket. Store the location of the second so we can emit it later. - second_bracket_location = Some(second_location); - input = &input[2..]; - } else { - // opening bracket - depth += 1; - input = &input[1..]; - } - - Token::Bracket { - kind: BracketKind::Opening, - location, - } - } - // opening bracket - (b'[', location) => { - depth += 1; - input = &input[1..]; - - Token::Bracket { - kind: BracketKind::Opening, - location, - } - } - // closing bracket - (b']', location) if depth > 0 => { - depth -= 1; - input = &input[1..]; - - Token::Bracket { - kind: BracketKind::Closing, - location, - } - } - // literal - (_, start_location) if depth == 0 => { - let mut bytes = 1; - let mut end_location = start_location; - - while let Some((_, location)) = - iter.next_if(|&(&byte, _)| !((version!(2..) && byte == b'\\') || byte == b'[')) - { - end_location = location; - bytes += 1; - } - - let value = &input[..bytes]; - input = &input[bytes..]; - - Token::Literal(value.spanned(start_location.to(end_location))) - } - // component part - (byte, start_location) => { - let mut bytes = 1; - let mut end_location = start_location; - let is_whitespace = byte.is_ascii_whitespace(); - - while let Some((_, location)) = iter.next_if(|&(byte, _)| { - !matches!(byte, b'\\' | b'[' | b']') - && is_whitespace == byte.is_ascii_whitespace() - }) { - end_location = location; - bytes += 1; - } - - let value = &input[..bytes]; - input = &input[bytes..]; - - Token::ComponentPart { - kind: if is_whitespace { - ComponentKind::Whitespace - } else { - ComponentKind::NotWhitespace - }, - value: value.spanned(start_location.to(end_location)), - } - } - })) - }); - - Lexed { - iter: iter.peekable(), - } -} diff --git a/vendor/time/src/format_description/parse/mod.rs b/vendor/time/src/format_description/parse/mod.rs deleted file mode 100644 index d058594d..00000000 --- a/vendor/time/src/format_description/parse/mod.rs +++ /dev/null @@ -1,262 +0,0 @@ -//! Parser for format descriptions. - -use alloc::boxed::Box; -use alloc::vec::Vec; - -pub use self::strftime::{parse_strftime_borrowed, parse_strftime_owned}; -use crate::{error, format_description}; - -/// A helper macro to make version restrictions simpler to read and write. -macro_rules! version { - ($range:expr) => { - $range.contains(&VERSION) - }; -} - -/// A helper macro to statically validate the version (when used as a const parameter). -macro_rules! validate_version { - ($version:ident) => { - let _ = $crate::format_description::parse::Version::<$version>::IS_VALID; - }; -} - -mod ast; -mod format_item; -mod lexer; -mod strftime; - -/// A struct that is used to ensure that the version is valid. -struct Version<const N: usize>; -impl<const N: usize> Version<N> { - /// A constant that panics if the version is not valid. This results in a post-monomorphization - /// error. - const IS_VALID: () = assert!(N >= 1 && N <= 2); -} - -/// Parse a sequence of items from the format description. -/// -/// The syntax for the format description can be found in [the -/// book](https://time-rs.github.io/book/api/format-description.html). -/// -/// This function exists for backward compatibility reasons. It is equivalent to calling -/// `parse_borrowed::<1>(s)`. In the future, this function will be deprecated in favor of -/// `parse_borrowed`. -pub fn parse( - s: &str, -) -> Result<Vec<format_description::BorrowedFormatItem<'_>>, error::InvalidFormatDescription> { - parse_borrowed::<1>(s) -} - -/// Parse a sequence of items from the format description. -/// -/// The syntax for the format description can be found in [the -/// book](https://time-rs.github.io/book/api/format-description.html). The version of the format -/// description is provided as the const parameter. **It is recommended to use version 2.** -pub fn parse_borrowed<const VERSION: usize>( - s: &str, -) -> Result<Vec<format_description::BorrowedFormatItem<'_>>, error::InvalidFormatDescription> { - validate_version!(VERSION); - let mut lexed = lexer::lex::<VERSION>(s.as_bytes()); - let ast = ast::parse::<_, VERSION>(&mut lexed); - let format_items = format_item::parse(ast); - Ok(format_items - .map(|res| res.and_then(TryInto::try_into)) - .collect::<Result<_, _>>()?) -} - -/// Parse a sequence of items from the format description. -/// -/// The syntax for the format description can be found in [the -/// book](https://time-rs.github.io/book/api/format-description.html). The version of the format -/// description is provided as the const parameter. -/// -/// Unlike [`parse`], this function returns [`OwnedFormatItem`], which owns its contents. This means -/// that there is no lifetime that needs to be handled. **It is recommended to use version 2.** -/// -/// [`OwnedFormatItem`]: crate::format_description::OwnedFormatItem -pub fn parse_owned<const VERSION: usize>( - s: &str, -) -> Result<format_description::OwnedFormatItem, error::InvalidFormatDescription> { - validate_version!(VERSION); - let mut lexed = lexer::lex::<VERSION>(s.as_bytes()); - let ast = ast::parse::<_, VERSION>(&mut lexed); - let format_items = format_item::parse(ast); - let items = format_items.collect::<Result<Box<_>, _>>()?; - Ok(items.into()) -} - -/// Attach [`Location`] information to each byte in the iterator. -fn attach_location<'item>( - iter: impl Iterator<Item = &'item u8>, -) -> impl Iterator<Item = (&'item u8, Location)> { - let mut byte_pos = 0; - - iter.map(move |byte| { - let location = Location { byte: byte_pos }; - byte_pos += 1; - (byte, location) - }) -} - -/// A location within a string. -#[derive(Clone, Copy)] -struct Location { - /// The zero-indexed byte of the string. - byte: u32, -} - -impl Location { - /// Create a new [`Span`] from `self` to `other`. - const fn to(self, end: Self) -> Span { - Span { start: self, end } - } - - /// Create a new [`Span`] consisting entirely of `self`. - const fn to_self(self) -> Span { - Span { - start: self, - end: self, - } - } - - /// Offset the location by the provided amount. - /// - /// Note that this assumes the resulting location is on the same line as the original location. - #[must_use = "this does not modify the original value"] - const fn offset(&self, offset: u32) -> Self { - Self { - byte: self.byte + offset, - } - } - - /// Create an error with the provided message at this location. - const fn error(self, message: &'static str) -> ErrorInner { - ErrorInner { - _message: message, - _span: Span { - start: self, - end: self, - }, - } - } -} - -/// A start and end point within a string. -#[derive(Clone, Copy)] -struct Span { - start: Location, - end: Location, -} - -impl Span { - /// Obtain a `Span` pointing at the start of the pre-existing span. - #[must_use = "this does not modify the original value"] - const fn shrink_to_start(&self) -> Self { - Self { - start: self.start, - end: self.start, - } - } - - /// Obtain a `Span` pointing at the end of the pre-existing span. - #[must_use = "this does not modify the original value"] - const fn shrink_to_end(&self) -> Self { - Self { - start: self.end, - end: self.end, - } - } - - /// Obtain a `Span` that ends before the provided position of the pre-existing span. - #[must_use = "this does not modify the original value"] - const fn shrink_to_before(&self, pos: u32) -> Self { - Self { - start: self.start, - end: Location { - byte: self.start.byte + pos - 1, - }, - } - } - - /// Obtain a `Span` that starts after provided position to the end of the pre-existing span. - #[must_use = "this does not modify the original value"] - const fn shrink_to_after(&self, pos: u32) -> Self { - Self { - start: Location { - byte: self.start.byte + pos + 1, - }, - end: self.end, - } - } - - /// Create an error with the provided message at this span. - const fn error(self, message: &'static str) -> ErrorInner { - ErrorInner { - _message: message, - _span: self, - } - } -} - -/// A value with an associated [`Span`]. -#[derive(Clone, Copy)] -struct Spanned<T> { - /// The value. - value: T, - /// Where the value was in the format string. - span: Span, -} - -impl<T> core::ops::Deref for Spanned<T> { - type Target = T; - - fn deref(&self) -> &Self::Target { - &self.value - } -} - -/// Helper trait to attach a [`Span`] to a value. -trait SpannedValue: Sized { - /// Attach a [`Span`] to a value. - fn spanned(self, span: Span) -> Spanned<Self>; -} - -impl<T> SpannedValue for T { - fn spanned(self, span: Span) -> Spanned<Self> { - Spanned { value: self, span } - } -} - -/// The internal error type. -struct ErrorInner { - /// The message displayed to the user. - _message: &'static str, - /// Where the error originated. - _span: Span, -} - -/// A complete error description. -struct Error { - /// The internal error. - _inner: Unused<ErrorInner>, - /// The error needed for interoperability with the rest of `time`. - public: error::InvalidFormatDescription, -} - -impl From<Error> for error::InvalidFormatDescription { - fn from(error: Error) -> Self { - error.public - } -} - -/// A value that may be used in the future, but currently is not. -/// -/// This struct exists so that data can semantically be passed around without _actually_ passing it -/// around. This way the data still exists if it is needed in the future. -// `PhantomData` is not used directly because we don't want to introduce any trait implementations. -struct Unused<T>(core::marker::PhantomData<T>); - -/// Indicate that a value is currently unused. -fn unused<T>(_: T) -> Unused<T> { - Unused(core::marker::PhantomData) -} diff --git a/vendor/time/src/format_description/parse/strftime.rs b/vendor/time/src/format_description/parse/strftime.rs deleted file mode 100644 index 5fcaf184..00000000 --- a/vendor/time/src/format_description/parse/strftime.rs +++ /dev/null @@ -1,487 +0,0 @@ -use alloc::string::String; -use alloc::vec::Vec; -use core::iter; - -use crate::error::InvalidFormatDescription; -use crate::format_description::parse::{ - attach_location, unused, Error, ErrorInner, Location, Spanned, SpannedValue, Unused, -}; -use crate::format_description::{self, modifier, BorrowedFormatItem, Component}; - -/// Parse a sequence of items from the [`strftime` format description][strftime docs]. -/// -/// The only heap allocation required is for the `Vec` itself. All components are bound to the -/// lifetime of the input. -/// -/// [strftime docs]: https://man7.org/linux/man-pages/man3/strftime.3.html -#[doc(alias = "parse_strptime_borrowed")] -pub fn parse_strftime_borrowed( - s: &str, -) -> Result<Vec<BorrowedFormatItem<'_>>, InvalidFormatDescription> { - let tokens = lex(s.as_bytes()); - let items = into_items(tokens).collect::<Result<_, _>>()?; - Ok(items) -} - -/// Parse a sequence of items from the [`strftime` format description][strftime docs]. -/// -/// This requires heap allocation for some owned items. -/// -/// [strftime docs]: https://man7.org/linux/man-pages/man3/strftime.3.html -#[doc(alias = "parse_strptime_owned")] -pub fn parse_strftime_owned( - s: &str, -) -> Result<format_description::OwnedFormatItem, InvalidFormatDescription> { - parse_strftime_borrowed(s).map(Into::into) -} - -#[derive(Debug, Clone, Copy, PartialEq)] -enum Padding { - /// The default padding for a numeric component. Indicated by no character. - Default, - /// Pad a numeric component with spaces. Indicated by an underscore. - Spaces, - /// Do not pad a numeric component. Indicated by a hyphen. - None, - /// Pad a numeric component with zeroes. Indicated by a zero. - Zeroes, -} - -enum Token<'a> { - Literal(Spanned<&'a [u8]>), - Component { - _percent: Unused<Location>, - padding: Spanned<Padding>, - component: Spanned<u8>, - }, -} - -fn lex(mut input: &[u8]) -> iter::Peekable<impl Iterator<Item = Result<Token<'_>, Error>>> { - let mut iter = attach_location(input.iter()).peekable(); - - iter::from_fn(move || { - Some(Ok(match iter.next()? { - (b'%', percent_loc) => match iter.next() { - Some((padding @ (b'_' | b'-' | b'0'), padding_loc)) => { - let padding = match padding { - b'_' => Padding::Spaces, - b'-' => Padding::None, - b'0' => Padding::Zeroes, - _ => unreachable!(), - }; - let (&component, component_loc) = iter.next()?; - input = &input[3..]; - Token::Component { - _percent: unused(percent_loc), - padding: padding.spanned(padding_loc.to_self()), - component: component.spanned(component_loc.to_self()), - } - } - Some((&component, component_loc)) => { - input = &input[2..]; - let span = component_loc.to_self(); - Token::Component { - _percent: unused(percent_loc), - padding: Padding::Default.spanned(span), - component: component.spanned(span), - } - } - None => { - return Some(Err(Error { - _inner: unused(percent_loc.error("unexpected end of input")), - public: InvalidFormatDescription::Expected { - what: "valid escape sequence", - index: percent_loc.byte as usize, - }, - })); - } - }, - (_, start_location) => { - let mut bytes = 1; - let mut end_location = start_location; - - while let Some((_, location)) = iter.next_if(|&(&byte, _)| byte != b'%') { - end_location = location; - bytes += 1; - } - - let value = &input[..bytes]; - input = &input[bytes..]; - - Token::Literal(value.spanned(start_location.to(end_location))) - } - })) - }) - .peekable() -} - -fn into_items<'iter, 'token: 'iter>( - mut tokens: iter::Peekable<impl Iterator<Item = Result<Token<'token>, Error>> + 'iter>, -) -> impl Iterator<Item = Result<BorrowedFormatItem<'token>, Error>> + 'iter { - iter::from_fn(move || { - let next = match tokens.next()? { - Ok(token) => token, - Err(err) => return Some(Err(err)), - }; - - Some(match next { - Token::Literal(spanned) => Ok(BorrowedFormatItem::Literal(*spanned)), - Token::Component { - _percent, - padding, - component, - } => parse_component(padding, component), - }) - }) -} - -fn parse_component( - padding: Spanned<Padding>, - component: Spanned<u8>, -) -> Result<BorrowedFormatItem<'static>, Error> { - let padding_or_default = |padding: Padding, default| match padding { - Padding::Default => default, - Padding::Spaces => modifier::Padding::Space, - Padding::None => modifier::Padding::None, - Padding::Zeroes => modifier::Padding::Zero, - }; - - /// Helper macro to create a component. - macro_rules! component { - ($name:ident { $($inner:tt)* }) => { - BorrowedFormatItem::Component(Component::$name(modifier::$name { - $($inner)* - })) - } - } - - Ok(match *component { - b'%' => BorrowedFormatItem::Literal(b"%"), - b'a' => component!(Weekday { - repr: modifier::WeekdayRepr::Short, - one_indexed: true, - case_sensitive: true, - }), - b'A' => component!(Weekday { - repr: modifier::WeekdayRepr::Long, - one_indexed: true, - case_sensitive: true, - }), - b'b' | b'h' => component!(Month { - repr: modifier::MonthRepr::Short, - padding: modifier::Padding::Zero, - case_sensitive: true, - }), - b'B' => component!(Month { - repr: modifier::MonthRepr::Long, - padding: modifier::Padding::Zero, - case_sensitive: true, - }), - b'c' => BorrowedFormatItem::Compound(&[ - component!(Weekday { - repr: modifier::WeekdayRepr::Short, - one_indexed: true, - case_sensitive: true, - }), - BorrowedFormatItem::Literal(b" "), - component!(Month { - repr: modifier::MonthRepr::Short, - padding: modifier::Padding::Zero, - case_sensitive: true, - }), - BorrowedFormatItem::Literal(b" "), - component!(Day { - padding: modifier::Padding::Space - }), - BorrowedFormatItem::Literal(b" "), - component!(Hour { - padding: modifier::Padding::Zero, - is_12_hour_clock: false, - }), - BorrowedFormatItem::Literal(b":"), - component!(Minute { - padding: modifier::Padding::Zero, - }), - BorrowedFormatItem::Literal(b":"), - component!(Second { - padding: modifier::Padding::Zero, - }), - BorrowedFormatItem::Literal(b" "), - component!(Year { - padding: modifier::Padding::Zero, - repr: modifier::YearRepr::Full, - range: modifier::YearRange::Extended, - iso_week_based: false, - sign_is_mandatory: false, - }), - ]), - b'C' => component!(Year { - padding: padding_or_default(*padding, modifier::Padding::Zero), - repr: modifier::YearRepr::Century, - range: modifier::YearRange::Extended, - iso_week_based: false, - sign_is_mandatory: false, - }), - b'd' => component!(Day { - padding: padding_or_default(*padding, modifier::Padding::Zero), - }), - b'D' => BorrowedFormatItem::Compound(&[ - component!(Month { - repr: modifier::MonthRepr::Numerical, - padding: modifier::Padding::Zero, - case_sensitive: true, - }), - BorrowedFormatItem::Literal(b"/"), - component!(Day { - padding: modifier::Padding::Zero, - }), - BorrowedFormatItem::Literal(b"/"), - component!(Year { - padding: modifier::Padding::Zero, - repr: modifier::YearRepr::LastTwo, - range: modifier::YearRange::Extended, - iso_week_based: false, - sign_is_mandatory: false, - }), - ]), - b'e' => component!(Day { - padding: padding_or_default(*padding, modifier::Padding::Space), - }), - b'F' => BorrowedFormatItem::Compound(&[ - component!(Year { - padding: modifier::Padding::Zero, - repr: modifier::YearRepr::Full, - range: modifier::YearRange::Extended, - iso_week_based: false, - sign_is_mandatory: false, - }), - BorrowedFormatItem::Literal(b"-"), - component!(Month { - padding: modifier::Padding::Zero, - repr: modifier::MonthRepr::Numerical, - case_sensitive: true, - }), - BorrowedFormatItem::Literal(b"-"), - component!(Day { - padding: modifier::Padding::Zero, - }), - ]), - b'g' => component!(Year { - padding: padding_or_default(*padding, modifier::Padding::Zero), - repr: modifier::YearRepr::LastTwo, - range: modifier::YearRange::Extended, - iso_week_based: true, - sign_is_mandatory: false, - }), - b'G' => component!(Year { - padding: modifier::Padding::Zero, - repr: modifier::YearRepr::Full, - range: modifier::YearRange::Extended, - iso_week_based: true, - sign_is_mandatory: false, - }), - b'H' => component!(Hour { - padding: padding_or_default(*padding, modifier::Padding::Zero), - is_12_hour_clock: false, - }), - b'I' => component!(Hour { - padding: padding_or_default(*padding, modifier::Padding::Zero), - is_12_hour_clock: true, - }), - b'j' => component!(Ordinal { - padding: padding_or_default(*padding, modifier::Padding::Zero), - }), - b'k' => component!(Hour { - padding: padding_or_default(*padding, modifier::Padding::Space), - is_12_hour_clock: false, - }), - b'l' => component!(Hour { - padding: padding_or_default(*padding, modifier::Padding::Space), - is_12_hour_clock: true, - }), - b'm' => component!(Month { - padding: padding_or_default(*padding, modifier::Padding::Zero), - repr: modifier::MonthRepr::Numerical, - case_sensitive: true, - }), - b'M' => component!(Minute { - padding: padding_or_default(*padding, modifier::Padding::Zero), - }), - b'n' => BorrowedFormatItem::Literal(b"\n"), - b'O' => { - return Err(Error { - _inner: unused(ErrorInner { - _message: "unsupported modifier", - _span: component.span, - }), - public: InvalidFormatDescription::NotSupported { - what: "modifier", - context: "", - index: component.span.start.byte as usize, - }, - }) - } - b'p' => component!(Period { - is_uppercase: true, - case_sensitive: true - }), - b'P' => component!(Period { - is_uppercase: false, - case_sensitive: true - }), - b'r' => BorrowedFormatItem::Compound(&[ - component!(Hour { - padding: modifier::Padding::Zero, - is_12_hour_clock: true, - }), - BorrowedFormatItem::Literal(b":"), - component!(Minute { - padding: modifier::Padding::Zero, - }), - BorrowedFormatItem::Literal(b":"), - component!(Second { - padding: modifier::Padding::Zero, - }), - BorrowedFormatItem::Literal(b" "), - component!(Period { - is_uppercase: true, - case_sensitive: true, - }), - ]), - b'R' => BorrowedFormatItem::Compound(&[ - component!(Hour { - padding: modifier::Padding::Zero, - is_12_hour_clock: false, - }), - BorrowedFormatItem::Literal(b":"), - component!(Minute { - padding: modifier::Padding::Zero, - }), - ]), - b's' => component!(UnixTimestamp { - precision: modifier::UnixTimestampPrecision::Second, - sign_is_mandatory: false, - }), - b'S' => component!(Second { - padding: padding_or_default(*padding, modifier::Padding::Zero), - }), - b't' => BorrowedFormatItem::Literal(b"\t"), - b'T' => BorrowedFormatItem::Compound(&[ - component!(Hour { - padding: modifier::Padding::Zero, - is_12_hour_clock: false, - }), - BorrowedFormatItem::Literal(b":"), - component!(Minute { - padding: modifier::Padding::Zero, - }), - BorrowedFormatItem::Literal(b":"), - component!(Second { - padding: modifier::Padding::Zero, - }), - ]), - b'u' => component!(Weekday { - repr: modifier::WeekdayRepr::Monday, - one_indexed: true, - case_sensitive: true, - }), - b'U' => component!(WeekNumber { - padding: padding_or_default(*padding, modifier::Padding::Zero), - repr: modifier::WeekNumberRepr::Sunday, - }), - b'V' => component!(WeekNumber { - padding: padding_or_default(*padding, modifier::Padding::Zero), - repr: modifier::WeekNumberRepr::Iso, - }), - b'w' => component!(Weekday { - repr: modifier::WeekdayRepr::Sunday, - one_indexed: true, - case_sensitive: true, - }), - b'W' => component!(WeekNumber { - padding: padding_or_default(*padding, modifier::Padding::Zero), - repr: modifier::WeekNumberRepr::Monday, - }), - b'x' => BorrowedFormatItem::Compound(&[ - component!(Month { - repr: modifier::MonthRepr::Numerical, - padding: modifier::Padding::Zero, - case_sensitive: true, - }), - BorrowedFormatItem::Literal(b"/"), - component!(Day { - padding: modifier::Padding::Zero - }), - BorrowedFormatItem::Literal(b"/"), - component!(Year { - padding: modifier::Padding::Zero, - repr: modifier::YearRepr::LastTwo, - range: modifier::YearRange::Extended, - iso_week_based: false, - sign_is_mandatory: false, - }), - ]), - b'X' => BorrowedFormatItem::Compound(&[ - component!(Hour { - padding: modifier::Padding::Zero, - is_12_hour_clock: false, - }), - BorrowedFormatItem::Literal(b":"), - component!(Minute { - padding: modifier::Padding::Zero, - }), - BorrowedFormatItem::Literal(b":"), - component!(Second { - padding: modifier::Padding::Zero, - }), - ]), - b'y' => component!(Year { - padding: padding_or_default(*padding, modifier::Padding::Zero), - repr: modifier::YearRepr::LastTwo, - range: modifier::YearRange::Extended, - iso_week_based: false, - sign_is_mandatory: false, - }), - b'Y' => component!(Year { - padding: modifier::Padding::Zero, - repr: modifier::YearRepr::Full, - range: modifier::YearRange::Extended, - iso_week_based: false, - sign_is_mandatory: false, - }), - b'z' => BorrowedFormatItem::Compound(&[ - component!(OffsetHour { - sign_is_mandatory: true, - padding: modifier::Padding::Zero, - }), - component!(OffsetMinute { - padding: modifier::Padding::Zero, - }), - ]), - b'Z' => { - return Err(Error { - _inner: unused(ErrorInner { - _message: "unsupported component", - _span: component.span, - }), - public: InvalidFormatDescription::NotSupported { - what: "component", - context: "", - index: component.span.start.byte as usize, - }, - }) - } - _ => { - return Err(Error { - _inner: unused(ErrorInner { - _message: "invalid component", - _span: component.span, - }), - public: InvalidFormatDescription::InvalidComponentName { - name: String::from_utf8_lossy(&[*component]).into_owned(), - index: component.span.start.byte as usize, - }, - }) - } - }) -} |
