1use std::fmt::{Debug, Formatter};
4use proc_macro2::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree};
5
6pub type KeftaResult<T> = Result<T, KeftaError>;
8
9#[derive(Debug)]
11pub enum KeftaTokenError {
12 ExpectedToken { span: Span },
14 Expected {
16 expected: &'static str,
18 description: Option<&'static str>,
20 found: TokenTree
22 },
23 Message(&'static str, Span)
25}
26
27pub enum KeftaError {
29 TokenError(KeftaTokenError),
31
32 ExpectedMarker { ident: Ident },
34 ExpectedValue { ident: Ident },
36 ExpectedContainer { ident: Ident },
38
39 Expected {
41 expected: KeftaExpected,
43 span: Span,
45 },
46
47 Multiple {
49 key: String,
50 count: usize,
51 span: Span,
52 },
53
54 Required {
56 key: String,
57 multiple: bool,
58 },
59
60 Message {
62 message: String,
63 span: Option<Span>,
64 },
65
66 #[cfg(feature = "syn")]
68 Syn(syn::Error)
69}
70
71#[derive(Debug)]
73pub enum KeftaExpected {
74 Literal,
75 Punct,
76 Ident,
77 Group,
78
79 Delimiter(Delimiter),
80
81 CharLiteral,
82 StringLiteral,
83 ByteLiteral,
84 NumericLiteral,
85 BooleanLiteral,
86}
87
88
89impl Debug for KeftaError {
90 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
91 match self {
92 KeftaError::TokenError(error) => Debug::fmt(&error, f),
93 #[cfg(feature = "syn")]
94 KeftaError::Syn(x) => Debug::fmt(&x, f),
95
96 KeftaError::ExpectedMarker { ident } =>
97 f.debug_tuple("ExpectedMarker")
98 .field(ident)
99 .finish(),
100 KeftaError::ExpectedValue { ident } =>
101 f.debug_tuple("ExpectedValue")
102 .field(ident)
103 .finish(),
104 KeftaError::ExpectedContainer { ident } =>
105 f.debug_tuple("ExpectedContainer")
106 .field(ident)
107 .finish(),
108 KeftaError::Expected { expected, span } =>
109 f.debug_tuple("ExpectedValue")
110 .field(expected)
111 .field(span)
112 .finish(),
113 KeftaError::Multiple { key, .. } =>
114 f.debug_tuple("ExpectedMultiple")
115 .field(key)
116 .finish(),
117 KeftaError::Required { key, .. } =>
118 f.debug_tuple("RequiredAttr")
119 .field(key)
120 .finish(),
121 KeftaError::Message { message, .. } => Debug::fmt(&message, f)
122 }
123 }
124}
125
126impl KeftaError {
127 pub fn build(self) -> (Span, String) {
128 match self {
129 #[cfg(feature = "syn")]
130 KeftaError::Syn(e) => (e.span(), e.to_string()),
131
132 KeftaError::TokenError(error) => match error {
133 KeftaTokenError::ExpectedToken { span } =>
134 (span, "expected a token, found the end of the stream".to_string()),
135 KeftaTokenError::Expected { expected, description, found } =>
136 (found.span(), format!(
137 "expected {}{} but found {}",
138 expected,
139 match description {
140 None => ",".to_string(),
141 Some(desc) => format!(" [{}]", desc.to_string()),
142 },
143 match found {
144 TokenTree::Ident(ident) => format!("ident `{}`", ident.to_string()),
145 TokenTree::Punct(punct) => format!("a `{}` token", punct.as_char()),
146 TokenTree::Literal(literal) => format!("literal `{}`", literal),
147 TokenTree::Group(group) => format!("a `{}` group", delimiter_str(group.delimiter())),
148 },
149 )),
150 KeftaTokenError::Message(msg, span) => (span, msg.to_string())
151 },
152
153 KeftaError::ExpectedMarker { ident } =>
154 (ident.span(), "expected a `marker` type attribute".to_string()),
155 KeftaError::ExpectedValue { ident } =>
156 (ident.span(), "expected a value".to_string()),
157 KeftaError::ExpectedContainer { ident } =>
158 (ident.span(), "expected a `container` attribute".to_string()),
159
160 KeftaError::Expected { expected, span } =>
161 (span, format!(
162 "expected `{}`",
163 match expected {
164 KeftaExpected::Literal => "a literal",
165 KeftaExpected::Punct => "a punct token",
166 KeftaExpected::Ident => "an identifier",
167 KeftaExpected::Group => "a group",
168 KeftaExpected::Delimiter(_delimiter) => "a group", KeftaExpected::CharLiteral => "a character literal (char)",
170 KeftaExpected::StringLiteral => "a string literal",
171 KeftaExpected::ByteLiteral => "a byte-string literal (b\"\")",
172 KeftaExpected::NumericLiteral => "a numeric literal",
173 KeftaExpected::BooleanLiteral => "a boolean literal (true/false)"
174 }
175 )),
176
177 KeftaError::Multiple { key, count, span } =>
178 (span, format!(
179 "found {} occurrences for `{}`, but only expected one",
180 count,
181 key
182 )),
183
184 KeftaError::Required { key, .. } =>
185 (Span::call_site(), format!(
186 "the attribute `{}` is required", key
187 )),
188
189 KeftaError::Message { message, span } =>
190 (span.unwrap_or_else(|| Span::call_site()), message),
191
192 }
194 }
195
196 pub fn to_compile_error(self) -> TokenStream {
197 let (span, msg) = self.build();
199
200 TokenStream::from_iter(vec![
202 TokenTree::Ident(Ident::new("compile_error", span.clone())),
203 TokenTree::Punct({
204 let mut punct = Punct::new('!', Spacing::Alone);
205 punct.set_span(span.clone());
206 punct
207 }),
208 TokenTree::Group({
209 let mut group = Group::new(Delimiter::Brace, {
210 TokenStream::from_iter(vec![TokenTree::Literal({
211 let mut string = Literal::string(&msg);
212 string.set_span(span.clone());
213 string
214 })])
215 });
216 group.set_span(span.clone());
217 group
218 }),
219 ])
220 }
221
222 #[cfg(feature="syn")]
223 pub fn into_syn(self) -> syn::Error {
224 match self {
225 KeftaError::Syn(e) => e,
226 e @ _ => {
227 let (span, msg) = e.build();
228 syn::Error::new(span, msg)
229 }
230 }
231 }
232}
233
234#[cfg(feature="syn")]
235impl Into<syn::Error> for KeftaError {
236 fn into(self) -> syn::Error {
237 self.into_syn()
238 }
239}
240
241
242fn delimiter_str(delimiter: Delimiter) -> &'static str {
243 match delimiter {
244 Delimiter::Parenthesis => "()",
245 Delimiter::Brace => "{}",
246 Delimiter::Bracket => "[]",
247 Delimiter::None => "_",
248 }
249}