Skip to content

Commit 7da3978

Browse files
authored
Add field attribute to disable (partial) getter generation (#45)
* Upgrade to Syn 2 and Darling 0.20 * Add field attribute to disable (partial) getter generation --------- Co-authored-by: Christiaan Biesterbosch <Kriskras99@users.noreply.github.com>
1 parent b094275 commit 7da3978

File tree

5 files changed

+83
-39
lines changed

5 files changed

+83
-39
lines changed

Cargo.toml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,12 @@ name = "superstruct"
1414
proc-macro = true
1515

1616
[dependencies]
17-
darling = "0.13.0"
18-
itertools = "0.10.1"
19-
proc-macro2 = "1.0.32"
20-
quote = "1.0.10"
21-
syn = "1.0.82"
22-
smallvec = "1.8.0"
17+
darling = "0.20.10"
18+
itertools = "0.13.0"
19+
proc-macro2 = "1.0.89"
20+
quote = "1.0.37"
21+
syn = "2.0.86"
22+
smallvec = "1.13.2"
2323

2424
[dev-dependencies]
2525
serde = { version = "1.0.130", features = ["derive"] }

book/src/config/field.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,20 @@ The error type for partial getters can currently only be configured on a per-str
6969
via the [`partial_getter_error`](./struct.md#partial-getter-error) attribute, although this may
7070
change in a future release.
7171

72+
## No Getter
73+
Disable the generation of (partial) getter functions for this field.
74+
This can be used for when two fields have the same name but different types:
75+
76+
```rust
77+
#[superstruct(variants(A, B))]
78+
struct NoGetter {
79+
#[superstruct(only(A), no_getter)]
80+
pub x: u64,
81+
#[superstruct(only(B), no_getter)]
82+
pub x: String,
83+
}
84+
```
85+
7286
## Flatten
7387

7488
```

src/attributes.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Utilities to help with parsing configuration attributes.
2-
use darling::{Error, FromMeta};
3-
use syn::{Ident, NestedMeta};
2+
use darling::{export::NestedMeta, Error, FromMeta};
3+
use syn::Ident;
44

55
/// Parse a list of nested meta items.
66
///

src/lib.rs

Lines changed: 49 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
1+
use std::{
2+
collections::HashMap,
3+
iter::{self, FromIterator},
4+
};
5+
16
use attributes::{IdentList, NestedMetaList};
2-
use darling::util::Override;
3-
use darling::FromMeta;
7+
use darling::{export::NestedMeta, util::Override, FromMeta};
48
use from::{
59
generate_from_enum_trait_impl_for_ref, generate_from_variant_trait_impl,
610
generate_from_variant_trait_impl_for_ref,
@@ -10,11 +14,9 @@ use macros::generate_all_map_macros;
1014
use proc_macro::TokenStream;
1115
use proc_macro2::{Span, TokenStream as TokenStream2};
1216
use quote::{format_ident, quote, ToTokens};
13-
use std::collections::HashMap;
14-
use std::iter::{self, FromIterator};
1517
use syn::{
16-
parse_macro_input, Attribute, AttributeArgs, Expr, Field, GenericParam, Ident, ItemStruct,
17-
Lifetime, LifetimeDef, Type, TypeGenerics, TypeParamBound,
18+
parse_macro_input, Attribute, Expr, Field, GenericParam, Ident, ItemStruct, Lifetime,
19+
LifetimeParam, Type, TypeGenerics, TypeParamBound,
1820
};
1921

2022
mod attributes;
@@ -82,6 +84,7 @@ struct FieldOpts {
8284
getter: Option<GetterOpts>,
8385
#[darling(default)]
8486
partial_getter: Option<GetterOpts>,
87+
no_getter: darling::util::Flag,
8588
}
8689

8790
/// Getter configuration for a specific field
@@ -135,6 +138,7 @@ struct FieldData {
135138
only_combinations: Vec<VariantKey>,
136139
getter_opts: GetterOpts,
137140
partial_getter_opts: GetterOpts,
141+
no_getter: bool,
138142
is_common: bool,
139143
}
140144

@@ -143,6 +147,10 @@ impl FieldData {
143147
self.is_common
144148
}
145149

150+
fn no_getter(&self) -> bool {
151+
self.no_getter
152+
}
153+
146154
/// Checks whether this field should be included in creating
147155
/// partial getters for the given type name.
148156
fn exists_in_meta(&self, type_name: &Ident) -> bool {
@@ -170,7 +178,10 @@ struct VariantKey {
170178

171179
#[proc_macro_attribute]
172180
pub fn superstruct(args: TokenStream, input: TokenStream) -> TokenStream {
173-
let attr_args = parse_macro_input!(args as AttributeArgs);
181+
let attr_args = match NestedMeta::parse_meta_list(args.into()) {
182+
Ok(args) => args,
183+
Err(err) => return err.to_compile_error().into(),
184+
};
174185
let item = parse_macro_input!(input as ItemStruct);
175186

176187
let type_name = &item.ident;
@@ -229,10 +240,7 @@ pub fn superstruct(args: TokenStream, input: TokenStream) -> TokenStream {
229240
.attrs
230241
.iter()
231242
.filter(|attr| is_superstruct_attr(attr))
232-
.map(|attr| {
233-
let meta = attr.parse_meta().unwrap();
234-
FieldOpts::from_meta(&meta).unwrap()
235-
})
243+
.map(|attr| FieldOpts::from_meta(&attr.meta).unwrap())
236244
.next()
237245
.unwrap_or_default();
238246

@@ -292,6 +300,12 @@ pub fn superstruct(args: TokenStream, input: TokenStream) -> TokenStream {
292300
panic!("can't set `flatten` and `getter` on the same field");
293301
} else if field_opts.flatten.is_some() && field_opts.partial_getter.is_some() {
294302
panic!("can't set `flatten` and `partial_getter` on the same field");
303+
} else if field_opts.flatten.is_some() && field_opts.no_getter.is_present() {
304+
panic!("can't set `flatten` and `no_getter` on the same field")
305+
} else if field_opts.getter.is_some() && field_opts.no_getter.is_present() {
306+
panic!("can't set `getter` and `no_getter` on the same field")
307+
} else if field_opts.partial_getter.is_some() && field_opts.no_getter.is_present() {
308+
panic!("can't set `partial_getter` and `no_getter` on the same field")
295309
}
296310

297311
let getter_opts = field_opts.getter.unwrap_or_default();
@@ -395,6 +409,7 @@ pub fn superstruct(args: TokenStream, input: TokenStream) -> TokenStream {
395409
only_combinations: vec![variant_key.clone()],
396410
getter_opts: <_>::default(),
397411
partial_getter_opts,
412+
no_getter: false,
398413
is_common: false,
399414
});
400415

@@ -418,6 +433,7 @@ pub fn superstruct(args: TokenStream, input: TokenStream) -> TokenStream {
418433
.collect_vec(),
419434
getter_opts,
420435
partial_getter_opts,
436+
no_getter: field_opts.no_getter.is_present(),
421437
is_common,
422438
});
423439
}
@@ -444,8 +460,7 @@ pub fn superstruct(args: TokenStream, input: TokenStream) -> TokenStream {
444460
.map_or(&[][..], |attrs| &attrs.metas);
445461
let spatt = specific_struct_attributes
446462
.iter()
447-
.chain(specific_struct_attributes_meta.iter())
448-
.unique();
463+
.chain(specific_struct_attributes_meta.iter());
449464

450465
let variant_code = quote! {
451466
#(
@@ -556,7 +571,7 @@ fn generate_wrapper_enums(
556571
let mut ref_ty_decl_generics = decl_generics.clone();
557572
ref_ty_decl_generics.params.insert(
558573
0,
559-
GenericParam::Lifetime(LifetimeDef::new(ref_ty_lifetime.clone())),
574+
GenericParam::Lifetime(LifetimeParam::new(ref_ty_lifetime.clone())),
560575
);
561576

562577
// If no lifetime bound exists for a generic param, inject one.
@@ -603,7 +618,7 @@ fn generate_wrapper_enums(
603618
let mut ref_mut_ty_decl_generics = decl_generics.clone();
604619
ref_mut_ty_decl_generics.params.insert(
605620
0,
606-
GenericParam::Lifetime(LifetimeDef::new(ref_mut_ty_lifetime.clone())),
621+
GenericParam::Lifetime(LifetimeParam::new(ref_mut_ty_lifetime.clone())),
607622
);
608623
let (ref_mut_impl_generics, ref_mut_ty_generics, _) =
609624
&ref_mut_ty_decl_generics.split_for_impl();
@@ -629,19 +644,19 @@ fn generate_wrapper_enums(
629644
// Construct the main impl block.
630645
let getters = fields
631646
.iter()
632-
.filter(|f| f.is_common())
647+
.filter(|f| f.is_common() && !f.no_getter())
633648
.map(|field_data| make_field_getter(type_name, variant_names, field_data, None, is_meta));
634649

635650
let mut_getters = fields
636651
.iter()
637-
.filter(|f| f.is_common() && !f.getter_opts.no_mut)
652+
.filter(|f| f.is_common() && !f.no_getter() && !f.getter_opts.no_mut)
638653
.map(|field_data| {
639654
make_mut_field_getter(type_name, variant_names, field_data, None, is_meta)
640655
});
641656

642657
let partial_getters = fields
643658
.iter()
644-
.filter(|f| !f.is_common())
659+
.filter(|f| !f.is_common() && !f.no_getter())
645660
.filter(|f| is_meta || f.exists_in_meta(type_name))
646661
.cartesian_product(&[false, true])
647662
.flat_map(|(field_data, mutability)| {
@@ -713,19 +728,22 @@ fn generate_wrapper_enums(
713728
output_items.push(impl_block.into());
714729

715730
// Construct the impl block for the *Ref type.
716-
let ref_getters = fields.iter().filter(|f| f.is_common()).map(|field_data| {
717-
make_field_getter(
718-
&ref_ty_name,
719-
variant_names,
720-
field_data,
721-
Some(&ref_ty_lifetime),
722-
is_meta,
723-
)
724-
});
731+
let ref_getters = fields
732+
.iter()
733+
.filter(|f| f.is_common() && !f.no_getter())
734+
.map(|field_data| {
735+
make_field_getter(
736+
&ref_ty_name,
737+
variant_names,
738+
field_data,
739+
Some(&ref_ty_lifetime),
740+
is_meta,
741+
)
742+
});
725743

726744
let ref_partial_getters = fields
727745
.iter()
728-
.filter(|f| !f.is_common())
746+
.filter(|f| !f.is_common() && !f.no_getter())
729747
.filter(|f| is_meta || f.exists_in_meta(type_name))
730748
.flat_map(|field_data| {
731749
let field_variants = &field_data.only_combinations;
@@ -762,7 +780,7 @@ fn generate_wrapper_enums(
762780
// Construct the impl block for the *RefMut type.
763781
let ref_mut_getters = fields
764782
.iter()
765-
.filter(|f| f.is_common() && !f.getter_opts.no_mut)
783+
.filter(|f| f.is_common() && !f.no_getter() && !f.getter_opts.no_mut)
766784
.map(|field_data| {
767785
make_mut_field_getter(
768786
&ref_mut_ty_name,
@@ -775,7 +793,7 @@ fn generate_wrapper_enums(
775793

776794
let ref_mut_partial_getters = fields
777795
.iter()
778-
.filter(|f| !f.is_common() && !f.partial_getter_opts.no_mut)
796+
.filter(|f| !f.is_common() && !f.no_getter() && !f.partial_getter_opts.no_mut)
779797
.filter(|f| is_meta || f.exists_in_meta(type_name))
780798
.flat_map(|field_data| {
781799
let field_variants = &field_data.only_combinations;
@@ -1123,7 +1141,7 @@ fn is_superstruct_attr(attr: &Attribute) -> bool {
11231141

11241142
/// Predicate for determining whether an attribute has the given `ident` as its path.
11251143
fn is_attr_with_ident(attr: &Attribute, ident: &str) -> bool {
1126-
attr.path
1144+
attr.path()
11271145
.get_ident()
11281146
.map_or(false, |attr_ident| *attr_ident == ident)
11291147
}

tests/basic.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,3 +138,15 @@ fn no_enum() {
138138
let b: MessageB = MessageB { y: 0 };
139139
assert_eq!(a.x, b.y);
140140
}
141+
142+
#[test]
143+
#[allow(dead_code)]
144+
fn no_getter() {
145+
#[superstruct(variants(A, B))]
146+
struct NoGetter {
147+
#[superstruct(only(A), no_getter)]
148+
pub x: u64,
149+
#[superstruct(only(B), no_getter)]
150+
pub x: String,
151+
}
152+
}

0 commit comments

Comments
 (0)