darling_core/codegen/
from_derive_impl.rs

1use 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            // If the caller wants `data` read into a field, we can use `data` as the local variable name
85            // because we know there are no other fields of that name.
86            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}