Skip to content

Commit e23fbf1

Browse files
authored
Fixed perfect derives in conjunction with #[derive(Asn1DefinedByRead)] and #[derive(Asn1DefinedByWrite)] (#506)
1 parent f8ca030 commit e23fbf1

File tree

3 files changed

+137
-16
lines changed

3 files changed

+137
-16
lines changed

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,15 @@ asn1 = { version = "0.20", default-features = false }
2424

2525
## Changelog
2626

27+
### [0.20.1]
28+
29+
#### Fixes
30+
31+
- Fixed ["perfect derives"](https://smallcultfollowing.com/babysteps/blog/2022/04/12/implied-bounds-and-perfect-derive/)
32+
in conjunction with `#[derive(Asn1DefinedByRead)]` and
33+
`#[derive(Asn1DefinedByWrite)]`.
34+
([#506](https://github.com/alex/rust-asn1/pull/506))
35+
2736
### [0.20.0]
2837

2938
#### :rotating_light: Breaking changes

asn1_derive/src/lib.rs

Lines changed: 80 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ pub fn derive_asn1_read(input: proc_macro::TokenStream) -> proc_macro::TokenStre
1414
let lifetime_name = add_lifetime_if_none(&mut generics);
1515
add_bounds(
1616
&mut generics,
17-
all_field_types(&input.data, &input.generics),
17+
all_field_types(&input.data, false, &input.generics),
1818
syn::parse_quote!(asn1::Asn1Readable<#lifetime_name>),
1919
syn::parse_quote!(asn1::Asn1DefinedByReadable<#lifetime_name, asn1::ObjectIdentifier>),
2020
false,
@@ -61,7 +61,7 @@ pub fn derive_asn1_write(input: proc_macro::TokenStream) -> proc_macro::TokenStr
6161
let mut input = syn::parse_macro_input!(input as syn::DeriveInput);
6262

6363
let name = input.ident;
64-
let fields = all_field_types(&input.data, &input.generics);
64+
let fields = all_field_types(&input.data, false, &input.generics);
6565
add_bounds(
6666
&mut input.generics,
6767
fields,
@@ -146,10 +146,17 @@ pub fn derive_asn1_defined_by_read(input: proc_macro::TokenStream) -> proc_macro
146146
let input = syn::parse_macro_input!(input as syn::DeriveInput);
147147

148148
let name = input.ident;
149-
let (_, ty_generics, where_clause) = input.generics.split_for_impl();
149+
let (_, ty_generics, _) = input.generics.split_for_impl();
150150
let mut generics = input.generics.clone();
151151
let lifetime_name = add_lifetime_if_none(&mut generics);
152-
let (impl_generics, _, _) = generics.split_for_impl();
152+
add_bounds(
153+
&mut generics,
154+
all_field_types(&input.data, true, &input.generics),
155+
syn::parse_quote!(asn1::Asn1Readable<#lifetime_name>),
156+
syn::parse_quote!(asn1::Asn1DefinedByReadable<#lifetime_name, asn1::ObjectIdentifier>),
157+
false,
158+
);
159+
let (impl_generics, _, where_clause) = generics.split_for_impl();
153160

154161
let mut read_block = vec![];
155162
let mut default_ident = None;
@@ -204,9 +211,17 @@ pub fn derive_asn1_defined_by_read(input: proc_macro::TokenStream) -> proc_macro
204211

205212
#[proc_macro_derive(Asn1DefinedByWrite, attributes(default, defined_by))]
206213
pub fn derive_asn1_defined_by_write(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
207-
let input = syn::parse_macro_input!(input as syn::DeriveInput);
214+
let mut input = syn::parse_macro_input!(input as syn::DeriveInput);
208215

209216
let name = input.ident;
217+
let fields = all_field_types(&input.data, true, &input.generics);
218+
add_bounds(
219+
&mut input.generics,
220+
fields,
221+
syn::parse_quote!(asn1::Asn1Writable),
222+
syn::parse_quote!(asn1::Asn1DefinedByWritable<asn1::ObjectIdentifier>),
223+
true,
224+
);
210225
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
211226

212227
let mut write_blocks = vec![];
@@ -273,10 +288,19 @@ fn add_lifetime_if_none(generics: &mut syn::Generics) -> syn::Lifetime {
273288
)));
274289
};
275290

276-
generics.lifetimes().next().unwrap().lifetime.clone()
291+
generics
292+
.lifetimes()
293+
.next()
294+
.expect("No lifetime found")
295+
.lifetime
296+
.clone()
277297
}
278298

279-
fn all_field_types(data: &syn::Data, generics: &syn::Generics) -> Vec<(syn::Type, OpType, bool)> {
299+
fn all_field_types(
300+
data: &syn::Data,
301+
ignore_properties: bool,
302+
generics: &syn::Generics,
303+
) -> Vec<(syn::Type, OpType, bool)> {
280304
let generic_params = generics
281305
.params
282306
.iter()
@@ -292,15 +316,27 @@ fn all_field_types(data: &syn::Data, generics: &syn::Generics) -> Vec<(syn::Type
292316
let mut field_types = vec![];
293317
match data {
294318
syn::Data::Struct(v) => {
295-
add_field_types(&mut field_types, &v.fields, None, &generic_params);
319+
add_field_types(
320+
&mut field_types,
321+
&v.fields,
322+
None,
323+
ignore_properties,
324+
&generic_params,
325+
);
296326
}
297327
syn::Data::Enum(v) => {
298328
for variant in &v.variants {
299-
let (op_type, _) = extract_field_properties(&variant.attrs);
329+
let op_type = if ignore_properties {
330+
None
331+
} else {
332+
let (op_type, _) = extract_field_properties(&variant.attrs);
333+
Some(op_type)
334+
};
300335
add_field_types(
301336
&mut field_types,
302337
&variant.fields,
303-
Some(op_type),
338+
op_type,
339+
ignore_properties,
304340
&generic_params,
305341
);
306342
}
@@ -314,17 +350,30 @@ fn add_field_types(
314350
field_types: &mut Vec<(syn::Type, OpType, bool)>,
315351
fields: &syn::Fields,
316352
op_type: Option<OpType>,
353+
ignore_properties: bool,
317354
generic_params: &[syn::Ident],
318355
) {
319356
match fields {
320357
syn::Fields::Named(v) => {
321358
for f in &v.named {
322-
add_field_type(field_types, f, op_type.clone(), generic_params);
359+
add_field_type(
360+
field_types,
361+
f,
362+
op_type.clone(),
363+
ignore_properties,
364+
generic_params,
365+
);
323366
}
324367
}
325368
syn::Fields::Unnamed(v) => {
326369
for f in &v.unnamed {
327-
add_field_type(field_types, f, op_type.clone(), generic_params);
370+
add_field_type(
371+
field_types,
372+
f,
373+
op_type.clone(),
374+
ignore_properties,
375+
generic_params,
376+
);
328377
}
329378
}
330379
syn::Fields::Unit => {}
@@ -376,6 +425,7 @@ fn add_field_type(
376425
field_types: &mut Vec<(syn::Type, OpType, bool)>,
377426
f: &syn::Field,
378427
op_type: Option<OpType>,
428+
ignore_properties: bool,
379429
generic_params: &[syn::Ident],
380430
) {
381431
if !type_contains_generic_param(&f.ty, generic_params) {
@@ -391,6 +441,8 @@ fn add_field_type(
391441
} else if let Some(OpType::Implicit(mut args)) = op_type {
392442
args.required = true;
393443
(OpType::Implicit(args), None)
444+
} else if ignore_properties {
445+
(OpType::Regular, None)
394446
} else {
395447
extract_field_properties(&f.attrs)
396448
};
@@ -508,21 +560,33 @@ fn extract_field_properties(attrs: &[syn::Attribute]) -> (OpType, Option<syn::Ex
508560
for attr in attrs {
509561
if attr.path().is_ident("explicit") {
510562
if let OpType::Regular = op_type {
511-
op_type = OpType::Explicit(attr.parse_args::<OpTypeArgs>().unwrap());
563+
op_type = OpType::Explicit(
564+
attr.parse_args::<OpTypeArgs>()
565+
.expect("Error parsing #[explicit]"),
566+
);
512567
} else {
513568
panic!("Can't specify #[explicit] or #[implicit] more than once")
514569
}
515570
} else if attr.path().is_ident("implicit") {
516571
if let OpType::Regular = op_type {
517-
op_type = OpType::Implicit(attr.parse_args::<OpTypeArgs>().unwrap());
572+
op_type = OpType::Implicit(
573+
attr.parse_args::<OpTypeArgs>()
574+
.expect("Error parsing #[implicit]"),
575+
);
518576
} else {
519577
panic!("Can't specify #[explicit] or #[implicit] more than once")
520578
}
521579
} else if attr.path().is_ident("default") {
522580
assert!(default.is_none(), "Can't specify #[default] more than once");
523-
default = Some(attr.parse_args::<syn::Expr>().unwrap());
581+
default = Some(
582+
attr.parse_args::<syn::Expr>()
583+
.expect("Error parsing #[default]"),
584+
);
524585
} else if attr.path().is_ident("defined_by") {
525-
op_type = OpType::DefinedBy(attr.parse_args::<syn::Ident>().unwrap());
586+
op_type = OpType::DefinedBy(
587+
attr.parse_args::<syn::Ident>()
588+
.expect("Error parsing #[defined_by]"),
589+
);
526590
}
527591
}
528592

tests/derive_test.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -828,3 +828,51 @@ fn test_perfect_derive() {
828828
(Ok(TaggedEnum::Explicit(1)), b"\xa1\x03\x02\x01\x01"),
829829
]);
830830
}
831+
832+
#[test]
833+
fn test_defined_by_perfect_derive() {
834+
trait X {
835+
type Type: PartialEq + std::fmt::Debug;
836+
}
837+
838+
#[derive(PartialEq, Debug)]
839+
struct Op;
840+
impl X for Op {
841+
type Type = u64;
842+
}
843+
844+
#[derive(asn1::Asn1Read, asn1::Asn1Write, PartialEq, Debug)]
845+
struct S<T: X> {
846+
oid: asn1::DefinedByMarker<asn1::ObjectIdentifier>,
847+
#[defined_by(oid)]
848+
value: Value<T>,
849+
}
850+
851+
pub const OID1: asn1::ObjectIdentifier = asn1::oid!(1, 2, 3);
852+
pub const OID2: asn1::ObjectIdentifier = asn1::oid!(1, 2, 4);
853+
854+
#[derive(asn1::Asn1DefinedByRead, asn1::Asn1DefinedByWrite, PartialEq, Debug)]
855+
enum Value<T: X> {
856+
#[defined_by(OID1)]
857+
A(T::Type),
858+
#[defined_by(OID2)]
859+
B(T::Type),
860+
}
861+
862+
assert_roundtrips::<S<Op>>(&[
863+
(
864+
Ok(S {
865+
oid: asn1::DefinedByMarker::marker(),
866+
value: Value::A(5),
867+
}),
868+
b"\x30\x07\x06\x02\x2a\x03\x02\x01\x05",
869+
),
870+
(
871+
Ok(S {
872+
oid: asn1::DefinedByMarker::marker(),
873+
value: Value::B(7),
874+
}),
875+
b"\x30\x07\x06\x02\x2a\x04\x02\x01\x07",
876+
),
877+
]);
878+
}

0 commit comments

Comments
 (0)