• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use proc_macro2::TokenStream;
2 use quote::{quote, ToTokens};
3 use syn::Ident;
4 
5 use crate::codegen::{ExtractAttribute, ForwardAttrs, OuterFromImpl, TraitImpl};
6 use crate::options::DataShape;
7 use crate::util::PathList;
8 
9 pub struct FromVariantImpl<'a> {
10     pub base: TraitImpl<'a>,
11     /// If set, the ident of the field into which the variant ident should be placed.
12     ///
13     /// This is one of `darling`'s "magic fields", which allow a type deriving a `darling`
14     /// trait to get fields from the input `syn` element added to the deriving struct
15     /// automatically.
16     pub ident: Option<&'a Ident>,
17     /// If set, the ident of the field into which the transformed output of the input
18     /// variant's fields should be placed.
19     ///
20     /// This is one of `darling`'s "magic fields".
21     pub fields: Option<&'a Ident>,
22     /// If set, the ident of the field into which the discriminant of the input variant
23     /// should be placed. The receiving field must be an `Option` as not all enums have
24     /// discriminants.
25     ///
26     /// This is one of `darling`'s "magic fields".
27     pub discriminant: Option<&'a Ident>,
28     pub attr_names: &'a PathList,
29     pub forward_attrs: ForwardAttrs<'a>,
30     pub from_ident: bool,
31     pub supports: Option<&'a DataShape>,
32 }
33 
34 impl<'a> ToTokens for FromVariantImpl<'a> {
to_tokens(&self, tokens: &mut TokenStream)35     fn to_tokens(&self, tokens: &mut TokenStream) {
36         let input = self.param_name();
37         let extractor = self.extractor();
38         let passed_ident = self
39             .ident
40             .as_ref()
41             .map(|i| quote!(#i: #input.ident.clone(),));
42         let passed_discriminant = self
43             .discriminant
44             .as_ref()
45             .map(|i| quote!(#i: #input.discriminant.as_ref().map(|(_, expr)| expr.clone()),));
46         let passed_attrs = self.forward_attrs.as_initializer();
47         let passed_fields = self
48             .fields
49             .as_ref()
50             .map(|i| quote!(#i: ::darling::ast::Fields::try_from(&#input.fields)?,));
51 
52         let inits = self.base.initializers();
53         let post_transform = self.base.post_transform_call();
54 
55         let default = if self.from_ident {
56             quote!(let __default: Self = ::darling::export::From::from(#input.ident.clone());)
57         } else {
58             self.base.fallback_decl()
59         };
60 
61         let supports = self.supports.map(|i| {
62             quote! {
63                 __errors.handle(#i.check(&#input.fields));
64             }
65         });
66 
67         let error_declaration = self.base.declare_errors();
68         let require_fields = self.base.require_fields();
69         let error_check = self.base.check_errors();
70 
71         self.wrap(
72             quote!(
73                 fn from_variant(#input: &::darling::export::syn::Variant) -> ::darling::Result<Self> {
74                     #error_declaration
75 
76                     #extractor
77 
78                     #supports
79 
80                     #require_fields
81 
82                     #error_check
83 
84                     #default
85 
86                     ::darling::export::Ok(Self {
87                         #passed_ident
88                         #passed_discriminant
89                         #passed_attrs
90                         #passed_fields
91                         #inits
92                     }) #post_transform
93                 }
94             ),
95             tokens,
96         );
97     }
98 }
99 
100 impl<'a> ExtractAttribute for FromVariantImpl<'a> {
local_declarations(&self) -> TokenStream101     fn local_declarations(&self) -> TokenStream {
102         self.base.local_declarations()
103     }
104 
attr_names(&self) -> &PathList105     fn attr_names(&self) -> &PathList {
106         self.attr_names
107     }
108 
forward_attrs(&self) -> &ForwardAttrs<'_>109     fn forward_attrs(&self) -> &ForwardAttrs<'_> {
110         &self.forward_attrs
111     }
112 
param_name(&self) -> TokenStream113     fn param_name(&self) -> TokenStream {
114         quote!(__variant)
115     }
116 
core_loop(&self) -> TokenStream117     fn core_loop(&self) -> TokenStream {
118         self.base.core_loop()
119     }
120 }
121 
122 impl<'a> OuterFromImpl<'a> for FromVariantImpl<'a> {
trait_path(&self) -> syn::Path123     fn trait_path(&self) -> syn::Path {
124         path!(::darling::FromVariant)
125     }
126 
trait_bound(&self) -> syn::Path127     fn trait_bound(&self) -> syn::Path {
128         path!(::darling::FromMeta)
129     }
130 
base(&'a self) -> &'a TraitImpl<'a>131     fn base(&'a self) -> &'a TraitImpl<'a> {
132         &self.base
133     }
134 }
135