Skip to content

Commit 9a43031

Browse files
committed
der/derive: support for skipped field
the parsing profiles (RustCrypto#987) rely on a PhantomData field to specify the underlying profile used when parsing. This is specified like: ``` rust pub struct TbsCertificate<P: Profile = Rfc5280> { // ... #[asn1(skipped = "Default::default")] pub(crate) _profile: PhantomData<P>, } ```
1 parent 8c29e12 commit 9a43031

File tree

4 files changed

+105
-12
lines changed

4 files changed

+105
-12
lines changed

der/derive/src/attributes.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,9 @@ pub(crate) struct FieldAttrs {
7979

8080
/// Is the inner type constructed?
8181
pub constructed: bool,
82+
83+
/// Is the type skipped?
84+
pub skipped: Option<Path>,
8285
}
8386

8487
impl FieldAttrs {
@@ -98,6 +101,7 @@ impl FieldAttrs {
98101
let mut optional = None;
99102
let mut tag_mode = None;
100103
let mut constructed = None;
104+
let mut skipped = None;
101105

102106
let mut parsed_attrs = Vec::new();
103107
AttrNameValue::from_attributes(attrs, &mut parsed_attrs);
@@ -154,6 +158,15 @@ impl FieldAttrs {
154158
}
155159

156160
constructed = Some(ty);
161+
// `skipped` attribute
162+
} else if attr.parse_value::<String>("skipped").is_some() {
163+
if skipped.is_some() {
164+
abort!(attr.name, "duplicate ASN.1 `skipped` attribute");
165+
}
166+
167+
skipped = Some(attr.value.parse().unwrap_or_else(|e| {
168+
abort!(attr.value, "error parsing ASN.1 `skipped` attribute: {}", e)
169+
}));
157170
} else {
158171
abort!(
159172
attr.name,
@@ -171,6 +184,7 @@ impl FieldAttrs {
171184
optional: optional.unwrap_or_default(),
172185
tag_mode: tag_mode.unwrap_or(type_attrs.tag_mode),
173186
constructed: constructed.unwrap_or_default(),
187+
skipped,
174188
}
175189
}
176190

der/derive/src/sequence.rs

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use field::SequenceField;
88
use proc_macro2::TokenStream;
99
use proc_macro_error::abort;
1010
use quote::quote;
11-
use syn::{DeriveInput, Ident, Lifetime};
11+
use syn::{DeriveInput, Ident, Lifetime, TypeParam};
1212

1313
/// Derive the `Sequence` trait for a struct
1414
pub(crate) struct DeriveSequence {
@@ -18,6 +18,9 @@ pub(crate) struct DeriveSequence {
1818
/// Lifetime of the struct.
1919
lifetime: Option<Lifetime>,
2020

21+
/// Type param of the struct.
22+
type_param: Option<TypeParam>,
23+
2124
/// Fields of the struct.
2225
fields: Vec<SequenceField>,
2326
}
@@ -40,6 +43,8 @@ impl DeriveSequence {
4043
.next()
4144
.map(|lt| lt.lifetime.clone());
4245

46+
let type_param = input.generics.type_params().next().cloned();
47+
4348
let type_attrs = TypeAttrs::parse(&input.attrs);
4449

4550
let fields = data
@@ -51,6 +56,7 @@ impl DeriveSequence {
5156
Self {
5257
ident: input.ident,
5358
lifetime,
59+
type_param,
5460
fields,
5561
}
5662
}
@@ -72,6 +78,13 @@ impl DeriveSequence {
7278
.map(|_| lifetime.clone())
7379
.unwrap_or_default();
7480

81+
let type_params = self.type_param.as_ref().map(|t| {
82+
let mut t = t.clone();
83+
t.default = None;
84+
t
85+
});
86+
let type_params_names = self.type_param.as_ref().map(|t| t.ident.clone());
87+
7588
let mut decode_body = Vec::new();
7689
let mut decode_result = Vec::new();
7790
let mut encoded_lengths = Vec::new();
@@ -81,13 +94,14 @@ impl DeriveSequence {
8194
decode_body.push(field.to_decode_tokens());
8295
decode_result.push(&field.ident);
8396

84-
let field = field.to_encode_tokens();
85-
encoded_lengths.push(quote!(#field.encoded_len()?));
86-
encode_fields.push(quote!(#field.encode(writer)?;));
97+
if let Some(field) = field.to_encode_tokens() {
98+
encoded_lengths.push(quote!(#field.encoded_len()?));
99+
encode_fields.push(quote!(#field.encode(writer)?;));
100+
}
87101
}
88102

89103
quote! {
90-
impl<#lifetime> ::der::DecodeValue<#lifetime> for #ident<#lt_params> {
104+
impl<#lifetime, #type_params> ::der::DecodeValue<#lifetime> for #ident<#lt_params #type_params_names> {
91105
fn decode_value<R: ::der::Reader<#lifetime>>(
92106
reader: &mut R,
93107
header: ::der::Header,
@@ -104,7 +118,7 @@ impl DeriveSequence {
104118
}
105119
}
106120

107-
impl<#lifetime> ::der::EncodeValue for #ident<#lt_params> {
121+
impl<#lifetime, #type_params> ::der::EncodeValue for #ident<#lt_params #type_params_names> {
108122
fn value_len(&self) -> ::der::Result<::der::Length> {
109123
use ::der::Encode as _;
110124

@@ -122,7 +136,7 @@ impl DeriveSequence {
122136
}
123137
}
124138

125-
impl<#lifetime> ::der::Sequence<#lifetime> for #ident<#lt_params> {}
139+
impl<#lifetime, #type_params> ::der::Sequence<#lifetime> for #ident<#lt_params #type_params_names> {}
126140
}
127141
}
128142
}

der/derive/src/sequence/field.rs

Lines changed: 66 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,22 @@ impl SequenceField {
7272
}
7373
}
7474

75+
if let Some(default) = &self.attrs.skipped {
76+
let ident = &self.ident;
77+
return quote! {
78+
let #ident = #default();
79+
};
80+
}
81+
7582
lowerer.into_tokens(&self.ident)
7683
}
7784

7885
/// Derive code for encoding a field of a sequence.
79-
pub(super) fn to_encode_tokens(&self) -> TokenStream {
86+
pub(super) fn to_encode_tokens(&self) -> Option<TokenStream> {
87+
if self.attrs.skipped.is_some() {
88+
return None;
89+
}
90+
8091
let mut lowerer = LowerFieldEncoder::new(&self.ident);
8192
let attrs = &self.attrs;
8293

@@ -101,7 +112,7 @@ impl SequenceField {
101112
lowerer.apply_default(&self.ident, default);
102113
}
103114

104-
lowerer.into_tokens()
115+
Some(lowerer.into_tokens())
105116
}
106117
}
107118

@@ -241,7 +252,7 @@ mod tests {
241252
use crate::{FieldAttrs, TagMode, TagNumber};
242253
use proc_macro2::Span;
243254
use quote::quote;
244-
use syn::{punctuated::Punctuated, Ident, Path, PathSegment, Type, TypePath};
255+
use syn::{punctuated::Punctuated, Ident, Path, PathArguments, PathSegment, Type, TypePath};
245256

246257
/// Create a [`Type::Path`].
247258
pub fn type_path(ident: Ident) -> Type {
@@ -273,6 +284,7 @@ mod tests {
273284
optional: false,
274285
tag_mode: TagMode::Explicit,
275286
constructed: false,
287+
skipped: None,
276288
};
277289

278290
let field_type = Ident::new("String", span);
@@ -292,7 +304,7 @@ mod tests {
292304
);
293305

294306
assert_eq!(
295-
field.to_encode_tokens().to_string(),
307+
field.to_encode_tokens().unwrap().to_string(),
296308
quote! {
297309
self.example_field
298310
}
@@ -313,6 +325,7 @@ mod tests {
313325
optional: false,
314326
tag_mode: TagMode::Implicit,
315327
constructed: false,
328+
skipped: None,
316329
};
317330

318331
let field_type = Ident::new("String", span);
@@ -343,7 +356,7 @@ mod tests {
343356
);
344357

345358
assert_eq!(
346-
field.to_encode_tokens().to_string(),
359+
field.to_encode_tokens().unwrap().to_string(),
347360
quote! {
348361
::der::asn1::ContextSpecificRef {
349362
tag_number: ::der::TagNumber::N0,
@@ -354,4 +367,52 @@ mod tests {
354367
.to_string()
355368
);
356369
}
370+
371+
#[test]
372+
fn skipped() {
373+
let span = Span::call_site();
374+
let ident = Ident::new("skipped", span);
375+
376+
let mut segments = Punctuated::new();
377+
segments.push(PathSegment {
378+
ident: Ident::new("Default", span),
379+
arguments: PathArguments::None,
380+
});
381+
segments.push(PathSegment {
382+
ident: Ident::new("default", span),
383+
arguments: PathArguments::None,
384+
});
385+
386+
let attrs = FieldAttrs {
387+
asn1_type: None,
388+
context_specific: Some(TagNumber(0)),
389+
default: None,
390+
extensible: false,
391+
optional: false,
392+
tag_mode: TagMode::Implicit,
393+
constructed: false,
394+
skipped: Some(Path {
395+
leading_colon: None,
396+
segments,
397+
}),
398+
};
399+
400+
let field_type = Ident::new("String", span);
401+
402+
let field = SequenceField {
403+
ident,
404+
attrs,
405+
field_type: type_path(field_type),
406+
};
407+
408+
assert_eq!(
409+
field.to_decode_tokens().to_string(),
410+
quote! {
411+
let skipped = Default::default();
412+
}
413+
.to_string()
414+
);
415+
416+
assert!(field.to_encode_tokens().is_none());
417+
}
357418
}

der/derive/src/value_ord.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,10 @@ impl ValueField {
171171

172172
/// Lower to [`TokenStream`].
173173
fn to_tokens(&self) -> TokenStream {
174+
if self.attrs.skipped.is_some() {
175+
return TokenStream::default();
176+
}
177+
174178
let ident = &self.ident;
175179

176180
if self.is_enum {

0 commit comments

Comments
 (0)