1 use proc_macro2::TokenStream; 2 use quote::ToTokens; 3 use syn::{DeriveInput, Field, Ident, Meta}; 4 5 use crate::codegen::FromVariantImpl; 6 use crate::options::{DataShape, OuterFrom, ParseAttribute, ParseData}; 7 use crate::{FromMeta, Result}; 8 9 #[derive(Debug, Clone)] 10 pub struct FromVariantOptions { 11 pub base: OuterFrom, 12 /// The field on the deriving struct into which the discriminant expression 13 /// should be placed by the derived `FromVariant` impl. 14 pub discriminant: Option<Ident>, 15 pub fields: Option<Ident>, 16 pub supports: Option<DataShape>, 17 } 18 19 impl FromVariantOptions { new(di: &DeriveInput) -> Result<Self>20 pub fn new(di: &DeriveInput) -> Result<Self> { 21 (FromVariantOptions { 22 base: OuterFrom::start(di)?, 23 discriminant: Default::default(), 24 fields: Default::default(), 25 supports: Default::default(), 26 }) 27 .parse_attributes(&di.attrs)? 28 .parse_body(&di.data) 29 } 30 } 31 32 impl<'a> From<&'a FromVariantOptions> for FromVariantImpl<'a> { from(v: &'a FromVariantOptions) -> Self33 fn from(v: &'a FromVariantOptions) -> Self { 34 FromVariantImpl { 35 base: (&v.base.container).into(), 36 ident: v.base.ident.as_ref(), 37 discriminant: v.discriminant.as_ref(), 38 fields: v.fields.as_ref(), 39 attr_names: &v.base.attr_names, 40 forward_attrs: v.base.as_forward_attrs(), 41 from_ident: v.base.from_ident, 42 supports: v.supports.as_ref(), 43 } 44 } 45 } 46 47 impl ParseAttribute for FromVariantOptions { parse_nested(&mut self, mi: &Meta) -> Result<()>48 fn parse_nested(&mut self, mi: &Meta) -> Result<()> { 49 if mi.path().is_ident("supports") { 50 self.supports = FromMeta::from_meta(mi)?; 51 Ok(()) 52 } else { 53 self.base.parse_nested(mi) 54 } 55 } 56 } 57 58 impl ParseData for FromVariantOptions { parse_field(&mut self, field: &Field) -> Result<()>59 fn parse_field(&mut self, field: &Field) -> Result<()> { 60 match field.ident.as_ref().map(|v| v.to_string()).as_deref() { 61 Some("discriminant") => { 62 self.discriminant.clone_from(&field.ident); 63 Ok(()) 64 } 65 Some("fields") => { 66 self.fields.clone_from(&field.ident); 67 Ok(()) 68 } 69 _ => self.base.parse_field(field), 70 } 71 } 72 validate_body(&self, errors: &mut crate::error::Accumulator)73 fn validate_body(&self, errors: &mut crate::error::Accumulator) { 74 self.base.validate_body(errors); 75 } 76 } 77 78 impl ToTokens for FromVariantOptions { to_tokens(&self, tokens: &mut TokenStream)79 fn to_tokens(&self, tokens: &mut TokenStream) { 80 FromVariantImpl::from(self).to_tokens(tokens) 81 } 82 } 83