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 {
118 matches!(self, Error::UnknownDataType(_))
119 }
120
121 pub fn is_invalid_rust_syntax(&self) -> bool {
123 matches!(self, Error::InvalidRustSyntax { .. })
124 }
125}
126
127impl fmt::Display for Error {
128 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
129 match self {
130 Self::UnknownDataType(_) => {
131 write!(fmt, "Unknown data type, only enum and struct are supported")
132 }
133 Self::InvalidRustSyntax { expected, .. } => {
134 write!(fmt, "Invalid rust syntax, expected {}", expected)
135 }
136 Self::ExpectedIdent(_) => write!(fmt, "Expected ident"),
137 Self::PushParse { error, .. } => write!(
138 fmt,
139 "Invalid code passed to `StreamBuilder::push_parsed`: {:?}",
140 error
141 ),
142 Self::Custom { error, .. } => write!(fmt, "{}", error),
143 }
144 }
145}
146
147impl Error {
148 pub fn into_token_stream(self) -> TokenStream {
150 let maybe_span = match &self {
151 Self::UnknownDataType(span)
152 | Self::ExpectedIdent(span)
153 | Self::InvalidRustSyntax { span, .. } => Some(*span),
154 Self::Custom { span, .. } | Self::PushParse { span, .. } => *span,
155 };
156 self.throw_with_span(maybe_span.unwrap_or_else(Span::call_site))
157 }
158
159 pub fn throw_with_span(self, span: Span) -> TokenStream {
161 let mut builder = StreamBuilder::new();
163 builder.ident_str("compile_error");
164 builder.punct('!');
165 builder
166 .group(Delimiter::Brace, |b| {
167 b.lit_str(self.to_string());
168 Ok(())
169 })
170 .unwrap();
171 builder.set_span_on_all_tokens(span);
172 builder.stream
173 }
174}