summaryrefslogtreecommitdiffstats
path: root/vendor/time-macros/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/time-macros/src/lib.rs')
-rw-r--r--vendor/time-macros/src/lib.rs132
1 files changed, 120 insertions, 12 deletions
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)] };