darling_core/error/
mod.rs

1//! The `darling::Error` type, the multiple error `Accumulator`, and their internals.
2//!
3//! Error handling is one of the core values of `darling`; creating great errors is hard and
4//! never the reason that a proc-macro author started writing their crate. As a result, the
5//! `Error` type in `darling` tries to make adding span information, suggestions, and other
6//! help content easy when manually implementing `darling` traits, and automatic when deriving
7//! them.
8
9use proc_macro2::{Span, TokenStream};
10use std::error::Error as StdError;
11use std::fmt;
12use std::iter::{self, Iterator};
13use std::string::ToString;
14use std::vec;
15use syn::spanned::Spanned;
16use syn::{Expr, Lit, LitStr, Path};
17
18#[cfg(feature = "diagnostics")]
19mod child;
20mod kind;
21mod util;
22
23use crate::util::path_to_string;
24
25use self::kind::{ErrorKind, ErrorUnknownValue, UnknownValuePosition};
26
27/// An alias of `Result` specific to attribute parsing.
28pub type Result<T> = ::std::result::Result<T, Error>;
29
30/// An error encountered during attribute parsing.
31///
32/// Given that most errors darling encounters represent code bugs in dependent crates,
33/// the internal structure of the error is deliberately opaque.
34///
35/// # Usage
36/// Proc-macro expansion happens very infrequently compared to runtime tasks such as
37/// deserialization, and it happens in the context of an expensive compilation taks.
38/// For that reason, darling prefers not to fail on the first error it encounters, instead
39/// doing as much work as it can, accumulating errors into a single report.
40///
41/// As a result, `darling::Error` is more of guaranteed-non-empty error collection
42/// than a single problem. These errors also have some notion of hierarchy, stemming from
43/// the hierarchical nature of darling's input.
44///
45/// These characteristics make for great experiences when using darling-powered crates,
46/// provided crates using darling adhere to some best practices:
47///
48/// 1. Do not attempt to simplify a `darling::Error` into some other error type, such as
49///    `syn::Error`. To surface compile errors, instead use `darling::Error::write_errors`.
50///    This preserves all span information, suggestions, etc. Wrapping a `darling::Error` in
51///    a custom error enum works as-expected and does not force any loss of fidelity.
52/// 2. Do not use early return (e.g. the `?` operator) for custom validations. Instead,
53///    create an [`error::Accumulator`](Accumulator) to collect errors as they are encountered.  Then use
54///    [`Accumulator::finish`] to return your validated result; it will give `Ok` if and only if
55///    no errors were encountered.  This can create very complex custom validation functions;
56///    in those cases, split independent "validation chains" out into their own functions to
57///    keep the main validator manageable.
58/// 3. Use `darling::Error::custom` to create additional errors as-needed, then call `with_span`
59///    to ensure those errors appear in the right place. Use `darling::util::SpannedValue` to keep
60///    span information around on parsed fields so that custom diagnostics can point to the correct
61///    parts of the input AST.
62#[derive(Debug, Clone)]
63pub struct Error {
64    kind: ErrorKind,
65    locations: Vec<String>,
66    /// The span to highlight in the emitted diagnostic.
67    span: Option<Span>,
68    /// Additional diagnostic messages to show with the error.
69    #[cfg(feature = "diagnostics")]
70    children: Vec<child::ChildDiagnostic>,
71}
72
73/// Error creation functions
74impl Error {
75    pub(in crate::error) fn new(kind: ErrorKind) -> Self {
76        Error {
77            kind,
78            locations: Vec::new(),
79            span: None,
80            #[cfg(feature = "diagnostics")]
81            children: vec![],
82        }
83    }
84
85    /// Creates a new error with a custom message.
86    pub fn custom<T: fmt::Display>(msg: T) -> Self {
87        Error::new(ErrorKind::Custom(msg.to_string()))
88    }
89
90    /// Creates a new error for a field that appears twice in the input.
91    pub fn duplicate_field(name: &str) -> Self {
92        Error::new(ErrorKind::DuplicateField(name.into()))
93    }
94
95    /// Creates a new error for a field that appears twice in the input. Helper to avoid repeating
96    /// the syn::Path to String conversion.
97    pub fn duplicate_field_path(path: &Path) -> Self {
98        Error::duplicate_field(&path_to_string(path))
99    }
100
101    /// Creates a new error for a non-optional field that does not appear in the input.
102    pub fn missing_field(name: &str) -> Self {
103        Error::new(ErrorKind::MissingField(name.into()))
104    }
105
106    /// Creates a new error for a field name that appears in the input but does not correspond
107    /// to a known field.
108    pub fn unknown_field(name: &str) -> Self {
109        Error::new(ErrorUnknownValue::new(UnknownValuePosition::Field, name).into())
110    }
111
112    /// Creates a new error for a field name that appears in the input but does not correspond
113    /// to a known field. Helper to avoid repeating the syn::Path to String conversion.
114    pub fn unknown_field_path(path: &Path) -> Self {
115        Error::unknown_field(&path_to_string(path))
116    }
117
118    /// Creates a new error for a field name that appears in the input but does not correspond to
119    /// a known attribute. The second argument is the list of known attributes; if a similar name
120    /// is found that will be shown in the emitted error message.
121    pub fn unknown_field_with_alts<'a, T, I>(field: &str, alternates: I) -> Self
122    where
123        T: AsRef<str> + 'a,
124        I: IntoIterator<Item = &'a T>,
125    {
126        Error::new(
127            ErrorUnknownValue::with_alts(UnknownValuePosition::Field, field, alternates).into(),
128        )
129    }
130
131    /// Creates a new error for a field name that appears in the input but does not correspond to
132    /// a known attribute. The second argument is the list of known attributes; if a similar name
133    /// is found that will be shown in the emitted error message.
134    pub fn unknown_field_path_with_alts<'a, T, I>(field: &Path, alternates: I) -> Self
135    where
136        T: AsRef<str> + 'a,
137        I: IntoIterator<Item = &'a T>,
138    {
139        Error::new(ErrorKind::UnknownField(
140            ErrorUnknownValue::with_alts(
141                UnknownValuePosition::Field,
142                &path_to_string(field),
143                alternates,
144            )
145            .into(),
146        ))
147    }
148
149    /// Creates a new error for a struct or variant that does not adhere to the supported shape.
150    pub fn unsupported_shape(shape: &str) -> Self {
151        Error::new(ErrorKind::UnsupportedShape {
152            observed: shape.into(),
153            expected: None,
154        })
155    }
156
157    pub fn unsupported_shape_with_expected<T: fmt::Display>(shape: &str, expected: &T) -> Self {
158        Error::new(ErrorKind::UnsupportedShape {
159            observed: shape.into(),
160            expected: Some(expected.to_string()),
161        })
162    }
163
164    pub fn unsupported_format(format: &str) -> Self {
165        Error::new(ErrorKind::UnexpectedFormat(format.into()))
166    }
167
168    /// Creates a new error for a field which has an unexpected literal type.
169    pub fn unexpected_type(ty: &str) -> Self {
170        Error::new(ErrorKind::UnexpectedType(ty.into()))
171    }
172
173    pub fn unexpected_expr_type(expr: &Expr) -> Self {
174        Error::unexpected_type(match *expr {
175            Expr::Array(_) => "array",
176            Expr::Assign(_) => "assign",
177            Expr::Async(_) => "async",
178            Expr::Await(_) => "await",
179            Expr::Binary(_) => "binary",
180            Expr::Block(_) => "block",
181            Expr::Break(_) => "break",
182            Expr::Call(_) => "call",
183            Expr::Cast(_) => "cast",
184            Expr::Closure(_) => "closure",
185            Expr::Const(_) => "const",
186            Expr::Continue(_) => "continue",
187            Expr::Field(_) => "field",
188            Expr::ForLoop(_) => "for_loop",
189            Expr::Group(_) => "group",
190            Expr::If(_) => "if",
191            Expr::Index(_) => "index",
192            Expr::Infer(_) => "infer",
193            Expr::Let(_) => "let",
194            Expr::Lit(_) => "lit",
195            Expr::Loop(_) => "loop",
196            Expr::Macro(_) => "macro",
197            Expr::Match(_) => "match",
198            Expr::MethodCall(_) => "method_call",
199            Expr::Paren(_) => "paren",
200            Expr::Path(_) => "path",
201            Expr::Range(_) => "range",
202            Expr::Reference(_) => "reference",
203            Expr::Repeat(_) => "repeat",
204            Expr::Return(_) => "return",
205            Expr::Struct(_) => "struct",
206            Expr::Try(_) => "try",
207            Expr::TryBlock(_) => "try_block",
208            Expr::Tuple(_) => "tuple",
209            Expr::Unary(_) => "unary",
210            Expr::Unsafe(_) => "unsafe",
211            Expr::Verbatim(_) => "verbatim",
212            Expr::While(_) => "while",
213            Expr::Yield(_) => "yield",
214            // non-exhaustive enum
215            _ => "unknown",
216        })
217        .with_span(expr)
218    }
219
220    /// Creates a new error for a field which has an unexpected literal type. This will automatically
221    /// extract the literal type name from the passed-in `Lit` and set the span to encompass only the
222    /// literal value.
223    ///
224    /// # Usage
225    /// This is most frequently used in overrides of the `FromMeta::from_value` method.
226    ///
227    /// ```rust
228    /// # // pretend darling_core is darling so the doc example looks correct.
229    /// # extern crate darling_core as darling;
230    /// # extern crate syn;
231    ///
232    /// use darling::{FromMeta, Error, Result};
233    /// use syn::{Lit, LitStr};
234    ///
235    /// pub struct Foo(String);
236    ///
237    /// impl FromMeta for Foo {
238    ///     fn from_value(value: &Lit) -> Result<Self> {
239    ///         if let Lit::Str(ref lit_str) = *value {
240    ///             Ok(Foo(lit_str.value()))
241    ///         } else {
242    ///             Err(Error::unexpected_lit_type(value))
243    ///         }
244    ///     }
245    /// }
246    ///
247    /// # fn main() {}
248    /// ```
249    pub fn unexpected_lit_type(lit: &Lit) -> Self {
250        Error::unexpected_type(match *lit {
251            Lit::Str(_) => "string",
252            Lit::ByteStr(_) => "byte string",
253            Lit::Byte(_) => "byte",
254            Lit::Char(_) => "char",
255            Lit::Int(_) => "int",
256            Lit::Float(_) => "float",
257            Lit::Bool(_) => "bool",
258            Lit::Verbatim(_) => "verbatim",
259            // non-exhaustive enum
260            _ => "unknown",
261        })
262        .with_span(lit)
263    }
264
265    /// Creates a new error for a value which doesn't match a set of expected literals.
266    pub fn unknown_value(value: &str) -> Self {
267        Error::new(ErrorUnknownValue::new(UnknownValuePosition::Value, value).into())
268    }
269
270    pub fn unknown_value_with_alts<'a, T, I>(value: &str, alternates: I) -> Self
271    where
272        T: AsRef<str> + 'a,
273        I: IntoIterator<Item = &'a T>,
274    {
275        Error::new(
276            ErrorUnknownValue::with_alts(UnknownValuePosition::Value, value, alternates).into(),
277        )
278    }
279
280    /// Creates a new error for a list which did not get enough items to proceed.
281    pub fn too_few_items(min: usize) -> Self {
282        Error::new(ErrorKind::TooFewItems(min))
283    }
284
285    /// Creates a new error when a list got more items than it supports. The `max` argument
286    /// is the largest number of items the receiver could accept.
287    pub fn too_many_items(max: usize) -> Self {
288        Error::new(ErrorKind::TooManyItems(max))
289    }
290
291    /// Bundle a set of multiple errors into a single `Error` instance.
292    ///
293    /// Usually it will be more convenient to use an [`error::Accumulator`](Accumulator).
294    ///
295    /// # Panics
296    /// This function will panic if `errors.is_empty() == true`.
297    pub fn multiple(mut errors: Vec<Error>) -> Self {
298        match errors.len() {
299            1 => errors
300                .pop()
301                .expect("Error array of length 1 has a first item"),
302            0 => panic!("Can't deal with 0 errors"),
303            _ => Error::new(ErrorKind::Multiple(errors)),
304        }
305    }
306
307    /// Creates an error collector, for aggregating multiple errors
308    ///
309    /// See [`Accumulator`] for details.
310    pub fn accumulator() -> Accumulator {
311        Default::default()
312    }
313}
314
315impl Error {
316    /// Create a new error about a literal string that doesn't match a set of known
317    /// or permissible values. This function can be made public if the API proves useful
318    /// beyond impls for `syn` types.
319    pub(crate) fn unknown_lit_str_value(value: &LitStr) -> Self {
320        Error::unknown_value(&value.value()).with_span(value)
321    }
322}
323
324/// Error instance methods
325#[allow(clippy::len_without_is_empty)] // Error can never be empty
326impl Error {
327    /// Check if this error is associated with a span in the token stream.
328    pub fn has_span(&self) -> bool {
329        self.span.is_some()
330    }
331
332    /// Tie a span to the error if none is already present. This is used in `darling::FromMeta`
333    /// and other traits to attach errors to the most specific possible location in the input
334    /// source code.
335    ///
336    /// All `darling`-built impls, either from the crate or from the proc macro, will call this
337    /// when appropriate during parsing, so it should not be necessary to call this unless you have
338    /// overridden:
339    ///
340    /// * `FromMeta::from_meta`
341    /// * `FromMeta::from_nested_meta`
342    /// * `FromMeta::from_value`
343    pub fn with_span<T: Spanned>(mut self, node: &T) -> Self {
344        if !self.has_span() {
345            self.span = Some(node.span());
346        }
347
348        self
349    }
350
351    /// Get a span for the error.
352    ///
353    /// # Return Value
354    /// This function will return [`Span::call_site()`](proc_macro2::Span) if [`Self::has_span`] is `false`.
355    /// To get the span only if one has been explicitly set for `self`, instead use [`Error::explicit_span`].
356    pub fn span(&self) -> Span {
357        self.span.unwrap_or_else(Span::call_site)
358    }
359
360    /// Get the span for `self`, if one has been set.
361    pub fn explicit_span(&self) -> Option<Span> {
362        self.span
363    }
364
365    /// Recursively converts a tree of errors to a flattened list.
366    ///
367    /// # Child Diagnostics
368    /// If the `diagnostics` feature is enabled, any child diagnostics on `self`
369    /// will be cloned down to all the errors within `self`.
370    pub fn flatten(self) -> Self {
371        Error::multiple(self.into_vec())
372    }
373
374    fn into_vec(self) -> Vec<Self> {
375        if let ErrorKind::Multiple(errors) = self.kind {
376            let locations = self.locations;
377
378            #[cfg(feature = "diagnostics")]
379            let children = self.children;
380
381            errors
382                .into_iter()
383                .flat_map(|error| {
384                    // This is mutated if the diagnostics feature is enabled
385                    #[allow(unused_mut)]
386                    let mut error = error.prepend_at(locations.clone());
387
388                    // Any child diagnostics in `self` are cloned down to all the distinct
389                    // errors contained in `self`.
390                    #[cfg(feature = "diagnostics")]
391                    error.children.extend(children.iter().cloned());
392
393                    error.into_vec()
394                })
395                .collect()
396        } else {
397            vec![self]
398        }
399    }
400
401    /// Adds a location to the error, such as a field or variant.
402    /// Locations must be added in reverse order of specificity.
403    pub fn at<T: fmt::Display>(mut self, location: T) -> Self {
404        self.locations.insert(0, location.to_string());
405        self
406    }
407
408    /// Adds a location to the error, such as a field or variant.
409    /// Locations must be added in reverse order of specificity. This is a helper function to avoid
410    /// repeating path to string logic.
411    pub fn at_path(self, path: &Path) -> Self {
412        self.at(path_to_string(path))
413    }
414
415    /// Gets the number of individual errors in this error.
416    ///
417    /// This function never returns `0`, as it's impossible to construct
418    /// a multi-error from an empty `Vec`.
419    pub fn len(&self) -> usize {
420        self.kind.len()
421    }
422
423    /// Consider additional field names as "did you mean" suggestions for
424    /// unknown field errors **if and only if** the caller appears to be operating
425    /// at error's origin (meaning no calls to [`Self::at`] have yet taken place).
426    ///
427    /// # Usage
428    /// `flatten` fields in derived trait implementations rely on this method to offer correct
429    /// "did you mean" suggestions in errors.
430    ///
431    /// Because the `flatten` field receives _all_ unknown fields, if a user mistypes a field name
432    /// that is present on the outer struct but not the flattened struct, they would get an incomplete
433    /// or inferior suggestion unless this method was invoked.
434    pub fn add_sibling_alts_for_unknown_field<'a, T, I>(mut self, alternates: I) -> Self
435    where
436        T: AsRef<str> + 'a,
437        I: IntoIterator<Item = &'a T>,
438    {
439        // The error may have bubbled up before this method was called,
440        // and in those cases adding alternates would be incorrect.
441        if !self.locations.is_empty() {
442            return self;
443        }
444
445        // This is a callback because we don't want to use the iterator
446        // if we don't need to.
447        let collect_alts = || {
448            alternates
449                .into_iter()
450                .map(|s| s.as_ref())
451                .collect::<Vec<_>>()
452        };
453
454        if let ErrorKind::UnknownField(unknown_field) = &mut self.kind {
455            unknown_field.add_alts(&collect_alts());
456        } else if let ErrorKind::Multiple(errors) = self.kind {
457            // Gather up the alternates to avoid unnecessary allocations
458            // on a per-contained-error basis.
459            let alts = collect_alts();
460            self.kind = ErrorKind::Multiple(
461                errors
462                    .into_iter()
463                    .map(|err| err.add_sibling_alts_for_unknown_field_internal(&alts))
464                    .collect(),
465            )
466        }
467
468        self
469    }
470
471    fn add_sibling_alts_for_unknown_field_internal(mut self, alternates: &[&str]) -> Self {
472        // The error may have bubbled up before this method was called,
473        // and in those cases adding alternates would be incorrect.
474        if !self.locations.is_empty() {
475            return self;
476        }
477
478        if let ErrorKind::UnknownField(unknown_field) = &mut self.kind {
479            unknown_field.add_alts(alternates);
480        } else if let ErrorKind::Multiple(errors) = self.kind {
481            self.kind = ErrorKind::Multiple(
482                errors
483                    .into_iter()
484                    .map(|err| err.add_sibling_alts_for_unknown_field_internal(alternates))
485                    .collect(),
486            )
487        }
488
489        self
490    }
491
492    /// Adds a location chain to the head of the error's existing locations.
493    fn prepend_at(mut self, mut locations: Vec<String>) -> Self {
494        if !locations.is_empty() {
495            locations.extend(self.locations);
496            self.locations = locations;
497        }
498
499        self
500    }
501
502    /// Gets the location slice.
503    #[cfg(test)]
504    pub(crate) fn location(&self) -> Vec<&str> {
505        self.locations.iter().map(|i| i.as_str()).collect()
506    }
507
508    /// Write this error and any children as compile errors into a `TokenStream` to
509    /// be returned by the proc-macro.
510    ///
511    /// The behavior of this method will be slightly different if the `diagnostics` feature
512    /// is enabled: In that case, the diagnostics will be emitted immediately by this call,
513    /// and an empty `TokenStream` will be returned.
514    ///
515    /// Return these tokens unmodified to avoid disturbing the attached span information.
516    ///
517    /// # Usage
518    /// ```rust,ignore
519    /// // in your proc-macro function
520    /// let opts = match MyOptions::from_derive_input(&ast) {
521    ///     Ok(val) => val,
522    ///     Err(err) => {
523    ///         return err.write_errors();
524    ///     }
525    /// }
526    /// ```
527    pub fn write_errors(self) -> TokenStream {
528        #[cfg(feature = "diagnostics")]
529        {
530            self.emit();
531            TokenStream::default()
532        }
533
534        #[cfg(not(feature = "diagnostics"))]
535        {
536            syn::Error::from(self).into_compile_error()
537        }
538    }
539
540    #[cfg(feature = "diagnostics")]
541    fn single_to_diagnostic(self) -> ::proc_macro::Diagnostic {
542        use proc_macro::{Diagnostic, Level};
543
544        // Delegate to dedicated error formatters when applicable.
545        //
546        // If span information is available, don't include the error property path
547        // since it's redundant and not consistent with native compiler diagnostics.
548        let diagnostic = match self.kind {
549            ErrorKind::UnknownField(euf) => euf.into_diagnostic(self.span),
550            ErrorKind::UnknownValue(euv) => euv.into_diagnostic(self.span),
551            _ => match self.span {
552                Some(span) => span.unwrap().error(self.kind.to_string()),
553                None => Diagnostic::new(Level::Error, self.to_string()),
554            },
555        };
556
557        self.children
558            .into_iter()
559            .fold(diagnostic, |out, child| child.append_to(out))
560    }
561
562    /// Transform this error and its children into a list of compiler diagnostics
563    /// and emit them. If the `Error` has associated span information, the diagnostics
564    /// will identify the correct location in source code automatically.
565    ///
566    /// # Stability
567    /// This is only available on `nightly` until the compiler `proc_macro_diagnostic`
568    /// feature stabilizes. Until then, it may break at any time.
569    #[cfg(feature = "diagnostics")]
570    pub fn emit(self) {
571        for error in self.flatten() {
572            error.single_to_diagnostic().emit()
573        }
574    }
575
576    /// Transform the error into a compiler diagnostic and - if the diagnostic points to
577    /// a specific code location - add a spanned help child diagnostic that points to the
578    /// parent derived trait.
579    ///
580    /// This is experimental and therefore not exposed outside the crate.
581    #[cfg(feature = "diagnostics")]
582    #[allow(dead_code)]
583    fn emit_with_macro_help_span(self) {
584        use proc_macro::Diagnostic;
585
586        for error in self.flatten() {
587            let needs_help = error.has_span();
588            let diagnostic = error.single_to_diagnostic();
589            Diagnostic::emit(if needs_help {
590                diagnostic.span_help(
591                    Span::call_site().unwrap(),
592                    "Encountered as part of this derive-mode-macro",
593                )
594            } else {
595                diagnostic
596            })
597        }
598    }
599}
600
601#[cfg(feature = "diagnostics")]
602macro_rules! add_child {
603    ($unspanned:ident, $spanned:ident, $level:ident) => {
604        #[doc = concat!("Add a child ", stringify!($unspanned), " message to this error.")]
605        #[doc = "# Example"]
606        #[doc = "```rust"]
607        #[doc = "# use darling_core::Error;"]
608        #[doc = concat!(r#"Error::custom("Example")."#, stringify!($unspanned), r#"("message content");"#)]
609        #[doc = "```"]
610        pub fn $unspanned<T: fmt::Display>(mut self, message: T) -> Self {
611            self.children.push(child::ChildDiagnostic::new(
612                child::Level::$level,
613                None,
614                message.to_string(),
615            ));
616            self
617        }
618
619        #[doc = concat!("Add a child ", stringify!($unspanned), " message to this error with its own span.")]
620        #[doc = "# Example"]
621        #[doc = "```rust"]
622        #[doc = "# use darling_core::Error;"]
623        #[doc = "# let item_to_span = proc_macro2::Span::call_site();"]
624        #[doc = concat!(r#"Error::custom("Example")."#, stringify!($spanned), r#"(&item_to_span, "message content");"#)]
625        #[doc = "```"]
626        pub fn $spanned<S: Spanned, T: fmt::Display>(mut self, span: &S, message: T) -> Self {
627            self.children.push(child::ChildDiagnostic::new(
628                child::Level::$level,
629                Some(span.span()),
630                message.to_string(),
631            ));
632            self
633        }
634    };
635}
636
637/// Add child diagnostics to the error.
638///
639/// # Example
640///
641/// ## Code
642///
643/// ```rust
644/// # use darling_core::Error;
645/// # let struct_ident = proc_macro2::Span::call_site();
646/// Error::custom("this is a demo")
647///     .with_span(&struct_ident)
648///     .note("we wrote this")
649///     .help("try doing this instead");
650/// ```
651/// ## Output
652///
653/// ```text
654/// error: this is a demo
655///   --> my_project/my_file.rs:3:5
656///    |
657/// 13 |     FooBar { value: String },
658///    |     ^^^^^^
659///    |
660///    = note: we wrote this
661///    = help: try doing this instead
662/// ```
663#[cfg(feature = "diagnostics")]
664impl Error {
665    add_child!(error, span_error, Error);
666    add_child!(warning, span_warning, Warning);
667    add_child!(note, span_note, Note);
668    add_child!(help, span_help, Help);
669}
670
671impl StdError for Error {
672    fn cause(&self) -> Option<&dyn StdError> {
673        None
674    }
675}
676
677impl fmt::Display for Error {
678    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
679        write!(f, "{}", self.kind)?;
680        if !self.locations.is_empty() {
681            write!(f, " at {}", self.locations.join("/"))?;
682        }
683
684        Ok(())
685    }
686}
687
688impl From<syn::Error> for Error {
689    fn from(e: syn::Error) -> Self {
690        // This impl assumes there is nothing but the message and span that needs to be preserved
691        // from the passed-in error. If this changes at some point, a new ErrorKind should be made
692        // to hold the syn::Error, and this impl should preserve it unmodified while setting its own
693        // span to be a copy of the passed-in error.
694        Self {
695            span: Some(e.span()),
696            ..Self::custom(e)
697        }
698    }
699}
700
701impl From<Error> for syn::Error {
702    fn from(e: Error) -> Self {
703        if e.len() == 1 {
704            if let Some(span) = e.explicit_span() {
705                // Don't include the location path if the error has an explicit span,
706                // since it will be redundant and isn't consistent with how rustc
707                // exposes errors.
708                syn::Error::new(span, e.kind)
709            } else {
710                // If the error's span is going to be the macro call site, include
711                // the location information to try and help the user pinpoint the issue.
712                syn::Error::new(e.span(), e)
713            }
714        } else {
715            let mut syn_errors = e.flatten().into_iter().map(syn::Error::from);
716            let mut error = syn_errors
717                .next()
718                .expect("darling::Error can never be empty");
719
720            for next_error in syn_errors {
721                error.combine(next_error);
722            }
723
724            error
725        }
726    }
727}
728
729// Don't want to publicly commit to Error supporting equality yet, but
730// not having it makes testing very difficult. Note that spans are not
731// considered for equality since that would break testing in most cases.
732#[cfg(test)]
733impl PartialEq for Error {
734    fn eq(&self, other: &Self) -> bool {
735        self.kind == other.kind && self.locations == other.locations
736    }
737}
738
739#[cfg(test)]
740impl Eq for Error {}
741
742impl IntoIterator for Error {
743    type Item = Error;
744    type IntoIter = IntoIter;
745
746    fn into_iter(self) -> IntoIter {
747        if let ErrorKind::Multiple(errors) = self.kind {
748            IntoIter {
749                inner: IntoIterEnum::Multiple(errors.into_iter()),
750            }
751        } else {
752            IntoIter {
753                inner: IntoIterEnum::Single(iter::once(self)),
754            }
755        }
756    }
757}
758
759enum IntoIterEnum {
760    Single(iter::Once<Error>),
761    Multiple(vec::IntoIter<Error>),
762}
763
764impl Iterator for IntoIterEnum {
765    type Item = Error;
766
767    fn next(&mut self) -> Option<Self::Item> {
768        match *self {
769            IntoIterEnum::Single(ref mut content) => content.next(),
770            IntoIterEnum::Multiple(ref mut content) => content.next(),
771        }
772    }
773}
774
775/// An iterator that moves out of an `Error`.
776pub struct IntoIter {
777    inner: IntoIterEnum,
778}
779
780impl Iterator for IntoIter {
781    type Item = Error;
782
783    fn next(&mut self) -> Option<Error> {
784        self.inner.next()
785    }
786}
787
788/// Accumulator for errors, for helping call [`Error::multiple`].
789///
790/// See the docs for [`darling::Error`](Error) for more discussion of error handling with darling.
791///
792/// # Panics
793///
794/// `Accumulator` panics on drop unless [`finish`](Self::finish), [`finish_with`](Self::finish_with),
795/// or [`into_inner`](Self::into_inner) has been called, **even if it contains no errors**.
796/// If you want to discard an `Accumulator` that you know to be empty, use `accumulator.finish().unwrap()`.
797///
798/// # Example
799///
800/// ```
801/// # extern crate darling_core as darling;
802/// # struct Thing;
803/// # struct Output;
804/// # impl Thing { fn validate(self) -> darling::Result<Output> { Ok(Output) } }
805/// fn validate_things(inputs: Vec<Thing>) -> darling::Result<Vec<Output>> {
806///     let mut errors = darling::Error::accumulator();
807///
808///     let outputs = inputs
809///         .into_iter()
810///         .filter_map(|thing| errors.handle_in(|| thing.validate()))
811///         .collect::<Vec<_>>();
812///
813///     errors.finish()?;
814///     Ok(outputs)
815/// }
816/// ```
817#[derive(Debug)]
818#[must_use = "Accumulator will panic on drop if not defused."]
819pub struct Accumulator(Option<Vec<Error>>);
820
821impl Accumulator {
822    /// Runs a closure, returning the successful value as `Some`, or collecting the error
823    ///
824    /// The closure's return type is `darling::Result`, so inside it one can use `?`.
825    pub fn handle_in<T, F: FnOnce() -> Result<T>>(&mut self, f: F) -> Option<T> {
826        self.handle(f())
827    }
828
829    /// Handles a possible error.
830    ///
831    /// Returns a successful value as `Some`, or collects the error and returns `None`.
832    pub fn handle<T>(&mut self, result: Result<T>) -> Option<T> {
833        match result {
834            Ok(y) => Some(y),
835            Err(e) => {
836                self.push(e);
837                None
838            }
839        }
840    }
841
842    /// Stop accumulating errors, producing `Ok` if there are no errors or producing
843    /// an error with all those encountered by the accumulator.
844    pub fn finish(self) -> Result<()> {
845        self.finish_with(())
846    }
847
848    /// Bundles the collected errors if there were any, or returns the success value
849    ///
850    /// Call this at the end of your input processing.
851    ///
852    /// If there were no errors recorded, returns `Ok(success)`.
853    /// Otherwise calls [`Error::multiple`] and returns the result as an `Err`.
854    pub fn finish_with<T>(self, success: T) -> Result<T> {
855        let errors = self.into_inner();
856        if errors.is_empty() {
857            Ok(success)
858        } else {
859            Err(Error::multiple(errors))
860        }
861    }
862
863    fn errors(&mut self) -> &mut Vec<Error> {
864        match &mut self.0 {
865            Some(errors) => errors,
866            None => panic!("darling internal error: Accumulator accessed after defuse"),
867        }
868    }
869
870    /// Returns the accumulated errors as a `Vec`.
871    ///
872    /// This function defuses the drop bomb.
873    #[must_use = "Accumulated errors should be handled or propagated to the caller"]
874    pub fn into_inner(mut self) -> Vec<Error> {
875        match self.0.take() {
876            Some(errors) => errors,
877            None => panic!("darling internal error: Accumulator accessed after defuse"),
878        }
879    }
880
881    /// Add one error to the collection.
882    pub fn push(&mut self, error: Error) {
883        self.errors().push(error)
884    }
885
886    /// Finish the current accumulation, and if there are no errors create a new `Self` so processing may continue.
887    ///
888    /// This is shorthand for:
889    ///
890    /// ```rust,ignore
891    /// errors.finish()?;
892    /// errors = Error::accumulator();
893    /// ```
894    ///
895    /// # Drop Behavior
896    /// This function returns a new [`Accumulator`] in the success case.
897    /// This new accumulator is "armed" and will detonate if dropped without being finished.
898    ///
899    /// # Example
900    ///
901    /// ```
902    /// # extern crate darling_core as darling;
903    /// # struct Thing;
904    /// # struct Output;
905    /// # impl Thing { fn validate(&self) -> darling::Result<Output> { Ok(Output) } }
906    /// fn validate(lorem_inputs: &[Thing], ipsum_inputs: &[Thing])
907    ///             -> darling::Result<(Vec<Output>, Vec<Output>)> {
908    ///     let mut errors = darling::Error::accumulator();
909    ///
910    ///     let lorems = lorem_inputs.iter().filter_map(|l| {
911    ///         errors.handle(l.validate())
912    ///     }).collect();
913    ///
914    ///     errors = errors.checkpoint()?;
915    ///
916    ///     let ipsums = ipsum_inputs.iter().filter_map(|l| {
917    ///         errors.handle(l.validate())
918    ///     }).collect();
919    ///
920    ///     errors.finish_with((lorems, ipsums))
921    /// }
922    /// # validate(&[], &[]).unwrap();
923    /// ```
924    pub fn checkpoint(self) -> Result<Accumulator> {
925        // The doc comment says on success we "return the Accumulator for future use".
926        // Actually, we have consumed it by feeding it to finish so we make a fresh one.
927        // This is OK since by definition of the success path, it was empty on entry.
928        self.finish()?;
929        Ok(Self::default())
930    }
931}
932
933impl Default for Accumulator {
934    fn default() -> Self {
935        Accumulator(Some(vec![]))
936    }
937}
938
939impl Extend<Error> for Accumulator {
940    fn extend<I>(&mut self, iter: I)
941    where
942        I: IntoIterator<Item = Error>,
943    {
944        self.errors().extend(iter)
945    }
946}
947
948impl Drop for Accumulator {
949    fn drop(&mut self) {
950        // don't try to panic if we are currently unwinding a panic
951        // otherwise we end up with an unhelful "thread panicked while panicking. aborting." message
952        if !std::thread::panicking() {
953            if let Some(errors) = &mut self.0 {
954                match errors.len() {
955                    0 => panic!("darling::error::Accumulator dropped without being finished"),
956                    error_count => panic!("darling::error::Accumulator dropped without being finished. {} errors were lost.", error_count)
957                }
958            }
959        }
960    }
961}
962
963#[cfg(test)]
964mod tests {
965    use super::Error;
966
967    #[test]
968    fn flatten_noop() {
969        let err = Error::duplicate_field("hello").at("world");
970        assert_eq!(err.clone().flatten(), err);
971    }
972
973    #[test]
974    fn flatten_simple() {
975        let err = Error::multiple(vec![
976            Error::unknown_field("hello").at("world"),
977            Error::missing_field("hell_no").at("world"),
978        ])
979        .at("foo")
980        .flatten();
981
982        assert!(err.location().is_empty());
983
984        let mut err_iter = err.into_iter();
985
986        let first = err_iter.next();
987        assert!(first.is_some());
988        assert_eq!(first.unwrap().location(), vec!["foo", "world"]);
989
990        let second = err_iter.next();
991        assert!(second.is_some());
992
993        assert_eq!(second.unwrap().location(), vec!["foo", "world"]);
994
995        assert!(err_iter.next().is_none());
996    }
997
998    #[test]
999    fn len_single() {
1000        let err = Error::duplicate_field("hello");
1001        assert_eq!(1, err.len());
1002    }
1003
1004    #[test]
1005    fn len_multiple() {
1006        let err = Error::multiple(vec![
1007            Error::duplicate_field("hello"),
1008            Error::missing_field("hell_no"),
1009        ]);
1010        assert_eq!(2, err.len());
1011    }
1012
1013    #[test]
1014    fn len_nested() {
1015        let err = Error::multiple(vec![
1016            Error::duplicate_field("hello"),
1017            Error::multiple(vec![
1018                Error::duplicate_field("hi"),
1019                Error::missing_field("bye"),
1020                Error::multiple(vec![Error::duplicate_field("whatsup")]),
1021            ]),
1022        ]);
1023
1024        assert_eq!(4, err.len());
1025    }
1026
1027    #[test]
1028    fn accum_ok() {
1029        let errs = Error::accumulator();
1030        assert_eq!("test", errs.finish_with("test").unwrap());
1031    }
1032
1033    #[test]
1034    fn accum_errr() {
1035        let mut errs = Error::accumulator();
1036        errs.push(Error::custom("foo!"));
1037        errs.finish().unwrap_err();
1038    }
1039
1040    #[test]
1041    fn accum_into_inner() {
1042        let mut errs = Error::accumulator();
1043        errs.push(Error::custom("foo!"));
1044        let errs: Vec<_> = errs.into_inner();
1045        assert_eq!(errs.len(), 1);
1046    }
1047
1048    #[test]
1049    #[should_panic(expected = "Accumulator dropped")]
1050    fn accum_drop_panic() {
1051        let _errs = Error::accumulator();
1052    }
1053
1054    #[test]
1055    #[should_panic(expected = "2 errors")]
1056    fn accum_drop_panic_with_error_count() {
1057        let mut errors = Error::accumulator();
1058        errors.push(Error::custom("first"));
1059        errors.push(Error::custom("second"));
1060    }
1061
1062    #[test]
1063    fn accum_checkpoint_error() {
1064        let mut errs = Error::accumulator();
1065        errs.push(Error::custom("foo!"));
1066        errs.checkpoint().unwrap_err();
1067    }
1068
1069    #[test]
1070    #[should_panic(expected = "Accumulator dropped")]
1071    fn accum_checkpoint_drop_panic() {
1072        let mut errs = Error::accumulator();
1073        errs = errs.checkpoint().unwrap();
1074        let _ = errs;
1075    }
1076}