Skip to content

Commit

Permalink
Fixes librasn#418. Updating macro and backend code to support default…
Browse files Browse the repository at this point in the history
… values with explicit tags. Adding test cases for this in a couple different scenarios.
  • Loading branch information
jusbeyer committed Mar 6, 2025
1 parent d97c44d commit 54726cd
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 3 deletions.
9 changes: 7 additions & 2 deletions macros/macros_impl/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -846,8 +846,13 @@ impl<'a> FieldConfig<'a> {

let encode = if self.tag.is_some() || self.container_config.automatic_tags {
if self.tag.as_ref().is_some_and(|tag| tag.is_explicit()) {
// Note: encoder must be aware if the field is optional and present, so we should not do the presence check on this level
quote!(encoder.encode_explicit_prefix(#tag, &self.#field)?;)
if self.default.is_some() {
// Note: encoder must be aware if the field is optional and present, so we should not do the presence check on this level
quote!(encoder.encode_default_with_explicit_prefix(#tag, &self.#field, #default_fn)?;)
} else {
// Note: encoder must be aware if the field is optional and present, so we should not do the presence check on this level
quote!(encoder.encode_explicit_prefix(#tag, &self.#field)?;)
}
} else if self.extension_addition {
quote!(
#constraint_def
Expand Down
16 changes: 15 additions & 1 deletion src/enc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,20 @@ pub trait Encoder<'encoder, const RCL: usize = 0, const ECL: usize = 0> {
}
}

/// Encode the preset value of an optional field using Explicit Tags
fn encode_default_with_explicit_prefix<E: Encode + PartialEq>(
&mut self,
tag: Tag,
value: &E,
default: impl FnOnce() -> E,
) -> Result<Self::Ok, Self::Error> {
match (*value != (default)()).then_some(value) {
Some(value) => self.encode_explicit_prefix(tag, value),
// TODO: We need to figure out why this is putting a NULL in when it should just be skipping
None => self.encode_none_with_tag(tag),
}
}

/// Encode the present value of an optional field.
fn encode_default_with_tag_and_constraints<E: Encode + PartialEq>(
&mut self,
Expand All @@ -368,7 +382,7 @@ pub trait Encoder<'encoder, const RCL: usize = 0, const ECL: usize = 0> {
) -> Result<Self::Ok, Self::Error> {
match (*value != (default)()).then_some(value) {
Some(value) => self.encode_some_with_tag_and_constraints(tag, constraints, value),
None => self.encode_none_with_tag(tag),
None => self.encode_none::<E>(),
}
}

Expand Down
37 changes: 37 additions & 0 deletions tests/explicit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,23 @@ pub struct Sequence {
b: bool,
}

#[derive(AsnType, Decode, Debug, Encode, PartialEq)]
pub struct SequenceWithDefault {
#[rasn(tag(explicit(application, 1)), default = "default_bool")]
b: bool,
}

#[derive(AsnType, Decode, Debug, Encode, PartialEq)]
pub struct SequenceWithMultiDefault {
#[rasn(tag(explicit(application, 1)), default = "default_bool")]
b: bool,
#[rasn(tag(explicit(application, 2)), default = "default_bool")]
b2: bool,
}
pub fn default_bool() -> bool {
true
}

#[derive(AsnType, Decode, Debug, Encode, PartialEq)]
#[rasn(tag(explicit(application, 1)))]
pub struct InlineSequence {
Expand Down Expand Up @@ -67,6 +84,13 @@ const _: () = assert!(Tag::const_eq(DelegateSequence::TAG, &InlineSet::TAG,));
#[test]
fn works() {
const EXPECTED: &[u8] = &[0x61, 0x5, 0x30, 0x3, 0x01, 0x1, 0xFF];
// Note that the explicitly tagged field is dropped.
// This makes it a sequence with 0 elements
const EXPECTED_DEFAULT: &[u8] = &[0x30, 0x00];
const EXPECTED_NOT_DEFAULT: &[u8] = &[0x30, 0x05, 0x61, 0x03, 0x01, 0x01, 0x00];
// NOTE: The explicit tag number is just different
const EXPECTED_MULTI_DEFAULT: &[u8] = &[0x30, 0x05, 0x62, 0x03, 0x01, 0x01, 0x00];

let delegate_seq = DelegateSequence(Sequence { b: true });
let inline_seq = InlineSequence { b: true };
let field_seq = SequenceField { b: true };
Expand All @@ -84,6 +108,19 @@ fn works() {
let inline_choice_enc = rasn::der::encode(&inline_choice).unwrap();
let wrapped_choice_enc = rasn::der::encode(&wrapped_choice).unwrap();

// Set the field to match the default value to have it dropped
let sequence_default = SequenceWithDefault { b: true };
let sequence_non_default = SequenceWithDefault { b: false };
let sequence_default_enc = rasn::der::encode(&sequence_default).unwrap();
let sequence_non_default_enc = rasn::der::encode(&sequence_non_default).unwrap();
// Verify it correctly includes encoded fields
let sequence_multi_default = SequenceWithMultiDefault { b: true, b2: false };
let sequence_multi_default_enc = rasn::der::encode(&sequence_multi_default).unwrap();

assert_eq!(sequence_non_default_enc, EXPECTED_NOT_DEFAULT);
assert_eq!(sequence_default_enc, EXPECTED_DEFAULT);
assert_eq!(sequence_multi_default_enc, EXPECTED_MULTI_DEFAULT);

assert_eq!(delegate_seq_enc, EXPECTED);
assert_eq!(inline_seq_enc, EXPECTED);
assert_eq!(field_seq_enc, EXPECTED);
Expand Down

0 comments on commit 54726cd

Please sign in to comment.