diff --git a/src/merge.rs b/src/merge.rs index 3fc9952..af9d937 100644 --- a/src/merge.rs +++ b/src/merge.rs @@ -1,11 +1,12 @@ use proc_macro2::{Span, TokenStream}; -use quote::quote; +use quote::{quote, ToTokens}; use syn::{Fields, Ident, Index, ItemStruct}; use crate::args::{Args, MergeFnName}; use crate::fields; const DEFAULT_FN_NAME: &str = "merge_opt"; +const CFG: &str = "cfg"; pub fn generate(item: &ItemStruct, opt_item: &ItemStruct, args: &Args) -> TokenStream { if let Some(merge_fn) = &args.merge { @@ -40,6 +41,14 @@ fn field_bindings(fields: &Fields, args: &Args) -> TokenStream { let mut tokens = TokenStream::new(); for (i, field) in fields.iter().enumerate() { + let mut cfg_attrs = TokenStream::new(); + + for attr in field.attrs.iter() { + if attr.path().is_ident(CFG) { + attr.to_tokens(&mut cfg_attrs); + } + } + let field_name = match &field.ident { // means that original item is a tuple struct None => { @@ -52,14 +61,20 @@ fn field_bindings(fields: &Fields, args: &Args) -> TokenStream { let field_tokens = if fields::is_option(field) && !args.rewrap { quote! { - if opt.#field_name.is_some() { - self.#field_name = opt.#field_name; + #cfg_attrs + { + if opt.#field_name.is_some() { + self.#field_name = opt.#field_name; + } } } } else { quote! { - if let Some(value) = opt.#field_name { - self.#field_name = value + #cfg_attrs + { + if let Some(value) = opt.#field_name { + self.#field_name = value + } } } }; diff --git a/tests/merge.rs b/tests/merge.rs index c6ff9c1..bd6d778 100644 --- a/tests/merge.rs +++ b/tests/merge.rs @@ -152,3 +152,42 @@ fn merge_tuple_struct() { assert_eq!(original_clone.0, opt4.0.unwrap()); assert_eq!(original_clone.1, opt4.1.unwrap()); } + +#[test] +fn merge_cfg_field() { + #![allow(unexpected_cfgs)] + + #[optfield(Opt, attrs, merge_fn)] + #[optfield(OptFieldAttrs, field_attrs, attrs, merge_fn = merge_opt_attrs)] + #[derive(Clone, Debug)] + struct Original { + #[cfg(some_feature)] + feature_field: String, + field: i32, + } + + let mut original = Original { field: 2 }; + let mut opt = Opt { + field: None, + feature_field: None, + }; + + original.merge_opt(opt.clone()); + assert_eq!(original.field, 2); + + opt.field = Some(3); + opt.feature_field = Some("test".to_string()); + + original.merge_opt(opt); + assert_eq!(original.field, 3); + + let mut opt_attrs = OptFieldAttrs { field: None }; + + original.merge_opt_attrs(opt_attrs.clone()); + assert_eq!(original.field, 3); + + opt_attrs.field = Some(4); + + original.merge_opt_attrs(opt_attrs); + assert_eq!(original.field, 4); +}