diff options
Diffstat (limited to 'vendor/time-macros')
20 files changed, 1715 insertions, 767 deletions
diff --git a/vendor/time-macros/.cargo-checksum.json b/vendor/time-macros/.cargo-checksum.json index 98cc1d644..9562cb38d 100644 --- a/vendor/time-macros/.cargo-checksum.json +++ b/vendor/time-macros/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"eb16c06efbfbf2ff5f48260785d4ecefbae6873d9d55c0ba2d388c6762e69b1f","LICENSE-Apache":"b8929fea28678da67251fb2daf9438f67503814211051861612441806d8edb05","LICENSE-MIT":"04620bf27e4a643dd47bf27652320c205acdb776c1f9f24bb8c3bfaba10804c5","src/date.rs":"ffcd3d0998ec67abb43a3f8eccc6104172f5061b855312b89d53bb82fece2460","src/datetime.rs":"5c7f6e07dc2f0dcfcd86216664df53bc008dbc86f346df57a9ff57f52fe43bc6","src/error.rs":"b597f98f425f1628b93ffea19f5f32163aa204e4cd25351bc114853a798e14b0","src/format_description/component.rs":"a05e7549db9bab4f3836f5fd5af18cacbfa6b323d0106b027e21bf438a5885e5","src/format_description/error.rs":"41253d7a02e14597915cf588811a272a90d1ce0f857f7769914e076dd5a66774","src/format_description/mod.rs":"da47af329408e9428753ad98ce433eaf026cfdd6e73e3142b23285251d32d0dd","src/format_description/modifier.rs":"c252c8a7d6608b594a6f715210ff67e804ae2f308025f62c8dd99d707627e4a9","src/format_description/parse.rs":"d65d6e7008030414ce6a860ff37c462c07ed89176a3f1462eeb46468a38fce7e","src/helpers/mod.rs":"54ce8e93512e18ef8761687eaac898a8227852a732f92aa5e80c28e23315bd0c","src/helpers/string.rs":"ba5699a4df344cbd71c4143f642f6bc07591f53978a9800d4b49ca1f461f87d9","src/lib.rs":"f99bded51bb861be5d708a3f756407f5b936a5febb719760c253a15113687e0d","src/offset.rs":"fc9341648e091b4d8f7bec47006c01c21cb038c7ef98bd36a492cf78e7533023","src/quote.rs":"b40251b0ca68e2362aff4297b87a027e48053f1a419113d3d0f7fe089a845a9c","src/serde_format_description.rs":"aa279c8005005fc87c52fa5e8be8ef8fc13ef456a18e3cd5d702ae81194ba4d9","src/time.rs":"3c06562358aed7ef624319c96e3f9c150a069606ab930de98ac379ef16b08100","src/to_tokens.rs":"825150a92396a019fee44f21da0bd257349e276d5e75a23ff86cfc625bef6f10"},"package":"d967f99f534ca7e495c575c62638eebc2898a8c84c119b89e250477bc4ba16b2"}
\ No newline at end of file +{"files":{"Cargo.toml":"74589b1a61b46282b57a9c7c723bf88105c73401b2397ea4044cc9d4d7bbd81b","LICENSE-Apache":"b8929fea28678da67251fb2daf9438f67503814211051861612441806d8edb05","LICENSE-MIT":"04620bf27e4a643dd47bf27652320c205acdb776c1f9f24bb8c3bfaba10804c5","src/date.rs":"ffcd3d0998ec67abb43a3f8eccc6104172f5061b855312b89d53bb82fece2460","src/datetime.rs":"5c7f6e07dc2f0dcfcd86216664df53bc008dbc86f346df57a9ff57f52fe43bc6","src/error.rs":"b3dea92631092068dd73e57e1cbf548f7ae85762826dcdea7fd6454bf357a50a","src/format_description/ast.rs":"2244ee0072e26ee686f5b8301eae8efd4bf53fc8e77104a88ef1d7f0fd15434b","src/format_description/format_item.rs":"03ff10699383e5ad08fe690199d45288f13363337abbc811a70b03a8b1703ab1","src/format_description/lexer.rs":"e7db7b6431f00c81b8d15a162088a1622ecd65bfb58d4e642c3c93a8dd5ae4ad","src/format_description/mod.rs":"f48c0ff590bc74529f06a98f60a6af5814bc30d1456bf0b81ac334c0b3f41bba","src/format_description/public/component.rs":"e2c2c8a189e2eb9f9354ff1d9d8edeafa34303e91dc58457df373e7e61c38b78","src/format_description/public/mod.rs":"5260592b310ea9e30808d30c92ea94c7bf1bdb171250a1342279e927d2528d73","src/format_description/public/modifier.rs":"37661e1f7cd9fd11a82f5a1ce6d5971686afa91e6feebc7b9d32df297e8b667f","src/helpers/mod.rs":"a8f8ed59a72b239d7a530357d212873f2e75ea924ec19a6d5d6e24a2baa8100c","src/helpers/string.rs":"3af2d0c701ca978c705922a272e76506dbdf0f376d44ed9ae7283086c67852ba","src/lib.rs":"4f799dcf9412cee499c0db951bd0972da73c11b6b39f7fe9c50615dbd2a3ae6f","src/offset.rs":"fc9341648e091b4d8f7bec47006c01c21cb038c7ef98bd36a492cf78e7533023","src/quote.rs":"e9a495682e436b5708e71113e0e10a32eb967148785f091cd25756781dad3173","src/serde_format_description.rs":"aa279c8005005fc87c52fa5e8be8ef8fc13ef456a18e3cd5d702ae81194ba4d9","src/shim.rs":"8083a3893f2224202f91d21c02df33df66a505ad1cf98dc9fa3f1b492ccf98c0","src/time.rs":"3c06562358aed7ef624319c96e3f9c150a069606ab930de98ac379ef16b08100","src/to_tokens.rs":"6636ea489c7484bad9b39f72d6956a04c95ce82d8462b12079cc03db778fd263"},"package":"fd80a657e71da814b8e5d60d3374fc6d35045062245d80224748ae522dd76f36"}
\ No newline at end of file diff --git a/vendor/time-macros/Cargo.toml b/vendor/time-macros/Cargo.toml index c770e23ad..9dbc16e07 100644 --- a/vendor/time-macros/Cargo.toml +++ b/vendor/time-macros/Cargo.toml @@ -11,9 +11,9 @@ [package] edition = "2021" -rust-version = "1.60.0" +rust-version = "1.63.0" name = "time-macros" -version = "0.2.6" +version = "0.2.8" authors = [ "Jacob Pratt <open-source@jhpratt.dev>", "Time contributors", diff --git a/vendor/time-macros/src/error.rs b/vendor/time-macros/src/error.rs index 4de369daf..849317f15 100644 --- a/vendor/time-macros/src/error.rs +++ b/vendor/time-macros/src/error.rs @@ -3,9 +3,6 @@ use std::fmt; use proc_macro::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree}; -#[cfg(any(feature = "formatting", feature = "parsing"))] -use crate::format_description::error::InvalidFormatDescription; - trait WithSpan { fn with_span(self, span: Span) -> Self; } @@ -38,12 +35,6 @@ pub(crate) enum Error { tree: TokenTree, }, UnexpectedEndOfInput, - #[cfg(any(feature = "formatting", feature = "parsing"))] - InvalidFormatDescription { - error: InvalidFormatDescription, - span_start: Option<Span>, - span_end: Option<Span>, - }, Custom { message: Cow<'static, str>, span_start: Option<Span>, @@ -59,11 +50,9 @@ impl fmt::Display for Error { write!(f, "invalid component: {name} was {value}") } #[cfg(any(feature = "formatting", feature = "parsing"))] - Self::ExpectedString { .. } => f.write_str("expected string"), + Self::ExpectedString { .. } => f.write_str("expected string literal"), Self::UnexpectedToken { tree } => write!(f, "unexpected token: {tree}"), Self::UnexpectedEndOfInput => f.write_str("unexpected end of input"), - #[cfg(any(feature = "formatting", feature = "parsing"))] - Self::InvalidFormatDescription { error, .. } => error.fmt(f), Self::Custom { message, .. } => f.write_str(message), } } @@ -76,8 +65,7 @@ impl Error { | Self::InvalidComponent { span_start, .. } | Self::Custom { span_start, .. } => *span_start, #[cfg(any(feature = "formatting", feature = "parsing"))] - Self::ExpectedString { span_start, .. } - | Self::InvalidFormatDescription { span_start, .. } => *span_start, + Self::ExpectedString { span_start, .. } => *span_start, Self::UnexpectedToken { tree } => Some(tree.span()), Self::UnexpectedEndOfInput => Some(Span::mixed_site()), } @@ -90,8 +78,7 @@ impl Error { | Self::InvalidComponent { span_end, .. } | Self::Custom { span_end, .. } => *span_end, #[cfg(any(feature = "formatting", feature = "parsing"))] - Self::ExpectedString { span_end, .. } - | Self::InvalidFormatDescription { span_end, .. } => *span_end, + Self::ExpectedString { span_end, .. } => *span_end, Self::UnexpectedToken { tree, .. } => Some(tree.span()), Self::UnexpectedEndOfInput => Some(Span::mixed_site()), } diff --git a/vendor/time-macros/src/format_description/ast.rs b/vendor/time-macros/src/format_description/ast.rs new file mode 100644 index 000000000..497c8965d --- /dev/null +++ b/vendor/time-macros/src/format_description/ast.rs @@ -0,0 +1,251 @@ +use std::boxed::Box; +use std::iter; + +use super::{lexer, unused, Error, Location, Spanned, SpannedValue, Unused}; + +pub(super) enum Item<'a> { + Literal(Spanned<&'a [u8]>), + EscapedBracket { + _first: Unused<Location>, + _second: Unused<Location>, + }, + Component { + _opening_bracket: Unused<Location>, + _leading_whitespace: Unused<Option<Spanned<&'a [u8]>>>, + name: Spanned<&'a [u8]>, + modifiers: Box<[Modifier<'a>]>, + _trailing_whitespace: Unused<Option<Spanned<&'a [u8]>>>, + _closing_bracket: Unused<Location>, + }, + Optional { + opening_bracket: Location, + _leading_whitespace: Unused<Option<Spanned<&'a [u8]>>>, + _optional_kw: Unused<Spanned<&'a [u8]>>, + _whitespace: Unused<Spanned<&'a [u8]>>, + nested_format_description: NestedFormatDescription<'a>, + closing_bracket: Location, + }, + First { + opening_bracket: Location, + _leading_whitespace: Unused<Option<Spanned<&'a [u8]>>>, + _first_kw: Unused<Spanned<&'a [u8]>>, + _whitespace: Unused<Spanned<&'a [u8]>>, + nested_format_descriptions: Box<[NestedFormatDescription<'a>]>, + closing_bracket: Location, + }, +} + +pub(super) struct NestedFormatDescription<'a> { + pub(super) _opening_bracket: Unused<Location>, + pub(super) items: Box<[Item<'a>]>, + pub(super) _closing_bracket: Unused<Location>, + pub(super) _trailing_whitespace: Unused<Option<Spanned<&'a [u8]>>>, +} + +pub(super) struct Modifier<'a> { + pub(super) _leading_whitespace: Unused<Spanned<&'a [u8]>>, + pub(super) key: Spanned<&'a [u8]>, + pub(super) _colon: Unused<Location>, + pub(super) value: Spanned<&'a [u8]>, +} + +pub(super) fn parse< + 'item: 'iter, + 'iter, + I: Iterator<Item = Result<lexer::Token<'item>, Error>>, + const VERSION: u8, +>( + tokens: &'iter mut lexer::Lexed<I>, +) -> impl Iterator<Item = Result<Item<'item>, Error>> + 'iter { + assert!(version!(1..=2)); + parse_inner::<_, false, VERSION>(tokens) +} + +fn parse_inner< + 'item, + I: Iterator<Item = Result<lexer::Token<'item>, Error>>, + const NESTED: bool, + const VERSION: u8, +>( + tokens: &mut lexer::Lexed<I>, +) -> impl Iterator<Item = Result<Item<'item>, Error>> + '_ { + 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: _, value } if NESTED => Ok(Item::Literal(value)), + lexer::Token::ComponentPart { kind: _, value: _ } => { + bug!("component part should have been consumed by `parse_component`") + } + }) + }) +} + +fn parse_component<'a, I: Iterator<Item = Result<lexer::Token<'a>, Error>>, const VERSION: u8>( + opening_bracket: Location, + tokens: &mut lexer::Lexed<I>, +) -> Result<Item<'a>, Error> { + let leading_whitespace = tokens.next_if_whitespace(); + + guard!(let Some(name) = tokens.next_if_not_whitespace() else { + let span = match leading_whitespace { + Some(Spanned { value: _, span }) => span, + None => opening_bracket.to(opening_bracket), + }; + return Err(span.error("expected component name")); + }); + + if *name == b"optional" { + guard!(let Some(whitespace) = tokens.next_if_whitespace() else { + return Err(name.span.error("expected whitespace after `optional`")); + }); + + let nested = parse_nested::<_, VERSION>(whitespace.span.end, tokens)?; + + guard!(let Some(closing_bracket) = tokens.next_if_closing_bracket() else { + return Err(opening_bracket.error("unclosed bracket")); + }); + + 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" { + guard!(let Some(whitespace) = tokens.next_if_whitespace() else { + return Err(name.span.error("expected whitespace after `first`")); + }); + + let mut nested_format_descriptions = Vec::new(); + while let Ok(description) = parse_nested::<_, VERSION>(whitespace.span.end, tokens) { + nested_format_descriptions.push(description); + } + + guard!(let Some(closing_bracket) = tokens.next_if_closing_bracket() else { + return Err(opening_bracket.error("unclosed bracket")); + }); + + 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 { + guard!(let Some(whitespace) = tokens.next_if_whitespace() else { break None }); + + if let Some(location) = tokens.next_if_opening_bracket() { + return Err(location + .to(location) + .error("modifier must be of the form `key:value`")); + } + + guard!(let Some(Spanned { value, span }) = tokens.next_if_not_whitespace() else { + break Some(whitespace); + }); + + guard!(let Some(colon_index) = value.iter().position(|&b| b == b':') else { + return Err(span.error("modifier must be of the form `key:value`")); + }); + let key = &value[..colon_index]; + let value = &value[colon_index + 1..]; + + if key.is_empty() { + return Err(span.shrink_to_start().error("expected modifier key")); + } + if value.is_empty() { + return Err(span.shrink_to_end().error("expected modifier value")); + } + + modifiers.push(Modifier { + _leading_whitespace: unused(whitespace), + key: key.spanned(span.shrink_to_before(colon_index as _)), + _colon: unused(span.start.offset(colon_index as _)), + value: value.spanned(span.shrink_to_after(colon_index as _)), + }); + }; + + guard!(let Some(closing_bracket) = tokens.next_if_closing_bracket() else { + return Err(opening_bracket.error("unclosed bracket")); + }); + + 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), + }) +} + +fn parse_nested<'a, I: Iterator<Item = Result<lexer::Token<'a>, Error>>, const VERSION: u8>( + last_location: Location, + tokens: &mut lexer::Lexed<I>, +) -> Result<NestedFormatDescription<'a>, Error> { + guard!(let Some(opening_bracket) = tokens.next_if_opening_bracket() else { + return Err(last_location.error("expected opening bracket")); + }); + let items = parse_inner::<_, true, VERSION>(tokens).collect::<Result<_, _>>()?; + guard!(let Some(closing_bracket) = tokens.next_if_closing_bracket() else { + return Err(opening_bracket.error("unclosed bracket")); + }); + 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-macros/src/format_description/component.rs b/vendor/time-macros/src/format_description/component.rs deleted file mode 100644 index 850da91d2..000000000 --- a/vendor/time-macros/src/format_description/component.rs +++ /dev/null @@ -1,168 +0,0 @@ -use proc_macro::{Ident, Span, TokenStream}; - -use crate::format_description::error::InvalidFormatDescription; -use crate::format_description::modifier; -use crate::format_description::modifier::Modifiers; -use crate::to_tokens::ToTokenStream; - -pub(crate) enum Component { - Day(modifier::Day), - Month(modifier::Month), - Ordinal(modifier::Ordinal), - Weekday(modifier::Weekday), - WeekNumber(modifier::WeekNumber), - Year(modifier::Year), - Hour(modifier::Hour), - Minute(modifier::Minute), - Period(modifier::Period), - Second(modifier::Second), - Subsecond(modifier::Subsecond), - OffsetHour(modifier::OffsetHour), - OffsetMinute(modifier::OffsetMinute), - OffsetSecond(modifier::OffsetSecond), -} - -impl ToTokenStream for Component { - fn append_to(self, ts: &mut TokenStream) { - let mut mts = TokenStream::new(); - - macro_rules! component_name_and_append { - ($($name:ident)*) => { - match self { - $(Self::$name(modifier) => { - modifier.append_to(&mut mts); - stringify!($name) - })* - } - }; - } - - let component = component_name_and_append![ - Day - Month - Ordinal - Weekday - WeekNumber - Year - Hour - Minute - Period - Second - Subsecond - OffsetHour - OffsetMinute - OffsetSecond - ]; - let component = Ident::new(component, Span::mixed_site()); - - quote_append! { ts - ::time::format_description::Component::#(component)(#S(mts)) - } - } -} - -pub(crate) enum NakedComponent { - Day, - Month, - Ordinal, - Weekday, - WeekNumber, - Year, - Hour, - Minute, - Period, - Second, - Subsecond, - OffsetHour, - OffsetMinute, - OffsetSecond, -} - -impl NakedComponent { - pub(crate) fn parse( - component_name: &[u8], - component_index: usize, - ) -> Result<Self, InvalidFormatDescription> { - match component_name { - b"day" => Ok(Self::Day), - b"month" => Ok(Self::Month), - b"ordinal" => Ok(Self::Ordinal), - b"weekday" => Ok(Self::Weekday), - b"week_number" => Ok(Self::WeekNumber), - b"year" => Ok(Self::Year), - b"hour" => Ok(Self::Hour), - b"minute" => Ok(Self::Minute), - b"period" => Ok(Self::Period), - b"second" => Ok(Self::Second), - b"subsecond" => Ok(Self::Subsecond), - b"offset_hour" => Ok(Self::OffsetHour), - b"offset_minute" => Ok(Self::OffsetMinute), - b"offset_second" => Ok(Self::OffsetSecond), - b"" => Err(InvalidFormatDescription::MissingComponentName { - index: component_index, - }), - _ => Err(InvalidFormatDescription::InvalidComponentName { - name: String::from_utf8_lossy(component_name).into_owned(), - index: component_index, - }), - } - } - - pub(crate) fn attach_modifiers(self, modifiers: Modifiers) -> Component { - match self { - Self::Day => Component::Day(modifier::Day { - padding: modifiers.padding.unwrap_or_default(), - }), - Self::Month => Component::Month(modifier::Month { - padding: modifiers.padding.unwrap_or_default(), - repr: modifiers.month_repr.unwrap_or_default(), - case_sensitive: modifiers.case_sensitive.unwrap_or(true), - }), - Self::Ordinal => Component::Ordinal(modifier::Ordinal { - padding: modifiers.padding.unwrap_or_default(), - }), - Self::Weekday => Component::Weekday(modifier::Weekday { - repr: modifiers.weekday_repr.unwrap_or_default(), - one_indexed: modifiers.weekday_is_one_indexed.unwrap_or(true), - case_sensitive: modifiers.case_sensitive.unwrap_or(true), - }), - Self::WeekNumber => Component::WeekNumber(modifier::WeekNumber { - padding: modifiers.padding.unwrap_or_default(), - repr: modifiers.week_number_repr.unwrap_or_default(), - }), - Self::Year => Component::Year(modifier::Year { - padding: modifiers.padding.unwrap_or_default(), - repr: modifiers.year_repr.unwrap_or_default(), - iso_week_based: modifiers.year_is_iso_week_based.unwrap_or_default(), - sign_is_mandatory: modifiers.sign_is_mandatory.unwrap_or_default(), - }), - Self::Hour => Component::Hour(modifier::Hour { - padding: modifiers.padding.unwrap_or_default(), - is_12_hour_clock: modifiers.hour_is_12_hour_clock.unwrap_or_default(), - }), - Self::Minute => Component::Minute(modifier::Minute { - padding: modifiers.padding.unwrap_or_default(), - }), - Self::Period => Component::Period(modifier::Period { - is_uppercase: modifiers.period_is_uppercase.unwrap_or(true), - case_sensitive: modifiers.case_sensitive.unwrap_or(true), - }), - Self::Second => Component::Second(modifier::Second { - padding: modifiers.padding.unwrap_or_default(), - }), - Self::Subsecond => Component::Subsecond(modifier::Subsecond { - digits: modifiers.subsecond_digits.unwrap_or_default(), - }), - Self::OffsetHour => Component::OffsetHour(modifier::OffsetHour { - sign_is_mandatory: modifiers.sign_is_mandatory.unwrap_or_default(), - padding: modifiers.padding.unwrap_or_default(), - }), - Self::OffsetMinute => Component::OffsetMinute(modifier::OffsetMinute { - padding: modifiers.padding.unwrap_or_default(), - }), - Self::OffsetSecond => Component::OffsetSecond(modifier::OffsetSecond { - padding: modifiers.padding.unwrap_or_default(), - }), - } - } -} diff --git a/vendor/time-macros/src/format_description/error.rs b/vendor/time-macros/src/format_description/error.rs deleted file mode 100644 index 9aacd7dc9..000000000 --- a/vendor/time-macros/src/format_description/error.rs +++ /dev/null @@ -1,29 +0,0 @@ -use std::fmt; - -pub(crate) enum InvalidFormatDescription { - UnclosedOpeningBracket { index: usize }, - InvalidComponentName { name: String, index: usize }, - InvalidModifier { value: String, index: usize }, - MissingComponentName { index: usize }, -} - -impl fmt::Display for InvalidFormatDescription { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - #[allow(clippy::enum_glob_use)] - use InvalidFormatDescription::*; - match self { - UnclosedOpeningBracket { index } => { - write!(f, "unclosed opening bracket at byte index {index}") - } - InvalidComponentName { name, index } => { - write!(f, "invalid component name `{name}` at byte index {index}",) - } - InvalidModifier { value, index } => { - write!(f, "invalid modifier `{value}` at byte index {index}") - } - MissingComponentName { index } => { - write!(f, "missing component name at byte index {index}") - } - } - } -} diff --git a/vendor/time-macros/src/format_description/format_item.rs b/vendor/time-macros/src/format_description/format_item.rs new file mode 100644 index 000000000..6a8cf555e --- /dev/null +++ b/vendor/time-macros/src/format_description/format_item.rs @@ -0,0 +1,442 @@ +use std::boxed::Box; +use std::num::NonZeroU16; +use std::str::{self, FromStr}; + +use super::{ast, unused, Error, Span, Spanned, Unused}; + +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)) +} + +pub(super) enum Item<'a> { + Literal(&'a [u8]), + Component(Component), + Optional { + value: Box<[Self]>, + _span: Unused<Span>, + }, + First { + value: Box<[Box<[Self]>]>, + _span: Unused<Span>, + }, +} + +impl 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: unused(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: unused(opening_bracket.to(closing_bracket)), + } + } + }) + } +} + +impl From<Item<'_>> for crate::format_description::public::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::public::OwnedFormatItem { + fn from(items: Box<[Item<'a>]>) -> Self { + let items = items.into_vec(); + if items.len() == 1 { + if let Ok([item]) = <[_; 1]>::try_from(items) { + item.into() + } else { + bug!("the length was just checked to be 1") + } + } else { + Self::Compound(items.into_iter().map(Self::from).collect()) + } + } +} + +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 { + fn with_modifiers( + modifiers: &[ast::Modifier<'_>], + _component_span: Span, + ) -> Result<Self, Error> + { + 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(modifier.key.span.error("invalid modifier key")); + } + + $(component_definition! { @if_required $($required)? then { + if this.$field.is_none() { + return Err(_component_span.error("missing required modifier")); + } + }})* + + Ok(this) + } + })* + + impl From<$name> for crate::format_description::public::Component { + fn from(component: $name) -> Self { + match component {$( + $name::$variant($variant { $($field),* }) => { + $crate::format_description::public::Component::$variant( + super::public::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() + } + } + ),*} + ) + } + )*} + } + } + + 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(name.span.error("invalid component")) + } + } +} + +component_definition! { + pub(super) enum Component { + Day = "day" { + padding = "padding": Option<Padding> => padding, + }, + 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, + base = "base": Option<YearBase> => iso_week_based, + sign_behavior = "sign": Option<SignBehavior> => sign_is_mandatory, + }, + } +} + +macro_rules! target_ty { + ($name:ident $type:ty) => { + $type + }; + ($name:ident) => { + super::public::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) => { + super::public::modifier::$name::$variant + }; +} + +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(value.span.error("invalid modifier value")) + } + } + + impl From<$name> for target_ty!($name $($target_ty)?) { + fn from(modifier: $name) -> Self { + match modifier { + $($name::$variant => target_value!($name $variant $($target_value)?)),* + } + } + } + )+}; +} + +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", + LastTwo = b"last_two", + } +} + +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(|| value.span.error("invalid modifier value")) +} diff --git a/vendor/time-macros/src/format_description/lexer.rs b/vendor/time-macros/src/format_description/lexer.rs new file mode 100644 index 000000000..2c927cb94 --- /dev/null +++ b/vendor/time-macros/src/format_description/lexer.rs @@ -0,0 +1,248 @@ +use core::iter; + +use super::{Error, Location, Spanned, SpannedValue}; + +pub(super) struct Lexed<I: Iterator> { + iter: core::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> { + pub(super) fn peek(&mut self) -> Option<&I::Item> { + self.iter.peek() + } + + 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 + } + } + + 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(); + Some(value) + } else { + None + } + } + + 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(); + Some(location) + } else { + None + } + } + + 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 + } + } + + 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(); + Some(location) + } else { + None + } + } +} + +pub(super) enum Token<'a> { + Literal(Spanned<&'a [u8]>), + Bracket { + kind: BracketKind, + location: Location, + }, + ComponentPart { + kind: ComponentKind, + value: Spanned<&'a [u8]>, + }, +} + +pub(super) enum BracketKind { + Opening, + Closing, +} + +pub(super) enum ComponentKind { + #[allow(clippy::missing_docs_in_private_items)] + Whitespace, + #[allow(clippy::missing_docs_in_private_items)] + NotWhitespace, +} + +fn attach_location<'item>( + iter: impl Iterator<Item = &'item u8>, + proc_span: proc_macro::Span, +) -> impl Iterator<Item = (&'item u8, Location)> { + let mut byte_pos = 0; + + iter.map(move |byte| { + let location = Location { + byte: byte_pos, + proc_span, + }; + byte_pos += 1; + (byte, location) + }) +} + +#[allow(clippy::unused_peekable)] // false positive +pub(super) fn lex<const VERSION: u8>( + mut input: &[u8], + proc_span: proc_macro::Span, +) -> Lexed<impl Iterator<Item = Result<Token<'_>, Error>>> { + assert!(version!(1..=2)); + + let mut depth: u8 = 0; + let mut iter = attach_location(input.iter(), proc_span).peekable(); + let mut second_bracket_location = None; + + let iter = iter::from_fn(move || { + if version!(..=1) { + if let Some(location) = second_bracket_location.take() { + return Some(Ok(Token::Bracket { + kind: BracketKind::Opening, + location, + })); + } + } + + Some(Ok(match iter.next()? { + (b'\\', backslash_loc) if version!(2..) => match iter.next() { + Some((b'\\' | b'[' | b']', char_loc)) => { + 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(loc.error("invalid escape sequence"))); + } + None => { + return Some(Err(backslash_loc.error("unexpected end of input"))); + } + }, + (b'[', location) if version!(..=1) => { + if let Some((_, second_location)) = iter.next_if(|&(&byte, _)| byte == b'[') { + second_bracket_location = Some(second_location); + input = &input[2..]; + } else { + depth += 1; + input = &input[1..]; + } + + Token::Bracket { + kind: BracketKind::Opening, + location, + } + } + (b'[', location) => { + depth += 1; + input = &input[1..]; + + Token::Bracket { + kind: BracketKind::Opening, + location, + } + } + (b']', location) if depth > 0 => { + depth -= 1; + input = &input[1..]; + + Token::Bracket { + kind: BracketKind::Closing, + location, + } + } + (_, 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))) + } + (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-macros/src/format_description/mod.rs b/vendor/time-macros/src/format_description/mod.rs index dd32db74d..fde1272f6 100644 --- a/vendor/time-macros/src/format_description/mod.rs +++ b/vendor/time-macros/src/format_description/mod.rs @@ -1,40 +1,171 @@ -mod component; -pub(crate) mod error; -pub(crate) mod modifier; -pub(crate) mod parse; +//! Parser for format descriptions. -use proc_macro::{Literal, TokenStream}; +use std::vec::Vec; -pub(crate) use self::component::Component; -pub(crate) use self::parse::parse; -use crate::to_tokens::ToTokenStream; +macro_rules! version { + ($range:expr) => { + $range.contains(&VERSION) + }; +} + +mod ast; +mod format_item; +mod lexer; +mod public; + +pub(crate) fn parse_with_version( + version: Option<crate::FormatDescriptionVersion>, + s: &[u8], + proc_span: proc_macro::Span, +) -> Result<Vec<crate::format_description::public::OwnedFormatItem>, crate::Error> { + match version { + Some(crate::FormatDescriptionVersion::V1) | None => parse::<1>(s, proc_span), + Some(crate::FormatDescriptionVersion::V2) => parse::<2>(s, proc_span), + } +} + +fn parse<const VERSION: u8>( + s: &[u8], + proc_span: proc_macro::Span, +) -> Result<Vec<crate::format_description::public::OwnedFormatItem>, crate::Error> { + let mut lexed = lexer::lex::<VERSION>(s, proc_span); + let ast = ast::parse::<_, VERSION>(&mut lexed); + let format_items = format_item::parse(ast); + Ok(format_items + .map(|res| res.map(Into::into)) + .collect::<Result<_, _>>()?) +} + +#[derive(Clone, Copy)] +struct Location { + byte: u32, + proc_span: proc_macro::Span, +} + +impl Location { + fn to(self, end: Self) -> Span { + Span { start: self, end } + } + + #[must_use = "this does not modify the original value"] + fn offset(&self, offset: u32) -> Self { + Self { + byte: self.byte + offset, + proc_span: self.proc_span, + } + } -mod helper { - #[must_use = "This does not modify the original slice."] - pub(crate) fn consume_whitespace<'a>(bytes: &'a [u8], index: &mut usize) -> &'a [u8] { - let first_non_whitespace = bytes - .iter() - .position(|c| !c.is_ascii_whitespace()) - .unwrap_or(bytes.len()); - *index += first_non_whitespace; - &bytes[first_non_whitespace..] + fn error(self, message: &'static str) -> Error { + Error { + message, + _span: unused(Span { + start: self, + end: self, + }), + proc_span: self.proc_span, + } } } -#[allow(single_use_lifetimes)] // false positive -#[allow(variant_size_differences)] -pub(crate) enum FormatItem<'a> { - Literal(&'a [u8]), - Component(Component), +#[derive(Clone, Copy)] +struct Span { + #[allow(clippy::missing_docs_in_private_items)] + start: Location, + #[allow(clippy::missing_docs_in_private_items)] + end: Location, } -impl ToTokenStream for FormatItem<'_> { - fn append_to(self, ts: &mut TokenStream) { - quote_append! { ts - ::time::format_description::FormatItem::#S(match self { - FormatItem::Literal(bytes) => quote! { Literal(#(Literal::byte_string(bytes))) }, - FormatItem::Component(component) => quote! { Component(#S(component)) }, - }) +impl Span { + #[must_use = "this does not modify the original value"] + const fn shrink_to_start(&self) -> Self { + Self { + start: self.start, + end: self.start, + } + } + + #[must_use = "this does not modify the original value"] + const fn shrink_to_end(&self) -> Self { + Self { + start: self.end, + end: self.end, + } + } + + #[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, + proc_span: self.start.proc_span, + }, + } + } + + #[must_use = "this does not modify the original value"] + fn shrink_to_after(&self, pos: u32) -> Self { + Self { + start: Location { + byte: self.start.byte + pos + 1, + proc_span: self.start.proc_span, + }, + end: self.end, } } + + fn error(self, message: &'static str) -> Error { + Error { + message, + _span: unused(self), + proc_span: self.start.proc_span, + } + } +} + +#[derive(Clone, Copy)] +struct Spanned<T> { + value: T, + span: Span, +} + +impl<T> core::ops::Deref for Spanned<T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.value + } +} + +trait SpannedValue: Sized { + fn spanned(self, span: Span) -> Spanned<Self>; +} + +impl<T> SpannedValue for T { + fn spanned(self, span: Span) -> Spanned<Self> { + Spanned { value: self, span } + } +} + +struct Error { + message: &'static str, + _span: Unused<Span>, + proc_span: proc_macro::Span, +} + +impl From<Error> for crate::Error { + fn from(error: Error) -> Self { + Self::Custom { + message: error.message.into(), + span_start: Some(error.proc_span), + span_end: Some(error.proc_span), + } + } +} + +struct Unused<T>(core::marker::PhantomData<T>); + +#[allow(clippy::missing_const_for_fn)] // false positive +fn unused<T>(_: T) -> Unused<T> { + Unused(core::marker::PhantomData) } diff --git a/vendor/time-macros/src/format_description/modifier.rs b/vendor/time-macros/src/format_description/modifier.rs deleted file mode 100644 index f4e641a7b..000000000 --- a/vendor/time-macros/src/format_description/modifier.rs +++ /dev/null @@ -1,417 +0,0 @@ -use core::mem; - -use proc_macro::{Ident, Span, TokenStream, TokenTree}; - -use crate::format_description::error::InvalidFormatDescription; -use crate::format_description::helper; -use crate::to_tokens::{ToTokenStream, ToTokenTree}; - -macro_rules! to_tokens { - ( - $(#[$struct_attr:meta])* - $struct_vis:vis struct $struct_name:ident {$( - $(#[$field_attr:meta])* - $field_vis:vis $field_name:ident : $field_ty:ty - ),+ $(,)?} - ) => { - $(#[$struct_attr])* - $struct_vis struct $struct_name {$( - $(#[$field_attr])* - $field_vis $field_name: $field_ty - ),+} - - impl ToTokenTree for $struct_name { - fn into_token_tree(self) -> TokenTree { - let mut tokens = TokenStream::new(); - let Self {$($field_name),+} = self; - - quote_append! { tokens - let mut value = ::time::format_description::modifier::$struct_name::default(); - }; - $( - quote_append!(tokens value.$field_name =); - $field_name.append_to(&mut tokens); - quote_append!(tokens ;); - )+ - quote_append!(tokens value); - - proc_macro::TokenTree::Group(proc_macro::Group::new( - proc_macro::Delimiter::Brace, - tokens, - )) - } - } - }; - - ( - $(#[$enum_attr:meta])* - $enum_vis:vis enum $enum_name:ident {$( - $(#[$variant_attr:meta])* - $variant_name:ident - ),+ $(,)?} - ) => { - $(#[$enum_attr])* - $enum_vis enum $enum_name {$( - $(#[$variant_attr])* - $variant_name - ),+} - - impl ToTokenStream for $enum_name { - fn append_to(self, ts: &mut TokenStream) { - quote_append! { ts - ::time::format_description::modifier::$enum_name:: - }; - let name = match self { - $(Self::$variant_name => stringify!($variant_name)),+ - }; - ts.extend([TokenTree::Ident(Ident::new(name, Span::mixed_site()))]); - } - } - } -} - -to_tokens! { - pub(crate) struct Day { - pub(crate) padding: Padding, - } -} - -to_tokens! { - pub(crate) enum MonthRepr { - Numerical, - Long, - Short, - } -} - -to_tokens! { - pub(crate) struct Month { - pub(crate) padding: Padding, - pub(crate) repr: MonthRepr, - pub(crate) case_sensitive: bool, - } -} - -to_tokens! { - pub(crate) struct Ordinal { - pub(crate) padding: Padding, - } -} - -to_tokens! { - pub(crate) enum WeekdayRepr { - Short, - Long, - Sunday, - Monday, - } -} - -to_tokens! { - pub(crate) struct Weekday { - pub(crate) repr: WeekdayRepr, - pub(crate) one_indexed: bool, - pub(crate) case_sensitive: bool, - } -} - -to_tokens! { - pub(crate) enum WeekNumberRepr { - Iso, - Sunday, - Monday, - } -} - -to_tokens! { - pub(crate) struct WeekNumber { - pub(crate) padding: Padding, - pub(crate) repr: WeekNumberRepr, - } -} - -to_tokens! { - pub(crate) enum YearRepr { - Full, - LastTwo, - } -} - -to_tokens! { - pub(crate) struct Year { - pub(crate) padding: Padding, - pub(crate) repr: YearRepr, - pub(crate) iso_week_based: bool, - pub(crate) sign_is_mandatory: bool, - } -} - -to_tokens! { - pub(crate) struct Hour { - pub(crate) padding: Padding, - pub(crate) is_12_hour_clock: bool, - } -} - -to_tokens! { - pub(crate) struct Minute { - pub(crate) padding: Padding, - } -} - -to_tokens! { - pub(crate) struct Period { - pub(crate) is_uppercase: bool, - pub(crate) case_sensitive: bool, - } -} - -to_tokens! { - pub(crate) struct Second { - pub(crate) padding: Padding, - } -} - -to_tokens! { - pub(crate) enum SubsecondDigits { - One, - Two, - Three, - Four, - Five, - Six, - Seven, - Eight, - Nine, - OneOrMore, - } -} - -to_tokens! { - pub(crate) struct Subsecond { - pub(crate) digits: SubsecondDigits, - } -} - -to_tokens! { - pub(crate) struct OffsetHour { - pub(crate) sign_is_mandatory: bool, - pub(crate) padding: Padding, - } -} - -to_tokens! { - pub(crate) struct OffsetMinute { - pub(crate) padding: Padding, - } -} - -to_tokens! { - pub(crate) struct OffsetSecond { - pub(crate) padding: Padding, - } -} - -to_tokens! { - pub(crate) enum Padding { - Space, - Zero, - None, - } -} - -macro_rules! impl_default { - ($($type:ty => $default:expr;)*) => {$( - impl Default for $type { - fn default() -> Self { - $default - } - } - )*}; -} - -impl_default! { - Day => Self { padding: Padding::default() }; - MonthRepr => Self::Numerical; - Month => Self { - padding: Padding::default(), - repr: MonthRepr::default(), - case_sensitive: true, - }; - Ordinal => Self { padding: Padding::default() }; - WeekdayRepr => Self::Long; - Weekday => Self { - repr: WeekdayRepr::default(), - one_indexed: true, - case_sensitive: true, - }; - WeekNumberRepr => Self::Iso; - WeekNumber => Self { - padding: Padding::default(), - repr: WeekNumberRepr::default(), - }; - YearRepr => Self::Full; - Year => Self { - padding: Padding::default(), - repr: YearRepr::default(), - iso_week_based: false, - sign_is_mandatory: false, - }; - Hour => Self { - padding: Padding::default(), - is_12_hour_clock: false, - }; - Minute => Self { padding: Padding::default() }; - Period => Self { is_uppercase: true, case_sensitive: true }; - Second => Self { padding: Padding::default() }; - SubsecondDigits => Self::OneOrMore; - Subsecond => Self { digits: SubsecondDigits::default() }; - OffsetHour => Self { - sign_is_mandatory: true, - padding: Padding::default(), - }; - OffsetMinute => Self { padding: Padding::default() }; - OffsetSecond => Self { padding: Padding::default() }; - Padding => Self::Zero; -} - -#[derive(Default)] -pub(crate) struct Modifiers { - pub(crate) padding: Option<Padding>, - pub(crate) hour_is_12_hour_clock: Option<bool>, - pub(crate) period_is_uppercase: Option<bool>, - pub(crate) month_repr: Option<MonthRepr>, - pub(crate) subsecond_digits: Option<SubsecondDigits>, - pub(crate) weekday_repr: Option<WeekdayRepr>, - pub(crate) weekday_is_one_indexed: Option<bool>, - pub(crate) week_number_repr: Option<WeekNumberRepr>, - pub(crate) year_repr: Option<YearRepr>, - pub(crate) year_is_iso_week_based: Option<bool>, - pub(crate) sign_is_mandatory: Option<bool>, - pub(crate) case_sensitive: Option<bool>, -} - -impl Modifiers { - #[allow(clippy::too_many_lines)] - pub(crate) fn parse( - component_name: &[u8], - mut bytes: &[u8], - index: &mut usize, - ) -> Result<Self, InvalidFormatDescription> { - let mut modifiers = Self::default(); - - while !bytes.is_empty() { - // Trim any whitespace between modifiers. - bytes = helper::consume_whitespace(bytes, index); - - let modifier; - if let Some(whitespace_loc) = bytes.iter().position(u8::is_ascii_whitespace) { - *index += whitespace_loc; - modifier = &bytes[..whitespace_loc]; - bytes = &bytes[whitespace_loc..]; - } else { - modifier = mem::take(&mut bytes); - } - - if modifier.is_empty() { - break; - } - - match (component_name, modifier) { - ( - b"day" | b"hour" | b"minute" | b"month" | b"offset_hour" | b"offset_minute" - | b"offset_second" | b"ordinal" | b"second" | b"week_number" | b"year", - b"padding:space", - ) => modifiers.padding = Some(Padding::Space), - ( - b"day" | b"hour" | b"minute" | b"month" | b"offset_hour" | b"offset_minute" - | b"offset_second" | b"ordinal" | b"second" | b"week_number" | b"year", - b"padding:zero", - ) => modifiers.padding = Some(Padding::Zero), - ( - b"day" | b"hour" | b"minute" | b"month" | b"offset_hour" | b"offset_minute" - | b"offset_second" | b"ordinal" | b"second" | b"week_number" | b"year", - b"padding:none", - ) => modifiers.padding = Some(Padding::None), - (b"hour", b"repr:24") => modifiers.hour_is_12_hour_clock = Some(false), - (b"hour", b"repr:12") => modifiers.hour_is_12_hour_clock = Some(true), - (b"month" | b"period" | b"weekday", b"case_sensitive:true") => { - modifiers.case_sensitive = Some(true) - } - (b"month" | b"period" | b"weekday", b"case_sensitive:false") => { - modifiers.case_sensitive = Some(false) - } - (b"month", b"repr:numerical") => modifiers.month_repr = Some(MonthRepr::Numerical), - (b"month", b"repr:long") => modifiers.month_repr = Some(MonthRepr::Long), - (b"month", b"repr:short") => modifiers.month_repr = Some(MonthRepr::Short), - (b"offset_hour" | b"year", b"sign:automatic") => { - modifiers.sign_is_mandatory = Some(false); - } - (b"offset_hour" | b"year", b"sign:mandatory") => { - modifiers.sign_is_mandatory = Some(true); - } - (b"period", b"case:upper") => modifiers.period_is_uppercase = Some(true), - (b"period", b"case:lower") => modifiers.period_is_uppercase = Some(false), - (b"subsecond", b"digits:1") => { - modifiers.subsecond_digits = Some(SubsecondDigits::One); - } - (b"subsecond", b"digits:2") => { - modifiers.subsecond_digits = Some(SubsecondDigits::Two); - } - (b"subsecond", b"digits:3") => { - modifiers.subsecond_digits = Some(SubsecondDigits::Three); - } - (b"subsecond", b"digits:4") => { - modifiers.subsecond_digits = Some(SubsecondDigits::Four); - } - (b"subsecond", b"digits:5") => { - modifiers.subsecond_digits = Some(SubsecondDigits::Five); - } - (b"subsecond", b"digits:6") => { - modifiers.subsecond_digits = Some(SubsecondDigits::Six); - } - (b"subsecond", b"digits:7") => { - modifiers.subsecond_digits = Some(SubsecondDigits::Seven); - } - (b"subsecond", b"digits:8") => { - modifiers.subsecond_digits = Some(SubsecondDigits::Eight); - } - (b"subsecond", b"digits:9") => { - modifiers.subsecond_digits = Some(SubsecondDigits::Nine); - } - (b"subsecond", b"digits:1+") => { - modifiers.subsecond_digits = Some(SubsecondDigits::OneOrMore); - } - (b"weekday", b"repr:short") => modifiers.weekday_repr = Some(WeekdayRepr::Short), - (b"weekday", b"repr:long") => modifiers.weekday_repr = Some(WeekdayRepr::Long), - (b"weekday", b"repr:sunday") => modifiers.weekday_repr = Some(WeekdayRepr::Sunday), - (b"weekday", b"repr:monday") => modifiers.weekday_repr = Some(WeekdayRepr::Monday), - (b"weekday", b"one_indexed:true") => modifiers.weekday_is_one_indexed = Some(true), - (b"weekday", b"one_indexed:false") => { - modifiers.weekday_is_one_indexed = Some(false); - } - (b"week_number", b"repr:iso") => { - modifiers.week_number_repr = Some(WeekNumberRepr::Iso); - } - (b"week_number", b"repr:sunday") => { - modifiers.week_number_repr = Some(WeekNumberRepr::Sunday); - } - (b"week_number", b"repr:monday") => { - modifiers.week_number_repr = Some(WeekNumberRepr::Monday); - } - (b"year", b"repr:full") => modifiers.year_repr = Some(YearRepr::Full), - (b"year", b"repr:last_two") => modifiers.year_repr = Some(YearRepr::LastTwo), - (b"year", b"base:calendar") => modifiers.year_is_iso_week_based = Some(false), - (b"year", b"base:iso_week") => modifiers.year_is_iso_week_based = Some(true), - _ => { - return Err(InvalidFormatDescription::InvalidModifier { - value: String::from_utf8_lossy(modifier).into_owned(), - index: *index, - }); - } - } - } - - Ok(modifiers) - } -} diff --git a/vendor/time-macros/src/format_description/parse.rs b/vendor/time-macros/src/format_description/parse.rs deleted file mode 100644 index 19c7bf608..000000000 --- a/vendor/time-macros/src/format_description/parse.rs +++ /dev/null @@ -1,84 +0,0 @@ -use proc_macro::Span; - -use crate::format_description::component::{Component, NakedComponent}; -use crate::format_description::error::InvalidFormatDescription; -use crate::format_description::{helper, modifier, FormatItem}; -use crate::Error; - -struct ParsedItem<'a> { - item: FormatItem<'a>, - remaining: &'a [u8], -} - -fn parse_component(mut s: &[u8], index: &mut usize) -> Result<Component, InvalidFormatDescription> { - s = helper::consume_whitespace(s, index); - - let component_index = *index; - let whitespace_loc = s - .iter() - .position(u8::is_ascii_whitespace) - .unwrap_or(s.len()); - *index += whitespace_loc; - let component_name = &s[..whitespace_loc]; - s = &s[whitespace_loc..]; - s = helper::consume_whitespace(s, index); - - Ok(NakedComponent::parse(component_name, component_index)? - .attach_modifiers(modifier::Modifiers::parse(component_name, s, index)?)) -} - -fn parse_literal<'a>(s: &'a [u8], index: &mut usize) -> ParsedItem<'a> { - let loc = s.iter().position(|&c| c == b'[').unwrap_or(s.len()); - *index += loc; - ParsedItem { - item: FormatItem::Literal(&s[..loc]), - remaining: &s[loc..], - } -} - -fn parse_item<'a>( - s: &'a [u8], - index: &mut usize, -) -> Result<ParsedItem<'a>, InvalidFormatDescription> { - if let [b'[', b'[', remaining @ ..] = s { - *index += 2; - return Ok(ParsedItem { - item: FormatItem::Literal(b"["), - remaining, - }); - }; - - if s.starts_with(b"[") { - if let Some(bracket_index) = s.iter().position(|&c| c == b']') { - *index += 1; // opening bracket - let ret_val = ParsedItem { - item: FormatItem::Component(parse_component(&s[1..bracket_index], index)?), - remaining: &s[bracket_index + 1..], - }; - *index += 1; // closing bracket - Ok(ret_val) - } else { - Err(InvalidFormatDescription::UnclosedOpeningBracket { index: *index }) - } - } else { - Ok(parse_literal(s, index)) - } -} - -pub(crate) fn parse(mut s: &[u8], span: Span) -> Result<Vec<FormatItem<'_>>, Error> { - let mut compound = Vec::new(); - let mut loc = 0; - - while !s.is_empty() { - let ParsedItem { item, remaining } = - parse_item(s, &mut loc).map_err(|error| Error::InvalidFormatDescription { - error, - span_start: Some(span), - span_end: Some(span), - })?; - s = remaining; - compound.push(item); - } - - Ok(compound) -} diff --git a/vendor/time-macros/src/format_description/public/component.rs b/vendor/time-macros/src/format_description/public/component.rs new file mode 100644 index 000000000..4737c6ce5 --- /dev/null +++ b/vendor/time-macros/src/format_description/public/component.rs @@ -0,0 +1,49 @@ +use proc_macro::{Ident, Span, TokenStream}; + +use super::modifier; +use crate::to_tokens::ToTokenStream; + +macro_rules! declare_component { + ($($name:ident)*) => { + pub(crate) enum Component {$( + $name(modifier::$name), + )*} + + impl ToTokenStream for Component { + fn append_to(self, ts: &mut TokenStream) { + let mut mts = TokenStream::new(); + + let component = match self {$( + Self::$name(modifier) => { + modifier.append_to(&mut mts); + stringify!($name) + } + )*}; + let component = Ident::new(component, Span::mixed_site()); + + quote_append! { ts + ::time::format_description::Component::#(component)(#S(mts)) + } + } + } + }; +} + +declare_component! { + Day + Month + Ordinal + Weekday + WeekNumber + Year + Hour + Minute + Period + Second + Subsecond + OffsetHour + OffsetMinute + OffsetSecond + Ignore + UnixTimestamp +} diff --git a/vendor/time-macros/src/format_description/public/mod.rs b/vendor/time-macros/src/format_description/public/mod.rs new file mode 100644 index 000000000..ccb0b6e2a --- /dev/null +++ b/vendor/time-macros/src/format_description/public/mod.rs @@ -0,0 +1,54 @@ +mod component; +pub(super) mod modifier; + +use proc_macro::{Literal, TokenStream}; + +pub(crate) use self::component::Component; +use crate::to_tokens::ToTokenStream; + +#[allow(variant_size_differences)] +pub(crate) enum OwnedFormatItem { + Literal(Box<[u8]>), + Component(Component), + Compound(Box<[Self]>), + Optional(Box<Self>), + First(Box<[Self]>), +} + +impl ToTokenStream for OwnedFormatItem { + fn append_to(self, ts: &mut TokenStream) { + match self { + Self::Literal(bytes) => quote_append! { ts + ::time::format_description::FormatItem::Literal { + 0: #(Literal::byte_string(bytes.as_ref())) + } + }, + Self::Component(component) => quote_append! { ts + ::time::format_description::FormatItem::Component { 0: #S(component) } + }, + Self::Compound(items) => { + let items = items + .into_vec() + .into_iter() + .map(|item| quote! { #S(item), }) + .collect::<TokenStream>(); + quote_append! { ts + ::time::format_description::FormatItem::Compound { 0: &[#S(items)] } + } + } + Self::Optional(item) => quote_append! {ts + ::time::format_description::FormatItem::Optional { 0: &#S(*item) } + }, + Self::First(items) => { + let items = items + .into_vec() + .into_iter() + .map(|item| quote! { #S(item), }) + .collect::<TokenStream>(); + quote_append! { ts + ::time::format_description::FormatItem::First { 0: &[#S(items)] } + } + } + } + } +} diff --git a/vendor/time-macros/src/format_description/public/modifier.rs b/vendor/time-macros/src/format_description/public/modifier.rs new file mode 100644 index 000000000..e39c6bf55 --- /dev/null +++ b/vendor/time-macros/src/format_description/public/modifier.rs @@ -0,0 +1,247 @@ +use std::num::NonZeroU16; + +use proc_macro::{Ident, Span, TokenStream, TokenTree}; + +use crate::to_tokens::{ToTokenStream, ToTokenTree}; + +macro_rules! to_tokens { + ( + $(#[$struct_attr:meta])* + $struct_vis:vis struct $struct_name:ident {$( + $(#[$field_attr:meta])* + $field_vis:vis $field_name:ident : $field_ty:ty + ),+ $(,)?} + ) => { + $(#[$struct_attr])* + $struct_vis struct $struct_name {$( + $(#[$field_attr])* + $field_vis $field_name: $field_ty + ),+} + + impl ToTokenTree for $struct_name { + fn into_token_tree(self) -> TokenTree { + let mut tokens = TokenStream::new(); + let Self {$($field_name),+} = self; + + quote_append! { tokens + let mut value = ::time::format_description::modifier::$struct_name::default(); + }; + $( + quote_append!(tokens value.$field_name =); + $field_name.append_to(&mut tokens); + quote_append!(tokens ;); + )+ + quote_append!(tokens value); + + proc_macro::TokenTree::Group(proc_macro::Group::new( + proc_macro::Delimiter::Brace, + tokens, + )) + } + } + }; + + ( + $(#[$enum_attr:meta])* + $enum_vis:vis enum $enum_name:ident {$( + $(#[$variant_attr:meta])* + $variant_name:ident + ),+ $(,)?} + ) => { + $(#[$enum_attr])* + $enum_vis enum $enum_name {$( + $(#[$variant_attr])* + $variant_name + ),+} + + impl ToTokenStream for $enum_name { + fn append_to(self, ts: &mut TokenStream) { + quote_append! { ts + ::time::format_description::modifier::$enum_name:: + }; + let name = match self { + $(Self::$variant_name => stringify!($variant_name)),+ + }; + ts.extend([TokenTree::Ident(Ident::new(name, Span::mixed_site()))]); + } + } + } +} + +to_tokens! { + pub(crate) struct Day { + pub(crate) padding: Padding, + } +} + +to_tokens! { + pub(crate) enum MonthRepr { + Numerical, + Long, + Short, + } +} + +to_tokens! { + pub(crate) struct Month { + pub(crate) padding: Padding, + pub(crate) repr: MonthRepr, + pub(crate) case_sensitive: bool, + } +} + +to_tokens! { + pub(crate) struct Ordinal { + pub(crate) padding: Padding, + } +} + +to_tokens! { + pub(crate) enum WeekdayRepr { + Short, + Long, + Sunday, + Monday, + } +} + +to_tokens! { + pub(crate) struct Weekday { + pub(crate) repr: WeekdayRepr, + pub(crate) one_indexed: bool, + pub(crate) case_sensitive: bool, + } +} + +to_tokens! { + pub(crate) enum WeekNumberRepr { + Iso, + Sunday, + Monday, + } +} + +to_tokens! { + pub(crate) struct WeekNumber { + pub(crate) padding: Padding, + pub(crate) repr: WeekNumberRepr, + } +} + +to_tokens! { + pub(crate) enum YearRepr { + Full, + LastTwo, + } +} + +to_tokens! { + pub(crate) struct Year { + pub(crate) padding: Padding, + pub(crate) repr: YearRepr, + pub(crate) iso_week_based: bool, + pub(crate) sign_is_mandatory: bool, + } +} + +to_tokens! { + pub(crate) struct Hour { + pub(crate) padding: Padding, + pub(crate) is_12_hour_clock: bool, + } +} + +to_tokens! { + pub(crate) struct Minute { + pub(crate) padding: Padding, + } +} + +to_tokens! { + pub(crate) struct Period { + pub(crate) is_uppercase: bool, + pub(crate) case_sensitive: bool, + } +} + +to_tokens! { + pub(crate) struct Second { + pub(crate) padding: Padding, + } +} + +to_tokens! { + pub(crate) enum SubsecondDigits { + One, + Two, + Three, + Four, + Five, + Six, + Seven, + Eight, + Nine, + OneOrMore, + } +} + +to_tokens! { + pub(crate) struct Subsecond { + pub(crate) digits: SubsecondDigits, + } +} + +to_tokens! { + pub(crate) struct OffsetHour { + pub(crate) sign_is_mandatory: bool, + pub(crate) padding: Padding, + } +} + +to_tokens! { + pub(crate) struct OffsetMinute { + pub(crate) padding: Padding, + } +} + +to_tokens! { + pub(crate) struct OffsetSecond { + pub(crate) padding: Padding, + } +} + +to_tokens! { + pub(crate) enum Padding { + Space, + Zero, + None, + } +} + +pub(crate) struct Ignore { + pub(crate) count: NonZeroU16, +} + +impl ToTokenTree for Ignore { + fn into_token_tree(self) -> TokenTree { + quote_group! {{ + ::time::format_description::modifier::Ignore::count(#(self.count)) + }} + } +} + +to_tokens! { + pub(crate) enum UnixTimestampPrecision { + Second, + Millisecond, + Microsecond, + Nanosecond, + } +} + +to_tokens! { + pub(crate) struct UnixTimestamp { + pub(crate) precision: UnixTimestampPrecision, + pub(crate) sign_is_mandatory: bool, + } +} diff --git a/vendor/time-macros/src/helpers/mod.rs b/vendor/time-macros/src/helpers/mod.rs index cbf3ba3ed..56300b3e6 100644 --- a/vendor/time-macros/src/helpers/mod.rs +++ b/vendor/time-macros/src/helpers/mod.rs @@ -4,17 +4,15 @@ mod string; use std::iter::Peekable; use std::str::FromStr; -#[cfg(any(feature = "formatting", feature = "parsing"))] -use proc_macro::TokenStream; use proc_macro::{token_stream, Span, TokenTree}; use time_core::util::{days_in_year, is_leap_year}; use crate::Error; #[cfg(any(feature = "formatting", feature = "parsing"))] -pub(crate) fn get_string_literal(tokens: TokenStream) -> Result<(Span, Vec<u8>), Error> { - let mut tokens = tokens.into_iter(); - +pub(crate) fn get_string_literal( + mut tokens: impl Iterator<Item = TokenTree>, +) -> Result<(Span, Vec<u8>), Error> { match (tokens.next(), tokens.next()) { (Some(TokenTree::Literal(literal)), None) => string::parse(&literal), (Some(tree), None) => Err(Error::ExpectedString { diff --git a/vendor/time-macros/src/helpers/string.rs b/vendor/time-macros/src/helpers/string.rs index fa3780f5e..6b478f60d 100644 --- a/vendor/time-macros/src/helpers/string.rs +++ b/vendor/time-macros/src/helpers/string.rs @@ -57,7 +57,7 @@ fn parse_lit_str_cooked(mut s: &str) -> Vec<u8> { continue 'outer; } }, - _ => unreachable!("invalid escape"), + _ => bug!("invalid escape"), } } b'\r' => { @@ -120,7 +120,7 @@ fn parse_lit_byte_str_cooked(mut v: &[u8]) -> Vec<u8> { continue 'outer; } }, - _ => unreachable!("invalid escape"), + _ => bug!("invalid escape"), } } b'\r' => { @@ -151,7 +151,7 @@ where b'0'..=b'9' => b1 - b'0', b'a'..=b'f' => 10 + (b1 - b'a'), b'A'..=b'F' => 10 + (b1 - b'A'), - _ => unreachable!("invalid hex escape"), + _ => bug!("invalid hex escape"), }; (ch, &s[2..]) } @@ -172,7 +172,7 @@ fn backslash_u(mut s: &str) -> (char, &str) { continue; } b'}' if digits != 0 => break, - _ => unreachable!("invalid unicode escape"), + _ => bug!("invalid unicode escape"), }; ch *= 0x10; ch += u32::from(digit); diff --git a/vendor/time-macros/src/lib.rs b/vendor/time-macros/src/lib.rs index 1afc313ea..84ad25113 100644 --- a/vendor/time-macros/src/lib.rs +++ b/vendor/time-macros/src/lib.rs @@ -1,7 +1,6 @@ #![deny( anonymous_parameters, clippy::all, - const_err, illegal_floating_point_literal_pattern, late_bound_lifetime_arguments, path_statements, @@ -34,8 +33,18 @@ clippy::option_if_let_else, // suggests terrible code )] +macro_rules! bug { + () => { compile_error!("provide an error message to help fix a possible bug") }; + ($descr:literal $($rest:tt)?) => { + unreachable!(concat!("internal error: ", $descr) $($rest)?) + } +} + #[macro_use] mod quote; +#[cfg(any(feature = "formatting", feature = "parsing"))] +#[macro_use] +mod shim; mod date; mod datetime; @@ -49,9 +58,12 @@ mod serde_format_description; mod time; mod to_tokens; +#[cfg(any(feature = "formatting", feature = "parsing"))] +use std::iter::Peekable; + use proc_macro::TokenStream; -#[cfg(all(feature = "serde", any(feature = "formatting", feature = "parsing")))] -use proc_macro::TokenTree; +#[cfg(any(feature = "formatting", feature = "parsing"))] +use proc_macro::{Ident, TokenTree}; use self::error::Error; @@ -76,11 +88,94 @@ macro_rules! impl_macros { impl_macros![date datetime offset time]; #[cfg(any(feature = "formatting", feature = "parsing"))] +enum FormatDescriptionVersion { + V1, + V2, +} + +#[cfg(any(feature = "formatting", feature = "parsing"))] +enum VersionOrModuleName { + Version(FormatDescriptionVersion), + ModuleName(Ident), +} + +#[cfg(any(feature = "formatting", feature = "parsing"))] +fn parse_format_description_version<const NO_EQUALS_IS_MOD_NAME: bool>( + iter: &mut Peekable<proc_macro::token_stream::IntoIter>, +) -> Result<Option<VersionOrModuleName>, Error> { + let version_ident = match iter.peek() { + Some(TokenTree::Ident(ident)) if ident.to_string() == "version" => match iter.next() { + Some(TokenTree::Ident(ident)) => ident, + _ => unreachable!(), + }, + _ => return Ok(None), + }; + match iter.peek() { + Some(TokenTree::Punct(punct)) if punct.as_char() == '=' => iter.next(), + _ if NO_EQUALS_IS_MOD_NAME => { + return Ok(Some(VersionOrModuleName::ModuleName(version_ident))); + } + Some(token) => { + return Err(Error::Custom { + message: "expected `=`".into(), + span_start: Some(token.span()), + span_end: Some(token.span()), + }); + } + None => { + return Err(Error::Custom { + message: "expected `=`".into(), + span_start: None, + span_end: None, + }); + } + }; + let version_literal = match iter.next() { + Some(TokenTree::Literal(literal)) => literal, + Some(token) => { + return Err(Error::Custom { + message: "expected 1 or 2".into(), + span_start: Some(token.span()), + span_end: Some(token.span()), + }); + } + None => { + return Err(Error::Custom { + message: "expected 1 or 2".into(), + span_start: None, + span_end: None, + }); + } + }; + let version = match version_literal.to_string().as_str() { + "1" => FormatDescriptionVersion::V1, + "2" => FormatDescriptionVersion::V2, + _ => { + return Err(Error::Custom { + message: "invalid format description version".into(), + span_start: Some(version_literal.span()), + span_end: Some(version_literal.span()), + }); + } + }; + helpers::consume_punct(',', iter)?; + + Ok(Some(VersionOrModuleName::Version(version))) +} + +#[cfg(any(feature = "formatting", feature = "parsing"))] #[proc_macro] pub fn format_description(input: TokenStream) -> TokenStream { (|| { + let mut input = input.into_iter().peekable(); + let version = match parse_format_description_version::<false>(&mut input)? { + Some(VersionOrModuleName::Version(version)) => Some(version), + None => None, + // This branch should never occur here, as `false` is the provided as a const parameter. + Some(VersionOrModuleName::ModuleName(_)) => bug!("branch should never occur"), + }; let (span, string) = helpers::get_string_literal(input)?; - let items = format_description::parse(&string, span)?; + let items = format_description::parse_with_version(version, &string, span)?; Ok(quote! {{ const DESCRIPTION: &[::time::format_description::FormatItem<'_>] = &[#S( @@ -100,12 +195,25 @@ pub fn format_description(input: TokenStream) -> TokenStream { pub fn serde_format_description(input: TokenStream) -> TokenStream { (|| { let mut tokens = input.into_iter().peekable(); - // First, an identifier (the desired module name) - let mod_name = match tokens.next() { - Some(TokenTree::Ident(ident)) => Ok(ident), - Some(tree) => Err(Error::UnexpectedToken { tree }), - None => Err(Error::UnexpectedEndOfInput), - }?; + + // First, the optional format description version. + let version = parse_format_description_version::<true>(&mut tokens)?; + let (version, mod_name) = match version { + Some(VersionOrModuleName::ModuleName(module_name)) => (None, Some(module_name)), + Some(VersionOrModuleName::Version(version)) => (Some(version), None), + None => (None, None), + }; + + // Next, an identifier (the desired module name) + // Only parse this if it wasn't parsed when attempting to get the version. + let mod_name = match mod_name { + Some(mod_name) => mod_name, + None => match tokens.next() { + Some(TokenTree::Ident(ident)) => Ok(ident), + Some(tree) => Err(Error::UnexpectedToken { tree }), + None => Err(Error::UnexpectedEndOfInput), + }?, + }; // Followed by a comma helpers::consume_punct(',', &mut tokens)?; @@ -126,8 +234,8 @@ pub fn serde_format_description(input: TokenStream) -> TokenStream { let (format, raw_format_string) = match tokens.peek() { // string literal Some(TokenTree::Literal(_)) => { - let (span, format_string) = helpers::get_string_literal(tokens.collect())?; - let items = format_description::parse(&format_string, span)?; + let (span, format_string) = helpers::get_string_literal(tokens)?; + let items = format_description::parse_with_version(version, &format_string, span)?; let items: TokenStream = items.into_iter().map(|item| quote! { #S(item), }).collect(); let items = quote! { &[#S(items)] }; diff --git a/vendor/time-macros/src/quote.rs b/vendor/time-macros/src/quote.rs index 2fe86cc98..295abe115 100644 --- a/vendor/time-macros/src/quote.rs +++ b/vendor/time-macros/src/quote.rs @@ -78,6 +78,10 @@ macro_rules! quote_inner { }; // Literal + ($ts:ident 0 $($tail:tt)*) => { + $ts.extend([::proc_macro::TokenTree::from(::proc_macro::Literal::usize_unsuffixed(0))]); + quote_inner!($ts $($tail)*); + }; ($ts:ident $l:literal $($tail:tt)*) => { $ts.extend([::proc_macro::TokenTree::from(::proc_macro::Literal::string(&$l))]); quote_inner!($ts $($tail)*); diff --git a/vendor/time-macros/src/shim.rs b/vendor/time-macros/src/shim.rs new file mode 100644 index 000000000..f31e5d501 --- /dev/null +++ b/vendor/time-macros/src/shim.rs @@ -0,0 +1,117 @@ +#![allow(unused_macros)] + +// The following code is copyright 2016 Alex Burka. Available under the MIT OR Apache-2.0 license. +// Some adaptations have been made to the original code. + +pub(crate) enum LetElseBodyMustDiverge {} + +#[allow(clippy::missing_docs_in_private_items)] +macro_rules! __guard_output { + ((($($imms:ident)*) ($($muts:ident)*)), + [($($pattern:tt)*) ($rhs:expr) ($diverge:expr)]) => { + __guard_impl!(@as_stmt + let ($($imms,)* $(mut $muts,)*) = { + #[allow(unused_mut)] + match $rhs { + $($pattern)* => { + ($($imms,)* $($muts,)*) + }, + _ => { + let _: $crate::shim::LetElseBodyMustDiverge = $diverge; + }, + } + } + ) + }; +} + +macro_rules! __guard_impl { + (@as_stmt $s:stmt) => { $s }; + (@collect () -> $($rest:tt)*) => { + __guard_output!($($rest)*) + }; + (@collect (($($inside:tt)*) $($tail:tt)*) -> $idents:tt, $thru:tt) => { + __guard_impl!(@collect ($($inside)* $($tail)*) -> $idents, $thru) + }; + (@collect ({$($inside:tt)*} $($tail:tt)*) -> $idents:tt, $thru:tt) => { + __guard_impl!(@collect ($($inside)* $($tail)*) -> $idents, $thru) + }; + (@collect ([$($inside:tt)*] $($tail:tt)*) -> $idents:tt, $thru:tt) => { + __guard_impl!(@collect ($($inside)* $($tail)*) -> $idents, $thru) + }; + (@collect (, $($tail:tt)*) -> $idents:tt, $thru:tt) => { + __guard_impl!(@collect ($($tail)*) -> $idents, $thru) + }; + (@collect (.. $($tail:tt)*) -> $idents:tt, $thru:tt) => { + __guard_impl!(@collect ($($tail)*) -> $idents, $thru) + }; + (@collect (@ $($tail:tt)*) -> $idents:tt, $thru:tt) => { + __guard_impl!(@collect ($($tail)*) -> $idents, $thru) + }; + (@collect (_ $($tail:tt)*) -> $idents:tt, $thru:tt) => { + __guard_impl!(@collect ($($tail)*) -> $idents, $thru) + }; + (@collect (& $($tail:tt)*) -> $idents:tt, $thru:tt) => { + __guard_impl!(@collect ($($tail)*) -> $idents, $thru) + }; + (@collect (:: <$($generic:tt),*> $($tail:tt)*) -> $idents:tt, $thru:tt) => { + __guard_impl!(@collect ($($tail)*) -> $idents, $thru) + }; + (@collect (:: $pathend:ident $($tail:tt)*) -> $idents:tt, $thru:tt) => { + __guard_impl!(@collect ($($tail)*) -> $idents, $thru) + }; + (@collect (| $($tail:tt)*) -> $idents:tt, $thru:tt) => { + __guard_impl!(@collect () -> $idents, $thru) + }; + (@collect ($id:ident: $($tail:tt)*) -> $idents:tt, $thru:tt) => { + __guard_impl!(@collect ($($tail)*) -> $idents, $thru) + }; + (@collect ($pathcomp:ident :: $pathend:ident $($tail:tt)*) -> $idents:tt, $thru:tt) => { + __guard_impl!(@collect ($($tail)*) -> $idents, $thru) + }; + (@collect ($id:ident ($($inside:tt)*) $($tail:tt)*) -> $idents:tt, $thru:tt) => { + __guard_impl!(@collect ($($inside)* $($tail)*) -> $idents, $thru) + }; + (@collect ($id:ident {$($inside:tt)*} $($tail:tt)*) -> $idents:tt, $thru:tt) => { + __guard_impl!(@collect ($($inside)* $($tail)*) -> $idents, $thru) + }; + (@collect (ref mut $id:ident $($tail:tt)*) -> (($($imms:ident)*) $muts:tt), $thru:tt) => { + __guard_impl!(@collect ($($tail)*) -> (($($imms)* $id) $muts), $thru) + }; + (@collect (ref $id:ident $($tail:tt)*) -> (($($imms:ident)*) $muts:tt), $thru:tt) => { + __guard_impl!(@collect ($($tail)*) -> (($($imms)* $id) $muts), $thru) + }; + (@collect (mut $id:ident $($tail:tt)*) -> ($imms:tt ($($muts:ident)*)), $thru:tt) => { + __guard_impl!(@collect ($($tail)*) -> ($imms ($($muts)* $id)), $thru) + }; + (@collect ($id:ident $($tail:tt)*) -> (($($imms:ident)*) $muts:tt), $thru:tt) => { + __guard_impl!(@collect ($($tail)*) -> (($($imms)* $id) $muts), $thru) + }; + (@split (else { $($diverge:tt)* } = $($tail:tt)*) -> ($pat:tt)) => { + __guard_impl!(@collect $pat -> (() ()), [$pat ($($tail)*) ({ $($diverge)* })]) + }; + (@split (= $($tail:tt)*) -> ($pat:tt)) => { + __guard_impl!(@split expr ($($tail)*) -> ($pat ())) + }; + (@split ($head:tt $($tail:tt)*) -> (($($pat:tt)*))) => { + __guard_impl!(@split ($($tail)*) -> (($($pat)* $head))) + }; + (@split expr (else { $($tail:tt)* }) -> ($pat:tt $expr:tt)) => { + __guard_impl!(@collect $pat -> (() ()), [$pat $expr ({ $($tail)* })]) + }; + (@split expr (else { $($body:tt)* } $($tail:tt)*) -> ($pat:tt ($($expr:tt)*))) => { + __guard_impl!(@split expr ($($tail)*) -> ($pat ($($expr)* else { $($body)* }))) + }; + (@split expr ($head:tt $($tail:tt)*) -> ($pat:tt ($($expr:tt)*))) => { + __guard_impl!(@split expr ($($tail)*) -> ($pat ($($expr)* $head))) + }; + (let $($tail:tt)*) => { + __guard_impl!(@split ($($tail)*) -> (())) + }; +} + +macro_rules! guard { + ($($input:tt)*) => { + __guard_impl!($($input)*) + }; +} diff --git a/vendor/time-macros/src/to_tokens.rs b/vendor/time-macros/src/to_tokens.rs index 3a293925c..7e7321153 100644 --- a/vendor/time-macros/src/to_tokens.rs +++ b/vendor/time-macros/src/to_tokens.rs @@ -1,3 +1,5 @@ +use std::num::NonZeroU16; + use proc_macro::{Group, Ident, Literal, Punct, Span, TokenStream, TokenTree}; pub(crate) trait ToTokenStream: Sized { @@ -39,6 +41,14 @@ impl ToTokenTree for &str { } } +impl ToTokenTree for NonZeroU16 { + fn into_token_tree(self) -> TokenTree { + quote_group! {{ + unsafe { ::core::num::NonZeroU16::new_unchecked(#(self.get())) } + }} + } +} + macro_rules! impl_for_tree_types { ($($type:ty)*) => {$( impl ToTokenTree for $type { |