1use crate::{
2 generate::{PushParseError, StreamBuilder},
3 prelude::*,
4};
5use std::fmt;
6
7#[derive(Debug)]
9pub enum Error {
10 UnknownDataType(Span),
14
15 InvalidRustSyntax {
20 span: Span,
22 expected: String,
24 },
25
26 ExpectedIdent(Span),
28
29 PushParse {
33 span: Option<Span>,
35 error: PushParseError,
37 },
38
39 Custom {
41 error: String,
43 span: Option<Span>,
45 },
46}
47
48impl From<PushParseError> for Error {
49 fn from(e: PushParseError) -> Self {
50 Self::PushParse {
51 span: None,
52 error: e,
53 }
54 }
55}
56
57impl Error {
58 pub fn custom(s: impl Into<String>) -> Self {
60 Self::Custom {
61 error: s.into(),
62 span: None,
63 }
64 }
65
66 pub fn custom_at(s: impl Into<String>, span: Span) -> Self {
68 Self::Custom {
69 error: s.into(),
70 span: Some(span),
71 }
72 }
73
74 pub fn custom_at_token(s: impl Into<String>, token: TokenTree) -> Self {
76 Self::Custom {
77 error: s.into(),
78 span: Some(token.span()),
79 }
80 }
81
82 pub fn custom_at_opt_token(s: impl Into<String>, token: Option<TokenTree>) -> Self {
84 Self::Custom {
85 error: s.into(),
86 span: token.map(|t| t.span()),
87 }
88 }
89
90 pub(crate) fn wrong_token<T>(token: Option<&TokenTree>, expected: &str) -> Result<T> {
91 Err(Self::InvalidRustSyntax {
92 span: token.map(|t| t.span()).unwrap_or_else(Span::call_site),
93 expected: format!("{}, got {:?}", expected, token),
94 })
95 }
96
97 pub fn with_span(mut self, new_span: Span) -> Self {
99 match &mut self {
100 Error::UnknownDataType(span) => *span = new_span,
101 Error::InvalidRustSyntax { span, .. } => *span = new_span,
102 Error::ExpectedIdent(span) => *span = new_span,
103 Error::PushParse { span, .. } => {
104 *span = Some(new_span);
105 }
106 Error::Custom { span, .. } => *span = Some(new_span),
107 }
108
109 self
110 }
111}
112
113#[cfg(test)]
115impl Error {
116 pub fn is_unknown_data_type(&self) -> bool {
117 matches!(self, Error::UnknownDataType(_))
118 }
119
120 pub fn is_invalid_rust_syntax(&self) -> bool {
121 matches!(self, Error::InvalidRustSyntax { .. })
122 }
123}
124
125impl fmt::Display for Error {
126 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
127 match self {
128 Self::UnknownDataType(_) => {
129 write!(fmt, "Unknown data type, only enum and struct are supported")
130 }
131 Self::InvalidRustSyntax { expected, .. } => {
132 write!(fmt, "Invalid rust syntax, expected {}", expected)
133 }
134 Self::ExpectedIdent(_) => write!(fmt, "Expected ident"),
135 Self::PushParse { error, .. } => write!(
136 fmt,
137 "Invalid code passed to `StreamBuilder::push_parsed`: {:?}",
138 error
139 ),
140 Self::Custom { error, .. } => write!(fmt, "{}", error),
141 }
142 }
143}
144
145impl Error {
146 pub fn into_token_stream(self) -> TokenStream {
148 let maybe_span = match &self {
149 Self::UnknownDataType(span)
150 | Self::ExpectedIdent(span)
151 | Self::InvalidRustSyntax { span, .. } => Some(*span),
152 Self::Custom { span, .. } | Self::PushParse { span, .. } => *span,
153 };
154 self.throw_with_span(maybe_span.unwrap_or_else(Span::call_site))
155 }
156
157 pub fn throw_with_span(self, span: Span) -> TokenStream {
159 let mut builder = StreamBuilder::new();
161 builder.ident_str("compile_error");
162 builder.punct('!');
163 builder
164 .group(Delimiter::Brace, |b| {
165 b.lit_str(self.to_string());
166 Ok(())
167 })
168 .unwrap();
169 builder.set_span_on_all_tokens(span);
170 builder.stream
171 }
172}