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