From c1d5996b770deec35b4249dd7fbe6c39e976cad9 Mon Sep 17 00:00:00 2001 From: 6d7a Date: Sun, 2 Mar 2025 20:44:21 +0100 Subject: [PATCH] fix(rasn): correctly bind nested list item constraints --- rasn-compiler-tests/tests/parameterization.rs | 6 +- rasn-compiler-tests/tests/structured_types.rs | 81 ++++++++++++++++++- rasn-compiler/src/generator/rasn/utils.rs | 31 +++++-- rasn-compiler/src/generator/tests.rs | 0 rasn-compiler/src/lexer/sequence.rs | 44 ++++++++++ rasn-compiler/src/validator/mod.rs | 2 +- 6 files changed, 148 insertions(+), 16 deletions(-) create mode 100644 rasn-compiler/src/generator/tests.rs diff --git a/rasn-compiler-tests/tests/parameterization.rs b/rasn-compiler-tests/tests/parameterization.rs index dbba0ce..0def266 100644 --- a/rasn-compiler-tests/tests/parameterization.rs +++ b/rasn-compiler-tests/tests/parameterization.rs @@ -114,13 +114,13 @@ e2e_pdu! { pub struct A2XPC5FlowBitRates { #[rasn(identifier = "a2X-GuaranteedFlowBitRate")] pub a2_x__guaranteed_flow_bit_rate: bool, - #[rasn(size("1.."), identifier = "iE-Extensions")] - pub i_e__extensions: Option>, + #[rasn(identifier = "iE-Extensions")] + pub i_e__extensions: Option, } impl A2XPC5FlowBitRates { pub fn new( a2_x__guaranteed_flow_bit_rate: bool, - i_e__extensions: Option>, + i_e__extensions: Option, ) -> Self { Self { a2_x__guaranteed_flow_bit_rate, diff --git a/rasn-compiler-tests/tests/structured_types.rs b/rasn-compiler-tests/tests/structured_types.rs index 614dd47..54eadc8 100644 --- a/rasn-compiler-tests/tests/structured_types.rs +++ b/rasn-compiler-tests/tests/structured_types.rs @@ -207,10 +207,8 @@ e2e_pdu!( #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)] #[rasn(choice, automatic_tags)] pub enum TFCSReconfAddR12CtfcSize { - #[rasn(size("1..=1024"))] - ctfc8Bit(SequenceOf), - #[rasn(size("1..=1024"))] - ctfc16Bit(SequenceOf), + ctfc8Bit(TFCSReconfAddR12CtfcSizeCtfc8Bit), + ctfc16Bit(TFCSReconfAddR12CtfcSizeCtfc16Bit), } #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)] #[rasn(automatic_tags, identifier = "TFCS-ReconfAdd-r12")] @@ -326,3 +324,78 @@ e2e_pdu!( } "# ); + +e2e_pdu!( + anonymous_sequence_of_item_in_sequence_member, + r#" + Ticket ::= SEQUENCE { + ages SEQUENCE OF INTEGER (1..5), + passenger Passenger OPTIONAL + } + + Passenger ::= ENUMERATED { + adult (0), + youth (1), + ... + } + "#, + r#" + #[derive(AsnType, Debug, Clone, Copy, Decode, Encode, PartialEq, Eq, Hash)] + #[rasn(enumerated)] + #[non_exhaustive] + pub enum Passenger{ + adult = 0, + youth = 1, + } + + #[doc = " Anonymous SEQUENCE OF member "] + #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)] + #[rasn(delegate, value("1..=5"), identifier = "INTEGER")] + pub struct AnonymousTicketAges(pub u8); + + #[doc = " Inner type "] + #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)] + #[rasn(delegate)] + pub struct TicketAges(pub SequenceOf); + + #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)] + #[rasn(automatic_tags)] + pub struct Ticket { + pub ages: TicketAges, + pub passenger: Option, + } + + impl Ticket { + pub fn new(ages: TicketAges, passenger: Option) -> Self { + Self { ages, passenger } + } + } + "# +); + +e2e_pdu!( + anonymous_set_of_item_in_choice_option, + r#" + Ticket ::= CHOICE { + age-set SET (SIZE (1..4)) OF INTEGER (1..5) + } + "#, + r#" + #[doc = " Anonymous SET OF member "] + #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)] + #[rasn(delegate, value("1..=5"), identifier = "INTEGER")] + pub struct AnonymousTicketAgeSet(pub u8); + + #[doc = " Inner type "] + #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)] + #[rasn(delegate, size("1..=4"))] + pub struct TicketAgeSet(pub SetOf); + + #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)] + #[rasn(choice, automatic_tags)] + pub enum Ticket { + #[rasn(identifier = "age-set")] + age_set(TicketAgeSet), + } + "# +); \ No newline at end of file diff --git a/rasn-compiler/src/generator/rasn/utils.rs b/rasn-compiler/src/generator/rasn/utils.rs index b9b927a..495d2d0 100644 --- a/rasn-compiler/src/generator/rasn/utils.rs +++ b/rasn-compiler/src/generator/rasn/utils.rs @@ -1,4 +1,4 @@ -use std::str::FromStr; +use std::{ops::Not, str::FromStr}; use proc_macro2::{Ident, Literal, Punct, Spacing, Span, TokenStream}; use quote::{format_ident, quote, ToTokens, TokenStreamExt}; @@ -310,7 +310,7 @@ impl Rasn { sequence_or_set.members.iter().enumerate().try_fold( FormattedMembers::default(), |mut acc, (i, m)| { - let nested = if self.needs_unnesting(&m.ty) { + let nested = if Self::needs_unnesting(&m.ty) { Some( self.generate_tld(ToplevelDefinition::Type(ToplevelTypeDefinition { parameterization: None, @@ -363,7 +363,13 @@ impl Rasn { parent_name, member.is_recursive, )?; - all_constraints.append(&mut member.constraints.clone()); + if Self::needs_unnesting(&member.ty) { + formatted_type_name = self.inner_name(&member.name, parent_name).to_token_stream(); + // All constraints are applied on the delegate type + all_constraints = Vec::new(); + } else { + all_constraints.append(&mut member.constraints.clone()); + } if (member.is_optional && member.default_value.is_none()) || member.name.starts_with("ext_group_") { @@ -418,7 +424,7 @@ impl Rasn { choice.options.iter().enumerate().try_fold( FormattedOptions::default(), |mut acc, (i, o)| { - let nested = if self.needs_unnesting(&o.ty) { + let nested = if Self::needs_unnesting(&o.ty) { Some( self.generate_tld(ToplevelDefinition::Type(ToplevelTypeDefinition { parameterization: None, @@ -463,13 +469,19 @@ impl Rasn { parent_name: &String, extension_annotation: TokenStream, ) -> Result { - let (mut all_constraints, formatted_type_name) = self.constraints_and_type_name( + let (mut all_constraints, mut formatted_type_name) = self.constraints_and_type_name( &member.ty, &member.name, parent_name, member.is_recursive, )?; - all_constraints.append(&mut member.constraints.clone()); + if Self::needs_unnesting(&member.ty) { + formatted_type_name = self.inner_name(&member.name, parent_name).to_token_stream(); + // All constraints are applied on the delegate type + all_constraints = Vec::new(); + } else { + all_constraints.append(&mut member.constraints.clone()); + } let range_annotations = self.format_range_annotations( matches!(member.ty, ASN1Type::Integer(_)), &all_constraints, @@ -882,7 +894,7 @@ impl Rasn { } } - pub(crate) fn needs_unnesting(&self, ty: &ASN1Type) -> bool { + pub(crate) fn needs_unnesting(ty: &ASN1Type) -> bool { match ty { ASN1Type::Enumerated(_) | ASN1Type::Choice(_) @@ -890,7 +902,10 @@ impl Rasn { | ASN1Type::Set(_) => true, ASN1Type::SequenceOf(SequenceOrSetOf { element_type, .. }) | ASN1Type::SetOf(SequenceOrSetOf { element_type, .. }) => { - self.needs_unnesting(element_type) + Self::needs_unnesting(element_type) + || element_type + .constraints() + .is_some_and(|c| c.is_empty().not()) } _ => false, } diff --git a/rasn-compiler/src/generator/tests.rs b/rasn-compiler/src/generator/tests.rs new file mode 100644 index 0000000..e69de29 diff --git a/rasn-compiler/src/lexer/sequence.rs b/rasn-compiler/src/lexer/sequence.rs index 7affef4..42275ec 100644 --- a/rasn-compiler/src/lexer/sequence.rs +++ b/rasn-compiler/src/lexer/sequence.rs @@ -823,4 +823,48 @@ integrityCheckValue ICV OPTIONAL ]) ); } + + #[test] + fn parses_anonymous_sequence_of_item_in_field() { + assert_eq!( + sequence( + r#" + SEQUENCE { + ages SEQUENCE OF INTEGER (1..5) + } + "# + .into() + ) + .unwrap() + .1, + ASN1Type::Sequence(SequenceOrSet { + components_of: vec![], + extensible: None, + constraints: vec![], + members: vec![SequenceOrSetMember { + name: "ages".into(), + tag: None, + ty: ASN1Type::SequenceOf(SequenceOrSetOf { + constraints: vec![], + element_type: Box::new(ASN1Type::Integer(Integer { + constraints: vec![Constraint::SubtypeConstraint(ElementSet { + set: ElementOrSetOperation::Element(SubtypeElement::ValueRange { + min: Some(ASN1Value::Integer(1,),), + max: Some(ASN1Value::Integer(5,),), + extensible: false, + },), + extensible: false, + },),], + distinguished_values: None, + },)), + is_recursive: false, + },), + default_value: None, + is_optional: false, + is_recursive: false, + constraints: vec![], + }], + },) + ) + } } diff --git a/rasn-compiler/src/validator/mod.rs b/rasn-compiler/src/validator/mod.rs index d5afc22..8651668 100644 --- a/rasn-compiler/src/validator/mod.rs +++ b/rasn-compiler/src/validator/mod.rs @@ -50,7 +50,7 @@ impl Validator { fn link(mut self) -> Result<(Self, Vec), LinkerError> { let mut warnings: Vec = vec![]; - // Linking of ASN1 values depends on linked ASN1 types, so we order the key colelction accordingly (note that we pop keys) + // Linking of ASN1 values depends on linked ASN1 types, so we order the key collection accordingly (note that we pop keys) let mut keys = self .tlds .iter()