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