diff options
Diffstat (limited to 'vendor/time-macros/src/error.rs')
-rw-r--r-- | vendor/time-macros/src/error.rs | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/vendor/time-macros/src/error.rs b/vendor/time-macros/src/error.rs new file mode 100644 index 000000000..4de369daf --- /dev/null +++ b/vendor/time-macros/src/error.rs @@ -0,0 +1,136 @@ +use std::borrow::Cow; +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; +} + +impl WithSpan for TokenTree { + fn with_span(mut self, span: Span) -> Self { + self.set_span(span); + self + } +} + +pub(crate) enum Error { + MissingComponent { + name: &'static str, + span_start: Option<Span>, + span_end: Option<Span>, + }, + InvalidComponent { + name: &'static str, + value: String, + span_start: Option<Span>, + span_end: Option<Span>, + }, + #[cfg(any(feature = "formatting", feature = "parsing"))] + ExpectedString { + span_start: Option<Span>, + span_end: Option<Span>, + }, + UnexpectedToken { + 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>, + span_end: Option<Span>, + }, +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::MissingComponent { name, .. } => write!(f, "missing component: {name}"), + Self::InvalidComponent { name, value, .. } => { + write!(f, "invalid component: {name} was {value}") + } + #[cfg(any(feature = "formatting", feature = "parsing"))] + Self::ExpectedString { .. } => f.write_str("expected string"), + 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), + } + } +} + +impl Error { + fn span_start(&self) -> Span { + match self { + Self::MissingComponent { span_start, .. } + | 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::UnexpectedToken { tree } => Some(tree.span()), + Self::UnexpectedEndOfInput => Some(Span::mixed_site()), + } + .unwrap_or_else(Span::mixed_site) + } + + fn span_end(&self) -> Span { + match self { + Self::MissingComponent { span_end, .. } + | 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::UnexpectedToken { tree, .. } => Some(tree.span()), + Self::UnexpectedEndOfInput => Some(Span::mixed_site()), + } + .unwrap_or_else(|| self.span_start()) + } + + pub(crate) fn to_compile_error(&self) -> TokenStream { + let (start, end) = (self.span_start(), self.span_end()); + + [ + TokenTree::from(Punct::new(':', Spacing::Joint)).with_span(start), + TokenTree::from(Punct::new(':', Spacing::Alone)).with_span(start), + TokenTree::from(Ident::new("core", start)), + TokenTree::from(Punct::new(':', Spacing::Joint)).with_span(start), + TokenTree::from(Punct::new(':', Spacing::Alone)).with_span(start), + TokenTree::from(Ident::new("compile_error", start)), + TokenTree::from(Punct::new('!', Spacing::Alone)).with_span(start), + TokenTree::from(Group::new( + Delimiter::Parenthesis, + TokenStream::from( + TokenTree::from(Literal::string(&self.to_string())).with_span(end), + ), + )) + .with_span(end), + ] + .iter() + .cloned() + .collect() + } + + /// Like `to_compile_error`, but for use in macros that produce items. + #[cfg(all(feature = "serde", any(feature = "formatting", feature = "parsing")))] + pub(crate) fn to_compile_error_standalone(&self) -> TokenStream { + let end = self.span_end(); + self.to_compile_error() + .into_iter() + .chain(std::iter::once( + TokenTree::from(Punct::new(';', Spacing::Alone)).with_span(end), + )) + .collect() + } +} |