Skip to content

Commit e0910cd

Browse files
authored
der_derive: add DecodeValue, EncodeValue macros (#1722)
* der_derive: add SequenceDecode, SequenceEncode macros * der_derive: rename macros to DecodeValue, EncodeValue
1 parent 4f2771d commit e0910cd

File tree

4 files changed

+145
-22
lines changed

4 files changed

+145
-22
lines changed

der/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,7 @@ pub use crate::{
385385
pub use crate::{asn1::Any, document::Document};
386386

387387
#[cfg(feature = "derive")]
388-
pub use der_derive::{BitString, Choice, Enumerated, Sequence, ValueOrd};
388+
pub use der_derive::{BitString, Choice, DecodeValue, EncodeValue, Enumerated, Sequence, ValueOrd};
389389

390390
#[cfg(feature = "flagset")]
391391
pub use flagset;

der/tests/derive.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -735,6 +735,56 @@ mod sequence {
735735
}
736736
}
737737

738+
/// Custom derive test cases for the `EncodeValue` macro.
739+
mod encode_value {
740+
use der::{Encode, EncodeValue, FixedTag, Tag};
741+
use hex_literal::hex;
742+
743+
#[derive(EncodeValue, Default, Eq, PartialEq, Debug)]
744+
#[asn1(tag_mode = "IMPLICIT")]
745+
pub struct EncodeOnlyCheck<'a> {
746+
#[asn1(type = "OCTET STRING", context_specific = "5")]
747+
pub field: &'a [u8],
748+
}
749+
impl FixedTag for EncodeOnlyCheck<'_> {
750+
const TAG: Tag = Tag::Sequence;
751+
}
752+
753+
#[test]
754+
fn sequence_encode_only_to_der() {
755+
let obj = EncodeOnlyCheck {
756+
field: &[0x33, 0x44],
757+
};
758+
759+
let der_encoded = obj.to_der().unwrap();
760+
761+
assert_eq!(der_encoded, hex!("30 04 85 02 33 44"));
762+
}
763+
}
764+
765+
/// Custom derive test cases for the `DecodeValue` macro.
766+
mod decode_value {
767+
use der::{Decode, DecodeValue, FixedTag, Tag};
768+
use hex_literal::hex;
769+
770+
#[derive(DecodeValue, Default, Eq, PartialEq, Debug)]
771+
#[asn1(tag_mode = "IMPLICIT")]
772+
pub struct DecodeOnlyCheck<'a> {
773+
#[asn1(type = "OCTET STRING", context_specific = "5")]
774+
pub field: &'a [u8],
775+
}
776+
impl FixedTag for DecodeOnlyCheck<'_> {
777+
const TAG: Tag = Tag::Sequence;
778+
}
779+
780+
#[test]
781+
fn sequence_decode_only_from_der() {
782+
let obj = DecodeOnlyCheck::from_der(&hex!("30 04 85 02 33 44")).unwrap();
783+
784+
assert_eq!(obj.field, &[0x33, 0x44]);
785+
}
786+
}
787+
738788
/// Custom derive test cases for the `BitString` macro.
739789
#[cfg(feature = "std")]
740790
mod bitstring {

der_derive/src/lib.rs

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ pub fn derive_enumerated(input: TokenStream) -> TokenStream {
261261
}
262262
}
263263

264-
/// Derive the [`Sequence`][1] trait on a `struct`.
264+
/// Derive the [`DecodeValue`][1], [`EncodeValue`][2], [`Sequence`][3] traits on a `struct`.
265265
///
266266
/// This custom derive macro can be used to automatically impl the
267267
/// `Sequence` trait for any struct which can be decoded/encoded as an
@@ -289,16 +289,42 @@ pub fn derive_enumerated(input: TokenStream) -> TokenStream {
289289
///
290290
/// # `#[asn1(type = "...")]` attribute
291291
///
292-
/// See [toplevel documentation for the `der_derive` crate][2] for more
292+
/// See [toplevel documentation for the `der_derive` crate][4] for more
293293
/// information about the `#[asn1]` attribute.
294294
///
295-
/// [1]: https://docs.rs/der/latest/der/trait.Sequence.html
296-
/// [2]: https://docs.rs/der_derive/
295+
/// [1]: https://docs.rs/der/latest/der/trait.DecodeValue.html
296+
/// [2]: https://docs.rs/der/latest/der/trait.EncodeValue.html
297+
/// [3]: https://docs.rs/der/latest/der/trait.Sequence.html
298+
/// [4]: https://docs.rs/der_derive/
297299
#[proc_macro_derive(Sequence, attributes(asn1))]
298300
pub fn derive_sequence(input: TokenStream) -> TokenStream {
299301
let input = parse_macro_input!(input as DeriveInput);
300302
match DeriveSequence::new(input) {
301-
Ok(t) => t.to_tokens().into(),
303+
Ok(t) => t.to_tokens_all().into(),
304+
Err(e) => e.to_compile_error().into(),
305+
}
306+
}
307+
308+
/// Derive the [`EncodeValue`][1] trait on a `struct`.
309+
///
310+
/// [1]: https://docs.rs/der/latest/der/trait.EncodeValue.html
311+
#[proc_macro_derive(EncodeValue, attributes(asn1))]
312+
pub fn derive_sequence_encode(input: TokenStream) -> TokenStream {
313+
let input = parse_macro_input!(input as DeriveInput);
314+
match DeriveSequence::new(input) {
315+
Ok(t) => t.to_tokens_encode().into(),
316+
Err(e) => e.to_compile_error().into(),
317+
}
318+
}
319+
320+
/// Derive the [`DecodeValue`][1] trait on a `struct`.
321+
///
322+
/// [1]: https://docs.rs/der/latest/der/trait.DecodeValue.html
323+
#[proc_macro_derive(DecodeValue, attributes(asn1))]
324+
pub fn derive_sequence_decode(input: TokenStream) -> TokenStream {
325+
let input = parse_macro_input!(input as DeriveInput);
326+
match DeriveSequence::new(input) {
327+
Ok(t) => t.to_tokens_decode().into(),
302328
Err(e) => e.to_compile_error().into(),
303329
}
304330
}

der_derive/src/sequence.rs

Lines changed: 63 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use crate::{ErrorType, TypeAttrs, default_lifetime};
77
use field::SequenceField;
88
use proc_macro2::TokenStream;
99
use quote::{ToTokens, quote};
10-
use syn::{DeriveInput, GenericParam, Generics, Ident, LifetimeParam};
10+
use syn::{DeriveInput, GenericParam, Generics, Ident, Lifetime, LifetimeParam};
1111

1212
/// Derive the `Sequence` trait for a struct
1313
pub(crate) struct DeriveSequence {
@@ -51,13 +51,10 @@ impl DeriveSequence {
5151
})
5252
}
5353

