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 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/// SyntaxErrors is a convenience wrapper for a list of syntax errors discovered while parsing
235/// something that derives Snafu.  It makes it easier for developers to add and return syntax
236/// errors while walking through the parse tree.
237#[derive(Debug, Default)]
238struct SyntaxErrors {
239    inner: Vec<syn::Error>,
240}
241
242impl SyntaxErrors {
243    /// Start a set of errors that all share the same location
244    fn scoped(&mut self, scope: ErrorLocation) -> SyntaxErrorsScoped<'_> {
245        SyntaxErrorsScoped {
246            errors: self,
247            scope,
248        }
249    }
250
251    /// Adds a new syntax error. The description will be used in the
252    /// compile error pointing to the tokens.
253    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    /// Adds the given list of errors.
259    fn extend(&mut self, errors: impl IntoIterator<Item = syn::Error>) {
260        self.inner.extend(errors);
261    }
262
263    #[allow(dead_code)]
264    /// Returns the number of errors that have been added.
265    fn len(&self) -> usize {
266        self.inner.len()
267    }
268
269    /// Consume the SyntaxErrors, returning Ok if there were no syntax errors added, or Err(list)
270    /// if there were syntax errors.
271    fn finish(self) -> MultiSynResult<()> {
272        if self.inner.is_empty() {
273            Ok(())
274        } else {
275            Err(self.inner)
276        }
277    }
278
279    /// Consume the SyntaxErrors and a Result, returning the success
280    /// value if neither have errors, otherwise combining the errors.
281    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    /// Adds a new syntax error. The description will be used in the
332    /// compile error pointing to the tokens.
333    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/// Helper structure to handle cases where an attribute is
340/// syntactically valid but semantically invalid.
341#[derive(Debug)]
342struct DoesNothing {
343    /// The name of the attribute that was misused.
344    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/// Helper structure to handle cases where an attribute was used on an
354/// element where it's not valid.
355#[derive(Debug)]
356struct OnlyValidOn {
357    /// The name of the attribute that was misused.
358    attribute: &'static str,
359    /// A description of where that attribute is valid.
360    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/// Helper structure to handle cases where a specific attribute value
373/// was used on an field where it's not valid.
374#[derive(Debug)]
375struct WrongField {
376    /// The name of the attribute that was misused.
377    attribute: &'static str,
378    /// The name of the field where that attribute is valid.
379    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/// Helper structure to handle cases where two incompatible attributes
392/// were specified on the same element.
393#[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/// Helper structure to handle cases where an attribute was
412/// incorrectly used multiple times on the same element.
413#[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/// AtMostOne is a helper to track attributes seen during parsing.  If more than one item is added,
430/// it's added to a list of DuplicateAttribute errors, using the given `name` and `location` as
431/// descriptors.
432///
433/// When done parsing a structure, call `finish` to get first attribute found, if any, and the list
434/// of errors, or call `finish_with_location` to get the attribute and the token tree where it was
435/// found, which can be useful for error reporting.
436#[derive(Debug)]
437struct AtMostOne<T, U>
438where
439    U: quote::ToTokens,
440{
441    name: &'static str,
442    location: ErrorLocation,
443    // We store all the values we've seen to allow for `iter`, which helps the `AtMostOne` be
444    // useful for additional manual error checking.
445    values: VecDeque<(T, U)>,
446    errors: SyntaxErrors,
447}
448
449impl<T, U> AtMostOne<T, U>
450where
451    U: quote::ToTokens + Clone,
452{
453    /// Creates an AtMostOne to track an attribute with the given
454    /// `name` on the given `location` (often referencing a parent
455    /// element).
456    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    /// Add an occurence of the attribute found at the given token tree `tokens`.
466    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    /// Returns the number of elements that have been added.
481    fn len(&self) -> usize {
482        self.values.len()
483    }
484
485    /// Returns true if no elements have been added, otherwise false.
486    #[allow(dead_code)]
487    fn is_empty(&self) -> bool {
488        self.values.is_empty()
489    }
490
491    /// Returns an iterator over all values that have been added.
492    ///
493    /// This can help with additional manual error checks beyond the duplication checks that
494    /// `AtMostOne` handles for you.
495    fn iter(&self) -> std::collections::vec_deque::Iter<(T, U)> {
496        self.values.iter()
497    }
498
499    /// Consumes the AtMostOne, returning the first item added, if any, and the list of errors
500    /// representing any items added beyond the first.
501    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    /// Like `finish` but also returns the location of the first item added.  Useful when you have
507    /// to do additional, manual error checking on the first item added, and you'd like to report
508    /// an accurate location for it in case of errors.
509    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(..) => { /* Just a regular doc comment. */ }
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                // TODO: can we have improved error handling for obvious type duplicates?
815                provides.push(provide);
816            }
817            Att::DocComment(_tts, doc_comment_line) => {
818                // We join all the doc comment attributes with a space,
819                // but end once the summary of the doc comment is
820                // complete, which is indicated by an empty line.
821                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        // Check whether we have multiple source/backtrace attributes on this field.
847        // We can't just add to source_fields/backtrace_fields from inside the attribute
848        // loop because source and backtrace are connected and require a bit of special
849        // logic after the attribute loop.  For example, we need to know whether there's a
850        // source transformation before we record a source field, but it might be on a
851        // later attribute.  We use the data field of `source_attrs` to track any
852        // transformations in case it was a `source(from(...))`, but for backtraces we
853        // don't need any more data.
854        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        // Keep track of the negative markers so we can check for inconsistencies and
860        // exclude fields even if they have the "source" or "backtrace" name.
861        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                                // If we've seen a `source(from)` then there will be a
876                                // `Some` value in `source_attrs`.
877                                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(..) => { /* Just a regular doc comment. */ }
937            }
938        }
939
940        // Add errors for any duplicated attributes on this field.
941        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                    // Specifying `backtrace` on a source field is how you request
994                    // delegation of the backtrace to the source error type.
995                    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        _ => {} // no conflict
1029    }
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            // `transparent` implies `context(false)`. Treat `transparent` as if setting
1069            // `context(false)` as well.
1070            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                    // todo: phrasing?
1112                }
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(..) => { /* Just a regular doc comment. */ }
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(..) => { /* Just a regular doc comment. */ }
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
1421/// A SnafuAttribute represents one SNAFU-specific attribute inside of `#[snafu(...)]`.  For
1422/// example, in `#[snafu(visibility(pub), display("hi"))]`, `visibility(pub)` and `display("hi")`
1423/// are each a SnafuAttribute.
1424///
1425/// We store the location in the source where we found the attribute (as a `TokenStream`) along
1426/// with the data.  The location can be used to give accurate error messages in case there was a
1427/// problem with the use of the attribute.
1428enum 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
1451// Private context selectors wouldn't be accessible outside the
1452// module, so we use `pub(super)`.
1453fn 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: &quote! { #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: &quote! { #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 = &quote! { #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: &quote! { #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 = &quote! { 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: &parameterized_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: &quote! { 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: &parameterized_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: &quote! { 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: &parameterized_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: &parameterized_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}