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