use crate::generate::PushParseError;
use crate::generate::StreamBuilder;
use crate::prelude::*;
use std::fmt;
#[derive(Debug)]
pub enum Error {
UnknownDataType(Span),
InvalidRustSyntax {
span: Span,
expected: String,
},
ExpectedIdent(Span),
PushParse {
span: Option<Span>,
error: PushParseError,
},
Custom {
error: String,
span: Option<Span>,
},
}
impl From<PushParseError> for Error {
fn from(e: PushParseError) -> Self {
Self::PushParse { span: None, error: e }
}
}
impl Error {
pub fn custom(s: impl Into<String>) -> Self {
Self::Custom {
error: s.into(),
span: None,
}
}
pub fn custom_at(
s: impl Into<String>,
span: Span,
) -> Self {
Self::Custom {
error: s.into(),
span: Some(span),
}
}
#[allow(clippy::needless_pass_by_value)]
pub fn custom_at_token(
s: impl Into<String>,
token: TokenTree,
) -> Self {
Self::Custom {
error: s.into(),
span: Some(token.span()),
}
}
pub fn custom_at_opt_token(
s: impl Into<String>,
token: Option<TokenTree>,
) -> Self {
Self::Custom {
error: s.into(),
span: token.map(|t| t.span()),
}
}
pub(crate) fn wrong_token<T>(
token: Option<&TokenTree>,
expected: &str,
) -> Result<T> {
Err(Self::InvalidRustSyntax {
span: token.map_or_else(Span::call_site, TokenTree::span),
expected: format!("{expected}, got {token:?}"),
})
}
#[must_use]
#[allow(clippy::match_same_arms)]
pub const fn with_span(
mut self,
new_span: Span,
) -> Self {
match &mut self {
| Self::UnknownDataType(span) => *span = new_span,
| Self::InvalidRustSyntax { span, .. } => *span = new_span,
| Self::ExpectedIdent(span) => *span = new_span,
| Self::PushParse { span, .. } => {
*span = Some(new_span);
},
| Self::Custom { span, .. } => *span = Some(new_span),
}
self
}
}
#[cfg(test)]
impl Error {
pub fn is_unknown_data_type(&self) -> bool {
matches!(self, Error::UnknownDataType(_))
}
pub fn is_invalid_rust_syntax(&self) -> bool {
matches!(self, Error::InvalidRustSyntax { .. })
}
}
impl fmt::Display for Error {
fn fmt(
&self,
fmt: &mut fmt::Formatter<'_>,
) -> fmt::Result {
match self {
| Self::UnknownDataType(_) => {
write!(fmt, "Unknown data type, only enum and struct are supported")
},
| Self::InvalidRustSyntax { expected, .. } => {
write!(fmt, "Invalid rust syntax, expected {expected}")
},
| Self::ExpectedIdent(_) => write!(fmt, "Expected ident"),
| Self::PushParse { error, .. } => {
write!(
fmt,
"Invalid code passed to `StreamBuilder::push_parsed`: {error:?}"
)
},
| Self::Custom { error, .. } => write!(fmt, "{error}"),
}
}
}
impl Error {
pub fn into_token_stream(self) -> TokenStream {
let maybe_span = match &self {
| Self::UnknownDataType(span)
| Self::ExpectedIdent(span)
| Self::InvalidRustSyntax { span, .. } => Some(*span),
| Self::Custom { span, .. } | Self::PushParse { span, .. } => *span,
};
self.throw_with_span(maybe_span.unwrap_or_else(Span::call_site))
}
#[must_use]
pub fn throw_with_span(
self,
span: Span,
) -> TokenStream {
let mut builder = StreamBuilder::new();
builder.ident_str("compile_error");
builder.punct('!');
builder
.group(Delimiter::Brace, |b| {
b.lit_str(self.to_string());
Ok(())
})
.unwrap();
builder.set_span_on_all_tokens(span);
builder.stream
}
}