1#![warn(unused_crate_dependencies)]
9
10use either::Either;
11use lazy_regex::{lazy_regex, Lazy, Regex};
12use proc_macro::TokenStream;
13use proc_macro2::{Span, TokenStream as TokenStream2};
14use quote::{format_ident, quote, ToTokens};
15use syn::{
16 braced,
17 parse::{self, Parse},
18 parse_macro_input,
19 punctuated::{self, Punctuated},
20 token::{self, Brace},
21 Attribute, DeriveInput, Error, Fields, Generics, Ident, LitStr, Result, Token, Variant,
22 Visibility,
23};
24
25#[cfg(test)]
26mod tests;
27
28type Tuple4<T> = (T, T, T, T);
33
34fn split_fields_attrs(fields: &mut Fields) -> Result<Option<Ident>> {
35 let mut span_ident = None;
36 for (idx, field) in fields.iter_mut().enumerate() {
37 for attr in &field.attrs {
38 if attr.meta.path().is_ident("diag") {
39 attr.parse_nested_meta(|meta| {
40 if meta.path.is_ident("span") {
41 span_ident = Some(field.ident.clone().unwrap_or(format_ident!("_{idx}")))
42 }
43 Ok(())
44 })?
45 }
46 }
47 field.attrs.retain(|attr| !attr.path().is_ident("diag"));
48 }
49 Ok(span_ident)
50}
51
52enum ErrorTree {
54 Prefix {
56 span: Span,
57 attrs: Vec<Attribute>,
58 nodes: Punctuated<ErrorTree, Token![,]>,
59 },
60 Variant {
64 span: Span,
65 attrs: Vec<Attribute>,
66 span_ident: Option<Ident>,
67 ident: Ident,
68 fields: Fields,
69 },
70}
71
72impl ErrorTree {
73 fn attrs(&self) -> &[Attribute] {
74 match self {
75 ErrorTree::Prefix { attrs, .. } => attrs,
76 ErrorTree::Variant { attrs, .. } => attrs,
77 }
78 }
79 fn ident(&self) -> Option<&Ident> {
80 match self {
81 ErrorTree::Prefix { .. } => None,
82 ErrorTree::Variant { ident, .. } => Some(ident),
83 }
84 }
85 fn fields(&self) -> Option<&Fields> {
86 match self {
87 ErrorTree::Prefix { .. } => None,
88 ErrorTree::Variant { fields, .. } => Some(fields),
89 }
90 }
91 fn span_ident(&self) -> Option<Ident> {
92 match self {
93 ErrorTree::Prefix { .. } => None,
94 ErrorTree::Variant { span_ident, .. } => span_ident.clone(),
95 }
96 }
97 fn span(&self) -> Span {
98 match self {
99 ErrorTree::Prefix { span, .. } => *span,
100 ErrorTree::Variant { span, .. } => *span,
101 }
102 }
103}
104
105impl Parse for ErrorTree {
106 fn parse(input: parse::ParseStream) -> syn::Result<Self> {
108 let attrs = input.call(Attribute::parse_outer)?;
109
110 if input.peek(Ident) {
111 let ident: Ident = input.parse()?;
112 let mut fields = if input.peek(token::Brace) {
113 Fields::Named(input.parse()?)
114 } else if input.peek(token::Paren) {
115 Fields::Unnamed(input.parse()?)
116 } else {
117 Fields::Unit
118 };
119 let span_ident = split_fields_attrs(&mut fields)?;
120 Ok(ErrorTree::Variant {
121 span: ident.span(),
122 attrs,
123 span_ident,
124 ident,
125 fields,
126 })
127 } else {
128 let span = input.span();
129 let children;
130 braced!(children in input);
131 let nodes = Punctuated::parse_terminated(&children)?;
132 Ok(ErrorTree::Prefix { span, attrs, nodes })
133 }
134 }
135}
136
137#[derive(Clone, Copy, Default)]
138enum Kind {
139 #[default]
140 Error,
141 Warn,
142}
143
144impl Kind {
145 fn short_str(&self) -> &'static str {
146 match self {
147 Kind::Error => "E",
148 Kind::Warn => "W",
149 }
150 }
151}
152
153impl TryFrom<LitStr> for Kind {
154 type Error = Error;
155
156 fn try_from(value: LitStr) -> Result<Self> {
157 match value.value().as_str() {
158 "error" | "Error" => Ok(Kind::Error),
159 "warn" | "Warn" => Ok(Kind::Warn),
160 _ => Err(Error::new_spanned(
161 value,
162 "Kind must be either `Error` or `Warn`.",
163 )),
164 }
165 }
166}
167
168impl ToTokens for Kind {
169 fn to_tokens(&self, tokens: &mut TokenStream2) {
170 let kind = match self {
171 Kind::Error => quote! { ::error_enum::Kind::Error },
172 Kind::Warn => quote! { ::error_enum::Kind::Warn },
173 };
174 tokens.extend(kind);
175 }
176}
177
178#[derive(Clone)]
180struct Config {
181 kind: Option<Kind>,
182 number: String,
183 msg: Option<LitStr>,
184 attrs: Vec<Attribute>,
185 ident: Option<Ident>,
186 fields: Option<Fields>,
187 span_field: Option<Ident>,
188 label: Option<LitStr>,
189 depth: usize,
190 nested: bool,
191 #[expect(unused)]
192 span: Span,
193}
194
195impl Config {
196 const fn new(span: Span) -> Self {
197 Self {
198 kind: None,
199 number: String::new(),
200 msg: None,
201 attrs: Vec::new(),
202 ident: None,
203 fields: None,
204 span_field: None,
205 label: None,
206 depth: 0,
207 nested: false,
208 span,
209 }
210 }
211 fn process(
212 &self,
213 attrs: &[Attribute],
214 ident: Option<&Ident>,
215 fields: Option<&Fields>,
216 span_field: Option<Ident>,
217 span: Span,
218 ) -> Result<Self> {
219 let mut kind = self.kind;
220 let mut number = self.number.clone();
221 let mut msg = self.msg.clone();
222 let mut label = self.label.clone();
223 let depth = self.depth + 1;
224 let mut nested = self.nested;
225 let mut unused_attrs = Vec::new();
226
227 for attr in attrs {
228 if attr.path().is_ident("diag") {
229 attr.parse_nested_meta(|meta| {
230 if meta.path.is_ident("kind") {
231 let value: LitStr = meta.value()?.parse()?;
232 kind = Some(value.try_into()?);
233 } else if meta.path.is_ident("number") {
234 let value: LitStr = meta.value()?.parse()?;
235 number.push_str(value.value().as_str());
236 } else if meta.path.is_ident("msg") {
237 let value: LitStr = meta.value()?.parse()?;
238 msg = Some(value);
239 } else if meta.path.is_ident("label") {
240 let value: LitStr = meta.value()?.parse()?;
241 label = Some(value);
242 } else if meta.path.is_ident("nested") {
243 nested = true;
244 } else {
245 return Err(Error::new_spanned(meta.path, "Unknown attribute key."));
246 }
247 Ok(())
248 })?
249 } else {
250 unused_attrs.push(attr.clone());
251 }
252 }
253
254 let ident = ident.cloned();
255 let fields = fields.cloned();
256 Ok(Self {
257 kind,
258 number,
259 msg,
260 attrs: unused_attrs,
261 ident,
262 fields,
263 span_field,
264 label,
265 depth,
266 nested,
267 span,
268 })
269 }
270}
271
272struct ErrorTreeIter<'i> {
273 stack: Vec<(punctuated::Iter<'i, ErrorTree>, Config)>,
274}
275
276impl<'i> ErrorTreeIter<'i> {
277 fn new(tree: punctuated::Iter<'i, ErrorTree>, config: Config) -> Result<Self> {
278 Ok(Self {
279 stack: vec![(tree, config)],
280 })
281 }
282 fn process_next(node: &'i ErrorTree, config: &Config, span: Span) -> Result<Config> {
283 let new_config = config.process(
284 node.attrs(),
285 node.ident(),
286 node.fields(),
287 node.span_ident(),
288 span,
289 )?;
290 Ok(new_config)
291 }
292}
293
294impl<'i> Iterator for ErrorTreeIter<'i> {
295 type Item = Result<Config>;
296
297 fn next(&mut self) -> Option<Self::Item> {
298 while let Some((slice, config)) = self.stack.last_mut() {
299 if let Some(node) = slice.next() {
300 let config = Self::process_next(node, config, node.span())
301 .map(Some)
302 .transpose()?;
303 if let Ok(config) = &config {
304 if let ErrorTree::Prefix { nodes, .. } = node {
305 self.stack.push((nodes.iter(), config.clone()));
306 }
307 }
308 return Some(config);
309 } else {
310 self.stack.pop();
311 }
312 }
313 None
314 }
315}
316
317enum ErrorEnumInner {
318 Multiple {
319 brace: Brace,
320 roots: Punctuated<ErrorTree, Token![,]>,
321 body: bool,
322 },
323 Single {
324 node: ErrorTree,
325 },
326}
327
328impl ErrorEnumInner {
329 fn iter(&self, config: Config) -> Result<impl Iterator<Item = Result<Config>> + '_> {
330 match self {
331 ErrorEnumInner::Multiple { roots, .. } => {
332 Ok(Either::Left(ErrorTreeIter::new(roots.iter(), config)?))
333 }
334 ErrorEnumInner::Single { node } => {
335 let iter = Either::Right(std::iter::once(ErrorTreeIter::process_next(
336 node,
337 &config,
338 node.span(),
339 )));
340 Ok(iter)
341 }
342 }
343 }
344}
345
346struct ErrorEnum {
354 attrs: Vec<Attribute>,
355 vis: Visibility,
356 name: Ident,
357 generics: Generics,
358 inner: ErrorEnumInner,
359 config: Config,
360}
361
362impl ErrorEnum {
363 fn iter(&self) -> Result<impl Iterator<Item = Result<Config>> + '_> {
364 self.inner.iter(self.config.clone())
365 }
366 fn is_enum(&self) -> bool {
367 matches!(self.inner, ErrorEnumInner::Multiple { .. })
368 }
369}
370
371impl Parse for ErrorEnum {
372 fn parse(input: parse::ParseStream) -> syn::Result<Self> {
373 let mut attrs = input.call(Attribute::parse_outer)?;
374 let vis = input.parse()?;
375 let name: Ident = input.parse()?;
376 let generics = input.parse()?;
377 let children;
378 let brace = braced!(children in input);
379 let config = Config::new(name.span()).process(&attrs, None, None, None, name.span())?;
380 attrs.retain(|attr| !attr.path().is_ident("diag"));
381
382 let roots = Punctuated::parse_terminated(&children)?;
383 let inner = ErrorEnumInner::Multiple {
384 body: true,
385 brace,
386 roots,
387 };
388 Ok(Self {
389 attrs,
390 vis,
391 generics,
392 name,
393 inner,
394 config,
395 })
396 }
397}
398
399impl TryFrom<DeriveInput> for ErrorEnum {
400 type Error = Error;
401
402 fn try_from(value: DeriveInput) -> Result<Self> {
403 let DeriveInput {
404 mut attrs,
405 vis,
406 ident,
407 generics,
408 data,
409 } = value;
410 match data {
411 syn::Data::Enum(data_enum) => {
412 let mut roots = Punctuated::new();
413 for pair in data_enum.variants.into_pairs() {
414 let (mut variant, comma) = pair.into_tuple();
415 let span = variant.ident.span();
416 let span_ident = split_fields_attrs(&mut variant.fields)?;
417 let node = ErrorTree::Variant {
418 span,
419 attrs: variant.attrs,
420 ident: variant.ident,
421 fields: variant.fields,
422 span_ident,
423 };
424 roots.push_value(node);
425 if let Some(comma) = comma {
426 roots.push_punct(comma);
427 }
428 }
429 let config =
430 Config::new(ident.span()).process(&attrs, None, None, None, ident.span())?;
431 attrs.retain(|attr| !attr.path().is_ident("diag"));
432
433 let inner = ErrorEnumInner::Multiple {
434 body: false,
435 brace: data_enum.brace_token,
436 roots,
437 };
438 Ok(Self {
439 attrs,
440 vis,
441 name: ident,
442 generics,
443 inner,
444 config,
445 })
446 }
447 syn::Data::Struct(mut data_struct) => {
448 let span = ident.span();
449 let span_ident = split_fields_attrs(&mut data_struct.fields)?;
450 let config =
451 Config::new(ident.span()).process(&attrs, None, None, None, ident.span())?;
452 attrs.retain(|attr| !attr.path().is_ident("diag"));
453
454 let node = ErrorTree::Variant {
455 span,
456 attrs,
457 ident: ident.clone(),
458 fields: data_struct.fields,
459 span_ident,
460 };
461
462 let inner = ErrorEnumInner::Single { node };
463
464 Ok(Self {
465 attrs: Vec::new(),
466 vis,
467 name: ident,
468 generics,
469 inner,
470 config,
471 })
472 }
473 _ => Err(Error::new_spanned(
474 ident,
475 "ErrorEnum can only be derived for enums or structs.",
476 )),
477 }
478 }
479}
480
481impl ErrorEnum {
482 fn variant<'a>(&'a self, ident: &'a Ident) -> impl ToTokens + 'a {
483 struct VariantPrefix<'a> {
484 ident: &'a Ident,
485 is_enum: bool,
486 }
487 impl<'a> ToTokens for VariantPrefix<'a> {
488 fn to_tokens(&self, tokens: &mut TokenStream2) {
489 let ident = self.ident;
490 if self.is_enum {
491 tokens.extend(quote! { Self::#ident });
492 } else {
493 tokens.extend(quote! { Self });
494 }
495 }
496 }
497
498 VariantPrefix {
499 ident,
500 is_enum: self.is_enum(),
501 }
502 }
503 fn doc(&self) -> Result<Vec<String>> {
504 self.iter()?
505 .map(|config| {
506 let Config {
507 number,
508 depth,
509 ident,
510 msg,
511 kind,
512 ..
513 } = config?;
514 let indent = " ".repeat(depth - 2);
515 let msg = msg.as_ref().map(|s| s.value());
516 let kind = kind.unwrap_or_default().short_str();
517 Ok(match (ident, msg) {
518 (Some(ident), Some(msg)) => {
519 format!("{indent}- `{kind}{number}`(**{ident}**): {msg}")
520 }
521 (None, Some(msg)) => format!("{indent}- `{kind}{number}`: {msg}"),
522 (Some(ident), None) => format!("{indent}- `{kind}{number}`(**{ident}**)"),
523 (None, None) => format!("{indent}- `{kind}{number}`"),
524 })
525 })
526 .collect()
527 }
528 fn variants(&self) -> Result<Vec<Variant>> {
529 self.iter()?
530 .filter_map(|config| {
531 config
532 .map(
533 |Config {
534 kind,
535 msg,
536 number,
537 attrs,
538 ident,
539 fields,
540 ..
541 }| {
542 Some((kind, msg, number, attrs, ident?, fields?))
543 },
544 )
545 .transpose()
546 })
547 .map(|config| {
548 let (kind, msg, number, mut attrs, ident, fields) = config?;
549
550 let kind = kind.unwrap_or_default();
551 let code = format!("{}{}", kind.short_str(), number);
552
553 let doc = match msg {
554 Some(msg) => {
555 format!("`{code}`: {msg}", msg = msg.value())
556 }
557 None => format!("`{code}`"),
558 };
559
560 attrs.push(syn::parse_quote! {
561 #[doc = #doc]
562 });
563 attrs.push(syn::parse_quote! {
564 #[doc(alias = #code)]
565 });
566
567 Ok(Variant {
568 attrs,
569 ident,
570 fields,
571 discriminant: None,
572 })
573 })
574 .collect()
575 }
576 fn used_unnamed_fields(msg: &LitStr) -> Result<Vec<Ident>> {
577 static ARG: Lazy<Regex> = lazy_regex!(r#"(^|[^\{])(\{\{)*\{(?<index>\d+)(:[^\{\}]*)?\}"#);
578 ARG.captures_iter(msg.value().as_str())
579 .map(|cap| {
580 let index = cap
581 .name("index")
582 .ok_or_else(|| Error::new_spanned(msg, "Invalid argument index."))?
583 .as_str()
584 .parse::<usize>()
585 .map_err(|err| {
586 Error::new_spanned(msg, format!("Invalid argument index: {err}"))
587 })?;
588 Ok(format_ident!("_{}", index))
589 })
590 .collect()
591 }
592 fn display_branch(&self, ident: &Ident, fields: &Fields, msg: &LitStr) -> Result<TokenStream2> {
593 let prefix = self.variant(ident);
594 match fields {
595 Fields::Named(named) => {
596 let members = named.named.iter().map(|f| f.ident.as_ref());
597 Ok(quote! {
598 #[allow(unused_variables)]
599 #prefix { #(#members),* } => ::core::write!(f, #msg),
600 })
601 }
602 Fields::Unnamed(unnamed) => {
603 let params = (0..unnamed.unnamed.len()).map(|i| format_ident!("_{}", i));
604 let args = Self::used_unnamed_fields(msg)?;
605 Ok(quote! {
606 #prefix ( #(#params),* ) => ::core::write!(f, #msg #(, #args)* ),
607 })
608 }
609 Fields::Unit => Ok(quote! {
610 #prefix => ::core::write!(f, #msg),
611 }),
612 }
613 }
614 fn display(&self) -> Result<Vec<TokenStream2>> {
615 self.iter()?
616 .filter_map(|config| {
617 config
618 .map(
619 |Config {
620 msg, ident, fields, ..
621 }| { Some((msg, ident?, fields?)) },
622 )
623 .transpose()
624 })
625 .map(|config| {
626 let (msg, ident, fields) = config?;
627 let msg = msg.ok_or_else(|| {
628 Error::new_spanned(
629 &ident,
630 "Missing message. Consider using `#[diag(msg = \"...\")]`",
631 )
632 })?;
633 self.display_branch(&ident, &fields, &msg)
634 })
635 .collect()
636 }
637 fn primary_label_branch(
638 &self,
639 ident: &Ident,
640 fields: &Fields,
641 label: &LitStr,
642 ) -> Result<TokenStream2> {
643 let prefix = self.variant(ident);
644 match fields {
645 Fields::Named(named) => {
646 let members = named.named.iter().map(|f| f.ident.as_ref());
647 Ok(quote! {
648 #[allow(unused_variables)]
649 #prefix { #(#members),* } => ::std::format!(#label),
650 })
651 }
652 Fields::Unnamed(unnamed) => {
653 let params = (0..unnamed.unnamed.len()).map(|i| format_ident!("_{}", i));
654 let args = Self::used_unnamed_fields(label)?;
655 Ok(quote! {
656 #prefix ( #(#params),* ) => ::std::format!(#label #(, #args)* ),
657 })
658 }
659 Fields::Unit => Ok(quote! {
660 #prefix => ::std::format!(#label),
661 }),
662 }
663 }
664 fn primary_label(&self) -> Result<Vec<TokenStream2>> {
665 self.iter()?
666 .filter_map(|config| {
667 config
668 .map(
669 |Config {
670 msg,
671 ident,
672 fields,
673 label,
674 ..
675 }| { Some((msg, ident?, fields?, label)) },
676 )
677 .transpose()
678 })
679 .map(|config| {
680 let (msg, ident, fields, label) = config?;
681 let label = label.or(msg).ok_or_else(|| {
682 Error::new_spanned(
683 &ident,
684 "Missing label or message. Consider using `#[diag(label = \"...\")]`",
685 )
686 })?;
687 self.primary_label_branch(&ident, &fields, &label)
688 })
689 .collect()
690 }
691 fn impl_error_enum_branch(
692 &self,
693 ident: &Ident,
694 fields: &Fields,
695 span_field: Option<Ident>,
696 kind: &Kind,
697 number: &str,
698 ) -> Result<Tuple4<TokenStream2>> {
699 let branch_ignored = match fields {
700 Fields::Named(_) => quote! { { .. } },
701 Fields::Unnamed(_) => quote! { (..) },
702 Fields::Unit => quote! {},
703 };
704 let code = format!("{}{}", kind.short_str(), number);
705
706 let prefix = self.variant(ident);
707
708 let kind = quote! {
709 #prefix #branch_ignored => #kind,
710 };
711 let number = quote! {
712 #prefix #branch_ignored => #number,
713 };
714 let code = quote! {
715 #prefix #branch_ignored => #code,
716 };
717 let span = if let Some(span_field) = span_field {
718 quote! {<::error_enum::SimpleSpan as ::core::convert::From<_>>::from(#span_field)}
719 } else {
720 quote! {<::error_enum::SimpleSpan as ::core::default::Default>::default()}
721 };
722 let primary_span = match fields {
723 Fields::Named(named) => {
724 let members = named.named.iter().map(|f| f.ident.as_ref());
725 quote! {
726 #[allow(unused_variables)]
727 #prefix { #(#members),* } => #span,
728 }
729 }
730 Fields::Unnamed(unnamed) => {
731 let params = (0..unnamed.unnamed.len()).map(|i| format_ident!("_{}", i));
732 quote! {
733 #[allow(unused_variables)]
734 #prefix ( #(#params),* ) => #span,
735 }
736 }
737 Fields::Unit => quote! {
738 #prefix => #span,
739 },
740 };
741 Ok((kind, number, code, primary_span))
742 }
743 fn impl_error_enum(&self) -> Result<Tuple4<Vec<TokenStream2>>> {
744 self.iter()?
745 .filter_map(|config| {
746 config
747 .map(
748 |Config {
749 ident,
750 fields,
751 span_field,
752 kind,
753 number,
754 ..
755 }| {
756 Some((ident?, fields?, span_field, kind, number))
757 },
758 )
759 .transpose()
760 })
761 .map(|config| {
762 let (ident, fields, span_field, kind, number) = config?;
763 let kind = kind.unwrap_or_default();
764 self.impl_error_enum_branch(&ident, &fields, span_field, &kind, &number)
765 })
766 .collect()
767 }
768 fn try_to_tokens(&self, tokens: &mut TokenStream2) -> Result<()> {
769 let attrs = &self.attrs;
770 let vis = &self.vis;
771 let name = &self.name;
772 let generics = &self.generics;
773
774 let doc = self.doc()?;
775
776 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
777
778 let variants = self.variants()?;
779
780 if let ErrorEnumInner::Multiple {
781 body: true, brace, ..
782 } = self.inner
783 {
784 tokens.extend(quote! {
785 #(#attrs)*
786 #[doc = "List of error variants:"]
787 #(
788 #[doc = #doc]
789 )*
790 #vis enum #name #generics
791 });
792 brace.surround(tokens, |tokens| {
793 tokens.extend(quote! { #(#variants, )* });
794 });
795 }
796
797 let display = self.display()?;
798 tokens.extend(quote! {
799 impl #impl_generics ::core::fmt::Display for #name #ty_generics #where_clause {
800 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
801 match self {
802 #(#display)*
803 }
804 }
805 }
806 impl #impl_generics ::core::error::Error for #name #ty_generics #where_clause {}
807 });
808
809 let (kind, number, code, primary_span) = self.impl_error_enum()?;
810 let primary_label = self.primary_label()?;
811 tokens.extend(quote! {
812 impl #impl_generics ::error_enum::ErrorType for #name #ty_generics #where_clause {
813 type Span = ::error_enum::SimpleSpan;
814 type Message = ::std::string::String;
815
816 fn kind(&self) -> ::error_enum::Kind {
817 match self {
818 #(#kind)*
819 }
820 }
821 fn number(&self) -> &::core::primitive::str {
822 match self {
823 #(#number)*
824 }
825 }
826 fn code(&self) -> &::core::primitive::str {
827 match self {
828 #(#code)*
829 }
830 }
831 fn primary_span(&self) -> ::error_enum::SimpleSpan {
832 match self {
833 #(#primary_span)*
834 }
835 }
836 fn primary_message(&self) -> ::std::string::String {
837 ::std::format!("{self}")
838 }
839 fn primary_label(&self) -> ::std::string::String {
840 match self {
841 #(#primary_label)*
842 }
843 }
844 }
845 });
846
847 Ok(())
848 }
849}
850
851impl ToTokens for ErrorEnum {
852 fn to_tokens(&self, tokens: &mut TokenStream2) {
853 let mut buffer = TokenStream2::new();
854 self.try_to_tokens(&mut buffer)
855 .inspect(|()| tokens.extend(buffer))
856 .unwrap_or_else(|err| {
857 let diag = err.to_compile_error();
858 tokens.extend(diag);
859 });
860 }
861}
862
863#[proc_macro]
906pub fn error_type(token: TokenStream) -> TokenStream {
907 let error = parse_macro_input!(token as ErrorEnum);
908 error.to_token_stream().into()
909}
910
911#[proc_macro_derive(ErrorType, attributes(diag))]
915pub fn error_enum(token: TokenStream) -> TokenStream {
916 let input: DeriveInput = parse_macro_input!(token as DeriveInput);
917 let error = ErrorEnum::try_from(input)
918 .map_or_else(|err| err.to_compile_error(), |e| e.to_token_stream());
919 error.into()
920}