darling_core/codegen/
from_derive_impl.rs1use proc_macro2::TokenStream;
2use quote::{quote, quote_spanned, ToTokens};
3use syn::Ident;
4
5use crate::{
6 ast::Data,
7 codegen::{ExtractAttribute, OuterFromImpl, TraitImpl},
8 options::{DeriveInputShapeSet, ForwardedField},
9 util::PathList,
10};
11
12use super::ForwardAttrs;
13
14pub struct FromDeriveInputImpl<'a> {
15 pub ident: Option<&'a Ident>,
16 pub generics: Option<&'a ForwardedField>,
17 pub vis: Option<&'a Ident>,
18 pub data: Option<&'a ForwardedField>,
19 pub base: TraitImpl<'a>,
20 pub attr_names: &'a PathList,
21 pub forward_attrs: ForwardAttrs<'a>,
22 pub from_ident: bool,
23 pub supports: Option<&'a DeriveInputShapeSet>,
24}
25
26impl ToTokens for FromDeriveInputImpl<'_> {
27 fn to_tokens(&self, tokens: &mut TokenStream) {
28 let ty_ident = self.base.ident;
29 let input = self.param_name();
30 let post_transform = self.base.post_transform_call();
31
32 if let Data::Struct(ref data) = self.base.data {
33 if data.is_newtype() {
34 self.wrap(
35 quote!{
36 fn from_derive_input(#input: &::darling::export::syn::DeriveInput) -> ::darling::Result<Self> {
37 ::darling::export::Ok(
38 #ty_ident(::darling::FromDeriveInput::from_derive_input(#input)?)
39 ) #post_transform
40 }
41 },
42 tokens,
43 );
44
45 return;
46 }
47 }
48
49 let passed_ident = self
50 .ident
51 .as_ref()
52 .map(|i| quote!(#i: #input.ident.clone(),));
53 let passed_vis = self.vis.as_ref().map(|i| quote!(#i: #input.vis.clone(),));
54 let passed_attrs = self.forward_attrs.as_initializer();
55
56 let read_generics = self.generics.map(|generics| {
57 let ident = &generics.ident;
58 let with = generics.with.as_ref().map(|p| quote!(#p)).unwrap_or_else(
59 || quote_spanned!(ident.span()=>::darling::FromGenerics::from_generics),
60 );
61 quote! {
62 let #ident = __errors.handle(#with(&#input.generics));
63 }
64 });
65
66 let pass_generics_to_receiver = self.generics.map(|g| g.as_initializer());
67
68 let check_shape = self
69 .supports
70 .map(|s| s.validator_path().into_token_stream())
71 .unwrap_or_else(|| quote!(::darling::export::Ok));
72
73 let read_data = self
74 .data
75 .as_ref()
76 .map(|i| match &i.with {
77 Some(p) => quote!(#p),
78 None => quote_spanned!(i.ident.span()=> ::darling::ast::Data::try_from),
79 })
80 .unwrap_or_else(|| quote!(::darling::export::Ok));
81
82 let supports = self.supports;
83 let validate_and_read_data = {
84 let let_binding = self.data.map(|d| {
87 let ident = &d.ident;
88 quote!(let #ident = )
89 });
90 quote! {
91 #supports
92 #let_binding __errors.handle(#check_shape(&#input.data).and_then(#read_data));
93 }
94 };
95
96 let pass_data_to_receiver = self.data.map(|f| f.as_initializer());
97
98 let inits = self.base.initializers();
99 let default = if self.from_ident {
100 quote!(let __default: Self = ::darling::export::From::from(#input.ident.clone());)
101 } else {
102 self.base.fallback_decl()
103 };
104
105 let grab_attrs = self.extractor();
106
107 let declare_errors = self.base.declare_errors();
108 let require_fields = self.base.require_fields();
109 let check_errors = self.base.check_errors();
110
111 self.wrap(
112 quote! {
113 fn from_derive_input(#input: &::darling::export::syn::DeriveInput) -> ::darling::Result<Self> {
114 #declare_errors
115
116 #grab_attrs
117
118 #validate_and_read_data
119
120 #read_generics
121
122 #require_fields
123
124 #check_errors
125
126 #default
127
128 ::darling::export::Ok(#ty_ident {
129 #passed_ident
130 #pass_generics_to_receiver
131 #passed_vis
132 #passed_attrs
133 #pass_data_to_receiver
134 #inits
135 }) #post_transform
136 }
137 },
138 tokens,
139 );
140 }
141}
142
143impl ExtractAttribute for FromDeriveInputImpl<'_> {
144 fn attr_names(&self) -> &PathList {
145 self.attr_names
146 }
147
148 fn forward_attrs(&self) -> &ForwardAttrs<'_> {
149 &self.forward_attrs
150 }
151
152 fn param_name(&self) -> TokenStream {
153 quote!(__di)
154 }
155
156 fn core_loop(&self) -> TokenStream {
157 self.base.core_loop()
158 }
159
160 fn local_declarations(&self) -> TokenStream {
161 self.base.local_declarations()
162 }
163}
164
165impl<'a> OuterFromImpl<'a> for FromDeriveInputImpl<'a> {
166 fn trait_path(&self) -> syn::Path {
167 path!(::darling::FromDeriveInput)
168 }
169
170 fn trait_bound(&self) -> syn::Path {
171 path!(::darling::FromMeta)
172 }
173
174 fn base(&'a self) -> &'a TraitImpl<'a> {
175 &self.base
176 }
177}