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