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 ident_case;
11 use syn::{self, Expr, Lit, Meta, NestedMeta};
12 
13 use {Error, Result};
14 
15 /// Create an instance from an item in an attribute declaration.
16 ///
17 /// # Implementing `FromMeta`
18 /// * 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.
19 /// * Implement only the `from_*` methods that you intend to support. The default implementations will return useful errors.
20 ///
21 /// # Provided Implementations
22 /// ## bool
23 ///
24 /// * Word with no value specified - becomes `true`.
25 /// * As a boolean literal, e.g. `foo = true`.
26 /// * As a string literal, e.g. `foo = "true"`.
27 ///
28 /// ## char
29 /// * As a char literal, e.g. `foo = '#'`.
30 /// * As a string literal consisting of a single character, e.g. `foo = "#"`.
31 ///
32 /// ## String
33 /// * As a string literal, e.g. `foo = "hello"`.
34 /// * As a raw string literal, e.g. `foo = r#"hello "world""#`.
35 ///
36 /// ## Number
37 /// * As a string literal, e.g. `foo = "-25"`.
38 /// * As an unquoted positive value, e.g. `foo = 404`. Negative numbers must be in quotation marks.
39 ///
40 /// ## ()
41 /// * Word with no value specified, e.g. `foo`. This is best used with `Option`.
42 ///   See `darling::util::Flag` for a more strongly-typed alternative.
43 ///
44 /// ## Option
45 /// * Any format produces `Some`.
46 ///
47 /// ## `Result<T, darling::Error>`
48 /// * Allows for fallible parsing; will populate the target field with the result of the
49 ///   parse attempt.
50 pub trait FromMeta: Sized {
51     fn from_nested_meta(item: &NestedMeta) -> Result<Self> {
52         (match *item {
53             NestedMeta::Lit(ref lit) => Self::from_value(lit),
54             NestedMeta::Meta(ref mi) => Self::from_meta(mi),
55         })
56         .map_err(|e| e.with_span(item))
57     }
58 
59     /// Create an instance from a `syn::Meta` by dispatching to the format-appropriate
60     /// trait function. This generally should not be overridden by implementers.
61     ///
62     /// # Error Spans
63     /// If this method is overridden and can introduce errors that weren't passed up from
64     /// other `from_meta` calls, the override must call `with_span` on the error using the
65     /// `item` to make sure that the emitted diagnostic points to the correct location in
66     /// source code.
67     fn from_meta(item: &Meta) -> Result<Self> {
68         (match *item {
69             Meta::Path(_) => Self::from_word(),
70             Meta::List(ref value) => Self::from_list(
71                 &value
72                     .nested
73                     .iter()
74                     .cloned()
75                     .collect::<Vec<syn::NestedMeta>>()[..],
76             ),
77             Meta::NameValue(ref value) => Self::from_value(&value.lit),
78         })
79         .map_err(|e| e.with_span(item))
80     }
G_DEFINE_TYPE_WITH_CODE(GladePlaceholder,glade_placeholder,GTK_TYPE_WIDGET,G_ADD_PRIVATE (GladePlaceholder)G_IMPLEMENT_INTERFACE (GTK_TYPE_SCROLLABLE,NULL)G_IMPLEMENT_INTERFACE (GLADE_TYPE_DRAG,glade_placeholder_drag_init))81 
82     /// Create an instance from the presence of the word in the attribute with no
83     /// additional options specified.
84     fn from_word() -> Result<Self> {
85         Err(Error::unsupported_format("word"))
86     }
87 
88     /// Create an instance from a list of nested meta items.
89     #[allow(unused_variables)]
90     fn from_list(items: &[NestedMeta]) -> Result<Self> {
91         Err(Error::unsupported_format("list"))
92     }
93 
94     /// Create an instance from a literal value of either `foo = "bar"` or `foo("bar")`.
95     /// This dispatches to the appropriate method based on the type of literal encountered,
96     /// and generally should not be overridden by implementers.
97     ///
98     /// # Error Spans
99     /// If this method is overridden, the override must make sure to add `value`'s span
100     /// information to the returned error by calling `with_span(value)` on the `Error` instance.
101     fn from_value(value: &Lit) -> Result<Self> {
102         (match *value {
103             Lit::Bool(ref b) => Self::from_bool(b.value),
104             Lit::Str(ref s) => Self::from_string(&s.value()),
105             Lit::Char(ref ch) => Self::from_char(ch.value()),
106             _ => Err(Error::unexpected_lit_type(value)),
107         })
108         .map_err(|e| e.with_span(value))
109     }
110 
111     /// Create an instance from a char literal in a value position.
112     #[allow(unused_variables)]
glade_placeholder_init(GladePlaceholder * placeholder)113     fn from_char(value: char) -> Result<Self> {
114         Err(Error::unexpected_type("char"))
115     }
116 
117     /// Create an instance from a string literal in a value position.
118     #[allow(unused_variables)]
119     fn from_string(value: &str) -> Result<Self> {
120         Err(Error::unexpected_type("string"))
121     }
122 
123     /// Create an instance from a bool literal in a value position.
124     #[allow(unused_variables)]
125     fn from_bool(value: bool) -> Result<Self> {
126         Err(Error::unexpected_type("bool"))
127     }
128 }
129 
130 // FromMeta impls for std and syn types.
131 
132 impl FromMeta for () {
133     fn from_word() -> Result<Self> {
134         Ok(())
135     }
glade_placeholder_finalize(GObject * object)136 }
137 
138 impl FromMeta for bool {
139     fn from_word() -> Result<Self> {
140         Ok(true)
141     }
142 
143     fn from_bool(value: bool) -> Result<Self> {
144         Ok(value)
145     }
146 
147     fn from_string(value: &str) -> Result<Self> {
148         value.parse().map_err(|_| Error::unknown_value(value))
149     }
150 }
151 
152 impl FromMeta for AtomicBool {
glade_placeholder_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)153     fn from_meta(mi: &Meta) -> Result<Self> {
154         FromMeta::from_meta(mi)
155             .map(AtomicBool::new)
156             .map_err(|e| e.with_span(mi))
157     }
158 }
159 
160 impl FromMeta for char {
161     fn from_char(value: char) -> Result<Self> {
162         Ok(value)
163     }
164 
165     fn from_string(s: &str) -> Result<Self> {
166         let mut chars = s.chars();
167         let char1 = chars.next();
168         let char2 = chars.next();
169 
170         if let (Some(char), None) = (char1, char2) {
171             Ok(char)
172         } else {
glade_placeholder_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)173             Err(Error::unexpected_type("string"))
174         }
175     }
176 }
177 
178 impl FromMeta for String {
179     fn from_string(s: &str) -> Result<Self> {
180         Ok(s.to_string())
181     }
182 }
183 
184 /// Generate an impl of `FromMeta` that will accept strings which parse to numbers or
185 /// integer literals.
186 macro_rules! from_meta_num {
187     ($ty:ident) => {
188         impl FromMeta for $ty {
189             fn from_string(s: &str) -> Result<Self> {
190                 s.parse().map_err(|_| Error::unknown_value(s))
191             }
192 
193             fn from_value(value: &Lit) -> Result<Self> {
194                 (match *value {
glade_placeholder_realize(GtkWidget * widget)195                     Lit::Str(ref s) => Self::from_string(&s.value()),
196                     Lit::Int(ref s) => Ok(s.base10_parse::<$ty>().unwrap()),
197                     _ => Err(Error::unexpected_lit_type(value)),
198                 })
199                 .map_err(|e| e.with_span(value))
200             }
201         }
202     };
203 }
204 
205 from_meta_num!(u8);
206 from_meta_num!(u16);
207 from_meta_num!(u32);
208 from_meta_num!(u64);
209 from_meta_num!(usize);
210 from_meta_num!(i8);
211 from_meta_num!(i16);
212 from_meta_num!(i32);
213 from_meta_num!(i64);
214 from_meta_num!(isize);
215 
216 /// Generate an impl of `FromMeta` that will accept strings which parse to floats or
217 /// float literals.
218 macro_rules! from_meta_float {
219     ($ty:ident) => {
220         impl FromMeta for $ty {
221             fn from_string(s: &str) -> Result<Self> {
222                 s.parse().map_err(|_| Error::unknown_value(s))
223             }
224 
225             fn from_value(value: &Lit) -> Result<Self> {
226                 (match *value {
227                     Lit::Str(ref s) => Self::from_string(&s.value()),
228                     Lit::Float(ref s) => Ok(s.base10_parse::<$ty>().unwrap()),
229                     _ => Err(Error::unexpected_lit_type(value)),
230                 })
231                 .map_err(|e| e.with_span(value))
232             }
glade_placeholder_unrealize(GtkWidget * widget)233         }
234     };
235 }
236 
237 from_meta_float!(f32);
238 from_meta_float!(f64);
239 
240 /// Parsing support for identifiers. This attempts to preserve span information
241 /// when available, but also supports parsing strings with the call site as the
242 /// emitted span.
243 impl FromMeta for syn::Ident {
244     fn from_string(value: &str) -> Result<Self> {
245         Ok(syn::Ident::new(value, ::proc_macro2::Span::call_site()))
246     }
247 
248     fn from_value(value: &Lit) -> Result<Self> {
249         if let Lit::Str(ref ident) = *value {
glade_placeholder_map(GtkWidget * widget)250             ident
251                 .parse()
252                 .map_err(|_| Error::unknown_lit_str_value(ident))
253         } else {
254             Err(Error::unexpected_lit_type(value))
255         }
256     }
257 }
258 
259 /// Parsing support for punctuated. This attempts to preserve span information
260 /// when available, but also supports parsing strings with the call site as the
261 /// emitted span.
262 impl<T: syn::parse::Parse, P: syn::parse::Parse> FromMeta for syn::punctuated::Punctuated<T, P> {
263     fn from_value(value: &Lit) -> Result<Self> {
264         if let Lit::Str(ref ident) = *value {
glade_placeholder_unmap(GtkWidget * widget)265             ident
266                 .parse_with(syn::punctuated::Punctuated::parse_terminated)
267                 .map_err(|_| Error::unknown_lit_str_value(ident))
268         } else {
269             Err(Error::unexpected_lit_type(value))
270         }
271     }
272 }
273 
274 /// Parsing support for an array, i.e. `example = "[1 + 2, 2 - 2, 3 * 4]"`.
275 impl FromMeta for syn::ExprArray {
276     fn from_value(value: &Lit) -> Result<Self> {
277         if let Lit::Str(ref ident) = *value {
278             ident
279                 .parse::<syn::ExprArray>()
glade_placeholder_size_allocate(GtkWidget * widget,GtkAllocation * allocation)280                 .map_err(|_| Error::unknown_lit_str_value(ident))
281         } else {
282             Err(Error::unexpected_lit_type(value))
283         }
284     }
285 }
286 
287 macro_rules! from_numeric_array {
288     ($ty:ident) => {
289         /// Parsing an unsigned integer array, i.e. `example = "[1, 2, 3, 4]"`.
290         impl FromMeta for Vec<$ty> {
291             fn from_value(value: &Lit) -> Result<Self> {
292                 let expr_array = syn::ExprArray::from_value(value)?;
293                 // To meet rust <1.36 borrow checker rules on expr_array.elems
294                 let v =
295                     expr_array
296                         .elems
glade_placeholder_draw(GtkWidget * widget,cairo_t * cr)297                         .iter()
298                         .map(|expr| match expr {
299                             Expr::Lit(lit) => $ty::from_value(&lit.lit),
300                             _ => Err(Error::custom("Expected array of unsigned integers")
301                                 .with_span(expr)),
302                         })
303                         .collect::<Result<Vec<$ty>>>();
304                 v
305             }
306         }
307     };
308 }
309 
310 from_numeric_array!(u8);
311 from_numeric_array!(u16);
312 from_numeric_array!(u32);
313 from_numeric_array!(u64);
314 from_numeric_array!(usize);
315 
316 /// Parsing support for paths. This attempts to preserve span information when available,
317 /// but also supports parsing strings with the call site as the emitted span.
318 impl FromMeta for syn::Path {
319     fn from_string(value: &str) -> Result<Self> {
320         syn::parse_str(value).map_err(|_| Error::unknown_value(value))
321     }
322 
323     fn from_value(value: &Lit) -> Result<Self> {
324         if let Lit::Str(ref path_str) = *value {
325             path_str
326                 .parse()
327                 .map_err(|_| Error::unknown_lit_str_value(path_str))
328         } else {
329             Err(Error::unexpected_lit_type(value))
330         }
331     }
332 }
333 
334 impl FromMeta for syn::Lit {
335     fn from_value(value: &Lit) -> Result<Self> {
336         Ok(value.clone())
337     }
338 }
339 
340 macro_rules! from_meta_lit {
341     ($impl_ty:path, $lit_variant:path) => {
342         impl FromMeta for $impl_ty {
343             fn from_value(value: &Lit) -> Result<Self> {
344                 if let $lit_variant(ref value) = *value {
345                     Ok(value.clone())
346                 } else {
347                     Err(Error::unexpected_lit_type(value))
348                 }
349             }
350         }
351     };
352 }
353 
354 from_meta_lit!(syn::LitInt, Lit::Int);
355 from_meta_lit!(syn::LitFloat, Lit::Float);
356 from_meta_lit!(syn::LitStr, Lit::Str);
357 from_meta_lit!(syn::LitByte, Lit::Byte);
358 from_meta_lit!(syn::LitByteStr, Lit::ByteStr);
359 from_meta_lit!(syn::LitChar, Lit::Char);
360 from_meta_lit!(syn::LitBool, Lit::Bool);
361 from_meta_lit!(proc_macro2::Literal, Lit::Verbatim);
glade_placeholder_update_cursor(GladePlaceholder * placeholder,GdkWindow * win)362 
363 impl FromMeta for syn::Meta {
364     fn from_meta(value: &syn::Meta) -> Result<Self> {
365         Ok(value.clone())
366     }
367 }
368 
369 impl FromMeta for syn::WhereClause {
370     fn from_string(value: &str) -> Result<Self> {
371         syn::parse_str(value).map_err(|_| Error::unknown_value(value))
372     }
373 }
glade_placeholder_enter_notify_event(GtkWidget * widget,GdkEventCrossing * event)374 
375 impl FromMeta for Vec<syn::WherePredicate> {
376     fn from_string(value: &str) -> Result<Self> {
377         syn::WhereClause::from_string(&format!("where {}", value))
378             .map(|c| c.predicates.into_iter().collect())
379     }
380 }
381 
glade_placeholder_motion_notify_event(GtkWidget * widget,GdkEventMotion * event)382 impl FromMeta for ident_case::RenameRule {
383     fn from_string(value: &str) -> Result<Self> {
384         value.parse().map_err(|_| Error::unknown_value(value))
385     }
386 }
387 
388 impl<T: FromMeta> FromMeta for Option<T> {
on_chooser_adaptor_widget_selected(_GladeAdaptorChooserWidget * chooser,GladeWidgetAdaptor * adaptor,GladePlaceholder * placeholder)389     fn from_meta(item: &Meta) -> Result<Self> {
390         FromMeta::from_meta(item).map(Some)
391     }
392 }
393 
394 impl<T: FromMeta> FromMeta for Box<T> {
395     fn from_meta(item: &Meta) -> Result<Self> {
396         FromMeta::from_meta(item).map(Box::new)
397     }
398 }
399 
glade_placeholder_popover_new(GladePlaceholder * placeholder,GtkWidget * relative_to)400 impl<T: FromMeta> FromMeta for Result<T> {
401     fn from_meta(item: &Meta) -> Result<Self> {
402         Ok(FromMeta::from_meta(item))
403     }
404 }
405 
406 /// Parses the meta-item, and in case of error preserves a copy of the input for
407 /// later analysis.
408 impl<T: FromMeta> FromMeta for ::std::result::Result<T, Meta> {
409     fn from_meta(item: &Meta) -> Result<Self> {
410         T::from_meta(item)
411             .map(Ok)
412             .or_else(|_| Ok(Err(item.clone())))
413     }
414 }
415 
416 impl<T: FromMeta> FromMeta for Rc<T> {
417     fn from_meta(item: &Meta) -> Result<Self> {
418         FromMeta::from_meta(item).map(Rc::new)
419     }
420 }
glade_placeholder_button_press(GtkWidget * widget,GdkEventButton * event)421 
422 impl<T: FromMeta> FromMeta for Arc<T> {
423     fn from_meta(item: &Meta) -> Result<Self> {
424         FromMeta::from_meta(item).map(Arc::new)
425     }
426 }
427 
428 impl<T: FromMeta> FromMeta for RefCell<T> {
429     fn from_meta(item: &Meta) -> Result<Self> {
430         FromMeta::from_meta(item).map(RefCell::new)
431     }
432 }
433 
434 fn path_to_string(path: &syn::Path) -> String {
435     path.segments
436         .iter()
437         .map(|s| s.ident.to_string())
438         .collect::<Vec<String>>()
439         .join("::")
440 }
441 
442 /// Trait to convert from a path into an owned key for a map.
443 trait KeyFromPath: Sized {
444     fn from_path(path: &syn::Path) -> Result<Self>;
445     fn to_display<'a>(&'a self) -> Cow<'a, str>;
446 }
447 
448 impl KeyFromPath for String {
449     fn from_path(path: &syn::Path) -> Result<Self> {
450         Ok(path_to_string(path))
451     }
452 
453     fn to_display<'a>(&'a self) -> Cow<'a, str> {
454         Cow::Borrowed(&self)
455     }
456 }
457 
458 impl KeyFromPath for syn::Path {
459     fn from_path(path: &syn::Path) -> Result<Self> {
460         Ok(path.clone())
461     }
462 
463     fn to_display<'a>(&'a self) -> Cow<'a, str> {
464         Cow::Owned(path_to_string(self))
465     }
466 }
467 
468 impl KeyFromPath for syn::Ident {
469     fn from_path(path: &syn::Path) -> Result<Self> {
470         if path.segments.len() == 1
471             && path.leading_colon.is_none()
472             && path.segments[0].arguments.is_empty()
473         {
474             Ok(path.segments[0].ident.clone())
475         } else {
476             Err(Error::custom("Key must be an identifier").with_span(path))
477         }
478     }
479 
480     fn to_display<'a>(&'a self) -> Cow<'a, str> {
481         Cow::Owned(self.to_string())
482     }
483 }
484 
glade_placeholder_popup_menu(GtkWidget * widget)485 macro_rules! hash_map {
486     ($key:ty) => {
487         impl<V: FromMeta, S: BuildHasher + Default> FromMeta for HashMap<$key, V, S> {
488             fn from_list(nested: &[syn::NestedMeta]) -> Result<Self> {
489                 // Convert the nested meta items into a sequence of (path, value result) result tuples.
490                 // An outer Err means no (key, value) structured could be found, while an Err in the
491                 // second position of the tuple means that value was rejected by FromMeta.
492                 //
493                 // We defer key conversion into $key so that we don't lose span information in the case
494                 // of String keys; we'll need it for good duplicate key errors later.
495                 let pairs = nested
496                     .iter()
497                     .map(|item| -> Result<(&syn::Path, Result<V>)> {
498                         match *item {
499                             syn::NestedMeta::Meta(ref inner) => {
500                                 let path = inner.path();
501                                 Ok((
502                                     path,
503                                     FromMeta::from_meta(inner).map_err(|e| e.at_path(&path)),
504                                 ))
505                             }
506                             syn::NestedMeta::Lit(_) => Err(Error::unsupported_format("literal")),
507                         }
508                     });
509 
510                 let mut errors = vec![];
511                 // We need to track seen keys separately from the final map, since a seen key with an
512                 // Err value won't go into the final map but should trigger a duplicate field error.
513                 //
514                 // This is a set of $key rather than Path to avoid the possibility that a key type
515                 // parses two paths of different values to the same key value.
516                 let mut seen_keys = HashSet::with_capacity(nested.len());
517 
518                 // The map to return in the Ok case. Its size will always be exactly nested.len(),
519                 // since otherwise ≥1 field had a problem and the entire map is dropped immediately
520                 // when the function returns `Err`.
521                 let mut map = HashMap::with_capacity_and_hasher(nested.len(), Default::default());
522 
523                 for item in pairs {
524                     match item {
525                         Ok((path, value)) => {
526                             let key: $key = match KeyFromPath::from_path(path) {
527                                 Ok(k) => k,
528                                 Err(e) => {
529                                     errors.push(e);
530 
531                                     // Surface value errors even under invalid keys
532                                     if let Err(val_err) = value {
533                                         errors.push(val_err);
534                                     }
535 
536                                     continue;
537                                 }
538                             };
539 
540                             let already_seen = seen_keys.contains(&key);
541 
542                             if already_seen {
543                                 errors.push(
544                                     Error::duplicate_field(&key.to_display()).with_span(path),
545                                 );
546                             }
547 
548                             match value {
549                                 Ok(_) if already_seen => {}
550                                 Ok(val) => {
551                                     map.insert(key.clone(), val);
552                                 }
553                                 Err(e) => {
554                                     errors.push(e);
555                                 }
556                             }
557 
558                             seen_keys.insert(key);
559                         }
560                         Err(e) => {
561                             errors.push(e);
562                         }
563                     }
564                 }
565 
566                 if !errors.is_empty() {
567                     return Err(Error::multiple(errors));
568                 }
569 
570                 Ok(map)
571             }
572         }
573     };
574 }
575 
576 // This is done as a macro rather than a blanket impl to avoid breaking backwards compatibility
577 // with 0.12.x, while still sharing the same impl.
glade_placeholder_drag_init(_GladeDragInterface * iface)578 hash_map!(String);
579 hash_map!(syn::Ident);
580 hash_map!(syn::Path);
581 
582 /// Tests for `FromMeta` implementations. Wherever the word `ignore` appears in test input,
583 /// it should not be considered by the parsing.
584 #[cfg(test)]
585 mod tests {
586     use proc_macro2::TokenStream;
glade_placeholder_class_init(GladePlaceholderClass * klass)587     use syn;
588 
589     use {Error, FromMeta, Result};
590 
591     /// parse a string as a syn::Meta instance.
592     fn pm(tokens: TokenStream) -> ::std::result::Result<syn::Meta, String> {
593         let attribute: syn::Attribute = parse_quote!(#[#tokens]);
594         attribute.parse_meta().map_err(|_| "Unable to parse".into())
595     }
596 
597     fn fm<T: FromMeta>(tokens: TokenStream) -> T {
598         FromMeta::from_meta(&pm(tokens).expect("Tests should pass well-formed input"))
599             .expect("Tests should pass valid input")
600     }
601 
602     #[test]
603     fn unit_succeeds() {
604         assert_eq!(fm::<()>(quote!(ignore)), ());
605     }
606 
607     #[test]
608     fn bool_succeeds() {
609         // word format
610         assert_eq!(fm::<bool>(quote!(ignore)), true);
611 
612         // bool literal
613         assert_eq!(fm::<bool>(quote!(ignore = true)), true);
614         assert_eq!(fm::<bool>(quote!(ignore = false)), false);
615 
616         // string literals
617         assert_eq!(fm::<bool>(quote!(ignore = "true")), true);
618         assert_eq!(fm::<bool>(quote!(ignore = "false")), false);
619     }
620 
621     #[test]
622     fn char_succeeds() {
623         // char literal
624         assert_eq!(fm::<char>(quote!(ignore = '��')), '��');
625 
626         // string literal
627         assert_eq!(fm::<char>(quote!(ignore = "��")), '��');
628     }
629 
630     #[test]
631     fn string_succeeds() {
632         // cooked form
633         assert_eq!(&fm::<String>(quote!(ignore = "world")), "world");
634 
635         // raw form
636         assert_eq!(&fm::<String>(quote!(ignore = r#"world"#)), "world");
637     }
638 
glade_placeholder_new(void)639     #[test]
640     fn number_succeeds() {
641         assert_eq!(fm::<u8>(quote!(ignore = "2")), 2u8);
642         assert_eq!(fm::<i16>(quote!(ignore = "-25")), -25i16);
643         assert_eq!(fm::<f64>(quote!(ignore = "1.4e10")), 1.4e10);
644     }
glade_placeholder_get_project(GladePlaceholder * placeholder)645 
646     #[test]
647     fn int_without_quotes() {
648         assert_eq!(fm::<u8>(quote!(ignore = 2)), 2u8);
649         assert_eq!(fm::<u16>(quote!(ignore = 255)), 255u16);
650         assert_eq!(fm::<u32>(quote!(ignore = 5000)), 5000u32);
651 
652         // Check that we aren't tripped up by incorrect suffixes
653         assert_eq!(fm::<u32>(quote!(ignore = 5000i32)), 5000u32);
654     }
655 
656     #[test]
657     fn float_without_quotes() {
658         assert_eq!(fm::<f32>(quote!(ignore = 2.)), 2.0f32);
659         assert_eq!(fm::<f32>(quote!(ignore = 2.0)), 2.0f32);
660         assert_eq!(fm::<f64>(quote!(ignore = 1.4e10)), 1.4e10f64);
661     }
662 
663     #[test]
664     fn meta_succeeds() {
665         use syn::Meta;
666 
667         assert_eq!(
668             fm::<Meta>(quote!(hello(world, today))),
669             pm(quote!(hello(world, today))).unwrap()
glade_placeholder_packing_actions(GladePlaceholder * placeholder)670         );
671     }
672 
673     #[test]
674     fn hash_map_succeeds() {
675         use std::collections::HashMap;
676 
677         let comparison = {
678             let mut c = HashMap::new();
679             c.insert("hello".to_string(), true);
680             c.insert("world".to_string(), false);
681             c.insert("there".to_string(), true);
682             c
683         };
684 
685         assert_eq!(
686             fm::<HashMap<String, bool>>(quote!(ignore(hello, world = false, there = "true"))),
687             comparison
688         );
689     }
690 
691     /// Check that a `HashMap` cannot have duplicate keys, and that the generated error
692     /// is assigned a span to correctly target the diagnostic message.
693     #[test]
694     fn hash_map_duplicate() {
695         use std::collections::HashMap;
696 
697         let err: Result<HashMap<String, bool>> =
698             FromMeta::from_meta(&pm(quote!(ignore(hello, hello = false))).unwrap());
699 
700         let err = err.expect_err("Duplicate keys in HashMap should error");
701 
702         assert!(err.has_span());
703         assert_eq!(err.to_string(), Error::duplicate_field("hello").to_string());
704     }
705 
706     #[test]
707     fn hash_map_multiple_errors() {
708         use std::collections::HashMap;
709 
710         let err = HashMap::<String, bool>::from_meta(
711             &pm(quote!(ignore(hello, hello = 3, hello = false))).unwrap(),
712         )
713         .expect_err("Duplicates and bad values should error");
714 
715         assert_eq!(err.len(), 3);
716         let errors = err.into_iter().collect::<Vec<_>>();
717         assert!(errors[0].has_span());
718         assert!(errors[1].has_span());
719         assert!(errors[2].has_span());
720     }
721 
722     #[test]
723     fn hash_map_ident_succeeds() {
724         use std::collections::HashMap;
725         use syn::parse_quote;
726 
727         let comparison = {
728             let mut c = HashMap::<syn::Ident, bool>::new();
729             c.insert(parse_quote!(first), true);
730             c.insert(parse_quote!(second), false);
731             c
732         };
733 
734         assert_eq!(
735             fm::<HashMap<syn::Ident, bool>>(quote!(ignore(first, second = false))),
736             comparison
737         );
738     }
739 
740     #[test]
741     fn hash_map_ident_rejects_non_idents() {
742         use std::collections::HashMap;
743 
744         let err: Result<HashMap<syn::Ident, bool>> =
745             FromMeta::from_meta(&pm(quote!(ignore(first, the::second))).unwrap());
746 
747         err.unwrap_err();
748     }
749 
750     #[test]
751     fn hash_map_path_succeeds() {
752         use std::collections::HashMap;
753         use syn::parse_quote;
754 
755         let comparison = {
756             let mut c = HashMap::<syn::Path, bool>::new();
757             c.insert(parse_quote!(first), true);
758             c.insert(parse_quote!(the::second), false);
759             c
760         };
761 
762         assert_eq!(
763             fm::<HashMap<syn::Path, bool>>(quote!(ignore(first, the::second = false))),
764             comparison
765         );
766     }
767 
768     /// Tests that fallible parsing will always produce an outer `Ok` (from `fm`),
769     /// and will accurately preserve the inner contents.
770     #[test]
771     fn darling_result_succeeds() {
772         fm::<Result<()>>(quote!(ignore)).unwrap();
773         fm::<Result<()>>(quote!(ignore(world))).unwrap_err();
774     }
775 
776     /// Test punctuated
777     #[test]
778     fn test_punctuated() {
779         fm::<syn::punctuated::Punctuated<syn::FnArg, syn::token::Comma>>(quote!(
780             ignore = "a: u8, b: Type"
781         ));
782         fm::<syn::punctuated::Punctuated<syn::Expr, syn::token::Comma>>(quote!(ignore = "a, b, c"));
783     }
784 
785     #[test]
786     fn test_expr_array() {
787         fm::<syn::ExprArray>(quote!(ignore = "[0x1, 0x2]"));
788         fm::<syn::ExprArray>(quote!(ignore = "[\"Hello World\", \"Test Array\"]"));
789     }
790 
791     #[test]
792     fn test_number_array() {
793         assert_eq!(
794             fm::<Vec<u8>>(quote!(ignore = "[16, 0xff]")),
795             vec![0x10, 0xff]
796         );
797         assert_eq!(
798             fm::<Vec<u16>>(quote!(ignore = "[32, 0xffff]")),
799             vec![0x20, 0xffff]
800         );
801         assert_eq!(
802             fm::<Vec<u32>>(quote!(ignore = "[48, 0xffffffff]")),
803             vec![0x30, 0xffffffff]
804         );
805         assert_eq!(
806             fm::<Vec<u64>>(quote!(ignore = "[64, 0xffffffffffffffff]")),
807             vec![0x40, 0xffffffffffffffff]
808         );
809         assert_eq!(
810             fm::<Vec<usize>>(quote!(ignore = "[80, 0xffffffff]")),
811             vec![0x50, 0xffffffff]
812         );
813     }
814 }
815