use std::borrow::Cow;
use std::fmt;
use proc_macro::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree};
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,
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 literal" ),
Self ::UnexpectedToken { tree } => write!(f, "unexpected token: {tree}" ),
Self ::UnexpectedEndOfInput => f.write_str("unexpected end of input" ),
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, .. } => *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, .. } => *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()
}
}
Messung V0.5 in Prozent C=71 H=96 G=84
¤ Dauer der Verarbeitung: 0.11 Sekunden
(vorverarbeitet am 2026-06-18)
¤
*© Formatika GbR, Deutschland