snafu_derive/
lib.rs

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