darling_core/codegen/
from_derive_impl.rs

1use proc_macro2::TokenStream;
2use quote::{quote, ToTokens};
3use syn::Ident;
4
5use crate::{
6    ast::Data,
7    codegen::{ExtractAttribute, OuterFromImpl, TraitImpl},
8    options::DeriveInputShapeSet,
9    util::PathList,
10};
11
12use super::ForwardAttrs;
13
14pub struct FromDeriveInputImpl<'a> {
15    pub ident: Option<&'a Ident>,
16    pub generics: Option<&'a Ident>,
17    pub vis: Option<&'a Ident>,
18    pub data: Option<&'a Ident>,
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<'a> ToTokens for FromDeriveInputImpl<'a> {
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_generics = self
55            .generics
56            .as_ref()
57            .map(|i| quote!(#i: ::darling::FromGenerics::from_generics(&#input.generics)?,));
58        let passed_attrs = self.forward_attrs.as_initializer();
59        let passed_body = self
60            .data
61            .as_ref()
62            .map(|i| quote!(#i: ::darling::ast::Data::try_from(&#input.data)?,));
63
64        let supports = self.supports.map(|i| {
65            quote! {
66                #i
67                __errors.handle(__validate_body(&#input.data));
68            }
69        });
70
71        let inits = self.base.initializers();
72        let default = if self.from_ident {
73            quote!(let __default: Self = ::darling::export::From::from(#input.ident.clone());)
74        } else {
75            self.base.fallback_decl()
76        };
77
78        let grab_attrs = self.extractor();
79
80        let declare_errors = self.base.declare_errors();
81        let require_fields = self.base.require_fields();
82        let check_errors = self.base.check_errors();
83
84        self.wrap(
85            quote! {
86                fn from_derive_input(#input: &::darling::export::syn::DeriveInput) -> ::darling::Result<Self> {
87                    #declare_errors
88
89                    #grab_attrs
90
91                    #supports
92
93                    #require_fields
94
95                    #check_errors
96
97                    #default
98
99                    ::darling::export::Ok(#ty_ident {
100                        #passed_ident
101                        #passed_generics
102                        #passed_vis
103                        #passed_attrs
104                        #passed_body
105                        #inits
106                    }) #post_transform
107                }
108            },
109            tokens,
110        );
111    }
112}
113
114impl<'a> ExtractAttribute for FromDeriveInputImpl<'a> {
115    fn attr_names(&self) -> &PathList {
116        self.attr_names
117    }
118
119    fn forward_attrs(&self) -> &ForwardAttrs<'_> {
120        &self.forward_attrs
121    }
122
123    fn param_name(&self) -> TokenStream {
124        quote!(__di)
125    }
126
127    fn core_loop(&self) -> TokenStream {
128        self.base.core_loop()
129    }
130
131    fn local_declarations(&self) -> TokenStream {
132        self.base.local_declarations()
133    }
134}
135
136impl<'a> OuterFromImpl<'a> for FromDeriveInputImpl<'a> {
137    fn trait_path(&self) -> syn::Path {
138        path!(::darling::FromDeriveInput)
139    }
140
141    fn trait_bound(&self) -> syn::Path {
142        path!(::darling::FromMeta)
143    }
144
145    fn base(&'a self) -> &'a TraitImpl<'a> {
146        &self.base
147    }
148}