54-
/// Lower the derived output into a [`TokenStream`].
55-
pub fn to_tokens(&self) -> TokenStream {
56-
let ident = &self.ident;
54+
/// Use the first lifetime parameter as lifetime for Decode/Encode lifetime
55+
/// if none found, add one.
56+
fn calc_lifetime(&self) -> (Generics, Lifetime) {
5757
let mut generics = self.generics.clone();
58-
59-
// Use the first lifetime parameter as lifetime for Decode/Encode lifetime
60-
// if none found, add one.
6158
let lifetime = generics
6259
.lifetimes()
6360
.next()
@@ -69,23 +66,39 @@ impl DeriveSequence {
6966
.insert(0, GenericParam::Lifetime(LifetimeParam::new(lt.clone())));
7067
lt
7168
});
72-
7369
// We may or may not have inserted a lifetime.
70+
(generics, lifetime)
71+
}
72+
73+
/// Lower the derived output into a [`TokenStream`] for Sequence trait impl.
74+
pub fn to_tokens_sequence_trait(&self) -> TokenStream {
75+
let ident = &self.ident;
76+
77+
let (der_generics, lifetime) = self.calc_lifetime();
78+
7479
let (_, ty_generics, where_clause) = self.generics.split_for_impl();
75-
let (impl_generics, _, _) = generics.split_for_impl();
80+
let (impl_generics, _, _) = der_generics.split_for_impl();
81+
82+
quote! {
83+
impl #impl_generics ::der::Sequence<#lifetime> for #ident #ty_generics #where_clause {}
84+
}
85+
}
86+
87+
/// Lower the derived output into a [`TokenStream`] for DecodeValue trait impl.
88+
pub fn to_tokens_decode(&self) -> TokenStream {
89+
let ident = &self.ident;
90+
91+
let (der_generics, lifetime) = self.calc_lifetime();
92+
93+
let (_, ty_generics, where_clause) = self.generics.split_for_impl();
94+
let (impl_generics, _, _) = der_generics.split_for_impl();
7695

7796
let mut decode_body = Vec::new();
7897
let mut decode_result = Vec::new();
79-
let mut encoded_lengths = Vec::new();
80-
let mut encode_fields = Vec::new();
8198

8299
for field in &self.fields {
83100
decode_body.push(field.to_decode_tokens());
84101
decode_result.push(&field.ident);
85-
86-
let field = field.to_encode_tokens();
87-
encoded_lengths.push(quote!(#field.encoded_len()?));
88-
encode_fields.push(quote!(#field.encode(writer)?;));
89102
}
90103

91104
let error = self.error.to_token_stream();
@@ -109,6 +122,26 @@ impl DeriveSequence {
109122
})
110123
}
111124
}
125+
}
126+
}
127+
128+
/// Lower the derived output into a [`TokenStream`] for EncodeValue trait impl.
129+
pub fn to_tokens_encode(&self) -> TokenStream {
130+
let ident = &self.ident;
131+
132+
let (_, ty_generics, where_clause) = self.generics.split_for_impl();
133+
let (impl_generics, _, _) = self.generics.split_for_impl();
134+
135+
let mut encoded_lengths = Vec::new();
136+
let mut encode_fields = Vec::new();
137+
138+
for field in &self.fields {
139+
let field = field.to_encode_tokens();
140+
encoded_lengths.push(quote!(#field.encoded_len()?));
141+
encode_fields.push(quote!(#field.encode(writer)?;));
142+
}
143+
144+
quote! {
112145

113146
impl #impl_generics ::der::EncodeValue for #ident #ty_generics #where_clause {
114147
fn value_len(&self) -> ::der::Result<::der::Length> {
@@ -127,8 +160,22 @@ impl DeriveSequence {
127160
Ok(())
128161
}
129162
}
163+
}
164+
}
130165

131-
impl #impl_generics ::der::Sequence<#lifetime> for #ident #ty_generics #where_clause {}
166+
/// Lower the derived output into a [`TokenStream`] for trait impls:
167+
/// - EncodeValue
168+
/// - DecodeValue
169+
/// - Sequence
170+
pub fn to_tokens_all(&self) -> TokenStream {
171+
let decode_tokens = self.to_tokens_decode();
172+
let encode_tokens = self.to_tokens_encode();
173+
let sequence_trait_tokens = self.to_tokens_sequence_trait();
174+
175+
quote! {
176+
#decode_tokens
177+
#encode_tokens
178+
#sequence_trait_tokens
132179
}
133180
}
134181
}

0 commit comments

Comments
 (0)