1use quote::ToTokens;
2use std::borrow::Cow;
3use std::cell::RefCell;
4use std::collections::btree_map::BTreeMap;
5use std::collections::hash_map::HashMap;
6use std::collections::HashSet;
7use std::hash::BuildHasher;
8use std::num;
9use std::rc::Rc;
10use std::sync::atomic::AtomicBool;
11use std::sync::Arc;
12use syn::spanned::Spanned;
13
14use syn::{Expr, Ident, Lit, Meta, Path};
15
16use crate::ast::{MetaNameValueInvalidExpr, NestedMeta};
17use crate::util::path_to_string;
18use crate::{Error, Result};
19
20pub trait FromMeta: Sized {
56 fn from_nested_meta(item: &NestedMeta) -> Result<Self> {
57 (match *item {
58 NestedMeta::Lit(ref lit) => Self::from_value(lit),
59 NestedMeta::Meta(ref mi) => Self::from_meta(mi),
60 NestedMeta::NameValueInvalidExpr(ref meta) => Self::from_invalid_expr(meta),
61 })
62 .map_err(|e| e.with_span(item))
63 }
64
65 fn from_meta(item: &Meta) -> Result<Self> {
74 (match *item {
75 Meta::Path(_) => Self::from_word(),
76 Meta::List(ref value) => {
77 Self::from_list(&NestedMeta::parse_meta_list(value.tokens.clone())?[..])
78 }
79 Meta::NameValue(ref value) => Self::from_expr(&value.value),
80 })
81 .map_err(|e| e.with_span(item))
82 }
83
84 fn from_none() -> Option<Self> {
95 None
96 }
97
98 fn from_word() -> Result<Self> {
101 Err(Error::unsupported_format("word"))
102 }
103
104 #[allow(unused_variables)]
106 fn from_list(items: &[NestedMeta]) -> Result<Self> {
107 Err(Error::unsupported_format("list"))
108 }
109
110 fn from_value(value: &Lit) -> Result<Self> {
118 (match *value {
119 Lit::Bool(ref b) => Self::from_bool(b.value),
120 Lit::Str(ref s) => Self::from_string(&s.value()),
121 Lit::Char(ref ch) => Self::from_char(ch.value()),
122 _ => Err(Error::unexpected_lit_type(value)),
123 })
124 .map_err(|e| e.with_span(value))
125 }
126
127 fn from_expr(expr: &Expr) -> Result<Self> {
128 match *expr {
129 Expr::Lit(ref lit) => Self::from_value(&lit.lit),
130 Expr::Group(ref group) => {
131 Self::from_expr(&group.expr)
137 }
138 _ => Err(Error::unexpected_expr_type(expr)),
139 }
140 .map_err(|e| e.with_span(expr))
141 }
142
143 fn from_invalid_expr(value: &MetaNameValueInvalidExpr) -> Result<Self> {
219 Err(value.error.clone())
220 }
221
222 #[allow(unused_variables)]
224 fn from_char(value: char) -> Result<Self> {
225 Err(Error::unexpected_type("char"))
226 }
227
228 #[allow(unused_variables)]
230 fn from_string(value: &str) -> Result<Self> {
231 Err(Error::unexpected_type("string"))
232 }
233
234 #[allow(unused_variables)]
236 fn from_bool(value: bool) -> Result<Self> {
237 Err(Error::unexpected_type("bool"))
238 }
239}
240
241impl FromMeta for () {
244 fn from_word() -> Result<Self> {
245 Ok(())
246 }
247
248 fn from_list(items: &[NestedMeta]) -> Result<Self> {
249 let mut errors = Error::accumulator();
250 for item in items {
251 errors.push(match item {
252 NestedMeta::Meta(meta) => Error::unknown_field_path(meta.path()).with_span(meta),
259 NestedMeta::NameValueInvalidExpr(meta) => {
260 Error::unknown_field_path(&meta.path).with_span(&meta.path.span())
261 }
262 NestedMeta::Lit(lit) => {
263 Error::unexpected_expr_type(&syn::Expr::Lit(syn::ExprLit {
264 attrs: vec![],
265 lit: lit.clone(),
266 }))
267 .with_span(lit)
268 }
269 });
270 }
271
272 errors.finish()
273 }
274}
275
276impl FromMeta for bool {
277 fn from_word() -> Result<Self> {
278 Ok(true)
279 }
280
281 #[allow(clippy::wrong_self_convention)] fn from_bool(value: bool) -> Result<Self> {
283 Ok(value)
284 }
285
286 fn from_string(value: &str) -> Result<Self> {
287 value.parse().map_err(|_| Error::unknown_value(value))
288 }
289}
290
291impl FromMeta for AtomicBool {
292 fn from_meta(mi: &Meta) -> Result<Self> {
293 FromMeta::from_meta(mi)
294 .map(AtomicBool::new)
295 .map_err(|e| e.with_span(mi))
296 }
297}
298
299impl FromMeta for char {
300 #[allow(clippy::wrong_self_convention)] fn from_char(value: char) -> Result<Self> {
302 Ok(value)
303 }
304
305 fn from_string(s: &str) -> Result<Self> {
306 let mut chars = s.chars();
307 let char1 = chars.next();
308 let char2 = chars.next();
309
310 if let (Some(char), None) = (char1, char2) {
311 Ok(char)
312 } else {
313 Err(Error::unexpected_type("string"))
314 }
315 }
316}
317
318impl FromMeta for String {
319 fn from_string(s: &str) -> Result<Self> {
320 Ok(s.to_string())
321 }
322}
323
324impl FromMeta for std::path::PathBuf {
325 fn from_string(s: &str) -> Result<Self> {
326 Ok(s.into())
327 }
328}
329
330macro_rules! from_meta_num {
333 ($ty:path) => {
334 impl FromMeta for $ty {
335 fn from_string(s: &str) -> Result<Self> {
336 s.parse().map_err(|_| Error::unknown_value(s))
337 }
338
339 fn from_value(value: &Lit) -> Result<Self> {
340 (match *value {
341 Lit::Str(ref s) => Self::from_string(&s.value()),
342 Lit::Int(ref s) => s.base10_parse::<$ty>().map_err(Error::from),
343 _ => Err(Error::unexpected_lit_type(value)),
344 })
345 .map_err(|e| e.with_span(value))
346 }
347 }
348 };
349}
350
351from_meta_num!(u8);
352from_meta_num!(u16);
353from_meta_num!(u32);
354from_meta_num!(u64);
355from_meta_num!(u128);
356from_meta_num!(usize);
357from_meta_num!(i8);
358from_meta_num!(i16);
359from_meta_num!(i32);
360from_meta_num!(i64);
361from_meta_num!(i128);
362from_meta_num!(isize);
363from_meta_num!(num::NonZeroU8);
364from_meta_num!(num::NonZeroU16);
365from_meta_num!(num::NonZeroU32);
366from_meta_num!(num::NonZeroU64);
367from_meta_num!(num::NonZeroU128);
368from_meta_num!(num::NonZeroUsize);
369from_meta_num!(num::NonZeroI8);
370from_meta_num!(num::NonZeroI16);
371from_meta_num!(num::NonZeroI32);
372from_meta_num!(num::NonZeroI64);
373from_meta_num!(num::NonZeroI128);
374from_meta_num!(num::NonZeroIsize);
375
376macro_rules! from_meta_float {
379 ($ty:ident) => {
380 impl FromMeta for $ty {
381 fn from_string(s: &str) -> Result<Self> {
382 s.parse().map_err(|_| Error::unknown_value(s))
383 }
384
385 fn from_value(value: &Lit) -> Result<Self> {
386 (match *value {
387 Lit::Str(ref s) => Self::from_string(&s.value()),
388 Lit::Float(ref s) => s.base10_parse::<$ty>().map_err(Error::from),
389 _ => Err(Error::unexpected_lit_type(value)),
390 })
391 .map_err(|e| e.with_span(value))
392 }
393 }
394 };
395}
396
397from_meta_float!(f32);
398from_meta_float!(f64);
399
400impl<T: syn::parse::Parse, P: syn::parse::Parse> FromMeta for syn::punctuated::Punctuated<T, P> {
404 fn from_value(value: &Lit) -> Result<Self> {
405 if let Lit::Str(ref ident) = *value {
406 ident
407 .parse_with(syn::punctuated::Punctuated::parse_terminated)
408 .map_err(|_| Error::unknown_lit_str_value(ident))
409 } else {
410 Err(Error::unexpected_lit_type(value))
411 }
412 }
413}
414
415impl FromMeta for syn::Expr {
424 fn from_expr(expr: &Expr) -> Result<Self> {
425 match expr {
426 Expr::Lit(syn::ExprLit {
427 lit: lit @ syn::Lit::Str(_),
428 ..
429 }) => Self::from_value(lit),
430 Expr::Group(group) => Self::from_expr(&group.expr), _ => Ok(expr.clone()),
432 }
433 }
434
435 fn from_string(value: &str) -> Result<Self> {
436 syn::parse_str(value).map_err(|_| Error::unknown_value(value))
437 }
438
439 fn from_value(value: &::syn::Lit) -> Result<Self> {
440 if let ::syn::Lit::Str(ref v) = *value {
441 v.parse::<syn::Expr>()
442 .map_err(|_| Error::unknown_lit_str_value(v))
443 } else {
444 Err(Error::unexpected_lit_type(value))
445 }
446 }
447}
448
449impl FromMeta for syn::Path {
451 fn from_string(value: &str) -> Result<Self> {
452 syn::parse_str(value).map_err(|_| Error::unknown_value(value))
453 }
454
455 fn from_value(value: &::syn::Lit) -> Result<Self> {
456 if let ::syn::Lit::Str(ref v) = *value {
457 v.parse().map_err(|_| Error::unknown_lit_str_value(v))
458 } else {
459 Err(Error::unexpected_lit_type(value))
460 }
461 }
462
463 fn from_expr(expr: &Expr) -> Result<Self> {
464 match expr {
465 Expr::Lit(lit) => Self::from_value(&lit.lit),
466 Expr::Path(path) => Ok(path.path.clone()),
467 Expr::Group(group) => Self::from_expr(&group.expr), _ => Err(Error::unexpected_expr_type(expr)),
469 }
470 }
471}
472
473impl FromMeta for syn::Ident {
474 fn from_string(value: &str) -> Result<Self> {
475 syn::parse_str(value).map_err(|_| Error::unknown_value(value))
476 }
477
478 fn from_value(value: &syn::Lit) -> Result<Self> {
479 if let syn::Lit::Str(ref v) = *value {
480 v.parse().map_err(|_| Error::unknown_lit_str_value(v))
481 } else {
482 Err(Error::unexpected_lit_type(value))
483 }
484 }
485
486 fn from_expr(expr: &Expr) -> Result<Self> {
487 match expr {
488 Expr::Lit(lit) => Self::from_value(&lit.lit),
489 Expr::Path(path) => match path.path.get_ident() {
493 Some(ident) => Ok(ident.clone()),
494 None => Err(Error::unexpected_expr_type(expr)),
495 },
496 Expr::Group(group) => Self::from_expr(&group.expr), _ => Err(Error::unexpected_expr_type(expr)),
498 }
499 }
500}
501
502macro_rules! from_syn_expr_type {
513 ($ty:path, $variant:ident) => {
514 impl FromMeta for $ty {
515 fn from_expr(expr: &syn::Expr) -> Result<Self> {
516 match expr {
517 syn::Expr::$variant(body) => Ok(body.clone()),
518 syn::Expr::Lit(expr_lit) => Self::from_value(&expr_lit.lit),
519 syn::Expr::Group(group) => Self::from_expr(&group.expr), _ => Err(Error::unexpected_expr_type(expr)),
521 }
522 }
523
524 fn from_value(value: &::syn::Lit) -> Result<Self> {
525 if let syn::Lit::Str(body) = &value {
526 body.parse::<$ty>()
527 .map_err(|_| Error::unknown_lit_str_value(body))
528 } else {
529 Err(Error::unexpected_lit_type(value))
530 }
531 }
532 }
533 };
534}
535
536from_syn_expr_type!(syn::ExprArray, Array);
537from_syn_expr_type!(syn::ExprPath, Path);
538from_syn_expr_type!(syn::ExprRange, Range);
539
540macro_rules! from_syn_parse {
546 ($ty:path) => {
547 impl FromMeta for $ty {
548 fn from_string(value: &str) -> Result<Self> {
549 syn::parse_str(value).map_err(|_| Error::unknown_value(value))
550 }
551
552 fn from_value(value: &::syn::Lit) -> Result<Self> {
553 if let ::syn::Lit::Str(ref v) = *value {
554 v.parse::<$ty>()
555 .map_err(|_| Error::unknown_lit_str_value(v))
556 } else {
557 Err(Error::unexpected_lit_type(value))
558 }
559 }
560
561 fn from_expr(expr: &Expr) -> Result<Self> {
562 match *expr {
563 Expr::Lit(ref lit) => Self::from_value(&lit.lit),
564 Expr::Group(ref group) => {
565 Self::from_expr(&group.expr)
571 }
572 _ => Ok(syn::parse2(expr.into_token_stream().clone())?),
575 }
576 .map_err(|e| e.with_span(expr))
577 }
578
579 fn from_invalid_expr(value: &MetaNameValueInvalidExpr) -> Result<Self> {
580 syn::parse2(value.value.clone()).map_err(Into::into)
581 }
582 }
583 };
584}
585
586from_syn_parse!(syn::Type);
587from_syn_parse!(syn::TypeArray);
588from_syn_parse!(syn::TypeFnPtr);
589from_syn_parse!(syn::TypeGroup);
590from_syn_parse!(syn::TypeImplTrait);
591from_syn_parse!(syn::TypeInfer);
592from_syn_parse!(syn::TypeMacro);
593from_syn_parse!(syn::TypeNever);
594from_syn_parse!(syn::TypeParam);
595from_syn_parse!(syn::TypeParen);
596from_syn_parse!(syn::TypePtr);
597from_syn_parse!(syn::TypeReference);
598from_syn_parse!(syn::TypeSlice);
599from_syn_parse!(syn::TypeTraitObject);
600from_syn_parse!(syn::TypeTuple);
601from_syn_parse!(syn::Visibility);
602from_syn_parse!(syn::WhereClause);
603
604impl FromMeta for syn::TypePath {
605 fn from_expr(expr: &Expr) -> Result<Self> {
607 match expr {
608 Expr::Path(body) => {
609 if body.attrs.is_empty() {
610 Ok(syn::TypePath {
611 attrs: vec![],
612 qself: body.qself.clone(),
613 path: body.path.clone(),
614 })
615 } else {
616 Err(Error::custom("attributes are not allowed").with_span(body))
617 }
618 }
619 Expr::Lit(expr_lit) => Self::from_value(&expr_lit.lit),
620 Expr::Group(group) => Self::from_expr(&group.expr),
621 _ => Err(Error::unexpected_expr_type(expr)),
622 }
623 }
624
625 fn from_string(value: &str) -> Result<Self> {
626 syn::parse_str(value).map_err(|_| Error::unknown_value(value))
627 }
628
629 fn from_value(value: &Lit) -> Result<Self> {
630 if let Lit::Str(ref v) = *value {
631 v.parse().map_err(|_| Error::unknown_lit_str_value(v))
632 } else {
633 Err(Error::unexpected_lit_type(value))
634 }
635 }
636}
637
638macro_rules! from_numeric_array {
639 ($ty:ident) => {
640 impl FromMeta for Vec<$ty> {
642 fn from_expr(expr: &syn::Expr) -> Result<Self> {
643 match expr {
644 syn::Expr::Array(expr_array) => expr_array
645 .elems
646 .iter()
647 .map(|expr| {
648 let unexpected = || {
649 Error::custom("Expected array of unsigned integers").with_span(expr)
650 };
651 match expr {
652 Expr::Lit(lit) => $ty::from_value(&lit.lit),
653 Expr::Group(group) => match &*group.expr {
654 Expr::Lit(lit) => $ty::from_value(&lit.lit),
655 _ => Err(unexpected()),
656 },
657 _ => Err(unexpected()),
658 }
659 })
660 .collect::<Result<Vec<$ty>>>(),
661 syn::Expr::Lit(expr_lit) => Self::from_value(&expr_lit.lit),
662 syn::Expr::Group(group) => Self::from_expr(&group.expr), _ => Err(Error::unexpected_expr_type(expr)),
664 }
665 }
666
667 fn from_value(value: &Lit) -> Result<Self> {
668 let expr_array = syn::ExprArray::from_value(value)?;
669 Self::from_expr(&syn::Expr::Array(expr_array))
670 }
671 }
672 };
673}
674
675from_numeric_array!(u8);
676from_numeric_array!(u16);
677from_numeric_array!(u32);
678from_numeric_array!(u64);
679from_numeric_array!(usize);
680
681impl FromMeta for syn::Lit {
682 fn from_value(value: &Lit) -> Result<Self> {
683 Ok(value.clone())
684 }
685}
686
687macro_rules! from_meta_lit {
688 ($impl_ty:path, $lit_variant:path) => {
689 impl FromMeta for $impl_ty {
690 fn from_value(value: &Lit) -> Result<Self> {
691 if let $lit_variant(ref value) = *value {
692 Ok(value.clone())
693 } else {
694 Err(Error::unexpected_lit_type(value))
695 }
696 }
697 }
698
699 impl FromMeta for Vec<$impl_ty> {
700 fn from_list(items: &[NestedMeta]) -> Result<Self> {
701 items
702 .iter()
703 .map(<$impl_ty as FromMeta>::from_nested_meta)
704 .collect()
705 }
706
707 fn from_value(value: &syn::Lit) -> Result<Self> {
708 let expr_array = syn::ExprArray::from_value(value)?;
709 Self::from_expr(&syn::Expr::Array(expr_array))
710 }
711
712 fn from_expr(expr: &syn::Expr) -> Result<Self> {
713 match expr {
714 syn::Expr::Array(expr_array) => expr_array
715 .elems
716 .iter()
717 .map(<$impl_ty as FromMeta>::from_expr)
718 .collect::<Result<Vec<_>>>(),
719 syn::Expr::Lit(expr_lit) => Self::from_value(&expr_lit.lit),
720 syn::Expr::Group(g) => Self::from_expr(&g.expr),
721 _ => Err(Error::unexpected_expr_type(expr)),
722 }
723 }
724 }
725 };
726}
727
728from_meta_lit!(syn::LitInt, Lit::Int);
729from_meta_lit!(syn::LitFloat, Lit::Float);
730from_meta_lit!(syn::LitStr, Lit::Str);
731from_meta_lit!(syn::LitByte, Lit::Byte);
732from_meta_lit!(syn::LitByteStr, Lit::ByteStr);
733from_meta_lit!(syn::LitChar, Lit::Char);
734from_meta_lit!(syn::LitBool, Lit::Bool);
735from_meta_lit!(proc_macro2::Literal, Lit::Verbatim);
736
737impl FromMeta for syn::Meta {
738 fn from_meta(value: &syn::Meta) -> Result<Self> {
739 Ok(value.clone())
740 }
741}
742
743impl FromMeta for Vec<syn::WherePredicate> {
744 fn from_string(value: &str) -> Result<Self> {
745 syn::WhereClause::from_string(&format!("where {}", value))
746 .map(|c| c.predicates.into_iter().collect())
747 }
748
749 fn from_value(value: &Lit) -> Result<Self> {
750 if let syn::Lit::Str(s) = value {
751 syn::WhereClause::from_value(&syn::Lit::Str(syn::LitStr::new(
752 &format!("where {}", s.value()),
753 value.span(),
754 )))
755 .map(|c| c.predicates.into_iter().collect())
756 } else {
757 Err(Error::unexpected_lit_type(value))
758 }
759 }
760}
761
762impl FromMeta for ident_case::RenameRule {
763 fn from_string(value: &str) -> Result<Self> {
764 value.parse().map_err(|_| Error::unknown_value(value))
765 }
766}
767
768impl<T: FromMeta> FromMeta for Option<T> {
769 fn from_none() -> Option<Self> {
770 Some(None)
771 }
772
773 fn from_meta(item: &Meta) -> Result<Self> {
774 FromMeta::from_meta(item).map(Some)
775 }
776}
777
778impl<T: FromMeta> FromMeta for Result<T> {
779 fn from_none() -> Option<Self> {
780 T::from_none().map(Ok)
781 }
782
783 fn from_list(items: &[NestedMeta]) -> Result<Self> {
787 Ok(FromMeta::from_list(items))
788 }
789
790 fn from_meta(item: &Meta) -> Result<Self> {
791 Ok(FromMeta::from_meta(item))
792 }
793}
794
795macro_rules! smart_pointer_t {
797 ($ty:path, $map_fn:path) => {
798 impl<T: FromMeta> FromMeta for $ty {
799 fn from_none() -> Option<Self> {
800 T::from_none().map($map_fn)
801 }
802
803 fn from_list(items: &[NestedMeta]) -> Result<Self> {
807 FromMeta::from_list(items).map($map_fn)
808 }
809
810 fn from_meta(item: &Meta) -> Result<Self> {
811 FromMeta::from_meta(item).map($map_fn)
812 }
813 }
814 };
815}
816
817smart_pointer_t!(Box<T>, Box::new);
818smart_pointer_t!(Rc<T>, Rc::new);
819smart_pointer_t!(Arc<T>, Arc::new);
820smart_pointer_t!(RefCell<T>, RefCell::new);
821
822impl<T: FromMeta> FromMeta for ::std::result::Result<T, Meta> {
825 fn from_meta(item: &Meta) -> Result<Self> {
826 T::from_meta(item)
827 .map(Ok)
828 .or_else(|_| Ok(Err(item.clone())))
829 }
830}
831
832trait KeyFromPath: Sized {
834 fn from_path(path: &syn::Path) -> Result<Self>;
835 fn to_display(&self) -> Cow<'_, str>;
836}
837
838impl KeyFromPath for String {
839 fn from_path(path: &syn::Path) -> Result<Self> {
840 Ok(path_to_string(path))
841 }
842
843 fn to_display(&self) -> Cow<'_, str> {
844 Cow::Borrowed(self)
845 }
846}
847
848impl KeyFromPath for syn::Path {
849 fn from_path(path: &syn::Path) -> Result<Self> {
850 Ok(path.clone())
851 }
852
853 fn to_display(&self) -> Cow<'_, str> {
854 Cow::Owned(path_to_string(self))
855 }
856}
857
858impl KeyFromPath for syn::Ident {
859 fn from_path(path: &syn::Path) -> Result<Self> {
860 if path.segments.len() == 1
861 && path.leading_colon.is_none()
862 && path.segments[0].arguments.is_empty()
863 {
864 Ok(path.segments[0].ident.clone())
865 } else {
866 Err(Error::custom("Key must be an identifier").with_span(path))
867 }
868 }
869
870 fn to_display(&self) -> Cow<'_, str> {
871 Cow::Owned(self.to_string())
872 }
873}
874
875macro_rules! map {
876 (hash_map, $key:ty, $nested:ident) => {
877 impl<V: FromMeta, S: BuildHasher + Default> FromMeta for HashMap<$key, V, S> {
878 map!(
879 HashMap::with_capacity_and_hasher($nested.len(), Default::default()),
880 $key,
881 $nested
882 );
883 }
884 };
885
886 (btree_map, $key:ty, $nested:ident) => {
887 impl<V: FromMeta> FromMeta for BTreeMap<$key, V> {
888 map!(BTreeMap::new(), $key, $nested);
889 }
890 };
891
892 ($new:expr, $key:ty, $nested:ident) => {
893 fn from_list($nested: &[NestedMeta]) -> Result<Self> {
894 let pairs = $nested
901 .iter()
902 .map(|item| -> Result<(&syn::Path, Result<V>)> {
903 match *item {
904 NestedMeta::Meta(ref inner) => {
905 let path = inner.path();
906 Ok((
907 path,
908 FromMeta::from_meta(inner).map_err(|e| e.at_path(&path)),
909 ))
910 }
911 NestedMeta::NameValueInvalidExpr(ref inner) => Ok((
912 &inner.path,
913 FromMeta::from_invalid_expr(inner).map_err(|e| e.at_path(&inner.path)),
914 )),
915 NestedMeta::Lit(_) => Err(Error::unsupported_format("expression")),
916 }
917 });
918
919 let mut errors = Error::accumulator();
920 let mut seen_keys = HashSet::with_capacity($nested.len());
926
927 let mut map = $new;
931
932 for item in pairs {
933 if let Some((path, value)) = errors.handle(item) {
934 let key: $key = match KeyFromPath::from_path(path) {
935 Ok(k) => k,
936 Err(e) => {
937 errors.push(e);
938
939 errors.handle(value);
941
942 continue;
943 }
944 };
945
946 let already_seen = seen_keys.contains(&key);
947
948 if already_seen {
949 errors.push(Error::duplicate_field(&key.to_display()).with_span(path));
950 }
951
952 match value {
953 Ok(_) if already_seen => {}
954 Ok(val) => {
955 map.insert(key.clone(), val);
956 }
957 Err(e) => {
958 errors.push(e);
959 }
960 }
961
962 seen_keys.insert(key);
963 }
964 }
965
966 errors.finish_with(map)
967 }
968 };
969}
970
971map!(hash_map, String, nested);
974map!(hash_map, syn::Ident, nested);
975map!(hash_map, syn::Path, nested);
976
977map!(btree_map, String, nested);
978map!(btree_map, syn::Ident, nested);
979
980#[doc(hidden)]
981#[allow(clippy::wrong_self_convention)]
1023pub mod autoref_specialization {
1024 use super::FromMeta;
1025 use std::marker::PhantomData;
1026
1027 pub struct FromMetaTag<T>(PhantomData<T>);
1028 pub struct FromMetaTagAll<T>(PhantomData<T>);
1029
1030 impl<T: FromMeta> FromMetaTag<T> {
1031 pub fn from_none(self) -> Option<T> {
1032 T::from_none()
1033 }
1034 }
1035
1036 impl<T> FromMetaTagAll<T> {
1037 pub fn from_none(self) -> Option<T> {
1038 None
1039 }
1040 }
1041
1042 pub trait SpecFromMeta<T>: Sized {
1043 fn tag(self) -> FromMetaTag<T> {
1044 FromMetaTag(PhantomData)
1045 }
1046 }
1047
1048 pub trait SpecFromMetaAll<T>: Sized {
1049 fn tag(self) -> FromMetaTagAll<T> {
1050 FromMetaTagAll(PhantomData)
1051 }
1052 }
1053
1054 impl<T> SpecFromMetaAll<T> for &&PhantomData<T> {}
1058
1059 impl<T: FromMeta> SpecFromMeta<T> for &PhantomData<T> {}
1060}
1061
1062impl FromMeta for Vec<Ident> {
1063 fn from_list(nested: &[NestedMeta]) -> Result<Self> {
1064 let items = nested.iter().map(|item| match *item {
1065 NestedMeta::Meta(ref inner) => Ok(inner.require_path_only()?.require_ident()?),
1066 NestedMeta::NameValueInvalidExpr(_) | NestedMeta::Lit(_) => {
1067 Err(Error::unsupported_format("expression"))
1068 }
1069 });
1070
1071 let mut errors = Error::accumulator();
1072
1073 let list = items
1074 .filter_map(|item| errors.handle(item))
1075 .cloned()
1076 .collect();
1077
1078 errors.finish_with(list)
1079 }
1080}
1081
1082impl FromMeta for Vec<Path> {
1083 fn from_list(nested: &[NestedMeta]) -> Result<Self> {
1084 let items = nested.iter().map(|item| match *item {
1085 NestedMeta::Meta(ref inner) => Ok(inner.require_path_only()?),
1086 NestedMeta::NameValueInvalidExpr(_) | NestedMeta::Lit(_) => {
1087 Err(Error::unsupported_format("expression"))
1088 }
1089 });
1090
1091 let mut errors = Error::accumulator();
1092
1093 let list = items
1094 .filter_map(|item| errors.handle(item))
1095 .cloned()
1096 .collect();
1097
1098 errors.finish_with(list)
1099 }
1100}
1101
1102impl FromMeta for HashSet<Ident> {
1103 fn from_list(nested: &[NestedMeta]) -> Result<Self> {
1104 let items = nested.iter().map(|item| match *item {
1105 NestedMeta::Meta(ref inner) => Ok(inner.require_path_only()?.require_ident()?),
1106 NestedMeta::NameValueInvalidExpr(_) | NestedMeta::Lit(_) => {
1107 Err(Error::unsupported_format("expression"))
1108 }
1109 });
1110
1111 let mut errors = Error::accumulator();
1112 let mut list = HashSet::with_capacity(nested.len());
1113
1114 for item in items {
1115 let Some(item) = errors.handle(item) else {
1116 continue;
1117 };
1118 if !list.insert(item.clone()) {
1119 errors.push(Error::duplicate_field(&item.to_string()).with_span(item))
1120 };
1121 }
1122
1123 errors.finish_with(list)
1124 }
1125}
1126
1127impl FromMeta for HashSet<Path> {
1128 fn from_list(nested: &[NestedMeta]) -> Result<Self> {
1129 let items = nested.iter().map(|item| match *item {
1130 NestedMeta::Meta(ref inner) => Ok(inner.require_path_only()?),
1131 NestedMeta::NameValueInvalidExpr(_) | NestedMeta::Lit(_) => {
1132 Err(Error::unsupported_format("expression"))
1133 }
1134 });
1135
1136 let mut errors = Error::accumulator();
1137 let mut list = HashSet::with_capacity(nested.len());
1138
1139 for item in items {
1140 let Some(item) = errors.handle(item) else {
1141 continue;
1142 };
1143 if !list.insert(item.clone()) {
1144 errors.push(Error::duplicate_field(&path_to_string(item)).with_span(item))
1145 };
1146 }
1147
1148 errors.finish_with(list)
1149 }
1150}
1151
1152#[cfg(test)]
1155mod tests {
1156 use std::{
1157 collections::HashSet,
1158 fmt::Debug,
1159 num::{NonZeroU32, NonZeroU64},
1160 };
1161
1162 use proc_macro2::TokenStream;
1163 use quote::quote;
1164 use syn::{
1165 parse_quote, Ident, Path, Type, TypeArray, TypeFnPtr, TypeImplTrait, TypeInfer, TypeNever,
1166 TypeParen, TypePtr, TypeReference, TypeSlice, TypeTraitObject, TypeTuple, Visibility,
1167 WhereClause,
1168 };
1169
1170 use crate::{Error, FromMeta, Result};
1171
1172 #[track_caller]
1173 fn test_type<T: FromMeta + PartialEq + Debug>(tokens: TokenStream, f: fn(T) -> Type) {
1174 let tokens_str = tokens.to_string();
1176 let t1 = pnm::<T>(tokens.clone()).expect("1");
1177 let t2 = pnm::<T>(quote! { #tokens_str }).expect("2");
1178 let type1 = pnm::<Type>(tokens).expect("3");
1179 let type2 = pnm::<Type>(quote! { #tokens_str }).expect("4");
1180
1181 assert_eq!(t1, t2, "5");
1182 assert_eq!(type1, type2, "6");
1183 assert_eq!(f(t1), type1, "7");
1184 assert_eq!(f(t2), type1, "8");
1185 }
1186
1187 fn pm(tokens: TokenStream) -> ::std::result::Result<syn::Meta, String> {
1189 let attribute: syn::Attribute = parse_quote!(#[#tokens]);
1190 Ok(attribute.meta)
1191 }
1192
1193 #[track_caller]
1195 fn pnm<T: FromMeta>(ts: TokenStream) -> Result<T> {
1196 T::from_nested_meta(&parse_quote!(ignore = #ts))
1197 }
1198
1199 #[track_caller]
1200 fn fm<T: FromMeta>(tokens: TokenStream) -> T {
1201 FromMeta::from_meta(&pm(tokens).expect("Tests should pass well-formed input"))
1202 .expect("Tests should pass valid input")
1203 }
1204
1205 #[test]
1206 fn unit_succeeds() {
1207 fm::<()>(quote!(ignore));
1208 fm::<()>(quote!(ignore()));
1209 }
1210
1211 #[test]
1212 #[should_panic(expected = "UnknownField")]
1213 fn unit_fails() {
1214 fm::<()>(quote!(ignore(foo = "bar")));
1215 }
1216
1217 #[test]
1218 #[allow(clippy::bool_assert_comparison)]
1219 fn bool_succeeds() {
1220 assert_eq!(fm::<bool>(quote!(ignore)), true);
1222
1223 assert_eq!(fm::<bool>(quote!(ignore = true)), true);
1225 assert_eq!(fm::<bool>(quote!(ignore = false)), false);
1226
1227 assert_eq!(fm::<bool>(quote!(ignore = "true")), true);
1229 assert_eq!(fm::<bool>(quote!(ignore = "false")), false);
1230 }
1231
1232 #[test]
1233 fn char_succeeds() {
1234 assert_eq!(fm::<char>(quote!(ignore = '😬')), '😬');
1236
1237 assert_eq!(fm::<char>(quote!(ignore = "😬")), '😬');
1239 }
1240
1241 #[test]
1242 fn string_succeeds() {
1243 assert_eq!(&fm::<String>(quote!(ignore = "world")), "world");
1245
1246 assert_eq!(&fm::<String>(quote!(ignore = r#"world"#)), "world");
1248 }
1249
1250 #[test]
1251 fn pathbuf_succeeds() {
1252 assert_eq!(
1253 fm::<std::path::PathBuf>(quote!(ignore = r#"C:\"#)),
1254 std::path::PathBuf::from(r#"C:\"#)
1255 );
1256 }
1257
1258 #[test]
1259 #[allow(clippy::float_cmp)] fn number_succeeds() {
1261 assert_eq!(fm::<u8>(quote!(ignore = "2")), 2u8);
1262 assert_eq!(fm::<i16>(quote!(ignore = "-25")), -25i16);
1263 assert_eq!(fm::<f64>(quote!(ignore = "1.4e10")), 1.4e10);
1264 }
1265
1266 #[should_panic(expected = "UnknownValue")]
1267 #[test]
1268 fn nonzero_number_fails() {
1269 fm::<NonZeroU64>(quote!(ignore = "0"));
1270 }
1271
1272 #[test]
1273 fn nonzero_number_succeeds() {
1274 assert_eq!(
1275 fm::<NonZeroU32>(quote!(ignore = "2")),
1276 NonZeroU32::new(2).unwrap()
1277 );
1278 }
1279
1280 #[test]
1281 fn int_without_quotes() {
1282 assert_eq!(fm::<u8>(quote!(ignore = 2)), 2u8);
1283 assert_eq!(fm::<u16>(quote!(ignore = 255)), 255u16);
1284 assert_eq!(fm::<u32>(quote!(ignore = 5000)), 5000u32);
1285
1286 assert_eq!(fm::<u32>(quote!(ignore = 5000i32)), 5000u32);
1288 }
1289
1290 #[test]
1291 fn negative_int_without_quotes() {
1292 assert_eq!(fm::<i8>(quote!(ignore = -2)), -2i8);
1293 assert_eq!(fm::<i32>(quote!(ignore = -255)), -255i32);
1294 }
1295
1296 #[test]
1297 #[allow(clippy::float_cmp)] fn float_without_quotes() {
1299 assert_eq!(fm::<f32>(quote!(ignore = 2.)), 2.0f32);
1300 assert_eq!(fm::<f32>(quote!(ignore = 2.0)), 2.0f32);
1301 assert_eq!(fm::<f64>(quote!(ignore = 1.4e10)), 1.4e10f64);
1302 }
1303
1304 #[test]
1305 fn too_large_int_produces_error() {
1306 assert!(fm::<Result<u8>>(quote!(ignore = 2000)).is_err());
1307 }
1308
1309 #[test]
1310 fn meta_succeeds() {
1311 use syn::Meta;
1312
1313 assert_eq!(
1314 fm::<Meta>(quote!(hello(world, today))),
1315 pm(quote!(hello(world, today))).unwrap()
1316 );
1317 }
1318
1319 #[test]
1320 fn hash_map_succeeds() {
1321 use std::collections::HashMap;
1322
1323 let comparison = {
1324 let mut c = HashMap::new();
1325 c.insert("hello".to_string(), true);
1326 c.insert("world".to_string(), false);
1327 c.insert("there".to_string(), true);
1328 c
1329 };
1330
1331 assert_eq!(
1332 fm::<HashMap<String, bool>>(quote!(ignore(hello, world = false, there = "true"))),
1333 comparison
1334 );
1335 }
1336
1337 #[test]
1340 fn hash_map_duplicate() {
1341 use std::collections::HashMap;
1342
1343 let err: Result<HashMap<String, bool>> =
1344 FromMeta::from_meta(&pm(quote!(ignore(hello, hello = false))).unwrap());
1345
1346 let err = err.expect_err("Duplicate keys in HashMap should error");
1347
1348 assert!(err.has_span());
1349 assert_eq!(err.to_string(), Error::duplicate_field("hello").to_string());
1350 }
1351
1352 #[test]
1353 fn hash_map_multiple_errors() {
1354 use std::collections::HashMap;
1355
1356 let err = HashMap::<String, bool>::from_meta(
1357 &pm(quote!(ignore(hello, hello = 3, hello = false))).unwrap(),
1358 )
1359 .expect_err("Duplicates and bad values should error");
1360
1361 assert_eq!(err.len(), 3);
1362 let errors = err.into_iter().collect::<Vec<_>>();
1363 assert!(errors[0].has_span());
1364 assert!(errors[1].has_span());
1365 assert!(errors[2].has_span());
1366 }
1367
1368 #[test]
1369 fn hash_map_ident_succeeds() {
1370 use std::collections::HashMap;
1371 use syn::parse_quote;
1372
1373 let comparison = {
1374 let mut c = HashMap::<syn::Ident, bool>::new();
1375 c.insert(parse_quote!(first), true);
1376 c.insert(parse_quote!(second), false);
1377 c
1378 };
1379
1380 assert_eq!(
1381 fm::<HashMap<syn::Ident, bool>>(quote!(ignore(first, second = false))),
1382 comparison
1383 );
1384 }
1385
1386 #[test]
1387 fn hash_map_ident_rejects_non_idents() {
1388 use std::collections::HashMap;
1389
1390 let err: Result<HashMap<syn::Ident, bool>> =
1391 FromMeta::from_meta(&pm(quote!(ignore(first, the::second))).unwrap());
1392
1393 err.unwrap_err();
1394 }
1395
1396 #[test]
1397 fn hash_map_path_succeeds() {
1398 use std::collections::HashMap;
1399 use syn::parse_quote;
1400
1401 let comparison = {
1402 let mut c = HashMap::<syn::Path, bool>::new();
1403 c.insert(parse_quote!(first), true);
1404 c.insert(parse_quote!(the::second), false);
1405 c
1406 };
1407
1408 assert_eq!(
1409 fm::<HashMap<syn::Path, bool>>(quote!(ignore(first, the::second = false))),
1410 comparison
1411 );
1412 }
1413
1414 #[test]
1415 fn btree_map_succeeds() {
1416 use std::collections::BTreeMap;
1417
1418 let comparison = {
1419 let mut c = BTreeMap::new();
1420 c.insert("hello".to_string(), true);
1421 c.insert("world".to_string(), false);
1422 c.insert("there".to_string(), true);
1423 c
1424 };
1425
1426 assert_eq!(
1427 fm::<BTreeMap<String, bool>>(quote!(ignore(hello, world = false, there = "true"))),
1428 comparison
1429 );
1430 }
1431
1432 #[test]
1435 fn btree_map_duplicate() {
1436 use std::collections::BTreeMap;
1437
1438 let err: Result<BTreeMap<String, bool>> =
1439 FromMeta::from_meta(&pm(quote!(ignore(hello, hello = false))).unwrap());
1440
1441 let err = err.expect_err("Duplicate keys in BTreeMap should error");
1442
1443 assert!(err.has_span());
1444 assert_eq!(err.to_string(), Error::duplicate_field("hello").to_string());
1445 }
1446
1447 #[test]
1448 fn btree_map_multiple_errors() {
1449 use std::collections::BTreeMap;
1450
1451 let err = BTreeMap::<String, bool>::from_meta(
1452 &pm(quote!(ignore(hello, hello = 3, hello = false))).unwrap(),
1453 )
1454 .expect_err("Duplicates and bad values should error");
1455
1456 assert_eq!(err.len(), 3);
1457 let errors = err.into_iter().collect::<Vec<_>>();
1458 assert!(errors[0].has_span());
1459 assert!(errors[1].has_span());
1460 assert!(errors[2].has_span());
1461 }
1462
1463 #[test]
1464 fn btree_map_ident_succeeds() {
1465 use std::collections::BTreeMap;
1466 use syn::parse_quote;
1467
1468 let comparison = {
1469 let mut c = BTreeMap::<syn::Ident, bool>::new();
1470 c.insert(parse_quote!(first), true);
1471 c.insert(parse_quote!(second), false);
1472 c
1473 };
1474
1475 assert_eq!(
1476 fm::<BTreeMap<syn::Ident, bool>>(quote!(ignore(first, second = false))),
1477 comparison
1478 );
1479 }
1480
1481 #[test]
1482 fn btree_map_ident_rejects_non_idents() {
1483 use std::collections::BTreeMap;
1484
1485 let err: Result<BTreeMap<syn::Ident, bool>> =
1486 FromMeta::from_meta(&pm(quote!(ignore(first, the::second))).unwrap());
1487
1488 err.unwrap_err();
1489 }
1490
1491 #[test]
1492 fn btree_map_expr_values_succeed() {
1493 use std::collections::BTreeMap;
1494 use syn::parse_quote;
1495
1496 let comparison: BTreeMap<String, syn::Expr> = vec![
1497 ("hello", parse_quote!(2 + 2)),
1498 ("world", parse_quote!(x.foo())),
1499 ]
1500 .into_iter()
1501 .map(|(k, v)| (k.to_string(), v))
1502 .collect();
1503
1504 assert_eq!(
1505 fm::<BTreeMap<String, syn::Expr>>(quote!(ignore(hello = 2 + 2, world = x.foo()))),
1506 comparison
1507 );
1508 }
1509
1510 #[test]
1511 fn vec_ident_succeeds() {
1512 let input: Vec<Ident> = vec![
1513 parse_quote!(hello),
1514 parse_quote!(world),
1515 parse_quote!(there),
1516 ];
1517
1518 assert_eq!(fm::<Vec<Ident>>(quote!(ignore(hello, world, there))), input);
1519 }
1520
1521 #[test]
1522 fn vec_ident_allows_duplicates() {
1523 let input: Vec<Ident> = vec![parse_quote!(hello), parse_quote!(hello)];
1524
1525 assert_eq!(fm::<Vec<Ident>>(quote!(ignore(hello, hello))), input);
1526 }
1527
1528 #[test]
1529 fn vec_ident_rejects_paths() {
1530 let result: Result<Vec<Ident>> =
1531 FromMeta::from_meta(&pm(quote!(ignore(the::world))).unwrap());
1532
1533 result.unwrap_err();
1534 }
1535
1536 #[test]
1537 fn vec_path_succeeds() {
1538 let input = vec![parse_quote!(hello), parse_quote!(the::world)];
1539
1540 assert_eq!(
1541 fm::<Vec<syn::Path>>(quote!(ignore(hello, the::world))),
1542 input
1543 );
1544 }
1545
1546 #[test]
1547 fn vec_path_allows_duplicates() {
1548 let input = vec![parse_quote!(hello), parse_quote!(hello)];
1549
1550 assert_eq!(fm::<Vec<Path>>(quote!(ignore(hello, hello))), input);
1551 }
1552
1553 #[test]
1554 fn hash_set_ident_succeeds() {
1555 let comparison: HashSet<Ident> = [parse_quote!(hello), parse_quote!(world)].into();
1556
1557 assert_eq!(
1558 fm::<HashSet<Ident>>(quote!(ignore(hello, world))),
1559 comparison
1560 );
1561 }
1562
1563 #[test]
1564 fn hash_set_ident_duplicate() {
1565 HashSet::<syn::Ident>::from_meta(&pm(quote!(ignore(hello, hello))).unwrap()).unwrap_err();
1566 }
1567
1568 #[test]
1569 fn hash_set_ident_multiple_errors() {
1570 let err = HashSet::<syn::Ident>::from_meta(
1571 &pm(quote!(ignore(hello, hello, the::world))).unwrap(),
1572 )
1573 .unwrap_err();
1574
1575 assert_eq!(err.len(), 2);
1576 }
1577
1578 #[test]
1579 fn hash_set_path_succeeds() {
1580 let comparison: HashSet<_> = [parse_quote!(hello), parse_quote!(the::world)].into();
1581
1582 assert_eq!(
1583 fm::<HashSet<syn::Path>>(quote!(ignore(hello, the::world))),
1584 comparison
1585 );
1586 }
1587
1588 #[test]
1589 fn hash_set_path_duplicate() {
1590 HashSet::<syn::Path>::from_meta(&pm(quote!(ignore(the::world, the::world))).unwrap())
1591 .unwrap_err();
1592 }
1593
1594 #[test]
1597 fn darling_result_succeeds() {
1598 fm::<Result<()>>(quote!(ignore)).unwrap();
1599 fm::<Result<()>>(quote!(ignore(world))).unwrap_err();
1600 }
1601
1602 #[test]
1604 fn test_punctuated() {
1605 fm::<syn::punctuated::Punctuated<syn::FnArg, syn::token::Comma>>(quote!(
1606 ignore = "a: u8, b: Type"
1607 ));
1608 fm::<syn::punctuated::Punctuated<syn::Expr, syn::token::Comma>>(quote!(ignore = "a, b, c"));
1609 }
1610
1611 #[test]
1612 fn test_expr_array() {
1613 fm::<syn::ExprArray>(quote!(ignore = "[0x1, 0x2]"));
1614 fm::<syn::ExprArray>(quote!(ignore = "[\"Hello World\", \"Test Array\"]"));
1615 }
1616
1617 #[test]
1618 fn test_expr() {
1619 fm::<syn::Expr>(quote!(ignore = "x + y"));
1620 fm::<syn::Expr>(quote!(ignore = "an_object.method_call()"));
1621 fm::<syn::Expr>(quote!(ignore = "{ a_statement(); in_a_block }"));
1622 }
1623
1624 #[test]
1625 fn test_expr_without_quotes() {
1626 fm::<syn::Expr>(quote!(ignore = x + y));
1627 fm::<syn::Expr>(quote!(ignore = an_object.method_call()));
1628 fm::<syn::Expr>(quote!(
1629 ignore = {
1630 a_statement();
1631 in_a_block
1632 }
1633 ));
1634 }
1635
1636 #[test]
1637 fn test_expr_path() {
1638 fm::<syn::ExprPath>(quote!(ignore = "std::mem::replace"));
1639 fm::<syn::ExprPath>(quote!(ignore = "x"));
1640 fm::<syn::ExprPath>(quote!(ignore = "example::<Test>"));
1641 }
1642
1643 #[test]
1644 fn test_expr_path_without_quotes() {
1645 fm::<syn::ExprPath>(quote!(ignore = std::mem::replace));
1646 fm::<syn::ExprPath>(quote!(ignore = x));
1647 fm::<syn::ExprPath>(quote!(ignore = example::<Test>));
1648 }
1649
1650 #[test]
1651 fn test_path_without_quotes() {
1652 fm::<syn::Path>(quote!(ignore = std::mem::replace));
1653 fm::<syn::Path>(quote!(ignore = x));
1654 fm::<syn::Path>(quote!(ignore = example::<Test>));
1655 }
1656
1657 #[test]
1658 fn test_number_array() {
1659 assert_eq!(fm::<Vec<u8>>(quote!(ignore = [16, 0xff])), vec![0x10, 0xff]);
1660 assert_eq!(
1661 fm::<Vec<u16>>(quote!(ignore = "[32, 0xffff]")),
1662 vec![0x20, 0xffff]
1663 );
1664 assert_eq!(
1665 fm::<Vec<u32>>(quote!(ignore = "[48, 0xffffffff]")),
1666 vec![0x30, 0xffffffff]
1667 );
1668 assert_eq!(
1669 fm::<Vec<u64>>(quote!(ignore = "[64, 0xffffffffffffffff]")),
1670 vec![0x40, 0xffffffffffffffff]
1671 );
1672 assert_eq!(
1673 fm::<Vec<usize>>(quote!(ignore = "[80, 0xffffffff]")),
1674 vec![0x50, 0xffffffff]
1675 );
1676 }
1677
1678 #[test]
1679 fn test_lit_array() {
1680 fm::<Vec<syn::LitStr>>(quote!(ignore = "[\"Hello World\", \"Test Array\"]"));
1681 fm::<Vec<syn::LitStr>>(quote!(ignore = ["Hello World", "Test Array"]));
1682 fm::<Vec<syn::LitChar>>(quote!(ignore = "['a', 'b', 'c']"));
1683 fm::<Vec<syn::LitBool>>(quote!(ignore = "[true]"));
1684 fm::<Vec<syn::LitStr>>(quote!(ignore = "[]"));
1685 fm::<Vec<syn::LitStr>>(quote!(ignore = []));
1686 fm::<Vec<syn::LitBool>>(quote!(ignore = [true, false]));
1687 }
1688
1689 #[test]
1690 fn expr_range_without_quotes() {
1691 fm::<syn::ExprRange>(quote!(ignore = 0..5));
1692 fm::<syn::ExprRange>(quote!(ignore = 0..=5));
1693 fm::<syn::ExprRange>(quote!(ignore = ..5));
1694 fm::<syn::ExprRange>(quote!(ignore = ..(x + y)));
1695 }
1696
1697 #[test]
1698 fn test_where_clause() {
1699 pnm::<WhereClause>(quote!(where T: Deserialize<'de>)).unwrap();
1700 pnm::<WhereClause>(quote!("where T: Deserialize<'de>, D: 'static")).unwrap();
1703 }
1704
1705 #[test]
1706 fn test_vis() {
1707 pnm::<Visibility>(quote!(pub(in crate::module))).unwrap();
1708 pnm::<Visibility>(quote!(pub)).unwrap();
1709 }
1710
1711 #[test]
1712 fn test_type_array() {
1713 test_type::<TypeArray>(quote!([u32; 4]), Type::Array);
1714 }
1715
1716 #[test]
1717 fn test_type_infer() {
1718 test_type::<TypeInfer>(quote!(_), Type::Infer);
1719 }
1720
1721 #[test]
1722 fn test_type_slice() {
1723 test_type::<TypeSlice>(quote!([u32]), Type::Slice);
1724 }
1725
1726 #[test]
1727 fn test_type_ptr() {
1728 test_type::<TypePtr>(quote!(*const T), Type::Ptr);
1729 test_type::<TypePtr>(quote!(*mut T), Type::Ptr);
1730 }
1731
1732 #[test]
1733 fn test_type_trait_object() {
1734 test_type::<TypeTraitObject>(quote!(dyn Trait), Type::TraitObject);
1735 }
1736
1737 #[test]
1738 fn test_type_never() {
1739 test_type::<TypeNever>(quote!(!), Type::Never);
1740 }
1741
1742 #[test]
1743 fn test_type_impl_trait() {
1744 test_type::<TypeImplTrait>(quote!(impl Trait + 'a), Type::ImplTrait);
1745 }
1746
1747 #[test]
1748 fn test_type_tuple() {
1749 test_type::<TypeTuple>(quote!((u32, i32)), Type::Tuple);
1750 }
1751
1752 #[test]
1753 fn test_type_reference() {
1754 test_type::<TypeReference>(quote!(&u32), Type::Reference);
1755 test_type::<TypeReference>(quote!(&'a mut u32), Type::Reference);
1756 }
1757
1758 #[test]
1759 fn test_type_bare_fn() {
1760 test_type::<TypeFnPtr>(quote!(fn(usize) -> bool), Type::FnPtr);
1761 }
1762
1763 #[test]
1764 fn test_type_paren() {
1765 test_type::<TypeParen>(quote!((u32)), Type::Paren);
1766 }
1767}