1use crate::generate::PushParseError;
2use crate::generate::StreamBuilder;
3use crate::prelude::*;
4use std::fmt;
5
6#[derive(Debug)]
8pub enum Error {
9 UnknownDataType(Span),
13
14 InvalidRustSyntax {
19 span: Span,
21 expected: String,
23 },
24
25 ExpectedIdent(Span),
27
28 PushParse {
32 span: Option<Span>,
34 error: PushParseError,
36 },
37
38 Custom {
40 error: String,
42 span: Option<Span>,
44 },
45}
46
47impl From<PushParseError> for Error {
48 fn from(e: PushParseError) -> Self {
49 Self::PushParse { span: None, error: e }
50 }
51}
52
53impl Error {
54 pub fn custom(s: impl Into<String>) -> Self {
56 Self::Custom {
57 error: s.into(),
58 span: None,
59 }
60 }
61
62 pub fn custom_at(
64 s: impl Into<String>,
65 span: Span,
66 ) -> Self {
67 Self::Custom {
68 error: s.into(),
69 span: Some(span),
70 }
71 }
72
73 #[allow(clippy::needless_pass_by_value)]
75 pub fn custom_at_token(
76 s: impl Into<String>,
77 token: TokenTree,
78 ) -> Self {
79 Self::Custom {
80 error: s.into(),
81 span: Some(token.span()),
82 }
83 }
84
85 pub fn custom_at_opt_token(
91 s: impl Into<String>,
92 token: Option<TokenTree>,
93 ) -> Self {
94 Self::Custom {
95 error: s.into(),
96 span: token.map(|t| t.span()),
97 }
98 }
99
100 pub(crate) fn wrong_token<T>(
101 token: Option<&TokenTree>,
102 expected: &str,
103 ) -> Result<T> {
104 Err(Self::InvalidRustSyntax {
105 span: token.map_or_else(Span::call_site, TokenTree::span),
106 expected: format!("{expected}, got {token:?}"),
107 })
108 }
109
110 #[must_use]
112 #[allow(clippy::match_same_arms)]
113 pub const fn with_span(
114 mut self,
115 new_span: Span,
116 ) -> Self {
117 match &mut self {
118 | Self::UnknownDataType(span) => *span = new_span,
119 | Self::InvalidRustSyntax { span, .. } => *span = new_span,
120 | Self::ExpectedIdent(span) => *span = new_span,
121 | Self::PushParse { span, .. } => {
122 *span = Some(new_span);
123 },
124 | Self::Custom { span, .. } => *span = Some(new_span),
125 }
126
127 self
128 }
129}
130
131#[cfg(test)]
133impl Error {
134 pub fn is_unknown_data_type(&self) -> bool {
139 matches!(self, Error::UnknownDataType(_))
140 }
141
142 pub fn is_invalid_rust_syntax(&self) -> bool {
148 matches!(self, Error::InvalidRustSyntax { .. })
149 }
150}
151
152impl fmt::Display for Error {
153 fn fmt(
154 &self,
155 fmt: &mut fmt::Formatter<'_>,
156 ) -> fmt::Result {
157 match self {
158 | Self::UnknownDataType(_) => {
159 write!(fmt, "Unknown data type, only enum and struct are supported")
160 },
161 | Self::InvalidRustSyntax { expected, .. } => {
162 write!(fmt, "Invalid rust syntax, expected {expected}")
163 },
164 | Self::ExpectedIdent(_) => write!(fmt, "Expected ident"),
165 | Self::PushParse { error, .. } => {
166 write!(
167 fmt,
168 "Invalid code passed to `StreamBuilder::push_parsed`: {error:?}"
169 )
170 },
171 | Self::Custom { error, .. } => write!(fmt, "{error}"),
172 }
173 }
174}
175
176impl Error {
177 pub fn into_token_stream(self) -> TokenStream {
183 let maybe_span = match &self {
184 | Self::UnknownDataType(span)
185 | Self::ExpectedIdent(span)
186 | Self::InvalidRustSyntax { span, .. } => Some(*span),
187 | Self::Custom { span, .. } | Self::PushParse { span, .. } => *span,
188 };
189 self.throw_with_span(maybe_span.unwrap_or_else(Span::call_site))
190 }
191
192 #[must_use]
198 pub fn throw_with_span(
199 self,
200 span: Span,
201 ) -> TokenStream {
202 let mut builder = StreamBuilder::new();
204 builder.ident_str("compile_error");
205 builder.punct('!');
206 builder
207 .group(Delimiter::Brace, |b| {
208 b.lit_str(self.to_string());
209 Ok(())
210 })
211 .unwrap();
212 builder.set_span_on_all_tokens(span);
213 builder.stream
214 }
215}