darling_core/
from_meta.rs

1use std::borrow::Cow;
2use std::cell::RefCell;
3use std::collections::btree_map::BTreeMap;
4use std::collections::hash_map::HashMap;
5use std::collections::HashSet;
6use std::hash::BuildHasher;
7use std::num;
8use std::rc::Rc;
9use std::sync::atomic::AtomicBool;
10use std::sync::Arc;
11
12use syn::{Expr, Lit, Meta};
13
14use crate::ast::NestedMeta;
15use crate::util::path_to_string;
16use crate::{Error, Result};
17
18/// Create an instance from an item in an attribute declaration.
19///
20/// # Implementing `FromMeta`
21/// * Do not take a dependency on the `ident` of the passed-in meta item. The ident will be set by the field name of the containing struct.
22/// * Implement only the `from_*` methods that you intend to support. The default implementations will return useful errors.
23///
24/// # Provided Implementations
25/// ## bool
26///
27/// * Word with no value specified - becomes `true`.
28/// * As a boolean literal, e.g. `foo = true`.
29/// * As a string literal, e.g. `foo = "true"`.
30///
31/// ## char
32/// * As a char literal, e.g. `foo = '#'`.
33/// * As a string literal consisting of a single character, e.g. `foo = "#"`.
34///
35/// ## String
36/// * As a string literal, e.g. `foo = "hello"`.
37/// * As a raw string literal, e.g. `foo = r#"hello "world""#`.
38///
39/// ## Number
40/// * As a string literal, e.g. `foo = "-25"`.
41/// * As an unquoted positive value, e.g. `foo = 404`. Negative numbers must be in quotation marks.
42///
43/// ## ()
44/// * Word with no value specified, e.g. `foo`. This is best used with `Option`.
45///   See `darling::util::Flag` for a more strongly-typed alternative.
46///
47/// ## Option
48/// * Any format produces `Some`.
49///
50/// ## `Result<T, darling::Error>`
51/// * Allows for fallible parsing; will populate the target field with the result of the
52///   parse attempt.
53pub trait FromMeta: Sized {
54    fn from_nested_meta(item: &NestedMeta) -> Result<Self> {
55        (match *item {
56            NestedMeta::Lit(ref lit) => Self::from_value(lit),
57            NestedMeta::Meta(ref mi) => Self::from_meta(mi),
58        })
59        .map_err(|e| e.with_span(item))
60    }
61
62    /// Create an instance from a `syn::Meta` by dispatching to the format-appropriate
63    /// trait function. This generally should not be overridden by implementers.
64    ///
65    /// # Error Spans
66    /// If this method is overridden and can introduce errors that weren't passed up from
67    /// other `from_meta` calls, the override must call `with_span` on the error using the
68    /// `item` to make sure that the emitted diagnostic points to the correct location in
69    /// source code.
70    fn from_meta(item: &Meta) -> Result<Self> {
71        (match *item {
72            Meta::Path(_) => Self::from_word(),
73            Meta::List(ref value) => {
74                Self::from_list(&NestedMeta::parse_meta_list(value.tokens.clone())?[..])
75            }
76            Meta::NameValue(ref value) => Self::from_expr(&value.value),
77        })
78        .map_err(|e| e.with_span(item))
79    }
80
81    /// When a field is omitted from a parent meta-item, `from_none` is used to attempt
82    /// recovery before a missing field error is generated.
83    ///
84    /// **Most types should not override this method.** `darling` already allows field-level
85    /// missing-field recovery using `#[darling(default)]` and `#[darling(default = "...")]`,
86    /// and users who add a `String` field to their `FromMeta`-deriving struct would be surprised
87    /// if they get back `""` instead of a missing field error when that field is omitted.
88    ///
89    /// The primary use-case for this is `Option<T>` fields gracefully handlling absence without
90    /// needing `#[darling(default)]`.
91    fn from_none() -> Option<Self> {
92        None
93    }
94
95    /// Create an instance from the presence of the word in the attribute with no
96    /// additional options specified.
97    fn from_word() -> Result<Self> {
98        Err(Error::unsupported_format("word"))
99    }
100
101    /// Create an instance from a list of nested meta items.
102    #[allow(unused_variables)]
103    fn from_list(items: &[NestedMeta]) -> Result<Self> {
104        Err(Error::unsupported_format("list"))
105    }
106
107    /// Create an instance from a literal value of either `foo = "bar"` or `foo("bar")`.
108    /// This dispatches to the appropriate method based on the type of literal encountered,
109    /// and generally should not be overridden by implementers.
110    ///
111    /// # Error Spans
112    /// If this method is overridden, the override must make sure to add `value`'s span
113    /// information to the returned error by calling `with_span(value)` on the `Error` instance.
114    fn from_value(value: &Lit) -> Result<Self> {
115        (match *value {
116            Lit::Bool(ref b) => Self::from_bool(b.value),
117            Lit::Str(ref s) => Self::from_string(&s.value()),
118            Lit::Char(ref ch) => Self::from_char(ch.value()),
119            _ => Err(Error::unexpected_lit_type(value)),
120        })
121        .map_err(|e| e.with_span(value))
122    }
123
124    fn from_expr(expr: &Expr) -> Result<Self> {
125        match *expr {
126            Expr::Lit(ref lit) => Self::from_value(&lit.lit),
127            Expr::Group(ref group) => {
128                // syn may generate this invisible group delimiter when the input to the darling
129                // proc macro (specifically, the attributes) are generated by a
130                // macro_rules! (e.g. propagating a macro_rules!'s expr)
131                // Since we want to basically ignore these invisible group delimiters,
132                // we just propagate the call to the inner expression.
133                Self::from_expr(&group.expr)
134            }
135            _ => Err(Error::unexpected_expr_type(expr)),
136        }
137        .map_err(|e| e.with_span(expr))
138    }
139
140    /// Create an instance from a char literal in a value position.
141    #[allow(unused_variables)]
142    fn from_char(value: char) -> Result<Self> {
143        Err(Error::unexpected_type("char"))
144    }
145
146    /// Create an instance from a string literal in a value position.
147    #[allow(unused_variables)]
148    fn from_string(value: &str) -> Result<Self> {
149        Err(Error::unexpected_type("string"))
150    }
151
152    /// Create an instance from a bool literal in a value position.
153    #[allow(unused_variables)]
154    fn from_bool(value: bool) -> Result<Self> {
155        Err(Error::unexpected_type("bool"))
156    }
157}
158
159// FromMeta impls for std and syn types.
160
161impl FromMeta for () {
162    fn from_word() -> Result<Self> {
163        Ok(())
164    }
165
166    fn from_list(items: &[NestedMeta]) -> Result<Self> {
167        let mut errors = Error::accumulator();
168        for item in items {
169            errors.push(match item {
170                // Use `unknown_field_path` rather than `too_many_items` so that when this is used with
171                // `flatten` the resulting error message will include the valid fields rather than a confusing
172                // message about having only expected zero items.
173                //
174                // The accumulator is used to ensure all these errors are returned at once, rather than
175                // only producing an error on the first unexpected field in the flattened list.
176                NestedMeta::Meta(meta) => Error::unknown_field_path(meta.path()).with_span(meta),
177                NestedMeta::Lit(lit) => Error::unexpected_expr_type(
178                    &(syn::ExprLit {
179                        attrs: vec![],
180                        lit: lit.clone(),
181                    }
182                    .into()),
183                )
184                .with_span(lit),
185            });
186        }
187
188        errors.finish()
189    }
190}
191
192impl FromMeta for bool {
193    fn from_word() -> Result<Self> {
194        Ok(true)
195    }
196
197    #[allow(clippy::wrong_self_convention)] // false positive
198    fn from_bool(value: bool) -> Result<Self> {
199        Ok(value)
200    }
201
202    fn from_string(value: &str) -> Result<Self> {
203        value.parse().map_err(|_| Error::unknown_value(value))
204    }
205}
206
207impl FromMeta for AtomicBool {
208    fn from_meta(mi: &Meta) -> Result<Self> {
209        FromMeta::from_meta(mi)
210            .map(AtomicBool::new)
211            .map_err(|e| e.with_span(mi))
212    }
213}
214
215impl FromMeta for char {
216    #[allow(clippy::wrong_self_convention)] // false positive
217    fn from_char(value: char) -> Result<Self> {
218        Ok(value)
219    }
220
221    fn from_string(s: &str) -> Result<Self> {
222        let mut chars = s.chars();
223        let char1 = chars.next();
224        let char2 = chars.next();
225
226        if let (Some(char), None) = (char1, char2) {
227            Ok(char)
228        } else {
229            Err(Error::unexpected_type("string"))
230        }
231    }
232}
233
234impl FromMeta for String {
235    fn from_string(s: &str) -> Result<Self> {
236        Ok(s.to_string())
237    }
238}
239
240impl FromMeta for std::path::PathBuf {
241    fn from_string(s: &str) -> Result<Self> {
242        Ok(s.into())
243    }
244}
245
246/// Generate an impl of `FromMeta` that will accept strings which parse to numbers or
247/// integer literals.
248macro_rules! from_meta_num {
249    ($ty:path) => {
250        impl FromMeta for $ty {
251            fn from_string(s: &str) -> Result<Self> {
252                s.parse().map_err(|_| Error::unknown_value(s))
253            }
254
255            fn from_value(value: &Lit) -> Result<Self> {
256                (match *value {
257                    Lit::Str(ref s) => Self::from_string(&s.value()),
258                    Lit::Int(ref s) => s.base10_parse::<$ty>().map_err(Error::from),
259                    _ => Err(Error::unexpected_lit_type(value)),
260                })
261                .map_err(|e| e.with_span(value))
262            }
263        }
264    };
265}
266
267from_meta_num!(u8);
268from_meta_num!(u16);
269from_meta_num!(u32);
270from_meta_num!(u64);
271from_meta_num!(u128);
272from_meta_num!(usize);
273from_meta_num!(i8);
274from_meta_num!(i16);
275from_meta_num!(i32);
276from_meta_num!(i64);
277from_meta_num!(i128);
278from_meta_num!(isize);
279from_meta_num!(num::NonZeroU8);
280from_meta_num!(num::NonZeroU16);
281from_meta_num!(num::NonZeroU32);
282from_meta_num!(num::NonZeroU64);
283from_meta_num!(num::NonZeroU128);
284from_meta_num!(num::NonZeroUsize);
285from_meta_num!(num::NonZeroI8);
286from_meta_num!(num::NonZeroI16);
287from_meta_num!(num::NonZeroI32);
288from_meta_num!(num::NonZeroI64);
289from_meta_num!(num::NonZeroI128);
290from_meta_num!(num::NonZeroIsize);
291
292/// Generate an impl of `FromMeta` that will accept strings which parse to floats or
293/// float literals.
294macro_rules! from_meta_float {
295    ($ty:ident) => {
296        impl FromMeta for $ty {
297            fn from_string(s: &str) -> Result<Self> {
298                s.parse().map_err(|_| Error::unknown_value(s))
299            }
300
301            fn from_value(value: &Lit) -> Result<Self> {
302                (match *value {
303                    Lit::Str(ref s) => Self::from_string(&s.value()),
304                    Lit::Float(ref s) => s.base10_parse::<$ty>().map_err(Error::from),
305                    _ => Err(Error::unexpected_lit_type(value)),
306                })
307                .map_err(|e| e.with_span(value))
308            }
309        }
310    };
311}
312
313from_meta_float!(f32);
314from_meta_float!(f64);
315
316/// Parsing support for punctuated. This attempts to preserve span information
317/// when available, but also supports parsing strings with the call site as the
318/// emitted span.
319impl<T: syn::parse::Parse, P: syn::parse::Parse> FromMeta for syn::punctuated::Punctuated<T, P> {
320    fn from_value(value: &Lit) -> Result<Self> {
321        if let Lit::Str(ref ident) = *value {
322            ident
323                .parse_with(syn::punctuated::Punctuated::parse_terminated)
324                .map_err(|_| Error::unknown_lit_str_value(ident))
325        } else {
326            Err(Error::unexpected_lit_type(value))
327        }
328    }
329}
330
331/// Support for arbitrary expressions as values in a meta item.
332///
333/// For backwards-compatibility to versions of `darling` based on `syn` 1,
334/// string literals will be "unwrapped" and their contents will be parsed
335/// as an expression.
336///
337/// See [`util::parse_expr`](crate::util::parse_expr) for functions to provide
338/// alternate parsing modes for this type.
339impl FromMeta for syn::Expr {
340    fn from_expr(expr: &Expr) -> Result<Self> {
341        match expr {
342            Expr::Lit(syn::ExprLit {
343                lit: lit @ syn::Lit::Str(_),
344                ..
345            }) => Self::from_value(lit),
346            Expr::Group(group) => Self::from_expr(&group.expr), // see FromMeta::from_expr
347            _ => Ok(expr.clone()),
348        }
349    }
350
351    fn from_string(value: &str) -> Result<Self> {
352        syn::parse_str(value).map_err(|_| Error::unknown_value(value))
353    }
354
355    fn from_value(value: &::syn::Lit) -> Result<Self> {
356        if let ::syn::Lit::Str(ref v) = *value {
357            v.parse::<syn::Expr>()
358                .map_err(|_| Error::unknown_lit_str_value(v))
359        } else {
360            Err(Error::unexpected_lit_type(value))
361        }
362    }
363}
364
365/// Parser for paths that supports both quote-wrapped and bare values.
366impl FromMeta for syn::Path {
367    fn from_string(value: &str) -> Result<Self> {
368        syn::parse_str(value).map_err(|_| Error::unknown_value(value))
369    }
370
371    fn from_value(value: &::syn::Lit) -> Result<Self> {
372        if let ::syn::Lit::Str(ref v) = *value {
373            v.parse().map_err(|_| Error::unknown_lit_str_value(v))
374        } else {
375            Err(Error::unexpected_lit_type(value))
376        }
377    }
378
379    fn from_expr(expr: &Expr) -> Result<Self> {
380        match expr {
381            Expr::Lit(lit) => Self::from_value(&lit.lit),
382            Expr::Path(path) => Ok(path.path.clone()),
383            Expr::Group(group) => Self::from_expr(&group.expr), // see FromMeta::from_expr
384            _ => Err(Error::unexpected_expr_type(expr)),
385        }
386    }
387}
388
389impl FromMeta for syn::Ident {
390    fn from_string(value: &str) -> Result<Self> {
391        syn::parse_str(value).map_err(|_| Error::unknown_value(value))
392    }
393
394    fn from_value(value: &syn::Lit) -> Result<Self> {
395        if let syn::Lit::Str(ref v) = *value {
396            v.parse().map_err(|_| Error::unknown_lit_str_value(v))
397        } else {
398            Err(Error::unexpected_lit_type(value))
399        }
400    }
401
402    fn from_expr(expr: &Expr) -> Result<Self> {
403        match expr {
404            Expr::Lit(lit) => Self::from_value(&lit.lit),
405            // All idents are paths, but not all paths are idents -
406            // the get_ident() method does additional validation to
407            // make sure the path is actually an ident.
408            Expr::Path(path) => match path.path.get_ident() {
409                Some(ident) => Ok(ident.clone()),
410                None => Err(Error::unexpected_expr_type(expr)),
411            },
412            Expr::Group(group) => Self::from_expr(&group.expr), // see FromMeta::from_expr
413            _ => Err(Error::unexpected_expr_type(expr)),
414        }
415    }
416}
417
418/// Adapter for various expression types.
419///
420/// Prior to syn 2.0, darling supported arbitrary expressions as long as they
421/// were wrapped in quotation marks. This was helpful for people writing
422/// libraries that needed expressions, but it now creates an ambiguity when
423/// parsing a meta item.
424///
425/// To address this, the macro supports both formats; if it cannot parse the
426/// item as an expression of the right type and the passed-in expression is
427/// a string literal, it will fall back to parsing the string contents.
428macro_rules! from_syn_expr_type {
429    ($ty:path, $variant:ident) => {
430        impl FromMeta for $ty {
431            fn from_expr(expr: &syn::Expr) -> Result<Self> {
432                match expr {
433                    syn::Expr::$variant(body) => Ok(body.clone()),
434                    syn::Expr::Lit(expr_lit) => Self::from_value(&expr_lit.lit),
435                    syn::Expr::Group(group) => Self::from_expr(&group.expr), // see FromMeta::from_expr
436                    _ => Err(Error::unexpected_expr_type(expr)),
437                }
438            }
439
440            fn from_value(value: &::syn::Lit) -> Result<Self> {
441                if let syn::Lit::Str(body) = &value {
442                    body.parse::<$ty>()
443                        .map_err(|_| Error::unknown_lit_str_value(body))
444                } else {
445                    Err(Error::unexpected_lit_type(value))
446                }
447            }
448        }
449    };
450}
451
452from_syn_expr_type!(syn::ExprArray, Array);
453from_syn_expr_type!(syn::ExprPath, Path);
454from_syn_expr_type!(syn::ExprRange, Range);
455
456/// Adapter from `syn::parse::Parse` to `FromMeta` for items that cannot
457/// be expressed in a [`syn::MetaNameValue`].
458///
459/// This cannot be a blanket impl, due to the `syn::Lit` family's need to handle non-string values.
460/// Therefore, we use a macro and a lot of impls.
461macro_rules! from_syn_parse {
462    ($ty:path) => {
463        impl FromMeta for $ty {
464            fn from_string(value: &str) -> Result<Self> {
465                syn::parse_str(value).map_err(|_| Error::unknown_value(value))
466            }
467
468            fn from_value(value: &::syn::Lit) -> Result<Self> {
469                if let ::syn::Lit::Str(ref v) = *value {
470                    v.parse::<$ty>()
471                        .map_err(|_| Error::unknown_lit_str_value(v))
472                } else {
473                    Err(Error::unexpected_lit_type(value))
474                }
475            }
476        }
477    };
478}
479
480from_syn_parse!(syn::Type);
481from_syn_parse!(syn::TypeArray);
482from_syn_parse!(syn::TypeBareFn);
483from_syn_parse!(syn::TypeGroup);
484from_syn_parse!(syn::TypeImplTrait);
485from_syn_parse!(syn::TypeInfer);
486from_syn_parse!(syn::TypeMacro);
487from_syn_parse!(syn::TypeNever);
488from_syn_parse!(syn::TypeParam);
489from_syn_parse!(syn::TypeParen);
490from_syn_parse!(syn::TypePtr);
491from_syn_parse!(syn::TypeReference);
492from_syn_parse!(syn::TypeSlice);
493from_syn_parse!(syn::TypeTraitObject);
494from_syn_parse!(syn::TypeTuple);
495from_syn_parse!(syn::Visibility);
496from_syn_parse!(syn::WhereClause);
497
498impl FromMeta for syn::TypePath {
499    /// Supports both quote-wrapped and bare values.
500    fn from_expr(expr: &Expr) -> Result<Self> {
501        match expr {
502            Expr::Path(body) => {
503                if body.attrs.is_empty() {
504                    Ok(syn::TypePath {
505                        qself: body.qself.clone(),
506                        path: body.path.clone(),
507                    })
508                } else {
509                    Err(Error::custom("attributes are not allowed").with_span(body))
510                }
511            }
512            Expr::Lit(expr_lit) => Self::from_value(&expr_lit.lit),
513            Expr::Group(group) => Self::from_expr(&group.expr),
514            _ => Err(Error::unexpected_expr_type(expr)),
515        }
516    }
517
518    fn from_string(value: &str) -> Result<Self> {
519        syn::parse_str(value).map_err(|_| Error::unknown_value(value))
520    }
521
522    fn from_value(value: &Lit) -> Result<Self> {
523        if let Lit::Str(ref v) = *value {
524            v.parse().map_err(|_| Error::unknown_lit_str_value(v))
525        } else {
526            Err(Error::unexpected_lit_type(value))
527        }
528    }
529}
530
531macro_rules! from_numeric_array {
532    ($ty:ident) => {
533        /// Parsing an unsigned integer array, i.e. `example = "[1, 2, 3, 4]"`.
534        impl FromMeta for Vec<$ty> {
535            fn from_expr(expr: &syn::Expr) -> Result<Self> {
536                match expr {
537                    syn::Expr::Array(expr_array) => expr_array
538                        .elems
539                        .iter()
540                        .map(|expr| {
541                            let unexpected = || {
542                                Error::custom("Expected array of unsigned integers").with_span(expr)
543                            };
544                            match expr {
545                                Expr::Lit(lit) => $ty::from_value(&lit.lit),
546                                Expr::Group(group) => match &*group.expr {
547                                    Expr::Lit(lit) => $ty::from_value(&lit.lit),
548                                    _ => Err(unexpected()),
549                                },
550                                _ => Err(unexpected()),
551                            }
552                        })
553                        .collect::<Result<Vec<$ty>>>(),
554                    syn::Expr::Lit(expr_lit) => Self::from_value(&expr_lit.lit),
555                    syn::Expr::Group(group) => Self::from_expr(&group.expr), // see FromMeta::from_expr
556                    _ => Err(Error::unexpected_expr_type(expr)),
557                }
558            }
559
560            fn from_value(value: &Lit) -> Result<Self> {
561                let expr_array = syn::ExprArray::from_value(value)?;
562                Self::from_expr(&syn::Expr::Array(expr_array))
563            }
564        }
565    };
566}
567
568from_numeric_array!(u8);
569from_numeric_array!(u16);
570from_numeric_array!(u32);
571from_numeric_array!(u64);
572from_numeric_array!(usize);
573
574impl FromMeta for syn::Lit {
575    fn from_value(value: &Lit) -> Result<Self> {
576        Ok(value.clone())
577    }
578}
579
580macro_rules! from_meta_lit {
581    ($impl_ty:path, $lit_variant:path) => {
582        impl FromMeta for $impl_ty {
583            fn from_value(value: &Lit) -> Result<Self> {
584                if let $lit_variant(ref value) = *value {
585                    Ok(value.clone())
586                } else {
587                    Err(Error::unexpected_lit_type(value))
588                }
589            }
590        }
591
592        impl FromMeta for Vec<$impl_ty> {
593            fn from_list(items: &[NestedMeta]) -> Result<Self> {
594                items
595                    .iter()
596                    .map(<$impl_ty as FromMeta>::from_nested_meta)
597                    .collect()
598            }
599
600            fn from_value(value: &syn::Lit) -> Result<Self> {
601                let expr_array = syn::ExprArray::from_value(value)?;
602                Self::from_expr(&syn::Expr::Array(expr_array))
603            }
604
605            fn from_expr(expr: &syn::Expr) -> Result<Self> {
606                match expr {
607                    syn::Expr::Array(expr_array) => expr_array
608                        .elems
609                        .iter()
610                        .map(<$impl_ty as FromMeta>::from_expr)
611                        .collect::<Result<Vec<_>>>(),
612                    syn::Expr::Lit(expr_lit) => Self::from_value(&expr_lit.lit),
613                    syn::Expr::Group(g) => Self::from_expr(&g.expr),
614                    _ => Err(Error::unexpected_expr_type(expr)),
615                }
616            }
617        }
618    };
619}
620
621from_meta_lit!(syn::LitInt, Lit::Int);
622from_meta_lit!(syn::LitFloat, Lit::Float);
623from_meta_lit!(syn::LitStr, Lit::Str);
624from_meta_lit!(syn::LitByte, Lit::Byte);
625from_meta_lit!(syn::LitByteStr, Lit::ByteStr);
626from_meta_lit!(syn::LitChar, Lit::Char);
627from_meta_lit!(syn::LitBool, Lit::Bool);
628from_meta_lit!(proc_macro2::Literal, Lit::Verbatim);
629
630impl FromMeta for syn::Meta {
631    fn from_meta(value: &syn::Meta) -> Result<Self> {
632        Ok(value.clone())
633    }
634}
635
636impl FromMeta for Vec<syn::WherePredicate> {
637    fn from_string(value: &str) -> Result<Self> {
638        syn::WhereClause::from_string(&format!("where {}", value))
639            .map(|c| c.predicates.into_iter().collect())
640    }
641
642    fn from_value(value: &Lit) -> Result<Self> {
643        if let syn::Lit::Str(s) = value {
644            syn::WhereClause::from_value(&syn::Lit::Str(syn::LitStr::new(
645                &format!("where {}", s.value()),
646                value.span(),
647            )))
648            .map(|c| c.predicates.into_iter().collect())
649        } else {
650            Err(Error::unexpected_lit_type(value))
651        }
652    }
653}
654
655impl FromMeta for ident_case::RenameRule {
656    fn from_string(value: &str) -> Result<Self> {
657        value.parse().map_err(|_| Error::unknown_value(value))
658    }
659}
660
661impl<T: FromMeta> FromMeta for Option<T> {
662    fn from_none() -> Option<Self> {
663        Some(None)
664    }
665
666    fn from_meta(item: &Meta) -> Result<Self> {
667        FromMeta::from_meta(item).map(Some)
668    }
669}
670
671impl<T: FromMeta> FromMeta for Result<T> {
672    fn from_none() -> Option<Self> {
673        T::from_none().map(Ok)
674    }
675
676    // `#[darling(flatten)]` forwards directly to this method, so it's
677    // necessary to declare it to avoid getting an unsupported format
678    // error if it's invoked directly.
679    fn from_list(items: &[NestedMeta]) -> Result<Self> {
680        Ok(FromMeta::from_list(items))
681    }
682
683    fn from_meta(item: &Meta) -> Result<Self> {
684        Ok(FromMeta::from_meta(item))
685    }
686}
687
688/// Create an impl that forwards to an inner type `T` for parsing.
689macro_rules! smart_pointer_t {
690    ($ty:path, $map_fn:path) => {
691        impl<T: FromMeta> FromMeta for $ty {
692            fn from_none() -> Option<Self> {
693                T::from_none().map($map_fn)
694            }
695
696            // `#[darling(flatten)]` forwards directly to this method, so it's
697            // necessary to declare it to avoid getting an unsupported format
698            // error if it's invoked directly.
699            fn from_list(items: &[NestedMeta]) -> Result<Self> {
700                FromMeta::from_list(items).map($map_fn)
701            }
702
703            fn from_meta(item: &Meta) -> Result<Self> {
704                FromMeta::from_meta(item).map($map_fn)
705            }
706        }
707    };
708}
709
710smart_pointer_t!(Box<T>, Box::new);
711smart_pointer_t!(Rc<T>, Rc::new);
712smart_pointer_t!(Arc<T>, Arc::new);
713smart_pointer_t!(RefCell<T>, RefCell::new);
714
715/// Parses the meta-item, and in case of error preserves a copy of the input for
716/// later analysis.
717impl<T: FromMeta> FromMeta for ::std::result::Result<T, Meta> {
718    fn from_meta(item: &Meta) -> Result<Self> {
719        T::from_meta(item)
720            .map(Ok)
721            .or_else(|_| Ok(Err(item.clone())))
722    }
723}
724
725/// Trait to convert from a path into an owned key for a map.
726trait KeyFromPath: Sized {
727    fn from_path(path: &syn::Path) -> Result<Self>;
728    fn to_display(&self) -> Cow<'_, str>;
729}
730
731impl KeyFromPath for String {
732    fn from_path(path: &syn::Path) -> Result<Self> {
733        Ok(path_to_string(path))
734    }
735
736    fn to_display(&self) -> Cow<'_, str> {
737        Cow::Borrowed(self)
738    }
739}
740
741impl KeyFromPath for syn::Path {
742    fn from_path(path: &syn::Path) -> Result<Self> {
743        Ok(path.clone())
744    }
745
746    fn to_display(&self) -> Cow<'_, str> {
747        Cow::Owned(path_to_string(self))
748    }
749}
750
751impl KeyFromPath for syn::Ident {
752    fn from_path(path: &syn::Path) -> Result<Self> {
753        if path.segments.len() == 1
754            && path.leading_colon.is_none()
755            && path.segments[0].arguments.is_empty()
756        {
757            Ok(path.segments[0].ident.clone())
758        } else {
759            Err(Error::custom("Key must be an identifier").with_span(path))
760        }
761    }
762
763    fn to_display(&self) -> Cow<'_, str> {
764        Cow::Owned(self.to_string())
765    }
766}
767
768macro_rules! map {
769    (hash_map, $key:ty, $nested:ident) => {
770        impl<V: FromMeta, S: BuildHasher + Default> FromMeta for HashMap<$key, V, S> {
771            map!(
772                HashMap::with_capacity_and_hasher($nested.len(), Default::default()),
773                $key,
774                $nested
775            );
776        }
777    };
778
779    (btree_map, $key:ty, $nested:ident) => {
780        impl<V: FromMeta> FromMeta for BTreeMap<$key, V> {
781            map!(BTreeMap::new(), $key, $nested);
782        }
783    };
784
785    ($new:expr, $key:ty, $nested:ident) => {
786        fn from_list($nested: &[NestedMeta]) -> Result<Self> {
787            // Convert the nested meta items into a sequence of (path, value result) result tuples.
788            // An outer Err means no (key, value) structured could be found, while an Err in the
789            // second position of the tuple means that value was rejected by FromMeta.
790            //
791            // We defer key conversion into $key so that we don't lose span information in the case
792            // of String keys; we'll need it for good duplicate key errors later.
793            let pairs = $nested
794                .iter()
795                .map(|item| -> Result<(&syn::Path, Result<V>)> {
796                    match *item {
797                        NestedMeta::Meta(ref inner) => {
798                            let path = inner.path();
799                            Ok((
800                                path,
801                                FromMeta::from_meta(inner).map_err(|e| e.at_path(&path)),
802                            ))
803                        }
804                        NestedMeta::Lit(_) => Err(Error::unsupported_format("expression")),
805                    }
806                });
807
808            let mut errors = Error::accumulator();
809            // We need to track seen keys separately from the final map, since a seen key with an
810            // Err value won't go into the final map but should trigger a duplicate field error.
811            //
812            // This is a set of $key rather than Path to avoid the possibility that a key type
813            // parses two paths of different values to the same key value.
814            let mut seen_keys = HashSet::with_capacity($nested.len());
815
816            // The map to return in the Ok case. Its size will always be exactly nested.len(),
817            // since otherwise ≥1 field had a problem and the entire map is dropped immediately
818            // when the function returns `Err`.
819            let mut map = $new;
820
821            for item in pairs {
822                if let Some((path, value)) = errors.handle(item) {
823                    let key: $key = match KeyFromPath::from_path(path) {
824                        Ok(k) => k,
825                        Err(e) => {
826                            errors.push(e);
827
828                            // Surface value errors even under invalid keys
829                            errors.handle(value);
830
831                            continue;
832                        }
833                    };
834
835                    let already_seen = seen_keys.contains(&key);
836
837                    if already_seen {
838                        errors.push(Error::duplicate_field(&key.to_display()).with_span(path));
839                    }
840
841                    match value {
842                        Ok(_) if already_seen => {}
843                        Ok(val) => {
844                            map.insert(key.clone(), val);
845                        }
846                        Err(e) => {
847                            errors.push(e);
848                        }
849                    }
850
851                    seen_keys.insert(key);
852                }
853            }
854
855            errors.finish_with(map)
856        }
857    };
858}
859
860// This is done as a macro rather than a blanket impl to avoid breaking backwards compatibility
861// with 0.12.x, while still sharing the same impl.
862map!(hash_map, String, nested);
863map!(hash_map, syn::Ident, nested);
864map!(hash_map, syn::Path, nested);
865
866map!(btree_map, String, nested);
867map!(btree_map, syn::Ident, nested);
868
869/// Tests for `FromMeta` implementations. Wherever the word `ignore` appears in test input,
870/// it should not be considered by the parsing.
871#[cfg(test)]
872mod tests {
873    use std::num::{NonZeroU32, NonZeroU64};
874
875    use proc_macro2::TokenStream;
876    use quote::quote;
877    use syn::parse_quote;
878
879    use crate::{Error, FromMeta, Result};
880
881    /// parse a string as a syn::Meta instance.
882    fn pm(tokens: TokenStream) -> ::std::result::Result<syn::Meta, String> {
883        let attribute: syn::Attribute = parse_quote!(#[#tokens]);
884        Ok(attribute.meta)
885    }
886
887    #[track_caller]
888    fn fm<T: FromMeta>(tokens: TokenStream) -> T {
889        FromMeta::from_meta(&pm(tokens).expect("Tests should pass well-formed input"))
890            .expect("Tests should pass valid input")
891    }
892
893    #[test]
894    fn unit_succeeds() {
895        fm::<()>(quote!(ignore));
896        fm::<()>(quote!(ignore()));
897    }
898
899    #[test]
900    #[should_panic(expected = "UnknownField")]
901    fn unit_fails() {
902        fm::<()>(quote!(ignore(foo = "bar")));
903    }
904
905    #[test]
906    #[allow(clippy::bool_assert_comparison)]
907    fn bool_succeeds() {
908        // word format
909        assert_eq!(fm::<bool>(quote!(ignore)), true);
910
911        // bool literal
912        assert_eq!(fm::<bool>(quote!(ignore = true)), true);
913        assert_eq!(fm::<bool>(quote!(ignore = false)), false);
914
915        // string literals
916        assert_eq!(fm::<bool>(quote!(ignore = "true")), true);
917        assert_eq!(fm::<bool>(quote!(ignore = "false")), false);
918    }
919
920    #[test]
921    fn char_succeeds() {
922        // char literal
923        assert_eq!(fm::<char>(quote!(ignore = '😬')), '😬');
924
925        // string literal
926        assert_eq!(fm::<char>(quote!(ignore = "😬")), '😬');
927    }
928
929    #[test]
930    fn string_succeeds() {
931        // cooked form
932        assert_eq!(&fm::<String>(quote!(ignore = "world")), "world");
933
934        // raw form
935        assert_eq!(&fm::<String>(quote!(ignore = r#"world"#)), "world");
936    }
937
938    #[test]
939    fn pathbuf_succeeds() {
940        assert_eq!(
941            fm::<std::path::PathBuf>(quote!(ignore = r#"C:\"#)),
942            std::path::PathBuf::from(r#"C:\"#)
943        );
944    }
945
946    #[test]
947    #[allow(clippy::float_cmp)] // we want exact equality
948    fn number_succeeds() {
949        assert_eq!(fm::<u8>(quote!(ignore = "2")), 2u8);
950        assert_eq!(fm::<i16>(quote!(ignore = "-25")), -25i16);
951        assert_eq!(fm::<f64>(quote!(ignore = "1.4e10")), 1.4e10);
952    }
953
954    #[should_panic(expected = "UnknownValue")]
955    #[test]
956    fn nonzero_number_fails() {
957        fm::<NonZeroU64>(quote!(ignore = "0"));
958    }
959
960    #[test]
961    fn nonzero_number_succeeds() {
962        assert_eq!(
963            fm::<NonZeroU32>(quote!(ignore = "2")),
964            NonZeroU32::new(2).unwrap()
965        );
966    }
967
968    #[test]
969    fn int_without_quotes() {
970        assert_eq!(fm::<u8>(quote!(ignore = 2)), 2u8);
971        assert_eq!(fm::<u16>(quote!(ignore = 255)), 255u16);
972        assert_eq!(fm::<u32>(quote!(ignore = 5000)), 5000u32);
973
974        // Check that we aren't tripped up by incorrect suffixes
975        assert_eq!(fm::<u32>(quote!(ignore = 5000i32)), 5000u32);
976    }
977
978    #[test]
979    fn negative_int_without_quotes() {
980        assert_eq!(fm::<i8>(quote!(ignore = -2)), -2i8);
981        assert_eq!(fm::<i32>(quote!(ignore = -255)), -255i32);
982    }
983
984    #[test]
985    #[allow(clippy::float_cmp)] // we want exact equality
986    fn float_without_quotes() {
987        assert_eq!(fm::<f32>(quote!(ignore = 2.)), 2.0f32);
988        assert_eq!(fm::<f32>(quote!(ignore = 2.0)), 2.0f32);
989        assert_eq!(fm::<f64>(quote!(ignore = 1.4e10)), 1.4e10f64);
990    }
991
992    #[test]
993    fn too_large_int_produces_error() {
994        assert!(fm::<Result<u8>>(quote!(ignore = 2000)).is_err());
995    }
996
997    #[test]
998    fn meta_succeeds() {
999        use syn::Meta;
1000
1001        assert_eq!(
1002            fm::<Meta>(quote!(hello(world, today))),
1003            pm(quote!(hello(world, today))).unwrap()
1004        );
1005    }
1006
1007    #[test]
1008    fn hash_map_succeeds() {
1009        use std::collections::HashMap;
1010
1011        let comparison = {
1012            let mut c = HashMap::new();
1013            c.insert("hello".to_string(), true);
1014            c.insert("world".to_string(), false);
1015            c.insert("there".to_string(), true);
1016            c
1017        };
1018
1019        assert_eq!(
1020            fm::<HashMap<String, bool>>(quote!(ignore(hello, world = false, there = "true"))),
1021            comparison
1022        );
1023    }
1024
1025    /// Check that a `HashMap` cannot have duplicate keys, and that the generated error
1026    /// is assigned a span to correctly target the diagnostic message.
1027    #[test]
1028    fn hash_map_duplicate() {
1029        use std::collections::HashMap;
1030
1031        let err: Result<HashMap<String, bool>> =
1032            FromMeta::from_meta(&pm(quote!(ignore(hello, hello = false))).unwrap());
1033
1034        let err = err.expect_err("Duplicate keys in HashMap should error");
1035
1036        assert!(err.has_span());
1037        assert_eq!(err.to_string(), Error::duplicate_field("hello").to_string());
1038    }
1039
1040    #[test]
1041    fn hash_map_multiple_errors() {
1042        use std::collections::HashMap;
1043
1044        let err = HashMap::<String, bool>::from_meta(
1045            &pm(quote!(ignore(hello, hello = 3, hello = false))).unwrap(),
1046        )
1047        .expect_err("Duplicates and bad values should error");
1048
1049        assert_eq!(err.len(), 3);
1050        let errors = err.into_iter().collect::<Vec<_>>();
1051        assert!(errors[0].has_span());
1052        assert!(errors[1].has_span());
1053        assert!(errors[2].has_span());
1054    }
1055
1056    #[test]
1057    fn hash_map_ident_succeeds() {
1058        use std::collections::HashMap;
1059        use syn::parse_quote;
1060
1061        let comparison = {
1062            let mut c = HashMap::<syn::Ident, bool>::new();
1063            c.insert(parse_quote!(first), true);
1064            c.insert(parse_quote!(second), false);
1065            c
1066        };
1067
1068        assert_eq!(
1069            fm::<HashMap<syn::Ident, bool>>(quote!(ignore(first, second = false))),
1070            comparison
1071        );
1072    }
1073
1074    #[test]
1075    fn hash_map_ident_rejects_non_idents() {
1076        use std::collections::HashMap;
1077
1078        let err: Result<HashMap<syn::Ident, bool>> =
1079            FromMeta::from_meta(&pm(quote!(ignore(first, the::second))).unwrap());
1080
1081        err.unwrap_err();
1082    }
1083
1084    #[test]
1085    fn hash_map_path_succeeds() {
1086        use std::collections::HashMap;
1087        use syn::parse_quote;
1088
1089        let comparison = {
1090            let mut c = HashMap::<syn::Path, bool>::new();
1091            c.insert(parse_quote!(first), true);
1092            c.insert(parse_quote!(the::second), false);
1093            c
1094        };
1095
1096        assert_eq!(
1097            fm::<HashMap<syn::Path, bool>>(quote!(ignore(first, the::second = false))),
1098            comparison
1099        );
1100    }
1101
1102    #[test]
1103    fn btree_map_succeeds() {
1104        use std::collections::BTreeMap;
1105
1106        let comparison = {
1107            let mut c = BTreeMap::new();
1108            c.insert("hello".to_string(), true);
1109            c.insert("world".to_string(), false);
1110            c.insert("there".to_string(), true);
1111            c
1112        };
1113
1114        assert_eq!(
1115            fm::<BTreeMap<String, bool>>(quote!(ignore(hello, world = false, there = "true"))),
1116            comparison
1117        );
1118    }
1119
1120    /// Check that a `HashMap` cannot have duplicate keys, and that the generated error
1121    /// is assigned a span to correctly target the diagnostic message.
1122    #[test]
1123    fn btree_map_duplicate() {
1124        use std::collections::BTreeMap;
1125
1126        let err: Result<BTreeMap<String, bool>> =
1127            FromMeta::from_meta(&pm(quote!(ignore(hello, hello = false))).unwrap());
1128
1129        let err = err.expect_err("Duplicate keys in BTreeMap should error");
1130
1131        assert!(err.has_span());
1132        assert_eq!(err.to_string(), Error::duplicate_field("hello").to_string());
1133    }
1134
1135    #[test]
1136    fn btree_map_multiple_errors() {
1137        use std::collections::BTreeMap;
1138
1139        let err = BTreeMap::<String, bool>::from_meta(
1140            &pm(quote!(ignore(hello, hello = 3, hello = false))).unwrap(),
1141        )
1142        .expect_err("Duplicates and bad values should error");
1143
1144        assert_eq!(err.len(), 3);
1145        let errors = err.into_iter().collect::<Vec<_>>();
1146        assert!(errors[0].has_span());
1147        assert!(errors[1].has_span());
1148        assert!(errors[2].has_span());
1149    }
1150
1151    #[test]
1152    fn btree_map_ident_succeeds() {
1153        use std::collections::BTreeMap;
1154        use syn::parse_quote;
1155
1156        let comparison = {
1157            let mut c = BTreeMap::<syn::Ident, bool>::new();
1158            c.insert(parse_quote!(first), true);
1159            c.insert(parse_quote!(second), false);
1160            c
1161        };
1162
1163        assert_eq!(
1164            fm::<BTreeMap<syn::Ident, bool>>(quote!(ignore(first, second = false))),
1165            comparison
1166        );
1167    }
1168
1169    #[test]
1170    fn btree_map_ident_rejects_non_idents() {
1171        use std::collections::BTreeMap;
1172
1173        let err: Result<BTreeMap<syn::Ident, bool>> =
1174            FromMeta::from_meta(&pm(quote!(ignore(first, the::second))).unwrap());
1175
1176        err.unwrap_err();
1177    }
1178
1179    #[test]
1180    fn btree_map_expr_values_succeed() {
1181        use std::collections::BTreeMap;
1182        use syn::parse_quote;
1183
1184        let comparison: BTreeMap<String, syn::Expr> = vec![
1185            ("hello", parse_quote!(2 + 2)),
1186            ("world", parse_quote!(x.foo())),
1187        ]
1188        .into_iter()
1189        .map(|(k, v)| (k.to_string(), v))
1190        .collect();
1191
1192        assert_eq!(
1193            fm::<BTreeMap<String, syn::Expr>>(quote!(ignore(hello = 2 + 2, world = x.foo()))),
1194            comparison
1195        );
1196    }
1197
1198    /// Tests that fallible parsing will always produce an outer `Ok` (from `fm`),
1199    /// and will accurately preserve the inner contents.
1200    #[test]
1201    fn darling_result_succeeds() {
1202        fm::<Result<()>>(quote!(ignore)).unwrap();
1203        fm::<Result<()>>(quote!(ignore(world))).unwrap_err();
1204    }
1205
1206    /// Test punctuated
1207    #[test]
1208    fn test_punctuated() {
1209        fm::<syn::punctuated::Punctuated<syn::FnArg, syn::token::Comma>>(quote!(
1210            ignore = "a: u8, b: Type"
1211        ));
1212        fm::<syn::punctuated::Punctuated<syn::Expr, syn::token::Comma>>(quote!(ignore = "a, b, c"));
1213    }
1214
1215    #[test]
1216    fn test_expr_array() {
1217        fm::<syn::ExprArray>(quote!(ignore = "[0x1, 0x2]"));
1218        fm::<syn::ExprArray>(quote!(ignore = "[\"Hello World\", \"Test Array\"]"));
1219    }
1220
1221    #[test]
1222    fn test_expr() {
1223        fm::<syn::Expr>(quote!(ignore = "x + y"));
1224        fm::<syn::Expr>(quote!(ignore = "an_object.method_call()"));
1225        fm::<syn::Expr>(quote!(ignore = "{ a_statement(); in_a_block }"));
1226    }
1227
1228    #[test]
1229    fn test_expr_without_quotes() {
1230        fm::<syn::Expr>(quote!(ignore = x + y));
1231        fm::<syn::Expr>(quote!(ignore = an_object.method_call()));
1232        fm::<syn::Expr>(quote!(
1233            ignore = {
1234                a_statement();
1235                in_a_block
1236            }
1237        ));
1238    }
1239
1240    #[test]
1241    fn test_expr_path() {
1242        fm::<syn::ExprPath>(quote!(ignore = "std::mem::replace"));
1243        fm::<syn::ExprPath>(quote!(ignore = "x"));
1244        fm::<syn::ExprPath>(quote!(ignore = "example::<Test>"));
1245    }
1246
1247    #[test]
1248    fn test_expr_path_without_quotes() {
1249        fm::<syn::ExprPath>(quote!(ignore = std::mem::replace));
1250        fm::<syn::ExprPath>(quote!(ignore = x));
1251        fm::<syn::ExprPath>(quote!(ignore = example::<Test>));
1252    }
1253
1254    #[test]
1255    fn test_path_without_quotes() {
1256        fm::<syn::Path>(quote!(ignore = std::mem::replace));
1257        fm::<syn::Path>(quote!(ignore = x));
1258        fm::<syn::Path>(quote!(ignore = example::<Test>));
1259    }
1260
1261    #[test]
1262    fn test_number_array() {
1263        assert_eq!(fm::<Vec<u8>>(quote!(ignore = [16, 0xff])), vec![0x10, 0xff]);
1264        assert_eq!(
1265            fm::<Vec<u16>>(quote!(ignore = "[32, 0xffff]")),
1266            vec![0x20, 0xffff]
1267        );
1268        assert_eq!(
1269            fm::<Vec<u32>>(quote!(ignore = "[48, 0xffffffff]")),
1270            vec![0x30, 0xffffffff]
1271        );
1272        assert_eq!(
1273            fm::<Vec<u64>>(quote!(ignore = "[64, 0xffffffffffffffff]")),
1274            vec![0x40, 0xffffffffffffffff]
1275        );
1276        assert_eq!(
1277            fm::<Vec<usize>>(quote!(ignore = "[80, 0xffffffff]")),
1278            vec![0x50, 0xffffffff]
1279        );
1280    }
1281
1282    #[test]
1283    fn test_lit_array() {
1284        fm::<Vec<syn::LitStr>>(quote!(ignore = "[\"Hello World\", \"Test Array\"]"));
1285        fm::<Vec<syn::LitStr>>(quote!(ignore = ["Hello World", "Test Array"]));
1286        fm::<Vec<syn::LitChar>>(quote!(ignore = "['a', 'b', 'c']"));
1287        fm::<Vec<syn::LitBool>>(quote!(ignore = "[true]"));
1288        fm::<Vec<syn::LitStr>>(quote!(ignore = "[]"));
1289        fm::<Vec<syn::LitStr>>(quote!(ignore = []));
1290        fm::<Vec<syn::LitBool>>(quote!(ignore = [true, false]));
1291    }
1292
1293    #[test]
1294    fn expr_range_without_quotes() {
1295        fm::<syn::ExprRange>(quote!(ignore = 0..5));
1296        fm::<syn::ExprRange>(quote!(ignore = 0..=5));
1297        fm::<syn::ExprRange>(quote!(ignore = ..5));
1298        fm::<syn::ExprRange>(quote!(ignore = ..(x + y)));
1299    }
1300}