diff --git a/book/src/config/field.md b/book/src/config/field.md index 1acae8d8..8b1b8995 100644 --- a/book/src/config/field.md +++ b/book/src/config/field.md @@ -69,6 +69,20 @@ The error type for partial getters can currently only be configured on a per-str via the [`partial_getter_error`](./struct.md#partial-getter-error) attribute, although this may change in a future release. +## No Getter +Disable the generation of (partial) getter functions for this field. +This can be used for when two fields have the same name but different types: + +```rust +#[superstruct(variants(A, B))] +struct NoGetter { + #[superstruct(only(A), no_getter)] + pub x: u64, + #[superstruct(only(B), no_getter)] + pub x: String, +} +``` + ## Flatten ``` diff --git a/src/lib.rs b/src/lib.rs index a41f7fc6..e7ac86f9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -84,6 +84,7 @@ struct FieldOpts { getter: Option, #[darling(default)] partial_getter: Option, + no_getter: darling::util::Flag, } /// Getter configuration for a specific field @@ -137,6 +138,7 @@ struct FieldData { only_combinations: Vec, getter_opts: GetterOpts, partial_getter_opts: GetterOpts, + no_getter: bool, is_common: bool, } @@ -145,6 +147,10 @@ impl FieldData { self.is_common } + fn no_getter(&self) -> bool { + self.no_getter + } + /// Checks whether this field should be included in creating /// partial getters for the given type name. fn exists_in_meta(&self, type_name: &Ident) -> bool { @@ -294,6 +300,12 @@ pub fn superstruct(args: TokenStream, input: TokenStream) -> TokenStream { panic!("can't set `flatten` and `getter` on the same field"); } else if field_opts.flatten.is_some() && field_opts.partial_getter.is_some() { panic!("can't set `flatten` and `partial_getter` on the same field"); + } else if field_opts.flatten.is_some() && field_opts.no_getter.is_present() { + panic!("can't set `flatten` and `no_getter` on the same field") + } else if field_opts.getter.is_some() && field_opts.no_getter.is_present() { + panic!("can't set `getter` and `no_getter` on the same field") + } else if field_opts.partial_getter.is_some() && field_opts.no_getter.is_present() { + panic!("can't set `partial_getter` and `no_getter` on the same field") } let getter_opts = field_opts.getter.unwrap_or_default(); @@ -397,6 +409,7 @@ pub fn superstruct(args: TokenStream, input: TokenStream) -> TokenStream { only_combinations: vec![variant_key.clone()], getter_opts: <_>::default(), partial_getter_opts, + no_getter: false, is_common: false, }); @@ -420,6 +433,7 @@ pub fn superstruct(args: TokenStream, input: TokenStream) -> TokenStream { .collect_vec(), getter_opts, partial_getter_opts, + no_getter: field_opts.no_getter.is_present(), is_common, }); } @@ -630,19 +644,19 @@ fn generate_wrapper_enums( // Construct the main impl block. let getters = fields .iter() - .filter(|f| f.is_common()) + .filter(|f| f.is_common() && !f.no_getter()) .map(|field_data| make_field_getter(type_name, variant_names, field_data, None, is_meta)); let mut_getters = fields .iter() - .filter(|f| f.is_common() && !f.getter_opts.no_mut) + .filter(|f| f.is_common() && !f.no_getter() && !f.getter_opts.no_mut) .map(|field_data| { make_mut_field_getter(type_name, variant_names, field_data, None, is_meta) }); let partial_getters = fields .iter() - .filter(|f| !f.is_common()) + .filter(|f| !f.is_common() && !f.no_getter()) .filter(|f| is_meta || f.exists_in_meta(type_name)) .cartesian_product(&[false, true]) .flat_map(|(field_data, mutability)| { @@ -714,19 +728,22 @@ fn generate_wrapper_enums( output_items.push(impl_block.into()); // Construct the impl block for the *Ref type. - let ref_getters = fields.iter().filter(|f| f.is_common()).map(|field_data| { - make_field_getter( - &ref_ty_name, - variant_names, - field_data, - Some(&ref_ty_lifetime), - is_meta, - ) - }); + let ref_getters = fields + .iter() + .filter(|f| f.is_common() && !f.no_getter()) + .map(|field_data| { + make_field_getter( + &ref_ty_name, + variant_names, + field_data, + Some(&ref_ty_lifetime), + is_meta, + ) + }); let ref_partial_getters = fields .iter() - .filter(|f| !f.is_common()) + .filter(|f| !f.is_common() && !f.no_getter()) .filter(|f| is_meta || f.exists_in_meta(type_name)) .flat_map(|field_data| { let field_variants = &field_data.only_combinations; @@ -763,7 +780,7 @@ fn generate_wrapper_enums( // Construct the impl block for the *RefMut type. let ref_mut_getters = fields .iter() - .filter(|f| f.is_common() && !f.getter_opts.no_mut) + .filter(|f| f.is_common() && !f.no_getter() && !f.getter_opts.no_mut) .map(|field_data| { make_mut_field_getter( &ref_mut_ty_name, @@ -776,7 +793,7 @@ fn generate_wrapper_enums( let ref_mut_partial_getters = fields .iter() - .filter(|f| !f.is_common() && !f.partial_getter_opts.no_mut) + .filter(|f| !f.is_common() && !f.no_getter() && !f.partial_getter_opts.no_mut) .filter(|f| is_meta || f.exists_in_meta(type_name)) .flat_map(|field_data| { let field_variants = &field_data.only_combinations; diff --git a/tests/basic.rs b/tests/basic.rs index 40770e81..3bbaaf17 100644 --- a/tests/basic.rs +++ b/tests/basic.rs @@ -138,3 +138,15 @@ fn no_enum() { let b: MessageB = MessageB { y: 0 }; assert_eq!(a.x, b.y); } + +#[test] +#[allow(dead_code)] +fn no_getter() { + #[superstruct(variants(A, B))] + struct NoGetter { + #[superstruct(only(A), no_getter)] + pub x: u64, + #[superstruct(only(B), no_getter)] + pub x: String, + } +}