Skip to content

Commit 7e102c5

Browse files
committed
Allow type parameter bounds in skip.
Signed-off-by: Toralf Wittner <[email protected]>
1 parent 4e089d8 commit 7e102c5

File tree

7 files changed

+141
-148
lines changed

7 files changed

+141
-148
lines changed

minicbor-derive/src/attrs.rs

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -124,15 +124,17 @@ impl Attributes {
124124
return Err(syn::Error::new(*s, "`tag` and `transparent` are mutually exclusive"))
125125
}
126126
}
127-
if let Some(Value::Skip(s)) = this.get(Kind::Skip) {
128-
if this.attrs.len() > 1 {
129-
return Err(syn::Error::new(*s, "`skip` does not allow other attributes"))
130-
}
127+
if this.contains_key(Kind::Skip)
128+
&& let Some((_, a)) = this.attrs
129+
.iter()
130+
.find(|(k, _)| !matches!(k, Kind::Skip | Kind::TypeParam))
131+
{
132+
return Err(syn::Error::new(a.span(), "`skip` can not be used with this attribute"))
131133
}
132-
if let Some(Value::Flat(_)) = this.get(Kind::Flat) {
133-
if let Some(Value::Encoding(Encoding::Map, s)) = this.get(Kind::Encoding) {
134-
return Err(syn::Error::new(*s, "flat enum does not support map encoding"))
135-
}
134+
if this.contains_key(Kind::Flat)
135+
&& let Some(Value::Encoding(Encoding::Map, s)) = this.get(Kind::Encoding)
136+
{
137+
return Err(syn::Error::new(*s, "flat enum does not support map encoding"))
136138
}
137139
// `skip_if` triggers the creation of a custom codec where `encode` and `decode`
138140
// correspond the the default routines, `is_nil` is defined via `skip_if`'s
@@ -662,17 +664,13 @@ impl Attributes {
662664
}
663665
}
664666
Value::CborLen(_, s) => {
665-
if let Some(Value::Codec(c, _)) = self.get(Kind::Codec) {
666-
if c.is_module() {
667-
return Err(syn::Error::new(*s, "`cbor_len` and `with` are mutually exclusive"))
668-
}
667+
if let Some(Value::Codec(c, _)) = self.get(Kind::Codec) && c.is_module() {
668+
return Err(syn::Error::new(*s, "`cbor_len` and `with` are mutually exclusive"))
669669
}
670670
}
671671
Value::Borrow(_, s) => {
672-
if let Some(idx) = self.index() {
673-
if idx.is_b() {
674-
return Err(syn::Error::new(*s, "`borrow` and `b` are mutually exclusive"))
675-
}
672+
if let Some(idx) = self.index() && idx.is_b() {
673+
return Err(syn::Error::new(*s, "`borrow` and `b` are mutually exclusive"))
676674
}
677675
}
678676
Value::Index(idx, s) if idx.is_b() => {

minicbor-derive/src/blacklist.rs

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,28 @@ use std::ops::Deref;
44
use crate::{collect_type_params, is_phantom_data, Mode};
55
use crate::{attrs::CustomCodec, fields::Fields};
66

7-
#[derive(Default)]
87
pub(crate) struct Blacklist(HashSet<syn::Ident>);
98

109
impl Blacklist {
10+
pub(crate) fn empty() -> Self {
11+
Self(HashSet::new())
12+
}
13+
1114
/// Generate a blacklist of type parameters that should not have bounds attached.
1215
///
1316
/// This includes:
1417
///
1518
/// - Type parameters of fields with a custom encode, decode or cbor_len function.
1619
/// - Fields that are skipped over.
1720
/// - Fields with a `PhantomData` type.
18-
pub(crate) fn new(mode: Mode, fields: &Fields, g: &syn::Generics) -> Blacklist {
19-
// Start with custom encode/decode/cbor_len functions.
21+
pub(crate) fn new(mode: Mode, fields: &Fields, g: &syn::Generics) -> Self {
22+
Self::empty()
23+
.with_mode(mode, fields, g)
24+
.with_skipped(fields, g)
25+
.with_phantoms(fields, g)
26+
}
27+
28+
pub(crate) fn with_mode(mut self, mode: Mode, fields: &Fields, g: &syn::Generics) -> Self {
2029
let mut blacklist = collect_type_params(g, fields.fields().filter(|f| {
2130
match mode {
2231
Mode::Encode => f.attrs.codec().map(|c| !c.require_encode_bound()).unwrap_or(false),
@@ -41,43 +50,49 @@ impl Blacklist {
4150
}));
4251
blacklist.retain(|ident| !others.contains(ident));
4352
}
53+
self.0.extend(blacklist);
54+
self
55+
}
4456

45-
// Extend the blacklist by type parameters only appearing in skipped fields.
57+
/// Extend the blacklist by type parameters only appearing in skipped fields.
58+
pub(crate) fn with_skipped(mut self, fields: &Fields, g: &syn::Generics) -> Self {
4659
let skipped = collect_type_params(g, fields.skipped());
4760
if !skipped.is_empty() {
4861
let regular = collect_type_params(g, fields.fields());
49-
blacklist.extend(skipped.difference(&regular).cloned())
62+
self.0.extend(skipped.difference(&regular).cloned())
5063
}
64+
self
65+
}
5166

52-
// And finally also by type parameters only appearing in `PhantomData`.
67+
pub(crate) fn with_phantoms(mut self, fields: &Fields, g: &syn::Generics) -> Self {
5368
let phantoms = collect_type_params(g, fields.fields().chain(fields.skipped()).filter(|f| {
5469
is_phantom_data(&f.typ)
5570
}));
5671
if !phantoms.is_empty() {
5772
let non_phantom = collect_type_params(g, fields.fields().chain(fields.skipped()).filter(|f| {
5873
!is_phantom_data(&f.typ)
5974
}));
60-
blacklist.extend(phantoms.difference(&non_phantom).cloned());
75+
self.0.extend(phantoms.difference(&non_phantom).cloned());
6176
}
62-
63-
Self(blacklist)
77+
self
6478
}
6579

80+
6681
/// Merge in another set of fields.
6782
///
6883
/// Any types in positive position, i.e. not blacklisted in the given
6984
/// fields argument will be removed from the blacklist.
7085
///
7186
/// Any types in negative position, i.e. blacklisted in the given fields
7287
/// argument will be add to the blacklist.
73-
pub(crate) fn merge(&mut self, m: Mode, f: &Fields, g: &syn::Generics) {
74-
let b = Blacklist::new(m, f, g);
88+
pub(crate) fn merge(&mut self, f: &Fields, g: &syn::Generics, b: Self) -> &mut Self {
7589
for t in collect_type_params(g, f.fields()).difference(&b) {
7690
self.0.remove(t);
7791
}
7892
for t in b.0 {
7993
self.0.insert(t);
8094
}
95+
self
8196
}
8297

8398
pub(crate) fn add<I>(&mut self, it: I)

minicbor-derive/src/cbor_len.rs

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,12 @@ fn on_struct(inp: &mut syn::DeriveInput) -> syn::Result<proc_macro2::TokenStream
3939
let blacklist = Blacklist::new(Mode::Length, &fields, &inp.generics);
4040
let cbor_len_bound = gen_cbor_len_bound()?;
4141
let params = inp.generics.type_params_mut();
42-
add_bound_to_type_params(cbor_len_bound, params, &blacklist, fields.fields().attributes(), Mode::Length);
42+
add_bound_to_type_params(Mode::Length, cbor_len_bound, params, &blacklist, fields.fields().attributes());
4343

4444
let blacklist = blacklist_is_nil_params(&inp.generics, &fields);
4545
let encode_bound = gen_encode_bound()?;
4646
let params = inp.generics.type_params_mut();
47-
add_bound_to_type_params(encode_bound, params, &blacklist, fields.fields().attributes(), Mode::Length);
47+
add_bound_to_type_params(Mode::Length, encode_bound, params, &blacklist, fields.fields().attributes());
4848

4949
let generics = add_typeparam(&inp.generics, gen_ctx_param()?, attrs.context_bound());
5050
let impl_generics = generics.split_for_impl().0;
@@ -90,13 +90,13 @@ fn on_enum(inp: &mut syn::DeriveInput) -> syn::Result<proc_macro2::TokenStream>
9090
let flat = enum_attrs.flat();
9191
let variants = Variants::try_from(name.span(), data.variants.iter(), &enum_attrs)?;
9292

93-
let mut blacklist_len = Blacklist::default();
94-
let mut blacklist_enc = Blacklist::default();
93+
let mut blacklist_len = Blacklist::empty();
94+
let mut blacklist_enc = Blacklist::empty();
9595
let mut field_attrs = Vec::new();
9696
let mut rows = Vec::new();
9797
for ((var, idx), attrs) in data.variants.iter().zip(variants.indices.iter()).zip(&variants.attrs) {
9898
let fields = Fields::try_from(var.ident.span(), var.fields.iter(), &[attrs, &enum_attrs])?;
99-
blacklist_len.merge(Mode::Length, &fields, &inp.generics);
99+
blacklist_len.merge(&fields, &inp.generics, Blacklist::new(Mode::Length, &fields, &inp.generics));
100100
blacklist_enc.add(HashSet::from(blacklist_is_nil_params(&inp.generics, &fields)));
101101
let con = &var.ident;
102102
let encoding = attrs.encoding().unwrap_or(enum_encoding);
@@ -158,11 +158,11 @@ fn on_enum(inp: &mut syn::DeriveInput) -> syn::Result<proc_macro2::TokenStream>
158158

159159
let cbor_len_bound = gen_cbor_len_bound()?;
160160
let params = inp.generics.type_params_mut();
161-
add_bound_to_type_params(cbor_len_bound, params, &blacklist_len, &field_attrs, Mode::Length);
161+
add_bound_to_type_params(Mode::Length, cbor_len_bound, params, &blacklist_len, &field_attrs);
162162

163163
let encode_bound = gen_encode_bound()?;
164164
let params = inp.generics.type_params_mut();
165-
add_bound_to_type_params(encode_bound, params, &blacklist_enc, &field_attrs, Mode::Length);
165+
add_bound_to_type_params(Mode::Length, encode_bound, params, &blacklist_enc, &field_attrs);
166166

167167
let generics = add_typeparam(&inp.generics, gen_ctx_param()?, enum_attrs.context_bound());
168168
let impl_generics = generics.split_for_impl().0;
@@ -296,10 +296,8 @@ fn cbor_len(custom: Option<&syn::ExprPath>, codec: Option<&CustomCodec>) -> proc
296296
if let Some(cu) = custom {
297297
return cu.to_token_stream()
298298
}
299-
if let Some(ce) = codec {
300-
if let Some(p) = ce.to_cbor_len_path() {
301-
return p.to_token_stream()
302-
}
299+
if let Some(ce) = codec && let Some(p) = ce.to_cbor_len_path() {
300+
return p.to_token_stream()
303301
}
304302
quote!(minicbor::CborLen::<Ctx>::cbor_len)
305303
}
@@ -349,7 +347,7 @@ fn on_tag(a: &Attributes) -> proc_macro2::TokenStream {
349347
}
350348

351349
fn blacklist_is_nil_params(generics: &syn::Generics, fields: &Fields) -> Blacklist {
352-
let mut blacklist = Blacklist::default();
350+
let mut blacklist = Blacklist::empty();
353351
blacklist.add({
354352
let mut with_is_nil = collect_type_params(generics, fields.fields().filter(|f| {
355353
f.attrs.codec().map(|c| c.is_is_nil()).unwrap_or(false)

minicbor-derive/src/decode.rs

Lines changed: 53 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
use quote::quote;
21
use std::collections::HashSet;
2+
3+
use quote::quote;
34
use syn::spanned::Spanned;
45

56
use crate::blacklist::Blacklist;
6-
use crate::{is_phantom_data, Mode};
7-
use crate::{add_bound_to_type_params, collect_type_params, is_cow, is_option, is_str, is_byte_slice};
8-
use crate::{add_typeparam, gen_ctx_param, add_bound_to_matching_type_params};
7+
use crate::{collect_type_params, Mode};
8+
use crate::{add_bound_to_type_params, is_cow, is_option, is_str, is_byte_slice};
9+
use crate::{add_typeparam, gen_ctx_param};
910
use crate::attrs::{Attributes, CustomCodec, Encoding, Level};
1011
use crate::fields::{Field, Fields};
1112
use crate::variants::Variants;
@@ -34,33 +35,39 @@ fn on_struct(inp: &mut syn::DeriveInput) -> syn::Result<proc_macro2::TokenStream
3435
unreachable!("`derive_from` matched against `syn::Data::Struct`")
3536
};
3637

37-
let name = &inp.ident;
38-
let attrs = Attributes::try_from_iter(Level::Struct, inp.attrs.iter())?;
39-
let fields = Fields::try_from(name.span(), data.fields.iter(), &[&attrs])?;
40-
let blacklist = Blacklist::new(Mode::Decode, &fields, &inp.generics);
38+
let name = &inp.ident;
39+
let attrs = Attributes::try_from_iter(Level::Struct, inp.attrs.iter())?;
40+
let fields = Fields::try_from(name.span(), data.fields.iter(), &[&attrs])?;
4141

42-
let mut lifetime = gen_lifetime()?;
42+
let mut lifetime = gen_lifetime();
4343
for l in lifetimes_to_constrain(fields.fields().map(|f| (&f.index, f.attrs.borrow(), &f.typ))) {
4444
if !lifetime.bounds.iter().any(|b| *b == l) {
4545
lifetime.bounds.push(l.clone())
4646
}
4747
}
4848

49-
// Collect type parameters which require a `Default` bound.
50-
let default_types =
51-
collect_type_params(&inp.generics, fields.fields().chain(fields.skipped()).filter(|f| {
52-
(f.attrs.default() || f.attrs.skip() || f.attrs.skip_if_codec()) && !is_phantom_data(&f.typ)
53-
}))
54-
.into_iter()
55-
.collect();
56-
57-
let bound = gen_decode_bound()?;
49+
let blacklist = Blacklist::new(Mode::Decode, &fields, &inp.generics);
50+
let bound = gen_decode_bound();
5851
let params = inp.generics.type_params_mut();
59-
add_bound_to_type_params(bound, params, &blacklist, fields.fields().attributes(), Mode::Decode);
52+
add_bound_to_type_params(Mode::Decode, bound, params, &blacklist, fields.fields().attributes());
6053

61-
let bound = gen_default_bound()?;
62-
let params = inp.generics.type_params_mut();
63-
add_bound_to_matching_type_params(bound, params, &default_types);
54+
// Collect type parameters which require a `Default` bound.
55+
let default_types: HashSet<syn::Ident> =
56+
collect_type_params(&inp.generics, fields.fields().chain(fields.skipped()).filter(|f| {
57+
f.attrs.default() || f.attrs.skip() || f.attrs.skip_if_codec()
58+
}));
59+
60+
let blacklist = Blacklist::empty()
61+
.with_mode(Mode::Decode, &fields, &inp.generics)
62+
.with_phantoms(&fields, &inp.generics);
63+
64+
let bound = gen_default_bound();
65+
let params = inp.generics.type_params_mut().filter(|p| default_types.contains(&p.ident));
66+
add_bound_to_type_params(Mode::Decode, bound, params, &blacklist,
67+
fields.fields().chain(fields.skipped()).filter_map(|f| {
68+
(f.attrs.default() || f.attrs.skip() || f.attrs.skip_if_codec()).then_some(&f.attrs)
69+
})
70+
);
6471

6572
let generics = add_lifetime(&inp.generics, lifetime);
6673
let generics = add_typeparam(&generics, gen_ctx_param()?, attrs.context_bound());
@@ -140,10 +147,12 @@ fn on_enum(inp: &mut syn::DeriveInput) -> syn::Result<proc_macro2::TokenStream>
140147
let flat = enum_attrs.flat();
141148
let variants = Variants::try_from(name.span(), data.variants.iter(), &enum_attrs)?;
142149

143-
let mut blacklist = Blacklist::default();
144-
let mut defaults = HashSet::new();
150+
let mut decode_blacklist = Blacklist::empty();
145151
let mut field_attrs = Vec::new();
146-
let mut lifetime = gen_lifetime()?;
152+
let mut default_blacklist = Blacklist::empty();
153+
let mut defaults = HashSet::new();
154+
let mut default_attrs = Vec::new();
155+
let mut lifetime = gen_lifetime();
147156
let mut rows = Vec::new();
148157
for ((var, idx), attrs) in data.variants.iter().zip(variants.indices.iter()).zip(&variants.attrs) {
149158
let fields = Fields::try_from(var.ident.span(), var.fields.iter(), &[attrs, &enum_attrs])?;
@@ -166,13 +175,14 @@ fn on_enum(inp: &mut syn::DeriveInput) -> syn::Result<proc_macro2::TokenStream>
166175
lifetime.bounds.push(l.clone())
167176
}
168177
}
169-
blacklist.merge(Mode::Decode, &fields, &inp.generics);
170-
// Collect type parameters which require a `Default` bound.
178+
decode_blacklist.merge(&fields, &inp.generics, Blacklist::new(Mode::Decode, &fields, &inp.generics));
179+
default_blacklist.merge(&fields, &inp.generics, Blacklist::empty()
180+
.with_mode(Mode::Decode, &fields, &inp.generics)
181+
.with_phantoms(&fields, &inp.generics));
171182
defaults.extend(
172183
collect_type_params(&inp.generics, fields.fields().chain(fields.skipped()).filter(|f| {
173-
(f.attrs.default() || f.attrs.skip() || f.attrs.skip_if_codec()) && !is_phantom_data(&f.typ)
184+
f.attrs.default() || f.attrs.skip() || f.attrs.skip_if_codec()
174185
}))
175-
.into_iter()
176186
);
177187
let statements = gen_statements(&fields, encoding, flat)?;
178188
if let syn::Fields::Named(_) = var.fields {
@@ -213,16 +223,21 @@ fn on_enum(inp: &mut syn::DeriveInput) -> syn::Result<proc_macro2::TokenStream>
213223
}
214224
};
215225
field_attrs.extend(fields.fields().attributes().cloned());
226+
default_attrs.extend(fields.fields().attributes().chain(fields.skipped().attributes()).cloned());
216227
rows.push(row)
217228
}
218229

219-
let bound = gen_decode_bound()?;
230+
let bound = gen_decode_bound();
220231
let params = inp.generics.type_params_mut();
221-
add_bound_to_type_params(bound, params, &blacklist, &field_attrs, Mode::Decode);
232+
add_bound_to_type_params(Mode::Decode, bound, params, &decode_blacklist, &field_attrs);
222233

223-
let bound = gen_default_bound()?;
224-
let params = inp.generics.type_params_mut();
225-
add_bound_to_matching_type_params(bound, params, &defaults);
234+
let bound = gen_default_bound();
235+
let params = inp.generics.type_params_mut().filter(|p| defaults.contains(&p.ident));
236+
add_bound_to_type_params(Mode::Decode, bound, params, &default_blacklist,
237+
default_attrs.iter().filter(|a| {
238+
a.default() || a.skip() || a.skip_if_codec()
239+
})
240+
);
226241

227242
let generics = add_lifetime(&inp.generics, lifetime);
228243
let generics = add_typeparam(&generics, gen_ctx_param()?, enum_attrs.context_bound());
@@ -527,12 +542,12 @@ fn make_transparent_impl
527542
})
528543
}
529544

530-
fn gen_decode_bound() -> syn::Result<syn::TypeParamBound> {
531-
syn::parse_str("minicbor::Decode<'bytes, Ctx>")
545+
fn gen_decode_bound() -> syn::TypeParamBound {
546+
syn::parse_quote!(minicbor::Decode<'bytes, Ctx>)
532547
}
533548

534-
fn gen_default_bound() -> syn::Result<syn::TypeParamBound> {
535-
syn::parse_str("Default")
549+
fn gen_default_bound() -> syn::TypeParamBound {
550+
syn::parse_quote!(Default)
536551
}
537552

538553
fn defs<'a, T>(fields: T) -> Vec<proc_macro2::TokenStream>

minicbor-derive/src/encode.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ fn on_struct(inp: &mut syn::DeriveInput) -> syn::Result<proc_macro2::TokenStream
4040

4141
let bound = gen_encode_bound()?;
4242
let params = inp.generics.type_params_mut();
43-
add_bound_to_type_params(bound, params, &blacklist, fields.fields().attributes(), Mode::Encode);
43+
add_bound_to_type_params(Mode::Encode, bound, params, &blacklist, fields.fields().attributes());
4444

4545
let generics = add_typeparam(&inp.generics, gen_ctx_param()?, attrs.context_bound());
4646
let impl_generics = generics.split_for_impl().0;
@@ -90,13 +90,13 @@ fn on_enum(inp: &mut syn::DeriveInput) -> syn::Result<proc_macro2::TokenStream>
9090
let flat = enum_attrs.flat();
9191
let variants = Variants::try_from(name.span(), data.variants.iter(), &enum_attrs)?;
9292

93-
let mut blacklist = Blacklist::default();
93+
let mut blacklist = Blacklist::empty();
9494
let mut field_attrs = Vec::new();
9595
let mut rows = Vec::new();
9696

9797
for ((var, idx), attrs) in data.variants.iter().zip(variants.indices.iter()).zip(&variants.attrs) {
9898
let fields = Fields::try_from(var.ident.span(), var.fields.iter(), &[attrs, &enum_attrs])?;
99-
blacklist.merge(Mode::Encode, &fields, &inp.generics);
99+
blacklist.merge(&fields, &inp.generics, Blacklist::new(Mode::Encode, &fields, &inp.generics));
100100
let con = &var.ident;
101101
let encoding = attrs.encoding().unwrap_or(enum_encoding);
102102
let tag = encode_tag(attrs);
@@ -207,7 +207,7 @@ fn on_enum(inp: &mut syn::DeriveInput) -> syn::Result<proc_macro2::TokenStream>
207207
{
208208
let bound = gen_encode_bound()?;
209209
let params = inp.generics.type_params_mut();
210-
add_bound_to_type_params(bound, params, &blacklist, &field_attrs, Mode::Encode);
210+
add_bound_to_type_params(Mode::Encode, bound, params, &blacklist, &field_attrs);
211211
}
212212

213213
let generics = add_typeparam(&inp.generics, gen_ctx_param()?, enum_attrs.context_bound());

0 commit comments

Comments
 (0)