darling_core/codegen/
from_meta_impl.rs
1use 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}
16
17impl ToTokens for FromMetaImpl<'_> {
18 fn to_tokens(&self, tokens: &mut TokenStream) {
19 let base = &self.base;
20
21 let from_word = self.from_word.as_ref().map(|body| {
22 quote_spanned! {body.span()=>
23 fn from_word() -> ::darling::Result<Self> {
24 ::darling::export::identity::<fn() -> ::darling::Result<Self>>(#body)()
25 }
26 }
27 });
28
29 let from_none = self.from_none.map(|body| {
30 quote_spanned! {body.span()=>
31 fn from_none() -> ::darling::export::Option<Self> {
32 ::darling::export::identity::<fn() -> ::darling::export::Option<Self>>(#body)()
33 }
34 }
35 });
36
37 let impl_block = match base.data {
38 Data::Struct(ref vd) if vd.style.is_unit() => {
40 let ty_ident = base.ident;
41 quote!(
42 fn from_word() -> ::darling::Result<Self> {
43 ::darling::export::Ok(#ty_ident)
44 }
45 )
46 }
47
48 Data::Struct(Fields {
50 ref fields,
51 style: Style::Tuple,
52 ..
53 }) if fields.len() == 1 => {
54 let ty_ident = base.ident;
55 quote!(
56 fn from_meta(__item: &::darling::export::syn::Meta) -> ::darling::Result<Self> {
57 ::darling::FromMeta::from_meta(__item)
58 .map_err(|e| e.with_span(&__item))
59 .map(#ty_ident)
60 }
61 )
62 }
63 Data::Struct(Fields {
64 style: Style::Tuple,
65 ..
66 }) => {
67 panic!("Multi-field tuples are not supported");
68 }
69 Data::Struct(ref data) => {
70 let inits = data.fields.iter().map(Field::as_initializer);
71 let declare_errors = base.declare_errors();
72 let require_fields = base.require_fields();
73 let check_errors = base.check_errors();
74 let decls = base.local_declarations();
75 let core_loop = base.core_loop();
76 let default = base.fallback_decl();
77 let post_transform = base.post_transform_call();
78
79 quote!(
80 #from_word
81
82 #from_none
83
84 fn from_list(__items: &[::darling::export::NestedMeta]) -> ::darling::Result<Self> {
85
86 #decls
87
88 #declare_errors
89
90 #core_loop
91
92 #require_fields
93
94 #check_errors
95
96 #default
97
98 ::darling::export::Ok(Self {
99 #(#inits),*
100 }) #post_transform
101 }
102 )
103 }
104 Data::Enum(ref variants) => {
105 let unit_arms = variants.iter().map(Variant::as_unit_match_arm);
106
107 let unknown_variant_err = if !variants.is_empty() {
108 let names = variants.iter().map(Variant::as_name);
109 quote! {
110 unknown_field_with_alts(__other, &[#(#names),*])
111 }
112 } else {
113 quote! {
114 unknown_field(__other)
115 }
116 };
117
118 let data_variants = variants.iter().map(Variant::as_data_match_arm);
119
120 quote!(
121 fn from_list(__outer: &[::darling::export::NestedMeta]) -> ::darling::Result<Self> {
122 match __outer.len() {
125 0 => ::darling::export::Err(::darling::Error::too_few_items(1)),
126 1 => {
127 if let ::darling::export::NestedMeta::Meta(ref __nested) = __outer[0] {
128 match ::darling::util::path_to_string(__nested.path()).as_ref() {
129 #(#data_variants)*
130 __other => ::darling::export::Err(::darling::Error::#unknown_variant_err.with_span(__nested))
131 }
132 } else {
133 ::darling::export::Err(::darling::Error::unsupported_format("literal"))
134 }
135 }
136 _ => ::darling::export::Err(::darling::Error::too_many_items(1)),
137 }
138 }
139
140 fn from_string(lit: &str) -> ::darling::Result<Self> {
141 match lit {
142 #(#unit_arms)*
143 __other => ::darling::export::Err(::darling::Error::unknown_value(__other))
144 }
145 }
146
147 #from_word
148
149 #from_none
150 )
151 }
152 };
153
154 self.wrap(impl_block, tokens);
155 }
156}
157
158impl<'a> OuterFromImpl<'a> for FromMetaImpl<'a> {
159 fn trait_path(&self) -> syn::Path {
160 path!(::darling::FromMeta)
161 }
162
163 fn base(&'a self) -> &'a TraitImpl<'a> {
164 &self.base
165 }
166}