1use proc_macro2::TokenStream;
2use quote::{quote, ToTokens};
3
4use crate::ast::{Data, Fields, Style};
5use crate::codegen::{Field, OuterFromImpl, TraitImpl, Variant};
6
7pub struct FromMetaImpl<'a> {
8 pub base: TraitImpl<'a>,
9}
10
11impl<'a> ToTokens for FromMetaImpl<'a> {
12 fn to_tokens(&self, tokens: &mut TokenStream) {
13 let base = &self.base;
14
15 let impl_block = match base.data {
16 // Unit structs allow empty bodies only.
17 Data::Struct(ref vd) if vd.style.is_unit() => {
18 let ty_ident = base.ident;
19 quote!(
20 fn from_word() -> ::darling::Result<Self> {
21 ::darling::export::Ok(#ty_ident)
22 }
23 )
24 }
25
26 // Newtype structs proxy to the sole value they contain.
27 Data::Struct(Fields {
28 ref fields,
29 style: Style::Tuple,
30 ..
31 }) if fields.len() == 1 => {
32 let ty_ident = base.ident;
33 quote!(
34 fn from_meta(__item: &::darling::export::syn::Meta) -> ::darling::Result<Self> {
35 ::darling::FromMeta::from_meta(__item)
36 .map_err(|e| e.with_span(&__item))
37 .map(#ty_ident)
38 }
39 )
40 }
41 Data::Struct(Fields {
42 style: Style::Tuple,
43 ..
44 }) => {
45 panic!("Multi-field tuples are not supported");
46 }
47 Data::Struct(ref data) => {
48 let inits = data.fields.iter().map(Field::as_initializer);
49 let declare_errors = base.declare_errors();
50 let require_fields = base.require_fields();
51 let check_errors = base.check_errors();
52 let decls = base.local_declarations();
53 let core_loop = base.core_loop();
54 let default = base.fallback_decl();
55 let post_transform = base.post_transform_call();
56
57 quote!(
58 fn from_list(__items: &[::darling::export::NestedMeta]) -> ::darling::Result<Self> {
59
60 #decls
61
62 #declare_errors
63
64 #core_loop
65
66 #require_fields
67
68 #check_errors
69
70 #default
71
72 ::darling::export::Ok(Self {
73 #(#inits),*
74 }) #post_transform
75 }
76 )
77 }
78 Data::Enum(ref variants) => {
79 let unit_arms = variants.iter().map(Variant::as_unit_match_arm);
80 let struct_arms = variants.iter().map(Variant::as_data_match_arm);
81
82 let unknown_variant_err = if !variants.is_empty() {
83 let names = variants.iter().map(Variant::as_name);
84 quote! {
85 unknown_field_with_alts(__other, &[#(#names),*])
86 }
87 } else {
88 quote! {
89 unknown_field(__other)
90 }
91 };
92
93 quote!(
94 fn from_list(__outer: &[::darling::export::NestedMeta]) -> ::darling::Result<Self> {
95 // An enum must have exactly one value inside the parentheses if it's not a unit
96 // match arm
97 match __outer.len() {
98 0 => ::darling::export::Err(::darling::Error::too_few_items(1)),
99 1 => {
100 if let ::darling::export::NestedMeta::Meta(ref __nested) = __outer[0] {
101 match ::darling::util::path_to_string(__nested.path()).as_ref() {
102 #(#struct_arms)*
103 __other => ::darling::export::Err(::darling::Error::#unknown_variant_err.with_span(__nested))
104 }
105 } else {
106 ::darling::export::Err(::darling::Error::unsupported_format("literal"))
107 }
108 }
109 _ => ::darling::export::Err(::darling::Error::too_many_items(1)),
110 }
111 }
112
113 fn from_string(lit: &str) -> ::darling::Result<Self> {
114 match lit {
115 #(#unit_arms)*
116 __other => ::darling::export::Err(::darling::Error::unknown_value(__other))
117 }
118 }
119 )
120 }
121 };
122
123 self.wrap(impl_block, tokens);
124 }
125}
126
127impl<'a> OuterFromImpl<'a> for FromMetaImpl<'a> {
128 fn trait_path(&self) -> syn::Path {
129 path!(::darling::FromMeta)
130 }
131
132 fn base(&'a self) -> &'a TraitImpl<'a> {
133 &self.base
134 }
135}
136