1#![recursion_limit = "128"] extern crate proc_macro;
4
5use crate::parse::attributes_from_syn;
6use proc_macro::TokenStream;
7use quote::quote;
8use std::collections::{BTreeSet, VecDeque};
9use std::fmt;
10
11mod parse;
12mod shared;
13
14#[proc_macro_derive(Snafu, attributes(snafu))]
16pub fn snafu_derive(input: TokenStream) -> TokenStream {
17 let ast = syn::parse(input).expect("Could not parse type to derive Error for");
18
19 impl_snafu_macro(ast)
20}
21
22mod report;
23#[proc_macro_attribute]
24pub fn report(attr: TokenStream, item: TokenStream) -> TokenStream {
25 report::body(attr, item)
26 .unwrap_or_else(|e| e.to_compile_error())
27 .into()
28}
29
30type MultiSynResult<T> = std::result::Result<T, Vec<syn::Error>>;
31
32type UserInput = Box<dyn quote::ToTokens>;
34
35enum ModuleName {
36 Default,
37 Custom(syn::Ident),
38}
39
40enum SnafuInfo {
41 Enum(EnumInfo),
42 NamedStruct(NamedStructInfo),
43 TupleStruct(TupleStructInfo),
44}
45
46struct EnumInfo {
47 crate_root: UserInput,
48 name: syn::Ident,
49 generics: syn::Generics,
50 variants: Vec<FieldContainer>,
51 default_visibility: Option<UserInput>,
52 default_suffix: SuffixKind,
53 module: Option<ModuleName>,
54}
55
56struct FieldContainer {
58 name: syn::Ident,
59 backtrace_field: Option<Field>,
60 implicit_fields: Vec<Field>,
61 selector_kind: ContextSelectorKind,
62 display_format: Option<Display>,
63 doc_comment: Option<DocComment>,
64 visibility: Option<UserInput>,
65 module: Option<ModuleName>,
66 provides: Vec<Provide>,
67 is_transparent: bool,
68}
69
70impl FieldContainer {
71 fn user_fields(&self) -> &[Field] {
72 self.selector_kind.user_fields()
73 }
74
75 fn provides(&self) -> &[Provide] {
76 &self.provides
77 }
78}
79
80struct Provide {
81 is_chain: bool,
82 is_opt: bool,
83 is_priority: bool,
84 is_ref: bool,
85 ty: syn::Type,
86 expr: syn::Expr,
87}
88
89enum SuffixKind {
90 Default,
91 None,
92 Some(syn::Ident),
93}
94
95impl SuffixKind {
96 fn resolve_with_default<'a>(&'a self, def: &'a Self) -> &'a Self {
97 use SuffixKind::*;
98
99 match self {
100 Default => def,
101 None => self,
102 Some(_) => self,
103 }
104 }
105}
106
107enum ContextSelectorKind {
108 Context {
109 suffix: SuffixKind,
110 source_field: Option<SourceField>,
111 user_fields: Vec<Field>,
112 },
113
114 Whatever {
115 source_field: Option<SourceField>,
116 message_field: Field,
117 },
118
119 NoContext {
120 source_field: SourceField,
121 },
122}
123
124impl ContextSelectorKind {
125 fn is_whatever(&self) -> bool {
126 matches!(self, ContextSelectorKind::Whatever { .. })
127 }
128
129 fn user_fields(&self) -> &[Field] {
130 match self {
131 ContextSelectorKind::Context { user_fields, .. } => user_fields,
132 ContextSelectorKind::Whatever { .. } => &[],
133 ContextSelectorKind::NoContext { .. } => &[],
134 }
135 }
136
137 fn source_field(&self) -> Option<&SourceField> {
138 match self {
139 ContextSelectorKind::Context { source_field, .. } => source_field.as_ref(),
140 ContextSelectorKind::Whatever { source_field, .. } => source_field.as_ref(),
141 ContextSelectorKind::NoContext { source_field } => Some(source_field),
142 }
143 }
144
145 fn message_field(&self) -> Option<&Field> {
146 match self {
147 ContextSelectorKind::Context { .. } => None,
148 ContextSelectorKind::Whatever { message_field, .. } => Some(message_field),
149 ContextSelectorKind::NoContext { .. } => None,
150 }
151 }
152}
153
154struct NamedStructInfo {
155 crate_root: UserInput,
156 field_container: FieldContainer,
157 generics: syn::Generics,
158}
159
160struct TupleStructInfo {
161 crate_root: UserInput,
162 name: syn::Ident,
163 generics: syn::Generics,
164 transformation: Transformation,
165 provides: Vec<Provide>,
166}
167
168#[derive(Clone)]
169pub(crate) struct Field {
170 name: syn::Ident,
171 ty: syn::Type,
172 provide: bool,
173 original: syn::Field,
174}
175
176impl Field {
177 fn name(&self) -> &syn::Ident {
178 &self.name
179 }
180}
181
182struct SourceField {
183 name: syn::Ident,
184 transformation: Transformation,
185 backtrace_delegate: bool,
186 provide: bool,
187}
188
189impl SourceField {
190 fn name(&self) -> &syn::Ident {
191 &self.name
192 }
193}
194
195enum Transformation {
196 None {
197 ty: syn::Type,
198 },
199 Transform {
200 source_ty: syn::Type,
201 target_ty: syn::Type,
202 expr: syn::Expr,
203 },
204}
205
206impl Transformation {
207 fn source_ty(&self) -> &syn::Type {
208 match self {
209 Transformation::None { ty } => ty,
210 Transformation::Transform { source_ty, .. } => source_ty,
211 }
212 }
213
214 fn target_ty(&self) -> &syn::Type {
215 match self {
216 Transformation::None { ty } => ty,
217 Transformation::Transform { target_ty, .. } => target_ty,
218 }
219 }
220
221 fn transformation(&self) -> proc_macro2::TokenStream {
222 match self {
223 Transformation::None { .. } => quote! { |v| v },
224 Transformation::Transform { expr, .. } => quote! { #expr },
225 }
226 }
227}
228
229enum ProvideKind {
230 Flag(bool),
231 Expression(Provide),
232}
233
234#[derive(Debug, Default)]
238struct SyntaxErrors {
239 inner: Vec<syn::Error>,
240}
241
242impl SyntaxErrors {
243 fn scoped(&mut self, scope: ErrorLocation) -> SyntaxErrorsScoped<'_> {
245 SyntaxErrorsScoped {
246 errors: self,
247 scope,
248 }
249 }
250
251 fn add(&mut self, tokens: impl quote::ToTokens, description: impl fmt::Display) {
254 self.inner
255 .push(syn::Error::new_spanned(tokens, description));
256 }
257
258 fn extend(&mut self, errors: impl IntoIterator<Item = syn::Error>) {
260 self.inner.extend(errors);
261 }
262
263 #[allow(dead_code)]
264 fn len(&self) -> usize {
266 self.inner.len()
267 }
268
269 fn finish(self) -> MultiSynResult<()> {
272 if self.inner.is_empty() {
273 Ok(())
274 } else {
275 Err(self.inner)
276 }
277 }
278
279 fn absorb<T>(mut self, res: MultiSynResult<T>) -> MultiSynResult<T> {
282 match res {
283 Ok(v) => self.finish().map(|()| v),
284 Err(e) => {
285 self.inner.extend(e);
286 Err(self.inner)
287 }
288 }
289 }
290}
291
292#[derive(Debug, Copy, Clone)]
293enum ErrorLocation {
294 OnEnum,
295 OnVariant,
296 InVariant,
297 OnField,
298 OnNamedStruct,
299 InNamedStruct,
300 OnTupleStruct,
301 OnTupleStructField,
302}
303
304impl fmt::Display for ErrorLocation {
305 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
306 use crate::ErrorLocation::*;
307
308 match self {
309 OnEnum => "on an enum".fmt(f),
310 OnVariant => "on an enum variant".fmt(f),
311 InVariant => "within an enum variant".fmt(f),
312 OnField => "on a field".fmt(f),
313 OnNamedStruct => "on a named struct".fmt(f),
314 InNamedStruct => "within a named struct".fmt(f),
315 OnTupleStruct => "on a tuple struct".fmt(f),
316 OnTupleStructField => "on a tuple struct field".fmt(f),
317 }
318 }
319}
320
321trait ErrorForLocation {
322 fn for_location(&self, location: ErrorLocation) -> String;
323}
324
325struct SyntaxErrorsScoped<'a> {
326 errors: &'a mut SyntaxErrors,
327 scope: ErrorLocation,
328}
329
330impl SyntaxErrorsScoped<'_> {
331 fn add(&mut self, tokens: impl quote::ToTokens, description: impl ErrorForLocation) {
334 let description = description.for_location(self.scope);
335 self.errors.add(tokens, description)
336 }
337}
338
339#[derive(Debug)]
342struct DoesNothing {
343 attribute: &'static str,
345}
346
347impl ErrorForLocation for DoesNothing {
348 fn for_location(&self, _location: ErrorLocation) -> String {
349 format!("`{}` attribute has no effect", self.attribute)
350 }
351}
352
353#[derive(Debug)]
356struct OnlyValidOn {
357 attribute: &'static str,
359 valid_on: &'static str,
361}
362
363impl ErrorForLocation for OnlyValidOn {
364 fn for_location(&self, location: ErrorLocation) -> String {
365 format!(
366 "`{}` attribute is only valid on {}, not {}",
367 self.attribute, self.valid_on, location,
368 )
369 }
370}
371
372#[derive(Debug)]
375struct WrongField {
376 attribute: &'static str,
378 valid_field: &'static str,
380}
381
382impl ErrorForLocation for WrongField {
383 fn for_location(&self, _location: ErrorLocation) -> String {
384 format!(
385 r#"`{}` attribute is only valid on a field named "{}", not on other fields"#,
386 self.attribute, self.valid_field,
387 )
388 }
389}
390
391#[derive(Debug)]
394struct IncompatibleAttributes(&'static [&'static str]);
395
396impl ErrorForLocation for IncompatibleAttributes {
397 fn for_location(&self, location: ErrorLocation) -> String {
398 let attrs_string = self
399 .0
400 .iter()
401 .map(|attr| format!("`{}`", attr))
402 .collect::<Vec<_>>()
403 .join(", ");
404 format!(
405 "Incompatible attributes [{}] specified {}",
406 attrs_string, location,
407 )
408 }
409}
410
411#[derive(Debug)]
414struct DuplicateAttribute {
415 attribute: &'static str,
416 location: ErrorLocation,
417}
418
419impl fmt::Display for DuplicateAttribute {
420 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
421 write!(
422 f,
423 "Multiple `{}` attributes are not supported {}",
424 self.attribute, self.location,
425 )
426 }
427}
428
429#[derive(Debug)]
437struct AtMostOne<T, U>
438where
439 U: quote::ToTokens,
440{
441 name: &'static str,
442 location: ErrorLocation,
443 values: VecDeque<(T, U)>,
446 errors: SyntaxErrors,
447}
448
449impl<T, U> AtMostOne<T, U>
450where
451 U: quote::ToTokens + Clone,
452{
453 fn new(name: &'static str, location: ErrorLocation) -> Self {
457 Self {
458 name,
459 location,
460 values: VecDeque::new(),
461 errors: SyntaxErrors::default(),
462 }
463 }
464
465 fn add(&mut self, item: T, tokens: U) {
467 if !self.values.is_empty() {
468 self.errors.add(
469 tokens.clone(),
470 DuplicateAttribute {
471 attribute: self.name,
472 location: self.location,
473 },
474 );
475 }
476 self.values.push_back((item, tokens));
477 }
478
479 #[allow(dead_code)]
480 fn len(&self) -> usize {
482 self.values.len()
483 }
484
485 #[allow(dead_code)]
487 fn is_empty(&self) -> bool {
488 self.values.is_empty()
489 }
490
491 fn iter(&self) -> std::collections::vec_deque::Iter<(T, U)> {
496 self.values.iter()
497 }
498
499 fn finish(self) -> (Option<T>, Vec<syn::Error>) {
502 let (value, errors) = self.finish_with_location();
503 (value.map(|(val, _location)| val), errors)
504 }
505
506 fn finish_with_location(mut self) -> (Option<(T, U)>, Vec<syn::Error>) {
510 let errors = match self.errors.finish() {
511 Ok(()) => Vec::new(),
512 Err(vec) => vec,
513 };
514 (self.values.pop_front(), errors)
515 }
516}
517
518fn impl_snafu_macro(ty: syn::DeriveInput) -> TokenStream {
519 match parse_snafu_information(ty) {
520 Ok(info) => info.into(),
521 Err(e) => to_compile_errors(e).into(),
522 }
523}
524
525fn to_compile_errors(errors: Vec<syn::Error>) -> proc_macro2::TokenStream {
526 let compile_errors = errors.iter().map(syn::Error::to_compile_error);
527 quote! { #(#compile_errors)* }
528}
529
530fn parse_snafu_information(ty: syn::DeriveInput) -> MultiSynResult<SnafuInfo> {
531 use syn::spanned::Spanned;
532 use syn::Data;
533
534 let span = ty.span();
535 let syn::DeriveInput {
536 ident,
537 generics,
538 data,
539 attrs,
540 ..
541 } = ty;
542
543 match data {
544 Data::Enum(enum_) => parse_snafu_enum(enum_, ident, generics, attrs).map(SnafuInfo::Enum),
545 Data::Struct(struct_) => parse_snafu_struct(struct_, ident, generics, attrs, span),
546 _ => Err(vec![syn::Error::new(
547 span,
548 "Can only derive `Snafu` for an enum or a newtype",
549 )]),
550 }
551}
552
553const ATTR_DISPLAY: OnlyValidOn = OnlyValidOn {
554 attribute: "display",
555 valid_on: "enum variants or structs with named fields",
556};
557
558const ATTR_SOURCE: OnlyValidOn = OnlyValidOn {
559 attribute: "source",
560 valid_on: "enum variant or struct fields with a name",
561};
562
563const ATTR_SOURCE_BOOL: OnlyValidOn = OnlyValidOn {
564 attribute: "source(bool)",
565 valid_on: "enum variant or struct fields with a name",
566};
567
568const ATTR_SOURCE_FALSE: WrongField = WrongField {
569 attribute: "source(false)",
570 valid_field: "source",
571};
572
573const ATTR_SOURCE_FROM: OnlyValidOn = OnlyValidOn {
574 attribute: "source(from)",
575 valid_on: "enum variant or struct fields with a name",
576};
577
578const ATTR_BACKTRACE: OnlyValidOn = OnlyValidOn {
579 attribute: "backtrace",
580 valid_on: "enum variant or struct fields with a name",
581};
582
583const ATTR_BACKTRACE_FALSE: WrongField = WrongField {
584 attribute: "backtrace(false)",
585 valid_field: "backtrace",
586};
587
588const ATTR_IMPLICIT: OnlyValidOn = OnlyValidOn {
589 attribute: "implicit",
590 valid_on: "enum variant or struct fields with a name",
591};
592
593const ATTR_IMPLICIT_FALSE: DoesNothing = DoesNothing {
594 attribute: "implicit(false)",
595};
596
597const ATTR_VISIBILITY: OnlyValidOn = OnlyValidOn {
598 attribute: "visibility",
599 valid_on: "an enum, enum variants, or a struct with named fields",
600};
601
602const ATTR_MODULE: OnlyValidOn = OnlyValidOn {
603 attribute: "module",
604 valid_on: "an enum or structs with named fields",
605};
606
607const ATTR_PROVIDE_FLAG: OnlyValidOn = OnlyValidOn {
608 attribute: "provide",
609 valid_on: "enum variant or struct fields with a name",
610};
611
612const ATTR_PROVIDE_FALSE: WrongField = WrongField {
613 attribute: "provide(false)",
614 valid_field: r#"source" or "backtrace"#,
615};
616
617const ATTR_PROVIDE_EXPRESSION: OnlyValidOn = OnlyValidOn {
618 attribute: "provide(type => expression)",
619 valid_on: "enum variants, structs with named fields, or tuple structs",
620};
621
622const ATTR_CONTEXT: OnlyValidOn = OnlyValidOn {
623 attribute: "context",
624 valid_on: "enum variants or structs with named fields",
625};
626
627const ATTR_CONTEXT_FLAG: OnlyValidOn = OnlyValidOn {
628 attribute: "context(bool)",
629 valid_on: "enum variants or structs with named fields",
630};
631
632const ATTR_WHATEVER: OnlyValidOn = OnlyValidOn {
633 attribute: "whatever",
634 valid_on: "enum variants or structs with named fields",
635};
636
637const ATTR_CRATE_ROOT: OnlyValidOn = OnlyValidOn {
638 attribute: "crate_root",
639 valid_on: "an enum or a struct",
640};
641
642const ATTR_TRANSPARENT: OnlyValidOn = OnlyValidOn {
643 attribute: "transparent",
644 valid_on: "enum variants or structs with named fields",
645};
646
647const ATTR_TRANSPARENT_FALSE: DoesNothing = DoesNothing {
648 attribute: "transparent(false)",
649};
650
651const SOURCE_BOOL_FROM_INCOMPATIBLE: IncompatibleAttributes =
652 IncompatibleAttributes(&["source(false)", "source(from)"]);
653
654fn parse_snafu_enum(
655 enum_: syn::DataEnum,
656 name: syn::Ident,
657 generics: syn::Generics,
658 attrs: Vec<syn::Attribute>,
659) -> MultiSynResult<EnumInfo> {
660 use syn::spanned::Spanned;
661 use syn::Fields;
662
663 let mut errors = SyntaxErrors::default();
664
665 let mut modules = AtMostOne::new("module", ErrorLocation::OnEnum);
666 let mut default_visibilities = AtMostOne::new("visibility", ErrorLocation::OnEnum);
667 let mut default_suffixes = AtMostOne::new("context(suffix)", ErrorLocation::OnEnum);
668 let mut crate_roots = AtMostOne::new("crate_root", ErrorLocation::OnEnum);
669 let mut enum_errors = errors.scoped(ErrorLocation::OnEnum);
670
671 for attr in attributes_from_syn(attrs)? {
672 use SnafuAttribute as Att;
673
674 match attr {
675 Att::Visibility(tokens, v) => default_visibilities.add(v, tokens),
676 Att::Display(tokens, ..) => enum_errors.add(tokens, ATTR_DISPLAY),
677 Att::Source(tokens, ss) => {
678 for s in ss {
679 match s {
680 Source::Flag(..) => enum_errors.add(tokens.clone(), ATTR_SOURCE_BOOL),
681 Source::From(..) => enum_errors.add(tokens.clone(), ATTR_SOURCE_FROM),
682 }
683 }
684 }
685 Att::CrateRoot(tokens, root) => crate_roots.add(root, tokens),
686 Att::Context(tokens, c) => match c {
687 Context::Suffix(s) => default_suffixes.add(s, tokens),
688 Context::Flag(_) => enum_errors.add(tokens, ATTR_CONTEXT_FLAG),
689 },
690 Att::Module(tokens, v) => modules.add(v, tokens),
691 Att::Provide(tokens, ProvideKind::Flag(..)) => {
692 enum_errors.add(tokens, ATTR_PROVIDE_FLAG)
693 }
694 Att::Provide(tokens, ProvideKind::Expression { .. }) => {
695 enum_errors.add(tokens, ATTR_PROVIDE_EXPRESSION)
696 }
697 Att::Backtrace(tokens, ..) => enum_errors.add(tokens, ATTR_BACKTRACE),
698 Att::Implicit(tokens, ..) => enum_errors.add(tokens, ATTR_IMPLICIT),
699 Att::Transparent(tokens, ..) => enum_errors.add(tokens, ATTR_TRANSPARENT),
700 Att::Whatever(tokens) => enum_errors.add(tokens, ATTR_WHATEVER),
701 Att::DocComment(..) => { }
702 }
703 }
704
705 let (module, errs) = modules.finish();
706 errors.extend(errs);
707
708 let (default_visibility, errs) = default_visibilities.finish();
709 errors.extend(errs);
710
711 let (maybe_default_suffix, errs) = default_suffixes.finish();
712 let default_suffix = maybe_default_suffix.unwrap_or(SuffixKind::Default);
713 errors.extend(errs);
714
715 let (maybe_crate_root, errs) = crate_roots.finish();
716 let crate_root = maybe_crate_root.unwrap_or_else(default_crate_root);
717 errors.extend(errs);
718
719 let variants: sponge::AllErrors<_, _> = enum_
720 .variants
721 .into_iter()
722 .map(|variant| {
723 let fields = match variant.fields {
724 Fields::Named(f) => f.named.into_iter().collect(),
725 Fields::Unnamed(_) => {
726 return Err(vec![syn::Error::new(
727 variant.fields.span(),
728 "Can only derive `Snafu` for enums with struct-like and unit enum variants",
729 )]);
730 }
731 Fields::Unit => vec![],
732 };
733
734 let name = variant.ident;
735 let span = name.span();
736
737 let attrs = attributes_from_syn(variant.attrs)?;
738
739 field_container(
740 name,
741 span,
742 attrs,
743 fields,
744 &mut errors,
745 ErrorLocation::OnVariant,
746 ErrorLocation::InVariant,
747 )
748 })
749 .collect();
750
751 let variants = errors.absorb(variants.into_result())?;
752
753 Ok(EnumInfo {
754 crate_root,
755 name,
756 generics,
757 variants,
758 default_visibility,
759 default_suffix,
760 module,
761 })
762}
763
764fn field_container(
765 name: syn::Ident,
766 variant_span: proc_macro2::Span,
767 attrs: Vec<SnafuAttribute>,
768 fields: Vec<syn::Field>,
769 errors: &mut SyntaxErrors,
770 outer_error_location: ErrorLocation,
771 inner_error_location: ErrorLocation,
772) -> MultiSynResult<FieldContainer> {
773 use quote::ToTokens;
774 use syn::spanned::Spanned;
775
776 let mut outer_errors = errors.scoped(outer_error_location);
777
778 let mut modules = AtMostOne::new("module", outer_error_location);
779 let mut display_formats = AtMostOne::new("display", outer_error_location);
780 let mut visibilities = AtMostOne::new("visibility", outer_error_location);
781 let mut provides = Vec::new();
782
783 let mut contexts = AtMostOne::new("context", outer_error_location);
784 let mut whatevers = AtMostOne::new("whatever", outer_error_location);
785 let mut transparents = AtMostOne::new("transparent", outer_error_location);
786
787 let mut doc_comment = DocComment::default();
788 let mut reached_end_of_doc_comment = false;
789
790 for attr in attrs {
791 use SnafuAttribute as Att;
792
793 match attr {
794 Att::Module(tokens, n) => modules.add(n, tokens),
795 Att::Display(tokens, d) => display_formats.add(d, tokens),
796 Att::Visibility(tokens, v) => visibilities.add(v, tokens),
797 Att::Context(tokens, c) => contexts.add(c, tokens),
798 Att::Whatever(tokens) => whatevers.add((), tokens),
799 Att::Transparent(tokens, t) => {
800 if t {
801 transparents.add((), tokens)
802 } else {
803 outer_errors.add(tokens, ATTR_TRANSPARENT_FALSE)
804 }
805 }
806 Att::Source(tokens, ..) => outer_errors.add(tokens, ATTR_SOURCE),
807 Att::Backtrace(tokens, ..) => outer_errors.add(tokens, ATTR_BACKTRACE),
808 Att::Implicit(tokens, ..) => outer_errors.add(tokens, ATTR_IMPLICIT),
809 Att::CrateRoot(tokens, ..) => outer_errors.add(tokens, ATTR_CRATE_ROOT),
810 Att::Provide(tokens, ProvideKind::Flag(..)) => {
811 outer_errors.add(tokens, ATTR_PROVIDE_FLAG)
812 }
813 Att::Provide(_tts, ProvideKind::Expression(provide)) => {
814 provides.push(provide);
816 }
817 Att::DocComment(_tts, doc_comment_line) => {
818 if !reached_end_of_doc_comment {
822 let trimmed = doc_comment_line.trim();
823 if trimmed.is_empty() {
824 reached_end_of_doc_comment = true;
825 } else {
826 doc_comment.push_str(trimmed);
827 }
828 }
829 }
830 }
831 }
832
833 let mut user_fields = Vec::new();
834 let mut source_fields = AtMostOne::new("source", inner_error_location);
835 let mut backtrace_fields = AtMostOne::new("backtrace", inner_error_location);
836 let mut implicit_fields = Vec::new();
837
838 for syn_field in fields {
839 let original = syn_field.clone();
840 let span = syn_field.span();
841 let name = syn_field
842 .ident
843 .as_ref()
844 .ok_or_else(|| vec![syn::Error::new(span, "Must have a named field")])?;
845
846 let mut source_attrs = AtMostOne::new("source", ErrorLocation::OnField);
855 let mut backtrace_attrs = AtMostOne::new("backtrace", ErrorLocation::OnField);
856 let mut implicit_attrs = AtMostOne::new("implicit", ErrorLocation::OnField);
857 let mut provide_attrs = AtMostOne::new("provide", ErrorLocation::OnField);
858
859 let mut source_opt_out = false;
862 let mut backtrace_opt_out = false;
863 let mut provide_opt_out = false;
864
865 let mut field_errors = errors.scoped(ErrorLocation::OnField);
866
867 for attr in attributes_from_syn(syn_field.attrs.clone())? {
868 use SnafuAttribute as Att;
869
870 match attr {
871 Att::Source(tokens, ss) => {
872 for s in ss {
873 match s {
874 Source::Flag(v) => {
875 let seen_source_from = source_attrs
878 .iter()
879 .map(|(val, _location)| val)
880 .any(Option::is_some);
881 if !v && seen_source_from {
882 field_errors.add(tokens.clone(), SOURCE_BOOL_FROM_INCOMPATIBLE);
883 }
884 if v {
885 source_attrs.add(None, tokens.clone());
886 } else if is_implicit_source(name) {
887 source_opt_out = true;
888 } else {
889 field_errors.add(tokens.clone(), ATTR_SOURCE_FALSE);
890 }
891 }
892 Source::From(t, e) => {
893 if source_opt_out {
894 field_errors.add(tokens.clone(), SOURCE_BOOL_FROM_INCOMPATIBLE);
895 }
896 source_attrs.add(Some((t, e)), tokens.clone());
897 }
898 }
899 }
900 }
901 Att::Backtrace(tokens, v) => {
902 if v {
903 backtrace_attrs.add((), tokens);
904 } else if is_implicit_backtrace(name) {
905 backtrace_opt_out = true;
906 } else {
907 field_errors.add(tokens, ATTR_BACKTRACE_FALSE);
908 }
909 }
910 Att::Implicit(tokens, v) => {
911 if v {
912 implicit_attrs.add((), tokens);
913 } else {
914 field_errors.add(tokens, ATTR_IMPLICIT_FALSE);
915 }
916 }
917 Att::Module(tokens, ..) => field_errors.add(tokens, ATTR_MODULE),
918 Att::Provide(tokens, ProvideKind::Flag(v)) => {
919 if v {
920 provide_attrs.add((), tokens);
921 } else if is_implicit_provide(name) {
922 provide_opt_out = true;
923 } else {
924 field_errors.add(tokens, ATTR_PROVIDE_FALSE)
925 }
926 }
927 Att::Provide(tokens, ProvideKind::Expression { .. }) => {
928 field_errors.add(tokens, ATTR_PROVIDE_EXPRESSION)
929 }
930 Att::Visibility(tokens, ..) => field_errors.add(tokens, ATTR_VISIBILITY),
931 Att::Display(tokens, ..) => field_errors.add(tokens, ATTR_DISPLAY),
932 Att::Context(tokens, ..) => field_errors.add(tokens, ATTR_CONTEXT),
933 Att::Transparent(tokens, ..) => field_errors.add(tokens, ATTR_TRANSPARENT),
934 Att::Whatever(tokens) => field_errors.add(tokens, ATTR_WHATEVER),
935 Att::CrateRoot(tokens, ..) => field_errors.add(tokens, ATTR_CRATE_ROOT),
936 Att::DocComment(..) => { }
937 }
938 }
939
940 let (source_attr, errs) = source_attrs.finish_with_location();
942 errors.extend(errs);
943 let (backtrace_attr, errs) = backtrace_attrs.finish_with_location();
944 errors.extend(errs);
945
946 let (implicit_attr, errs) = implicit_attrs.finish();
947 errors.extend(errs);
948
949 let (provide_attr, errs) = provide_attrs.finish();
950 errors.extend(errs);
951
952 let field = Field {
953 name: name.clone(),
954 ty: syn_field.ty.clone(),
955 provide: provide_attr.is_some() || (is_implicit_provide(name) && !provide_opt_out),
956 original,
957 };
958
959 let source_attr = source_attr.or_else(|| {
960 if is_implicit_source(&field.name) && !source_opt_out {
961 Some((None, syn_field.clone().into_token_stream()))
962 } else {
963 None
964 }
965 });
966
967 let backtrace_attr = backtrace_attr.or_else(|| {
968 if is_implicit_backtrace(&field.name) && !backtrace_opt_out {
969 Some(((), syn_field.clone().into_token_stream()))
970 } else {
971 None
972 }
973 });
974
975 let implicit_attr = implicit_attr.is_some();
976
977 if let Some((maybe_transformation, location)) = source_attr {
978 let Field {
979 name, ty, provide, ..
980 } = field;
981 let transformation = maybe_transformation
982 .map(|(source_ty, expr)| Transformation::Transform {
983 source_ty,
984 target_ty: ty.clone(),
985 expr,
986 })
987 .unwrap_or_else(|| Transformation::None { ty });
988
989 source_fields.add(
990 SourceField {
991 name,
992 transformation,
993 backtrace_delegate: backtrace_attr.is_some(),
996 provide,
997 },
998 location,
999 );
1000 } else if let Some((_, location)) = backtrace_attr {
1001 backtrace_fields.add(field, location);
1002 } else if implicit_attr {
1003 implicit_fields.push(field);
1004 } else {
1005 user_fields.push(field);
1006 }
1007 }
1008
1009 let (source, errs) = source_fields.finish_with_location();
1010 errors.extend(errs);
1011
1012 let (backtrace, errs) = backtrace_fields.finish_with_location();
1013 errors.extend(errs);
1014
1015 match (&source, &backtrace) {
1016 (Some(source), Some(backtrace)) if source.0.backtrace_delegate => {
1017 let source_location = source.1.clone();
1018 let backtrace_location = backtrace.1.clone();
1019 errors.add(
1020 source_location,
1021 "Cannot have `backtrace` field and `backtrace` attribute on a source field in the same variant",
1022 );
1023 errors.add(
1024 backtrace_location,
1025 "Cannot have `backtrace` field and `backtrace` attribute on a source field in the same variant",
1026 );
1027 }
1028 _ => {} }
1030
1031 let (module, errs) = modules.finish();
1032 errors.extend(errs);
1033
1034 let (display_format, errs) = display_formats.finish_with_location();
1035 errors.extend(errs);
1036
1037 let (visibility, errs) = visibilities.finish();
1038 errors.extend(errs);
1039
1040 let (is_context, errs) = contexts.finish_with_location();
1041 let mut is_context = is_context.map(|(c, tt)| (c.into_enabled(), tt));
1042 let mut is_context_false_checks_source = "Context selectors without context";
1043 errors.extend(errs);
1044
1045 let (is_whatever, errs) = whatevers.finish_with_location();
1046 errors.extend(errs);
1047
1048 let (is_transparent, errs) = transparents.finish_with_location();
1049 errors.extend(errs);
1050
1051 if let (Some((_, d_tt)), Some((_, t_tt))) = (&display_format, &is_transparent) {
1052 let txt = "`transparent` errors cannot have a display format because they delegate `Display` to their source";
1053 errors.extend([
1054 syn::Error::new_spanned(d_tt, txt),
1055 syn::Error::new_spanned(t_tt, txt),
1056 ]);
1057 }
1058
1059 match (&is_context, &is_transparent) {
1060 (Some(((true, _), c_tt)), Some((_, t_tt))) => {
1061 let txt = "`transparent` errors cannot have context";
1062 errors.extend([
1063 syn::Error::new_spanned(c_tt, txt),
1064 syn::Error::new_spanned(t_tt, txt),
1065 ]);
1066 }
1067 (None, Some((_, t_tt))) => {
1068 is_context = Some(((false, SuffixKind::Default), t_tt.clone()));
1071 is_context_false_checks_source = "`transparent` errors";
1072 }
1073 (Some(((false, _), _)), Some(_)) | (_, None) => {}
1074 }
1075
1076 let source_field = source.map(|(val, _tts)| val);
1077
1078 let selector_kind = match (is_context, is_whatever) {
1079 (Some(((true, _), c_tt)), Some(((), o_tt))) => {
1080 let txt = "Cannot be both a `context` and `whatever` error";
1081 return Err(vec![
1082 syn::Error::new_spanned(c_tt, txt),
1083 syn::Error::new_spanned(o_tt, txt),
1084 ]);
1085 }
1086
1087 (Some(((true, suffix), _)), None) => ContextSelectorKind::Context {
1088 suffix,
1089 source_field,
1090 user_fields,
1091 },
1092
1093 (None, None) => ContextSelectorKind::Context {
1094 suffix: SuffixKind::Default,
1095 source_field,
1096 user_fields,
1097 },
1098
1099 (Some(((false, _), _)), Some(_)) | (None, Some(_)) => {
1100 let mut messages = AtMostOne::new("message", outer_error_location);
1101
1102 for f in user_fields {
1103 if is_implicit_message(&f.name) {
1104 let l = f.original.clone();
1105 messages.add(f, l);
1106 } else {
1107 errors.add(
1108 f.original,
1109 "Whatever selectors must not have context fields",
1110 );
1111 }
1113 }
1114
1115 let (message_field, errs) = messages.finish();
1116 errors.extend(errs);
1117
1118 let message_field = message_field.ok_or_else(|| {
1119 vec![syn::Error::new(
1120 variant_span,
1121 "Whatever selectors must have a message field",
1122 )]
1123 })?;
1124
1125 ContextSelectorKind::Whatever {
1126 source_field,
1127 message_field,
1128 }
1129 }
1130
1131 (Some(((false, _), _)), None) => {
1132 errors.extend(user_fields.into_iter().map(|Field { original, .. }| {
1133 syn::Error::new_spanned(
1134 original,
1135 format_args!(
1136 "{} must not have context fields",
1137 is_context_false_checks_source
1138 ),
1139 )
1140 }));
1141
1142 let source_field = source_field.ok_or_else(|| {
1143 vec![syn::Error::new(
1144 variant_span,
1145 format_args!(
1146 "{} must have a source field",
1147 is_context_false_checks_source
1148 ),
1149 )]
1150 })?;
1151
1152 ContextSelectorKind::NoContext { source_field }
1153 }
1154 };
1155
1156 Ok(FieldContainer {
1157 name,
1158 backtrace_field: backtrace.map(|(val, _tts)| val),
1159 implicit_fields,
1160 selector_kind,
1161 display_format: display_format.map(|(d, _)| d),
1162 doc_comment: doc_comment.finish(),
1163 visibility,
1164 module,
1165 provides,
1166 is_transparent: is_transparent.is_some(),
1167 })
1168}
1169
1170const IMPLICIT_SOURCE_FIELD_NAME: &str = "source";
1171const IMPLICIT_BACKTRACE_FIELD_NAME: &str = "backtrace";
1172const IMPLICIT_MESSAGE_FIELD_NAME: &str = "message";
1173
1174fn is_implicit_source(name: &proc_macro2::Ident) -> bool {
1175 name == IMPLICIT_SOURCE_FIELD_NAME
1176}
1177
1178fn is_implicit_backtrace(name: &proc_macro2::Ident) -> bool {
1179 name == IMPLICIT_BACKTRACE_FIELD_NAME
1180}
1181
1182fn is_implicit_message(name: &proc_macro2::Ident) -> bool {
1183 name == IMPLICIT_MESSAGE_FIELD_NAME
1184}
1185
1186fn is_implicit_provide(name: &proc_macro2::Ident) -> bool {
1187 is_implicit_source(name) || is_implicit_backtrace(name)
1188}
1189
1190fn parse_snafu_struct(
1191 struct_: syn::DataStruct,
1192 name: syn::Ident,
1193 generics: syn::Generics,
1194 attrs: Vec<syn::Attribute>,
1195 span: proc_macro2::Span,
1196) -> MultiSynResult<SnafuInfo> {
1197 use syn::Fields;
1198
1199 match struct_.fields {
1200 Fields::Named(f) => {
1201 let f = f.named.into_iter().collect();
1202 parse_snafu_named_struct(f, name, generics, attrs, span).map(SnafuInfo::NamedStruct)
1203 }
1204 Fields::Unnamed(f) => {
1205 parse_snafu_tuple_struct(f, name, generics, attrs, span).map(SnafuInfo::TupleStruct)
1206 }
1207 Fields::Unit => parse_snafu_named_struct(vec![], name, generics, attrs, span)
1208 .map(SnafuInfo::NamedStruct),
1209 }
1210}
1211
1212fn parse_snafu_named_struct(
1213 fields: Vec<syn::Field>,
1214 name: syn::Ident,
1215 generics: syn::Generics,
1216 attrs: Vec<syn::Attribute>,
1217 span: proc_macro2::Span,
1218) -> MultiSynResult<NamedStructInfo> {
1219 let mut errors = SyntaxErrors::default();
1220
1221 let attrs = attributes_from_syn(attrs)?;
1222
1223 let mut crate_roots = AtMostOne::new("crate_root", ErrorLocation::OnNamedStruct);
1224
1225 let attrs = attrs
1226 .into_iter()
1227 .flat_map(|attr| match attr {
1228 SnafuAttribute::CrateRoot(tokens, root) => {
1229 crate_roots.add(root, tokens);
1230 None
1231 }
1232 other => Some(other),
1233 })
1234 .collect();
1235
1236 let field_container = field_container(
1237 name,
1238 span,
1239 attrs,
1240 fields,
1241 &mut errors,
1242 ErrorLocation::OnNamedStruct,
1243 ErrorLocation::InNamedStruct,
1244 )?;
1245
1246 let (maybe_crate_root, errs) = crate_roots.finish();
1247 let crate_root = maybe_crate_root.unwrap_or_else(default_crate_root);
1248 errors.extend(errs);
1249
1250 errors.finish()?;
1251
1252 Ok(NamedStructInfo {
1253 crate_root,
1254 field_container,
1255 generics,
1256 })
1257}
1258
1259fn parse_snafu_tuple_struct(
1260 mut fields: syn::FieldsUnnamed,
1261 name: syn::Ident,
1262 generics: syn::Generics,
1263 attrs: Vec<syn::Attribute>,
1264 span: proc_macro2::Span,
1265) -> MultiSynResult<TupleStructInfo> {
1266 let mut transformations = AtMostOne::new("source(from)", ErrorLocation::OnTupleStruct);
1267 let mut crate_roots = AtMostOne::new("crate_root", ErrorLocation::OnTupleStruct);
1268 let mut provides = Vec::new();
1269
1270 let mut errors = SyntaxErrors::default();
1271 let mut struct_errors = errors.scoped(ErrorLocation::OnTupleStruct);
1272
1273 for attr in attributes_from_syn(attrs)? {
1274 use SnafuAttribute as Att;
1275
1276 match attr {
1277 Att::Module(tokens, ..) => struct_errors.add(tokens, ATTR_MODULE),
1278 Att::Provide(tokens, ProvideKind::Flag(..)) => {
1279 struct_errors.add(tokens, ATTR_PROVIDE_FLAG)
1280 }
1281 Att::Provide(_tokens, ProvideKind::Expression(provide)) => {
1282 provides.push(provide);
1283 }
1284 Att::Display(tokens, ..) => struct_errors.add(tokens, ATTR_DISPLAY),
1285 Att::Visibility(tokens, ..) => struct_errors.add(tokens, ATTR_VISIBILITY),
1286 Att::Source(tokens, ss) => {
1287 for s in ss {
1288 match s {
1289 Source::Flag(..) => struct_errors.add(tokens.clone(), ATTR_SOURCE_BOOL),
1290 Source::From(t, e) => transformations.add((t, e), tokens.clone()),
1291 }
1292 }
1293 }
1294 Att::Backtrace(tokens, ..) => struct_errors.add(tokens, ATTR_BACKTRACE),
1295 Att::Implicit(tokens, ..) => struct_errors.add(tokens, ATTR_IMPLICIT),
1296 Att::Context(tokens, ..) => struct_errors.add(tokens, ATTR_CONTEXT),
1297 Att::Whatever(tokens) => struct_errors.add(tokens, ATTR_WHATEVER),
1298 Att::Transparent(tokens, ..) => struct_errors.add(tokens, ATTR_TRANSPARENT),
1299 Att::CrateRoot(tokens, root) => crate_roots.add(root, tokens),
1300 Att::DocComment(..) => { }
1301 }
1302 }
1303
1304 fn one_field_error(span: proc_macro2::Span) -> syn::Error {
1305 syn::Error::new(
1306 span,
1307 "Can only derive `Snafu` for tuple structs with exactly one field",
1308 )
1309 }
1310
1311 let inner = fields
1312 .unnamed
1313 .pop()
1314 .ok_or_else(|| vec![one_field_error(span)])?;
1315 if !fields.unnamed.is_empty() {
1316 return Err(vec![one_field_error(span)]);
1317 }
1318
1319 let inner = inner.into_value();
1320
1321 let mut field_errors = errors.scoped(ErrorLocation::OnTupleStructField);
1322
1323 for attr in attributes_from_syn(inner.attrs)? {
1324 use SnafuAttribute as Att;
1325
1326 match attr {
1327 Att::Backtrace(tokens, ..) => field_errors.add(tokens, ATTR_BACKTRACE),
1328 Att::Context(tokens, ..) => field_errors.add(tokens, ATTR_CONTEXT),
1329 Att::CrateRoot(tokens, ..) => field_errors.add(tokens, ATTR_CRATE_ROOT),
1330 Att::Display(tokens, ..) => field_errors.add(tokens, ATTR_DISPLAY),
1331 Att::Implicit(tokens, ..) => field_errors.add(tokens, ATTR_IMPLICIT),
1332 Att::Module(tokens, ..) => field_errors.add(tokens, ATTR_MODULE),
1333 Att::Provide(tokens, ..) => field_errors.add(tokens, ATTR_PROVIDE_FLAG),
1334 Att::Source(tokens, ..) => field_errors.add(tokens.clone(), ATTR_SOURCE),
1335 Att::Transparent(tokens, ..) => field_errors.add(tokens, ATTR_TRANSPARENT),
1336 Att::Visibility(tokens, ..) => field_errors.add(tokens, ATTR_VISIBILITY),
1337 Att::Whatever(tokens) => field_errors.add(tokens, ATTR_WHATEVER),
1338 Att::DocComment(..) => { }
1339 }
1340 }
1341
1342 let ty = inner.ty;
1343 let (maybe_transformation, errs) = transformations.finish();
1344 let transformation = maybe_transformation
1345 .map(|(source_ty, expr)| Transformation::Transform {
1346 source_ty,
1347 target_ty: ty.clone(),
1348 expr,
1349 })
1350 .unwrap_or_else(|| Transformation::None { ty });
1351 errors.extend(errs);
1352
1353 let (maybe_crate_root, errs) = crate_roots.finish();
1354 let crate_root = maybe_crate_root.unwrap_or_else(default_crate_root);
1355 errors.extend(errs);
1356
1357 errors.finish()?;
1358
1359 Ok(TupleStructInfo {
1360 crate_root,
1361 name,
1362 generics,
1363 transformation,
1364 provides,
1365 })
1366}
1367
1368enum Context {
1369 Flag(bool),
1370 Suffix(SuffixKind),
1371}
1372
1373impl Context {
1374 fn into_enabled(self) -> (bool, SuffixKind) {
1375 match self {
1376 Context::Flag(b) => (b, SuffixKind::None),
1377 Context::Suffix(suffix) => (true, suffix),
1378 }
1379 }
1380}
1381
1382enum Source {
1383 Flag(bool),
1384 From(syn::Type, syn::Expr),
1385}
1386
1387struct Display {
1388 exprs: Vec<syn::Expr>,
1389 shorthand_names: BTreeSet<syn::Ident>,
1390 assigned_names: BTreeSet<syn::Ident>,
1391}
1392
1393#[derive(Default)]
1394struct DocComment {
1395 content: String,
1396 shorthand_names: BTreeSet<syn::Ident>,
1397}
1398
1399impl DocComment {
1400 fn push_str(&mut self, s: &str) {
1401 if !self.content.is_empty() {
1402 self.content.push(' ');
1403 }
1404 self.content.push_str(s);
1405 }
1406
1407 fn finish(mut self) -> Option<Self> {
1408 if self.content.is_empty() {
1409 None
1410 } else {
1411 self.shorthand_names.extend(
1412 crate::parse::extract_field_names(&self.content)
1413 .map(|n| quote::format_ident!("{}", n)),
1414 );
1415
1416 Some(self)
1417 }
1418 }
1419}
1420
1421enum SnafuAttribute {
1429 Backtrace(proc_macro2::TokenStream, bool),
1430 Context(proc_macro2::TokenStream, Context),
1431 CrateRoot(proc_macro2::TokenStream, UserInput),
1432 Display(proc_macro2::TokenStream, Display),
1433 DocComment(proc_macro2::TokenStream, String),
1434 Implicit(proc_macro2::TokenStream, bool),
1435 Module(proc_macro2::TokenStream, ModuleName),
1436 Provide(proc_macro2::TokenStream, ProvideKind),
1437 Source(proc_macro2::TokenStream, Vec<Source>),
1438 Transparent(proc_macro2::TokenStream, bool),
1439 Visibility(proc_macro2::TokenStream, UserInput),
1440 Whatever(proc_macro2::TokenStream),
1441}
1442
1443fn default_crate_root() -> UserInput {
1444 Box::new(quote! { ::snafu })
1445}
1446
1447fn private_visibility() -> UserInput {
1448 Box::new(quote! {})
1449}
1450
1451fn default_context_selector_visibility_in_module() -> proc_macro2::TokenStream {
1454 quote! { pub(super) }
1455}
1456
1457impl From<SnafuInfo> for proc_macro::TokenStream {
1458 fn from(other: SnafuInfo) -> proc_macro::TokenStream {
1459 match other {
1460 SnafuInfo::Enum(e) => e.into(),
1461 SnafuInfo::NamedStruct(s) => s.into(),
1462 SnafuInfo::TupleStruct(s) => s.into(),
1463 }
1464 }
1465}
1466
1467impl From<EnumInfo> for proc_macro::TokenStream {
1468 fn from(other: EnumInfo) -> proc_macro::TokenStream {
1469 other.generate_snafu().into()
1470 }
1471}
1472
1473impl From<NamedStructInfo> for proc_macro::TokenStream {
1474 fn from(other: NamedStructInfo) -> proc_macro::TokenStream {
1475 other.generate_snafu().into()
1476 }
1477}
1478
1479impl From<TupleStructInfo> for proc_macro::TokenStream {
1480 fn from(other: TupleStructInfo) -> proc_macro::TokenStream {
1481 other.generate_snafu().into()
1482 }
1483}
1484
1485trait GenericAwareNames {
1486 fn name(&self) -> &syn::Ident;
1487
1488 fn generics(&self) -> &syn::Generics;
1489
1490 fn parameterized_name(&self) -> UserInput {
1491 let enum_name = self.name();
1492 let original_generics = self.provided_generic_names();
1493
1494 Box::new(quote! { #enum_name<#(#original_generics,)*> })
1495 }
1496
1497 fn provided_generic_types_without_defaults(&self) -> Vec<proc_macro2::TokenStream> {
1498 use syn::TypeParam;
1499
1500 self.generics()
1501 .type_params()
1502 .map(|t| {
1503 let TypeParam {
1504 attrs,
1505 ident,
1506 colon_token,
1507 bounds,
1508 ..
1509 } = t;
1510 quote! {
1511 #(#attrs)*
1512 #ident
1513 #colon_token
1514 #bounds
1515 }
1516 })
1517 .collect()
1518 }
1519
1520 fn provided_generics_without_defaults(&self) -> Vec<proc_macro2::TokenStream> {
1521 self.provided_generic_lifetimes()
1522 .into_iter()
1523 .chain(self.provided_generic_types_without_defaults())
1524 .chain(self.provided_generic_consts_without_defaults())
1525 .collect()
1526 }
1527
1528 fn provided_generic_lifetimes(&self) -> Vec<proc_macro2::TokenStream> {
1529 use syn::LifetimeParam;
1530
1531 self.generics()
1532 .lifetimes()
1533 .map(|l| {
1534 let LifetimeParam {
1535 attrs, lifetime, ..
1536 } = l;
1537 quote! {
1538 #(#attrs)*
1539 #lifetime
1540 }
1541 })
1542 .collect()
1543 }
1544
1545 fn provided_generic_consts_without_defaults(&self) -> Vec<proc_macro2::TokenStream> {
1546 self.generics()
1547 .const_params()
1548 .map(|c| {
1549 let syn::ConstParam {
1550 attrs,
1551 const_token,
1552 ident,
1553 colon_token,
1554 ty,
1555 ..
1556 } = c;
1557 quote! {
1558 #(#attrs)*
1559 #const_token
1560 #ident
1561 #colon_token
1562 #ty
1563 }
1564 })
1565 .collect()
1566 }
1567
1568 fn provided_generic_names(&self) -> Vec<proc_macro2::TokenStream> {
1569 use syn::{ConstParam, GenericParam, LifetimeParam, TypeParam};
1570
1571 self.generics()
1572 .params
1573 .iter()
1574 .map(|p| match p {
1575 GenericParam::Type(TypeParam { ident, .. }) => quote! { #ident },
1576 GenericParam::Lifetime(LifetimeParam { lifetime, .. }) => quote! { #lifetime },
1577 GenericParam::Const(ConstParam { ident, .. }) => quote! { #ident },
1578 })
1579 .collect()
1580 }
1581
1582 fn provided_where_clauses(&self) -> Vec<proc_macro2::TokenStream> {
1583 self.generics()
1584 .where_clause
1585 .iter()
1586 .flat_map(|c| c.predicates.iter().map(|p| quote! { #p }))
1587 .collect()
1588 }
1589}
1590
1591impl EnumInfo {
1592 fn generate_snafu(self) -> proc_macro2::TokenStream {
1593 let context_selectors = ContextSelectors(&self);
1594 let display_impl = DisplayImpl(&self);
1595 let error_impl = ErrorImpl(&self);
1596 let error_compat_impl = ErrorCompatImpl(&self);
1597
1598 let context = match &self.module {
1599 None => quote! { #context_selectors },
1600 Some(module_name) => {
1601 use crate::shared::ContextModule;
1602
1603 let context_module = ContextModule {
1604 container_name: self.name(),
1605 body: &context_selectors,
1606 visibility: Some(&self.default_visibility),
1607 module_name,
1608 };
1609
1610 quote! { #context_module }
1611 }
1612 };
1613
1614 quote! {
1615 #context
1616 #display_impl
1617 #error_impl
1618 #error_compat_impl
1619 }
1620 }
1621}
1622
1623impl GenericAwareNames for EnumInfo {
1624 fn name(&self) -> &syn::Ident {
1625 &self.name
1626 }
1627
1628 fn generics(&self) -> &syn::Generics {
1629 &self.generics
1630 }
1631}
1632
1633struct ContextSelectors<'a>(&'a EnumInfo);
1634
1635impl<'a> quote::ToTokens for ContextSelectors<'a> {
1636 fn to_tokens(&self, stream: &mut proc_macro2::TokenStream) {
1637 let context_selectors = self
1638 .0
1639 .variants
1640 .iter()
1641 .map(|variant| ContextSelector(self.0, variant));
1642
1643 stream.extend({
1644 quote! {
1645 #(#context_selectors)*
1646 }
1647 })
1648 }
1649}
1650
1651struct ContextSelector<'a>(&'a EnumInfo, &'a FieldContainer);
1652
1653impl<'a> quote::ToTokens for ContextSelector<'a> {
1654 fn to_tokens(&self, stream: &mut proc_macro2::TokenStream) {
1655 use crate::shared::ContextSelector;
1656
1657 let enum_name = &self.0.name;
1658 let default_suffix = &self.0.default_suffix;
1659
1660 let FieldContainer {
1661 name: variant_name,
1662 selector_kind,
1663 ..
1664 } = self.1;
1665
1666 let default_visibility;
1667 let selector_visibility = match (
1668 &self.1.visibility,
1669 &self.0.default_visibility,
1670 &self.0.module,
1671 ) {
1672 (Some(v), _, _) | (_, Some(v), _) => Some(&**v),
1673 (None, None, Some(_)) => {
1674 default_visibility = default_context_selector_visibility_in_module();
1675 Some(&default_visibility as _)
1676 }
1677 (None, None, None) => None,
1678 };
1679
1680 let selector_doc_string = format!(
1681 "SNAFU context selector for the `{}::{}` variant",
1682 enum_name, variant_name,
1683 );
1684
1685 let context_selector = ContextSelector {
1686 backtrace_field: self.1.backtrace_field.as_ref(),
1687 implicit_fields: &self.1.implicit_fields,
1688 crate_root: &self.0.crate_root,
1689 error_constructor_name: "e! { #enum_name::#variant_name },
1690 original_generics_without_defaults: &self.0.provided_generics_without_defaults(),
1691 parameterized_error_name: &self.0.parameterized_name(),
1692 selector_doc_string: &selector_doc_string,
1693 selector_kind,
1694 selector_name: variant_name,
1695 user_fields: selector_kind.user_fields(),
1696 visibility: selector_visibility,
1697 where_clauses: &self.0.provided_where_clauses(),
1698 default_suffix,
1699 };
1700
1701 stream.extend(quote! { #context_selector });
1702 }
1703}
1704
1705struct DisplayImpl<'a>(&'a EnumInfo);
1706
1707impl<'a> quote::ToTokens for DisplayImpl<'a> {
1708 fn to_tokens(&self, stream: &mut proc_macro2::TokenStream) {
1709 use self::shared::{Display, DisplayMatchArm};
1710
1711 let enum_name = &self.0.name;
1712
1713 let arms: Vec<_> = self
1714 .0
1715 .variants
1716 .iter()
1717 .map(|variant| {
1718 let FieldContainer {
1719 display_format,
1720 doc_comment,
1721 name: variant_name,
1722 selector_kind,
1723 ..
1724 } = variant;
1725
1726 let arm = DisplayMatchArm {
1727 field_container: variant,
1728 default_name: &variant_name,
1729 display_format: display_format.as_ref(),
1730 doc_comment: doc_comment.as_ref(),
1731 pattern_ident: "e! { #enum_name::#variant_name },
1732 selector_kind,
1733 };
1734
1735 quote! { #arm }
1736 })
1737 .collect();
1738
1739 let display = Display {
1740 arms: &arms,
1741 original_generics: &self.0.provided_generics_without_defaults(),
1742 parameterized_error_name: &self.0.parameterized_name(),
1743 where_clauses: &self.0.provided_where_clauses(),
1744 };
1745
1746 let display_impl = quote! { #display };
1747
1748 stream.extend(display_impl)
1749 }
1750}
1751
1752struct ErrorImpl<'a>(&'a EnumInfo);
1753
1754impl<'a> quote::ToTokens for ErrorImpl<'a> {
1755 fn to_tokens(&self, stream: &mut proc_macro2::TokenStream) {
1756 use self::shared::{Error, ErrorProvideMatchArm, ErrorSourceMatchArm};
1757
1758 let crate_root = &self.0.crate_root;
1759
1760 let mut variants_to_description = Vec::with_capacity(self.0.variants.len());
1761 let mut variants_to_source = Vec::with_capacity(self.0.variants.len());
1762 let mut variants_to_provide = Vec::with_capacity(self.0.variants.len());
1763
1764 for field_container in &self.0.variants {
1765 let enum_name = &self.0.name;
1766 let variant_name = &field_container.name;
1767 let pattern_ident = "e! { #enum_name::#variant_name };
1768
1769 let error_description_match_arm = quote! {
1770 #pattern_ident { .. } => stringify!(#pattern_ident),
1771 };
1772
1773 let error_source_match_arm = ErrorSourceMatchArm {
1774 field_container,
1775 pattern_ident,
1776 };
1777 let error_source_match_arm = quote! { #error_source_match_arm };
1778
1779 let error_provide_match_arm = ErrorProvideMatchArm {
1780 crate_root,
1781 field_container,
1782 pattern_ident,
1783 };
1784 let error_provide_match_arm = quote! { #error_provide_match_arm };
1785
1786 variants_to_description.push(error_description_match_arm);
1787 variants_to_source.push(error_source_match_arm);
1788 variants_to_provide.push(error_provide_match_arm);
1789 }
1790
1791 let error_impl = Error {
1792 crate_root,
1793 parameterized_error_name: &self.0.parameterized_name(),
1794 description_arms: &variants_to_description,
1795 source_arms: &variants_to_source,
1796 original_generics: &self.0.provided_generics_without_defaults(),
1797 where_clauses: &self.0.provided_where_clauses(),
1798 provide_arms: &variants_to_provide,
1799 };
1800 let error_impl = quote! { #error_impl };
1801
1802 stream.extend(error_impl);
1803 }
1804}
1805
1806struct ErrorCompatImpl<'a>(&'a EnumInfo);
1807
1808impl<'a> quote::ToTokens for ErrorCompatImpl<'a> {
1809 fn to_tokens(&self, stream: &mut proc_macro2::TokenStream) {
1810 use self::shared::{ErrorCompat, ErrorCompatBacktraceMatchArm};
1811
1812 let variants_to_backtrace: Vec<_> = self
1813 .0
1814 .variants
1815 .iter()
1816 .map(|field_container| {
1817 let crate_root = &self.0.crate_root;
1818 let enum_name = &self.0.name;
1819 let variant_name = &field_container.name;
1820
1821 let match_arm = ErrorCompatBacktraceMatchArm {
1822 field_container,
1823 crate_root,
1824 pattern_ident: "e! { #enum_name::#variant_name },
1825 };
1826
1827 quote! { #match_arm }
1828 })
1829 .collect();
1830
1831 let error_compat_impl = ErrorCompat {
1832 crate_root: &self.0.crate_root,
1833 parameterized_error_name: &self.0.parameterized_name(),
1834 backtrace_arms: &variants_to_backtrace,
1835 original_generics: &self.0.provided_generics_without_defaults(),
1836 where_clauses: &self.0.provided_where_clauses(),
1837 };
1838
1839 let error_compat_impl = quote! { #error_compat_impl };
1840
1841 stream.extend(error_compat_impl);
1842 }
1843}
1844
1845impl NamedStructInfo {
1846 fn generate_snafu(self) -> proc_macro2::TokenStream {
1847 let parameterized_struct_name = self.parameterized_name();
1848 let original_generics = self.provided_generics_without_defaults();
1849 let where_clauses = self.provided_where_clauses();
1850
1851 let Self {
1852 crate_root,
1853 field_container:
1854 FieldContainer {
1855 name,
1856 selector_kind,
1857 backtrace_field,
1858 implicit_fields,
1859 display_format,
1860 doc_comment,
1861 visibility,
1862 module,
1863 ..
1864 },
1865 ..
1866 } = &self;
1867 let field_container = &self.field_container;
1868
1869 let user_fields = selector_kind.user_fields();
1870
1871 use crate::shared::{Error, ErrorProvideMatchArm, ErrorSourceMatchArm};
1872
1873 let pattern_ident = "e! { Self };
1874
1875 let error_description_match_arm = quote! {
1876 #pattern_ident { .. } => stringify!(#name),
1877 };
1878
1879 let error_source_match_arm = ErrorSourceMatchArm {
1880 field_container,
1881 pattern_ident,
1882 };
1883 let error_source_match_arm = quote! { #error_source_match_arm };
1884
1885 let error_provide_match_arm = ErrorProvideMatchArm {
1886 crate_root: &crate_root,
1887 field_container,
1888 pattern_ident,
1889 };
1890 let error_provide_match_arm = quote! { #error_provide_match_arm };
1891
1892 let error_impl = Error {
1893 crate_root: &crate_root,
1894 description_arms: &[error_description_match_arm],
1895 original_generics: &original_generics,
1896 parameterized_error_name: ¶meterized_struct_name,
1897 provide_arms: &[error_provide_match_arm],
1898 source_arms: &[error_source_match_arm],
1899 where_clauses: &where_clauses,
1900 };
1901 let error_impl = quote! { #error_impl };
1902
1903 use self::shared::{ErrorCompat, ErrorCompatBacktraceMatchArm};
1904
1905 let match_arm = ErrorCompatBacktraceMatchArm {
1906 field_container,
1907 crate_root: &crate_root,
1908 pattern_ident: "e! { Self },
1909 };
1910 let match_arm = quote! { #match_arm };
1911
1912 let error_compat_impl = ErrorCompat {
1913 crate_root: &crate_root,
1914 parameterized_error_name: ¶meterized_struct_name,
1915 backtrace_arms: &[match_arm],
1916 original_generics: &original_generics,
1917 where_clauses: &where_clauses,
1918 };
1919
1920 use crate::shared::{Display, DisplayMatchArm};
1921
1922 let arm = DisplayMatchArm {
1923 field_container,
1924 default_name: &name,
1925 display_format: display_format.as_ref(),
1926 doc_comment: doc_comment.as_ref(),
1927 pattern_ident: "e! { Self },
1928 selector_kind,
1929 };
1930 let arm = quote! { #arm };
1931
1932 let display_impl = Display {
1933 arms: &[arm],
1934 original_generics: &original_generics,
1935 parameterized_error_name: ¶meterized_struct_name,
1936 where_clauses: &where_clauses,
1937 };
1938
1939 use crate::shared::ContextSelector;
1940
1941 let selector_doc_string = format!("SNAFU context selector for the `{}` error", name);
1942
1943 let default_visibility;
1944 let selector_visibility = match (visibility, module) {
1945 (Some(v), _) => Some(&**v),
1946 (None, Some(_)) => {
1947 default_visibility = default_context_selector_visibility_in_module();
1948 Some(&default_visibility as _)
1949 }
1950 (None, None) => None,
1951 };
1952
1953 let context_selector = ContextSelector {
1954 backtrace_field: backtrace_field.as_ref(),
1955 implicit_fields,
1956 crate_root: &crate_root,
1957 error_constructor_name: &name,
1958 original_generics_without_defaults: &original_generics,
1959 parameterized_error_name: ¶meterized_struct_name,
1960 selector_doc_string: &selector_doc_string,
1961 selector_kind,
1962 selector_name: &field_container.name,
1963 user_fields,
1964 visibility: selector_visibility,
1965 where_clauses: &where_clauses,
1966 default_suffix: &SuffixKind::Default,
1967 };
1968
1969 let context = match module {
1970 None => quote! { #context_selector },
1971 Some(module_name) => {
1972 use crate::shared::ContextModule;
1973
1974 let context_module = ContextModule {
1975 container_name: self.name(),
1976 body: &context_selector,
1977 visibility: visibility.as_ref().map(|x| &**x),
1978 module_name,
1979 };
1980
1981 quote! { #context_module }
1982 }
1983 };
1984
1985 quote! {
1986 #error_impl
1987 #error_compat_impl
1988 #display_impl
1989 #context
1990 }
1991 }
1992}
1993
1994impl GenericAwareNames for NamedStructInfo {
1995 fn name(&self) -> &syn::Ident {
1996 &self.field_container.name
1997 }
1998
1999 fn generics(&self) -> &syn::Generics {
2000 &self.generics
2001 }
2002}
2003
2004impl TupleStructInfo {
2005 fn generate_snafu(self) -> proc_macro2::TokenStream {
2006 let parameterized_struct_name = self.parameterized_name();
2007
2008 let TupleStructInfo {
2009 crate_root,
2010 generics,
2011 name,
2012 transformation,
2013 provides,
2014 } = self;
2015
2016 let inner_type = transformation.source_ty();
2017 let transformation = transformation.transformation();
2018
2019 let where_clauses: Vec<_> = generics
2020 .where_clause
2021 .iter()
2022 .flat_map(|c| c.predicates.iter().map(|p| quote! { #p }))
2023 .collect();
2024
2025 let description_fn = quote! {
2026 fn description(&self) -> &str {
2027 #crate_root::Error::description(&self.0)
2028 }
2029 };
2030
2031 let cause_fn = quote! {
2032 fn cause(&self) -> ::core::option::Option<&dyn #crate_root::Error> {
2033 #crate_root::Error::cause(&self.0)
2034 }
2035 };
2036
2037 let source_fn = quote! {
2038 fn source(&self) -> ::core::option::Option<&(dyn #crate_root::Error + 'static)> {
2039 #crate_root::Error::source(&self.0)
2040 }
2041 };
2042
2043 let backtrace_fn = quote! {
2044 fn backtrace(&self) -> ::core::option::Option<&#crate_root::Backtrace> {
2045 #crate_root::ErrorCompat::backtrace(&self.0)
2046 }
2047 };
2048
2049 let provide_fn = if cfg!(feature = "unstable-provider-api") {
2050 use shared::error::PROVIDE_ARG;
2051
2052 let provides = shared::error::enhance_provider_list(&provides);
2053 let cached_expressions = shared::error::quote_cached_expressions(&provides);
2054 let user_chained = shared::error::quote_chained(&crate_root, &provides);
2055
2056 let (hi_explicit_calls, lo_explicit_calls) =
2057 shared::error::build_explicit_provide_calls(&provides);
2058
2059 Some(quote! {
2060 fn provide<'a>(&'a self, #PROVIDE_ARG: &mut #crate_root::error::Request<'a>) {
2061 match self {
2062 Self(v) => {
2063 #(#cached_expressions;)*
2064 #(#hi_explicit_calls;)*
2065 v.provide(#PROVIDE_ARG);
2066 #(#user_chained;)*
2067 #(#lo_explicit_calls;)*
2068 }
2069 };
2070 }
2071 })
2072 } else {
2073 None
2074 };
2075
2076 let error_impl = quote! {
2077 #[allow(single_use_lifetimes)]
2078 impl#generics #crate_root::Error for #parameterized_struct_name
2079 where
2080 #(#where_clauses),*
2081 {
2082 #description_fn
2083 #cause_fn
2084 #source_fn
2085 #provide_fn
2086 }
2087 };
2088
2089 let error_compat_impl = quote! {
2090 #[allow(single_use_lifetimes)]
2091 impl#generics #crate_root::ErrorCompat for #parameterized_struct_name
2092 where
2093 #(#where_clauses),*
2094 {
2095 #backtrace_fn
2096 }
2097 };
2098
2099 let display_impl = quote! {
2100 #[allow(single_use_lifetimes)]
2101 impl#generics ::core::fmt::Display for #parameterized_struct_name
2102 where
2103 #(#where_clauses),*
2104 {
2105 fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
2106 ::core::fmt::Display::fmt(&self.0, f)
2107 }
2108 }
2109 };
2110
2111 let from_impl = quote! {
2112 impl#generics ::core::convert::From<#inner_type> for #parameterized_struct_name
2113 where
2114 #(#where_clauses),*
2115 {
2116 fn from(other: #inner_type) -> Self {
2117 #name((#transformation)(other))
2118 }
2119 }
2120 };
2121
2122 quote! {
2123 #error_impl
2124 #error_compat_impl
2125 #display_impl
2126 #from_impl
2127 }
2128 }
2129}
2130
2131impl GenericAwareNames for TupleStructInfo {
2132 fn name(&self) -> &syn::Ident {
2133 &self.name
2134 }
2135
2136 fn generics(&self) -> &syn::Generics {
2137 &self.generics
2138 }
2139}
2140
2141mod sponge {
2142 use std::iter::FromIterator;
2143
2144 pub struct AllErrors<T, E>(Result<T, Vec<E>>);
2145
2146 impl<T, E> AllErrors<T, E> {
2147 pub fn into_result(self) -> Result<T, Vec<E>> {
2148 self.0
2149 }
2150 }
2151
2152 impl<C, T, E> FromIterator<Result<C, E>> for AllErrors<T, E>
2153 where
2154 T: FromIterator<C>,
2155 {
2156 fn from_iter<I>(i: I) -> Self
2157 where
2158 I: IntoIterator<Item = Result<C, E>>,
2159 {
2160 let mut errors = Vec::new();
2161
2162 let inner = i
2163 .into_iter()
2164 .flat_map(|v| match v {
2165 Ok(v) => Ok(v),
2166 Err(e) => {
2167 errors.push(e);
2168 Err(())
2169 }
2170 })
2171 .collect();
2172
2173 if errors.is_empty() {
2174 AllErrors(Ok(inner))
2175 } else {
2176 AllErrors(Err(errors))
2177 }
2178 }
2179 }
2180
2181 impl<C, T, E> FromIterator<Result<C, Vec<E>>> for AllErrors<T, E>
2182 where
2183 T: FromIterator<C>,
2184 {
2185 fn from_iter<I>(i: I) -> Self
2186 where
2187 I: IntoIterator<Item = Result<C, Vec<E>>>,
2188 {
2189 let mut errors = Vec::new();
2190
2191 let inner = i
2192 .into_iter()
2193 .flat_map(|v| match v {
2194 Ok(v) => Ok(v),
2195 Err(e) => {
2196 errors.extend(e);
2197 Err(())
2198 }
2199 })
2200 .collect();
2201
2202 if errors.is_empty() {
2203 AllErrors(Ok(inner))
2204 } else {
2205 AllErrors(Err(errors))
2206 }
2207 }
2208 }
2209}