#![allow(
clippy::missing_const_for_fn, // irrelevant for proc macros
clippy::missing_docs_in_private_items, // TODO remove
clippy::std_instead_of_core, // irrelevant for proc macros
clippy::std_instead_of_alloc, // irrelevant for proc macros
clippy::alloc_instead_of_core, // irrelevant for proc macros
missing_docs, // TODO remove
)]
#[allow(unused_macros)]
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;
mod date; mod datetime; mod error; #[cfg(any(feature = "formatting", feature = "parsing"))] mod format_description; mod helpers; mod offset; #[cfg(all(feature = "serde", any(feature = "formatting", feature = "parsing")))] mod serde_format_description; mod time; mod to_tokens;
#[cfg(any(feature = "formatting", feature = "parsing"))] use std::iter::Peekable;
use proc_macro::TokenStream; #[cfg(any(feature = "formatting", feature = "parsing"))] use proc_macro::{Ident, TokenTree};
#[cfg(any(feature = "formatting", feature = "parsing"))] #[proc_macro] pubfn format_description(input: TokenStream) -> TokenStream {
(|| { letmut 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_with_version(version, &string, span)?;
// 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)?;
// Then, the type to create serde serializers for (e.g., `OffsetDateTime`). let formattable = match tokens.next() {
Some(tree @ TokenTree::Ident(_)) => Ok(tree),
Some(tree) => Err(Error::UnexpectedToken { tree }),
None => Err(Error::UnexpectedEndOfInput),
}?;
// Another comma
helpers::consume_punct(',', &mut tokens)?;
// We now have two options. The user can either provide a format description as a string or // they can provide a path to a format description. If the latter, all remaining tokens are // assumed to be part of the path. let (format, format_description_display) = match tokens.peek() { // string literal
Some(TokenTree::Literal(_)) => { 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! { const ITEMS: &[::time::format_description::BorrowedFormatItem<'_>]
= &[#S(items)];
ITEMS
};
(items, String::from_utf8_lossy(&format_string).into_owned())
} // path
Some(_) => { let tokens = tokens.collect::<TokenStream>(); let tokens_string = tokens.to_string();
(
quote! {{ // We can't just do `super::path` because the path could be an absolute // path. In that case, we'd be generating `super::::path`, which is invalid. // Even if we took that into account, it's not possible to know if it's an // external crate, which would just require emitting `path` directly. By // taking this approach, we can leave it to the compiler to do the actual // resolution. mod __path_hack { pub(super) usesuper::super::*; pub(super) use#S(tokens) as FORMAT;
}
__path_hack::FORMAT
}},
tokens_string,
)
}
None => return Err(Error::UnexpectedEndOfInput),
};
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.