darling_core/codegen/
from_meta_impl.rs1use std::borrow::Cow;
2
3use proc_macro2::TokenStream;
4use quote::{quote, quote_spanned, ToTokens};
5use syn::spanned::Spanned;
6
7use crate::ast::{Data, Fields, Style};
8use crate::codegen::{Field, OuterFromImpl, TraitImpl, Variant};
9use crate::util::Callable;
10
11pub struct FromMetaImpl<'a> {
12 pub base: TraitImpl<'a>,
13 pub from_word: Option<Cow<'a, Callable>>,
14 pub from_none: Option<&'a Callable>,
15 pub from_expr: Option<&'a Callable>,
16 pub derive_syn_parse: bool,
17}
18
19impl ToTokens for FromMetaImpl<'_> {
20 fn to_tokens(&self, tokens: &mut TokenStream) {
21 let base = &self.base;
22
23 let from_word = self.from_word.as_ref().map(|body| {
24 quote_spanned! {body.span()=>
25 fn from_word() -> ::darling::Result<Self> {
26 ::darling::export::identity::<fn() -> ::darling::Result<Self>>(#body)()
27 }
28 }
29 });
30
31 let from_none = self.from_none.map(|body| {
32 quote_spanned! {body.span()=>
33 fn from_none() -> ::darling::export::Option<Self> {
34 ::darling::export::identity::<fn() -> ::darling::export::Option<Self>>(#body)()
35 }
36 }
37 });
38
39 let from_expr = self.from_expr.map(|body| {
40 quote_spanned! {body.span()=>
41 fn from_expr(expr: &::darling::export::syn::Expr) -> ::darling::Result<Self> {
42 ::darling::export::identity::<fn(&::darling::export::syn::Expr) -> ::darling::Result<Self>>(#body)(expr)
43 }
44 }
45 });
46
47 let impl_block = match base.data {
48 Data::Struct(ref vd) if vd.style.is_unit() => {
50 let ty_ident = base.ident;
51 quote!(
52 fn from_word() -> ::darling::Result<Self> {
53 ::darling::export::Ok(#ty_ident)
54 }
55 )
56 }
57
58 Data::Struct(Fields {
60 ref fields,
61 style: Style::Tuple,
62 ..
63 }) if fields.len() == 1 => {
64 let ty_ident = base.ident;
65 quote!(
66 fn from_meta(__item: &::darling::export::syn::Meta) -> ::darling::Result<Self> {
67 ::darling::FromMeta::from_meta(__item)
68 .map_err(|e| e.with_span(&__item))
69 .map(#ty_ident)
70 }
71 )
72 }
73 Data::Struct(Fields {
74 style: Style::Tuple,
75 ..
76 }) => {
77 panic!("Multi-field tuples are not supported");
78 }
79 Data::Struct(ref data) => {
80 let inits = data.fields.iter().map(Field::as_initializer);
81 let declare_errors = base.declare_errors();
82 let require_fields = base.require_fields();
83 let check_errors = base.check_errors();
84 let decls = base.local_declarations();
85 let core_loop = base.core_loop();
86 let default = base.fallback_decl();
87 let post_transform = base.post_transform_call();
88
89 quote!(
90 #from_word
91
92 #from_none
93
94 #from_expr
95
96 fn from_list(__items: &[::darling::export::NestedMeta]) -> ::darling::Result<Self> {
97
98 #decls
99
100 #declare_errors
101
102 #core_loop
103
104 #require_fields
105
106 #check_errors
107
108 #default
109
110 ::darling::export::Ok(Self {
111 #(#inits),*
112 }) #post_transform
113 }
114 )
115 }
116 Data::Enum(ref variants) => {
117 let unit_arms = variants.iter().map(Variant::as_unit_match_arm);
118
119 let (unknown_variant_err, unknown_unit_variant_err) = if !variants.is_empty() {
120 let names = variants.iter().map(Variant::as_name);
121 let names = quote!(&[#(#names),*]);
122 (
123 quote! {
124 unknown_field_with_alts(__other, #names)
125 },
126 quote! {
127 unknown_value_with_alts(__other, #names)
128 },
129 )
130 } else {
131 (
132 quote! {
133 unknown_field(__other)
134 },
135 quote!(unknown_value(__other)),
136 )
137 };
138
139 let data_variants = variants.iter().map(Variant::as_data_match_arm);
140
141 quote!(
142 fn from_list(__outer: &[::darling::export::NestedMeta]) -> ::darling::Result<Self> {
143 match __outer.len() {
146 0 => ::darling::export::Err(::darling::Error::too_few_items(1)),
147 1 => {
148 if let ::darling::export::NestedMeta::Meta(ref __nested) = __outer[0] {
149 match ::darling::util::path_to_string(__nested.path()).as_ref() {
150 #(#data_variants)*
151 __other => ::darling::export::Err(::darling::Error::#unknown_variant_err.with_span(__nested))
152 }
153 } else {
154 ::darling::export::Err(::darling::Error::unsupported_format("literal"))
155 }
156 }
157 _ => ::darling::export::Err(::darling::Error::too_many_items(1)),
158 }
159 }
160
161 fn from_string(lit: &str) -> ::darling::Result<Self> {
162 match lit {
163 #(#unit_arms)*
164 __other => ::darling::export::Err(::darling::Error::#unknown_unit_variant_err)
165 }
166 }
167
168 #from_word
169
170 #from_none
171
172 #from_expr
173 )
174 }
175 };
176
177 self.wrap(impl_block, tokens);
178 if self.derive_syn_parse {
179 ParseImpl(self).to_tokens(tokens);
180 }
181 }
182}
183
184impl<'a> OuterFromImpl<'a> for FromMetaImpl<'a> {
185 fn trait_path(&self) -> syn::Path {
186 path!(::darling::FromMeta)
187 }
188
189 fn base(&'a self) -> &'a TraitImpl<'a> {
190 &self.base
191 }
192}
193
194struct ParseImpl<'a>(&'a FromMetaImpl<'a>);
195
196impl<'a> OuterFromImpl<'a> for ParseImpl<'a> {
197 fn trait_path(&self) -> syn::Path {
198 path!(::darling::export::syn::parse::Parse)
199 }
200
201 fn base(&'a self) -> &'a TraitImpl<'a> {
202 &self.0.base
203 }
204
205 fn trait_bound(&self) -> syn::Path {
206 self.0.trait_path()
209 }
210}
211
212impl ToTokens for ParseImpl<'_> {
213 fn to_tokens(&self, tokens: &mut TokenStream) {
214 let from_meta = self.0.trait_path();
215 let impl_block = quote! {
216 fn parse(input: ::darling::export::syn::parse::ParseStream<'_>) -> ::darling::export::syn::Result<Self> {
217 use ::darling::export::IntoIterator;
218
219 let items = ::darling::export::syn::punctuated::Punctuated::<::darling::export::NestedMeta, ::darling::export::syn::Token![,]>::parse_terminated(input)?
220 .into_iter()
221 .collect::<::darling::export::Vec<_>>();
222 <Self as #from_meta>::from_list(&items).map_err(::darling::export::Into::into)
223 }
224 };
225
226 self.wrap(impl_block, tokens);
227 }
228}