error_enum_macros/
lib.rs

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