From 3f556459092605071db013a12cfc1f845b77c521 Mon Sep 17 00:00:00 2001 From: Jean-Pierre Marcotte Date: Sun, 1 Feb 2026 10:41:41 -0500 Subject: [PATCH 01/13] Fix DEFAULT value generation for constrained integer newtypes When generating DEFAULT value functions for constrained integers like `UInt8 ::= INTEGER (0..255)`, the compiler now correctly wraps the literal in the newtype constructor. Before: `fn default() -> UInt8 { 8 }` After: `fn default() -> UInt8 { UInt8(8) }` Partially addresses #167 --- rasn-compiler-tests/tests/edge_cases.rs | 10 ++++ ...__constrained_integer_newtype_default.snap | 42 +++++++++++++++ rasn-compiler/src/generator/rasn/utils.rs | 51 +++++++++++++++++-- 3 files changed, 100 insertions(+), 3 deletions(-) create mode 100644 rasn-compiler-tests/tests/snapshots/edge_cases__constrained_integer_newtype_default.snap diff --git a/rasn-compiler-tests/tests/edge_cases.rs b/rasn-compiler-tests/tests/edge_cases.rs index 04351632..5a1a2a6e 100644 --- a/rasn-compiler-tests/tests/edge_cases.rs +++ b/rasn-compiler-tests/tests/edge_cases.rs @@ -126,3 +126,13 @@ e2e_pdu!( LDAPString ::= [UNIVERSAL 4] IMPLICIT UTF8String "# ); + +e2e_pdu!( + constrained_integer_newtype_default, + r#" + UInt8 ::= INTEGER (0..255) + MySeq ::= SEQUENCE { + value UInt8 DEFAULT 8 + } + "# +); diff --git a/rasn-compiler-tests/tests/snapshots/edge_cases__constrained_integer_newtype_default.snap b/rasn-compiler-tests/tests/snapshots/edge_cases__constrained_integer_newtype_default.snap new file mode 100644 index 00000000..0020b435 --- /dev/null +++ b/rasn-compiler-tests/tests/snapshots/edge_cases__constrained_integer_newtype_default.snap @@ -0,0 +1,42 @@ +--- +source: rasn-compiler-tests/tests/edge_cases.rs +description: "\n UInt8 ::= INTEGER (0..255)\n MySeq ::= SEQUENCE {\n value UInt8 DEFAULT 8\n }\n " +--- +Generated: +#[allow( + non_camel_case_types, + non_snake_case, + non_upper_case_globals, + unused, + clippy::too_many_arguments +)] +pub mod test_module { + extern crate alloc; + use core::borrow::Borrow; + use rasn::prelude::*; + use std::sync::LazyLock; + #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)] + #[rasn(automatic_tags)] + pub struct MySeq { + #[rasn(default = "my_seq_value_default")] + pub value: UInt8, + } + impl MySeq { + pub fn new(value: UInt8) -> Self { + Self { value } + } + } + impl std::default::Default for MySeq { + fn default() -> Self { + Self { + value: my_seq_value_default(), + } + } + } + fn my_seq_value_default() -> UInt8 { + UInt8(8) + } + #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)] + #[rasn(delegate, value("0..=255"))] + pub struct UInt8(pub u8); +} diff --git a/rasn-compiler/src/generator/rasn/utils.rs b/rasn-compiler/src/generator/rasn/utils.rs index 7d52e7bd..595075b6 100644 --- a/rasn-compiler/src/generator/rasn/utils.rs +++ b/rasn-compiler/src/generator/rasn/utils.rs @@ -833,7 +833,29 @@ impl Rasn { } } ASN1Value::Boolean(b) => Ok(b.to_token_stream()), - ASN1Value::Integer(i) => Ok(Literal::i128_unsuffixed(*i).to_token_stream()), + ASN1Value::Integer(i) => { + let literal = Literal::i128_unsuffixed(*i); + // Wrap in newtype if type_name is a custom type (not a primitive integer) + if let Some(ty) = type_name { + let ty_str = ty.to_string(); + if !matches!( + ty_str.as_str(), + "i8" | "u8" + | "i16" + | "u16" + | "i32" + | "u32" + | "i64" + | "u64" + | "i128" + | "u128" + | "Integer" + ) { + return Ok(quote!(#ty(#literal))); + } + } + Ok(literal.into_token_stream()) + } ASN1Value::String(s) => Ok(s.to_token_stream()), ASN1Value::Real(r) => Ok(r.to_token_stream()), ASN1Value::BitStringNamedBits(_) => Err(GeneratorError { @@ -879,9 +901,11 @@ impl Rasn { None => s, } } + // Pass None for type_name to inner value_to_tokens because nester + // handles the wrapping via supertypes Ok(nester( self, - self.value_to_tokens(value, type_name)?, + self.value_to_tokens(value, None)?, supertypes.clone(), )) } @@ -896,7 +920,28 @@ impl Rasn { let val = Literal::i128_suffixed(*value); Ok(quote!(Integer::from(#val))) } - _ => Ok(Literal::i128_unsuffixed(*value).into_token_stream()), + _ => { + let literal = Literal::i128_unsuffixed(*value); + // Wrap in newtype if type_name is a custom type (not a primitive integer) + if let Some(ty) = type_name { + let ty_str = ty.to_string(); + if !matches!( + ty_str.as_str(), + "i8" | "u8" + | "i16" + | "u16" + | "i32" + | "u32" + | "i64" + | "u64" + | "i128" + | "u128" + ) { + return Ok(quote!(#ty(#literal))); + } + } + Ok(literal.into_token_stream()) + } } } ASN1Value::LinkedCharStringValue(string_type, value) => { From babaed46b1b93fa5c92ffc7b3c39c9534c2657a2 Mon Sep 17 00:00:00 2001 From: Jean-Pierre Marcotte Date: Sun, 1 Feb 2026 10:41:53 -0500 Subject: [PATCH 02/13] Fix DEFAULT value generation for SEQUENCE OF newtypes SEQUENCE OF types with DEFAULT values now generate proper newtype wrappers and anonymous inner element types. Before: fn my_data_default() -> SequenceOf { alloc::vec![...] } After: fn my_data_default() -> MySeqOf { MySeqOf(alloc::vec![AnonymousMySeqOf(FixedOctetString::from([...]))]) } Fixes #159 --- rasn-compiler-tests/tests/edge_cases.rs | 11 +++ ...ge_cases__sequence_of_newtype_default.snap | 48 ++++++++++++ rasn-compiler/src/generator/rasn/utils.rs | 77 +++++++++++++++---- 3 files changed, 123 insertions(+), 13 deletions(-) create mode 100644 rasn-compiler-tests/tests/snapshots/edge_cases__sequence_of_newtype_default.snap diff --git a/rasn-compiler-tests/tests/edge_cases.rs b/rasn-compiler-tests/tests/edge_cases.rs index 5a1a2a6e..1737bcb2 100644 --- a/rasn-compiler-tests/tests/edge_cases.rs +++ b/rasn-compiler-tests/tests/edge_cases.rs @@ -136,3 +136,14 @@ e2e_pdu!( } "# ); + +e2e_pdu!( + sequence_of_newtype_default, + r#" + MyOctet ::= OCTET STRING + OctetList ::= SEQUENCE OF MyOctet + MySeq ::= SEQUENCE { + data OctetList DEFAULT { 'CAFE'H, 'BABE'H } + } + "# +); diff --git a/rasn-compiler-tests/tests/snapshots/edge_cases__sequence_of_newtype_default.snap b/rasn-compiler-tests/tests/snapshots/edge_cases__sequence_of_newtype_default.snap new file mode 100644 index 00000000..6b312faa --- /dev/null +++ b/rasn-compiler-tests/tests/snapshots/edge_cases__sequence_of_newtype_default.snap @@ -0,0 +1,48 @@ +--- +source: rasn-compiler-tests/tests/edge_cases.rs +description: "\n MyOctet ::= OCTET STRING\n OctetList ::= SEQUENCE OF MyOctet\n MySeq ::= SEQUENCE {\n data OctetList DEFAULT { 'CAFE'H, 'BABE'H }\n }\n " +--- +Generated: +#[allow( + non_camel_case_types, + non_snake_case, + non_upper_case_globals, + unused, + clippy::too_many_arguments +)] +pub mod test_module { + extern crate alloc; + use core::borrow::Borrow; + use rasn::prelude::*; + use std::sync::LazyLock; + #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)] + #[rasn(delegate)] + pub struct MyOctet(pub OctetString); + #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)] + #[rasn(automatic_tags)] + pub struct MySeq { + #[rasn(default = "my_seq_data_default")] + pub data: OctetList, + } + impl MySeq { + pub fn new(data: OctetList) -> Self { + Self { data } + } + } + impl std::default::Default for MySeq { + fn default() -> Self { + Self { + data: my_seq_data_default(), + } + } + } + fn my_seq_data_default() -> OctetList { + OctetList(alloc::vec![ + MyOctet(>::from(&[202, 254])), + MyOctet(>::from(&[186, 190])) + ]) + } + #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)] + #[rasn(delegate)] + pub struct OctetList(pub SequenceOf); +} diff --git a/rasn-compiler/src/generator/rasn/utils.rs b/rasn-compiler/src/generator/rasn/utils.rs index 595075b6..6a9a836e 100644 --- a/rasn-compiler/src/generator/rasn/utils.rs +++ b/rasn-compiler/src/generator/rasn/utils.rs @@ -695,11 +695,16 @@ impl Rasn { let mut output = TokenStream::new(); for member in members { if let Some(value) = member.optionality.default() { + // Determine the return type, handling inline types that get delegate wrappers + let ty = if Self::needs_unnesting(&member.ty) { + self.inner_name(&member.name, parent_name).to_token_stream() + } else { + self.type_to_tokens(&member.ty)? + }; let val = self.value_to_tokens( value, - Some(&self.to_rust_title_case(&self.type_to_tokens(&member.ty)?.to_string())), + Some(&self.to_rust_title_case(&ty.to_string())), )?; - let ty = self.type_to_tokens(&member.ty)?; let method_name = self.default_method_name(parent_name, &member.name); output.append_all(quote! { fn #method_name() -> #ty { @@ -809,8 +814,20 @@ impl Rasn { } } ASN1Value::OctetString(o) => { - let bytes = o.iter().map(|byte| Literal::u8_unsuffixed(*byte)); - Ok(quote!(>::from(&[#(#bytes),*]))) + let bytes: Vec<_> = o.iter().map(|byte| Literal::u8_unsuffixed(*byte)).collect(); + // When wrapping in an anonymous type (from SEQUENCE OF with constrained element), + // use FixedOctetString if the size matches + if let Some(ty) = type_name { + let ty_str = ty.to_string(); + if ty_str != "OctetString" && !ty_str.starts_with("FixedOctetString") { + // For anonymous types, use FixedOctetString when we have a fixed-size array + // This handles cases like SEQUENCE OF OCTET STRING (SIZE (6)) + let fixed_octet = quote!(FixedOctetString::from([#(#bytes),*])); + return Ok(quote!(#ty(#fixed_octet))); + } + } + let octet_str = quote!(>::from(&[#(#bytes),*])); + Ok(octet_str) } ASN1Value::SequenceOrSet(_) => Err(error!( Unidentified, @@ -885,11 +902,33 @@ impl Rasn { None => Ok(quote!(#t.parse::<_>().unwrap())), }, ASN1Value::LinkedArrayLikeValue(seq) => { + // Determine if we need to wrap inner elements in an anonymous type + // When outer type is a custom type (not SequenceOf/SetOf), elements may + // need wrapping in Anonymous{OuterTypeName} + let inner_type_name = type_name.and_then(|ty| { + let ty_str = ty.to_string(); + if !ty_str.starts_with("SequenceOf") && !ty_str.starts_with("SetOf") { + let anon_name = format_ident!("Anonymous{}", ty_str); + Some(anon_name.to_token_stream()) + } else { + None + } + }); + let elems = seq .iter() - .map(|v| self.value_to_tokens(v, None)) + .map(|v| self.value_to_tokens(v, inner_type_name.as_ref())) .collect::, _>>()?; - Ok(quote!(alloc::vec![#(#elems),*])) + let vec_expr = quote!(alloc::vec![#(#elems),*]); + + // Wrap in outer newtype if type_name is a custom type (not SequenceOf/SetOf) + if let Some(ty) = type_name { + let ty_str = ty.to_string(); + if !ty_str.starts_with("SequenceOf") && !ty_str.starts_with("SetOf") { + return Ok(quote!(#ty(#vec_expr))); + } + } + Ok(vec_expr) } ASN1Value::LinkedNestedValue { supertypes, value } => { fn nester(generator: &Rasn, s: TokenStream, mut types: Vec) -> TokenStream { @@ -901,13 +940,25 @@ impl Rasn { None => s, } } - // Pass None for type_name to inner value_to_tokens because nester - // handles the wrapping via supertypes - Ok(nester( - self, - self.value_to_tokens(value, None)?, - supertypes.clone(), - )) + // Pass None for type_name to avoid double-wrapping (nester handles outer wrap) + // For LinkedArrayLikeValue, we handle inner element wrapping separately + let inner_tokens = match value.as_ref() { + ASN1Value::LinkedArrayLikeValue(seq) => { + // Compute anonymous inner type name from the outer type + let inner_type_name = supertypes.last().map(|outer| { + let outer_str = self.to_rust_title_case(outer).to_string(); + format_ident!("Anonymous{}", outer_str).to_token_stream() + }); + // Process elements with the anonymous inner type name + let elems = seq + .iter() + .map(|v| self.value_to_tokens(v, inner_type_name.as_ref())) + .collect::, _>>()?; + quote!(alloc::vec![#(#elems),*]) + } + _ => self.value_to_tokens(value, None)?, + }; + Ok(nester(self, inner_tokens, supertypes.clone())) } ASN1Value::LinkedIntValue { integer_type, From 62514646c6988d0ded34563942534cb8667360f8 Mon Sep 17 00:00:00 2001 From: Jean-Pierre Marcotte Date: Sun, 1 Feb 2026 16:34:32 -0500 Subject: [PATCH 03/13] Add external module mapping for imports from external crates This feature allows mapping ASN.1 module names to external Rust crate paths, so that IMPORTS from those modules generate `use crate_path::Type;` instead of `use super::module_name::Type;`. Useful when compiling ASN.1 specs that import from standard modules (like PKIX1Explicit88) where pre-built Rust crates exist (like rasn-pkix). Partially addresses #167 --- .../tests/external_module_mapping.rs | 220 ++++++++++++++++++ rasn-compiler/src/generator/rasn/mod.rs | 126 ++++++++-- rasn-compiler/src/lib.rs | 2 +- 3 files changed, 327 insertions(+), 21 deletions(-) create mode 100644 rasn-compiler-tests/tests/external_module_mapping.rs diff --git a/rasn-compiler-tests/tests/external_module_mapping.rs b/rasn-compiler-tests/tests/external_module_mapping.rs new file mode 100644 index 00000000..2f4888a8 --- /dev/null +++ b/rasn-compiler-tests/tests/external_module_mapping.rs @@ -0,0 +1,220 @@ +//! Tests for external module mapping feature. +//! +//! This feature allows mapping ASN.1 module names to external Rust crate paths, +//! so that IMPORTS from those modules generate `use crate_path::Type;` instead +//! of `use super::module_name::Type;`. + +use std::collections::HashMap; + +use rasn_compiler::prelude::*; + +/// Test that external module mapping generates correct import statements. +#[test] +fn external_module_mapping_generates_correct_import() { + let mut config = RasnConfig::default(); + + // Map PKIX1Explicit88 to rasn_pkix crate + config.external_module_mappings.insert( + "PKIX1Explicit88".to_string(), + ExternalModuleMapping { + rust_path: "rasn_pkix".to_string(), + type_mappings: HashMap::new(), + }, + ); + + let asn1 = r#" + TestModule DEFINITIONS AUTOMATIC TAGS ::= BEGIN + IMPORTS Certificate FROM PKIX1Explicit88 { 1 2 3 }; + + MyCert ::= Certificate + END + "#; + + let result = Compiler::::new_with_config(config) + .add_asn_literal(asn1) + .compile_to_string() + .unwrap(); + + // Verify the generated code uses external crate import + assert!( + result.generated.contains("use rasn_pkix::Certificate;"), + "Expected external crate import, got:\n{}", + result.generated + ); + + // Verify it does NOT use sibling module import + assert!( + !result.generated.contains("use super::pkix1_explicit88"), + "Should not have sibling module import, got:\n{}", + result.generated + ); +} + +/// Test external module mapping with multiple types imported. +#[test] +fn external_module_mapping_multiple_types() { + let mut config = RasnConfig::default(); + + config.external_module_mappings.insert( + "PKIX1Explicit88".to_string(), + ExternalModuleMapping { + rust_path: "rasn_pkix".to_string(), + type_mappings: HashMap::new(), + }, + ); + + let asn1 = r#" + TestModule DEFINITIONS AUTOMATIC TAGS ::= BEGIN + IMPORTS Certificate, CertificateList, Time FROM PKIX1Explicit88 { 1 2 3 }; + + MyCert ::= Certificate + MyList ::= CertificateList + END + "#; + + let result = Compiler::::new_with_config(config) + .add_asn_literal(asn1) + .compile_to_string() + .unwrap(); + + // Verify all types are imported from external crate (order may vary after formatting) + assert!( + result.generated.contains("use rasn_pkix::") + && result.generated.contains("Certificate") + && result.generated.contains("CertificateList") + && result.generated.contains("Time"), + "Expected all types from external crate, got:\n{}", + result.generated + ); + + // Verify no sibling imports for PKIX + assert!( + !result.generated.contains("super::pkix1_explicit88"), + "Should not have sibling module import" + ); +} + +/// Test external module mapping with explicit type name mapping. +#[test] +fn external_module_mapping_with_type_mapping() { + let mut config = RasnConfig::default(); + + let mut type_mappings = HashMap::new(); + // Map ASN.1 type name to different Rust type name + type_mappings.insert("MyAsn1Type".to_string(), "RustTypeName".to_string()); + + config.external_module_mappings.insert( + "ExternalModule".to_string(), + ExternalModuleMapping { + rust_path: "my_crate::submodule".to_string(), + type_mappings, + }, + ); + + let asn1 = r#" + TestModule DEFINITIONS AUTOMATIC TAGS ::= BEGIN + IMPORTS MyAsn1Type FROM ExternalModule { 1 2 3 }; + + MyType ::= MyAsn1Type + END + "#; + + let result = Compiler::::new_with_config(config) + .add_asn_literal(asn1) + .compile_to_string() + .unwrap(); + + // Verify the mapped type name is used in the import + assert!( + result.generated.contains("use my_crate::submodule::RustTypeName;"), + "Expected mapped type name in import, got:\n{}", + result.generated + ); +} + +/// Test that unmapped modules still use default sibling import. +#[test] +fn unmapped_module_uses_sibling_import() { + let mut config = RasnConfig::default(); + + // Only map one module + config.external_module_mappings.insert( + "MappedModule".to_string(), + ExternalModuleMapping { + rust_path: "mapped_crate".to_string(), + type_mappings: HashMap::new(), + }, + ); + + // Note: multiple IMPORTS statements need to be combined in ASN.1 + let asn1 = r#" + TestModule DEFINITIONS AUTOMATIC TAGS ::= BEGIN + IMPORTS + MappedType FROM MappedModule { 1 2 3 } + UnmappedType FROM UnmappedModule { 1 2 3 }; + + MyType1 ::= MappedType + MyType2 ::= UnmappedType + END + "#; + + let result = Compiler::::new_with_config(config) + .add_asn_literal(asn1) + .compile_to_string() + .unwrap(); + + // Verify mapped module uses external import + assert!( + result.generated.contains("use mapped_crate::"), + "Expected external crate import for mapped module, got:\n{}", + result.generated + ); + + // Verify unmapped module uses sibling import + assert!( + result.generated.contains("use super::unmapped_module::"), + "Expected sibling import for unmapped module, got:\n{}", + result.generated + ); +} + +/// Test external module mapping with lowercase constant imports. +#[test] +fn external_module_mapping_with_constant() { + let mut config = RasnConfig::default(); + + config.external_module_mappings.insert( + "ConstModule".to_string(), + ExternalModuleMapping { + rust_path: "const_crate".to_string(), + type_mappings: HashMap::new(), + }, + ); + + let asn1 = r#" + TestModule DEFINITIONS AUTOMATIC TAGS ::= BEGIN + IMPORTS myConstant, MyType FROM ConstModule { 1 2 3 }; + + MyLocalType ::= MyType + END + "#; + + let result = Compiler::::new_with_config(config) + .add_asn_literal(asn1) + .compile_to_string() + .unwrap(); + + // Verify constant is imported with correct case (SCREAMING_SNAKE_CASE) + assert!( + result.generated.contains("MY_CONSTANT"), + "Expected constant with SCREAMING_SNAKE_CASE, got:\n{}", + result.generated + ); + + // Verify type is also imported + assert!( + result.generated.contains("MyType"), + "Expected type to be imported, got:\n{}", + result.generated + ); +} diff --git a/rasn-compiler/src/generator/rasn/mod.rs b/rasn-compiler/src/generator/rasn/mod.rs index a76b4017..a7e71879 100644 --- a/rasn-compiler/src/generator/rasn/mod.rs +++ b/rasn-compiler/src/generator/rasn/mod.rs @@ -1,4 +1,5 @@ use std::{ + collections::HashMap, env, error::Error, io::{self, Write}, @@ -35,6 +36,35 @@ pub struct Rasn { required_derives: Vec, } +/// Maps an external ASN.1 module to a Rust crate path. +/// +/// When the ASN.1 compiler encounters an IMPORT from a module that has an external mapping, +/// it generates `use ::;` instead of `use super::::;`. +/// +/// # Example +/// ``` +/// use std::collections::HashMap; +/// use rasn_compiler::prelude::*; +/// +/// let mut config = RasnConfig::default(); +/// config.external_module_mappings.insert( +/// "PKIX1Explicit88".to_string(), +/// ExternalModuleMapping { +/// rust_path: "rasn_pkix".to_string(), +/// type_mappings: HashMap::new(), +/// }, +/// ); +/// ``` +#[derive(Clone, Debug, Default, PartialEq, Eq)] +pub struct ExternalModuleMapping { + /// Rust crate path (e.g., "rasn_pkix", "my_crate::submodule") + pub rust_path: String, + /// Optional type name mappings if ASN.1 names differ from Rust names. + /// Key: ASN.1 type name, Value: Rust type name. + /// If a type is not in this map, its name is converted using standard rules. + pub type_mappings: HashMap, +} + #[cfg_attr(target_family = "wasm", wasm_bindgen(getter_with_clone))] #[derive(Debug)] /// A configuration for the [Rasn] backend @@ -72,6 +102,27 @@ pub struct Config { pub type_annotations: Vec, /// Create bindings for a `no_std` environment pub no_std_compliant_bindings: bool, + /// Maps ASN.1 module names to external Rust crate paths. + /// + /// When the compiler encounters an IMPORT from a module listed here, + /// it generates `use ::;` instead of the default + /// `use super::::;`. + /// + /// This is useful for referencing types from external crates like `rasn-pkix` + /// without having to compile their ASN.1 sources. + /// + /// # Example + /// ```ignore + /// config.external_module_mappings.insert( + /// "PKIX1Explicit88".to_string(), + /// ExternalModuleMapping { + /// rust_path: "rasn_pkix".to_string(), + /// type_mappings: HashMap::new(), + /// }, + /// ); + /// ``` + #[cfg_attr(target_family = "wasm", wasm_bindgen(skip))] + pub external_module_mappings: HashMap, } #[cfg(target_family = "wasm")] @@ -94,6 +145,7 @@ impl Config { custom_imports: custom_imports.map_or(Vec::new(), |c| c.into_vec()), type_annotations: type_annotations .map_or(Config::default().type_annotations, |c| c.into_vec()), + external_module_mappings: HashMap::new(), } } } @@ -109,6 +161,7 @@ impl Default for Config { type_annotations: vec![String::from( "#[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)]", )], + external_module_mappings: HashMap::new(), } } } @@ -183,29 +236,62 @@ impl Backend for Rasn { ..Default::default() })?; let imports = module.imports.iter().map(|import| { - let module = - self.to_rust_snake_case(&import.global_module_reference.module_reference); - let mut usages = Some(vec![]); - 'imports: for usage in &import.types { - if usage.contains("{}") || usage.chars().all(|c| c.is_uppercase() || c == '-') { - usages = None; - break 'imports; - } else if usage.starts_with(|c: char| c.is_lowercase()) { - if let Some(us) = usages.as_mut() { - us.push(self.to_rust_const_case(usage).to_token_stream()) - } - } else if usage.starts_with(|c: char| c.is_uppercase()) { - if let Some(us) = usages.as_mut() { - us.push(self.to_rust_title_case(usage).to_token_stream()) + let asn1_module_name = &import.global_module_reference.module_reference; + + // Check if this module has an external mapping + if let Some(mapping) = self.config.external_module_mappings.get(asn1_module_name) { + // Generate external crate import + let rust_path: TokenStream = mapping + .rust_path + .parse() + .expect("Invalid rust_path in external module mapping"); + + let types: Vec = import + .types + .iter() + .map(|t| { + // Check if there's an explicit type mapping + let rust_name = mapping + .type_mappings + .get(t) + .map(|s| s.as_str()) + .unwrap_or(t); + // Convert to appropriate Rust case + if rust_name.starts_with(|c: char| c.is_lowercase()) { + self.to_rust_const_case(rust_name).to_token_stream() + } else { + self.to_rust_title_case(rust_name).to_token_stream() + } + }) + .collect(); + + quote!(use #rust_path::{ #(#types),* };) + } else { + // Default behavior: sibling module import + let module = self.to_rust_snake_case(asn1_module_name); + let mut usages = Some(vec![]); + 'imports: for usage in &import.types { + if usage.contains("{}") || usage.chars().all(|c| c.is_uppercase() || c == '-') + { + usages = None; + break 'imports; + } else if usage.starts_with(|c: char| c.is_lowercase()) { + if let Some(us) = usages.as_mut() { + us.push(self.to_rust_const_case(usage).to_token_stream()) + } + } else if usage.starts_with(|c: char| c.is_uppercase()) { + if let Some(us) = usages.as_mut() { + us.push(self.to_rust_title_case(usage).to_token_stream()) + } } } + let used_imports = if self.config.default_wildcard_imports { + vec![TokenStream::from_str("*").unwrap()] + } else { + usages.unwrap_or(vec![TokenStream::from_str("*").unwrap()]) + }; + quote!(use super:: #module::{ #(#used_imports),* };) } - let used_imports = if self.config.default_wildcard_imports { - vec![TokenStream::from_str("*").unwrap()] - } else { - usages.unwrap_or(vec![TokenStream::from_str("*").unwrap()]) - }; - quote!(use super:: #module::{ #(#used_imports),* };) }); let (pdus, warnings): (Vec, Vec) = tlds.into_iter().fold((vec![], vec![]), |mut acc, tld| { diff --git a/rasn-compiler/src/lib.rs b/rasn-compiler/src/lib.rs index 767ebbd4..c170d357 100644 --- a/rasn-compiler/src/lib.rs +++ b/rasn-compiler/src/lib.rs @@ -39,7 +39,7 @@ pub mod prelude { }; pub use crate::generator::{ error::*, - rasn::{Config as RasnConfig, Rasn as RasnBackend}, + rasn::{Config as RasnConfig, ExternalModuleMapping, Rasn as RasnBackend}, typescript::{Config as TsConfig, Typescript as TypescriptBackend}, Backend, GeneratedModule, }; From 4997dc9a1ea88d6e8582d0147825572748670949 Mon Sep 17 00:00:00 2001 From: Jean-Pierre Marcotte Date: Wed, 4 Feb 2026 07:42:46 -0500 Subject: [PATCH 04/13] fix: don't wrap inline constrained integers in newtype for DEFAULT Inline constrained integers like INTEGER (0..255) map to primitive types (u8, u32, etc.) and should not be wrapped in a newtype constructor. --- rasn-compiler-tests/tests/edge_cases.rs | 32 +++++++++++++++++++++++ rasn-compiler/src/generator/rasn/utils.rs | 18 ++++++++++--- 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/rasn-compiler-tests/tests/edge_cases.rs b/rasn-compiler-tests/tests/edge_cases.rs index 1737bcb2..7cfc9440 100644 --- a/rasn-compiler-tests/tests/edge_cases.rs +++ b/rasn-compiler-tests/tests/edge_cases.rs @@ -147,3 +147,35 @@ e2e_pdu!( } "# ); + +#[test] +fn inline_constrained_integer_default() { + // INTEGER with inline constraint should NOT wrap in newtype + let generated = rasn_compiler::Compiler::::new() + .add_asn_literal( + r#" + TestModule DEFINITIONS AUTOMATIC TAGS ::= BEGIN + TestSeq ::= SEQUENCE { + count INTEGER (0..255) DEFAULT 1, + bigCount INTEGER (0..4294967295) DEFAULT 100 + } + END + "#, + ) + .compile_to_string() + .unwrap() + .generated; + + // Should NOT generate U8(1) or U32(100) - just bare literals + assert!( + !generated.contains("U8(1)") && !generated.contains("U32(100)"), + "Inline constrained integers should not be wrapped. Generated:\n{}", + generated + ); + assert!( + generated.contains("fn test_seq_count_default() -> u8") + && generated.contains("1\n"), + "Should generate bare integer literal. Generated:\n{}", + generated + ); +} diff --git a/rasn-compiler/src/generator/rasn/utils.rs b/rasn-compiler/src/generator/rasn/utils.rs index 6a9a836e..20e81b62 100644 --- a/rasn-compiler/src/generator/rasn/utils.rs +++ b/rasn-compiler/src/generator/rasn/utils.rs @@ -701,10 +701,20 @@ impl Rasn { } else { self.type_to_tokens(&member.ty)? }; - let val = self.value_to_tokens( - value, - Some(&self.to_rust_title_case(&ty.to_string())), - )?; + + // For primitive types, don't convert case (avoids u32 -> U32 issue) + let ty_str = ty.to_string(); + let type_name_for_value = if matches!( + ty_str.as_str(), + "i8" | "u8" | "i16" | "u16" | "i32" | "u32" | "i64" | "u64" + | "i128" | "u128" | "bool" | "f64" | "Integer" + ) { + None // Don't pass type_name for primitives + } else { + Some(self.to_rust_title_case(&ty_str)) + }; + + let val = self.value_to_tokens(value, type_name_for_value.as_ref())?; let method_name = self.default_method_name(parent_name, &member.name); output.append_all(quote! { fn #method_name() -> #ty { From 29cb7af19919725da669f9956c8307002cd724a0 Mon Sep 17 00:00:00 2001 From: Jean-Pierre Marcotte Date: Wed, 4 Feb 2026 07:43:26 -0500 Subject: [PATCH 05/13] fix: pass type context to CHOICE values in LinkedNestedValue CHOICE values need the type name to generate correct variant syntax. The LinkedNestedValue handler was passing None, breaking CHOICE generation. --- rasn-compiler/src/generator/rasn/utils.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/rasn-compiler/src/generator/rasn/utils.rs b/rasn-compiler/src/generator/rasn/utils.rs index 20e81b62..3b32cd74 100644 --- a/rasn-compiler/src/generator/rasn/utils.rs +++ b/rasn-compiler/src/generator/rasn/utils.rs @@ -966,6 +966,11 @@ impl Rasn { .collect::, _>>()?; quote!(alloc::vec![#(#elems),*]) } + ASN1Value::Choice { .. } => { + // CHOICE values need type context - get from supertypes + let choice_type = supertypes.last().map(|t| self.to_rust_title_case(t)); + self.value_to_tokens(value, choice_type.as_ref())? + } _ => self.value_to_tokens(value, None)?, }; Ok(nester(self, inner_tokens, supertypes.clone())) From 452782b2845bebcff2de721016dad2ddc620117c Mon Sep 17 00:00:00 2001 From: Jean-Pierre Marcotte Date: Wed, 4 Feb 2026 08:30:08 -0500 Subject: [PATCH 06/13] fix: pass type context to LinkedStructLikeValue in LinkedNestedValue When a LinkedStructLikeValue is nested inside a LinkedNestedValue, we need to provide type context for proper code generation. Previously this was falling through to the catch-all case that passed None, causing generation failures. Now we try to get the type from supertypes first, falling back to the passed-in type_name parameter when supertypes is empty (linker limitation). This fix enables generation for many more DEFAULT values including: - Nested SEQUENCE defaults in x520 SelectedAttributeTypes - Complex struct-like values in x501 OperationalBindingManagement - Additional value constants in x692 modules --- ...es_modules@itu-t_f_f515_2003_Uds.asn1.snap | 2507 ++++++++++- ...s_modules@itu-t_f_f515_2003_Uds2.asn1.snap | 2509 ++++++++++- ...t_q_q1218_1995_IN-CS-1-Datatypes.asn1.snap | 3890 ++++++++++++++++- ...itu-t_q_q824.1_1995_CAISDNModule.asn1.snap | 10 +- ...es@itu-t_t_t173_1997_ISOMHEG-sir.asn1.snap | 118 +- ...MHSDirectoryObjectsAndAttributes.asn1.snap | 212 +- ...t_x_x411_1999_MTAAbstractService.asn1.snap | 23 +- ..._x_x420_1999_IPMSAutoActionTypes.asn1.snap | 11 +- ...TC1_OperationalBindingManagement.asn1.snap | 56 +- ...TC2_OperationalBindingManagement.asn1.snap | 56 +- ...001_OperationalBindingManagement.asn1.snap | 57 +- ...005_OperationalBindingManagement.asn1.snap | 118 +- ...008_OperationalBindingManagement.asn1.snap | 118 +- ...x520_2012_SelectedAttributeTypes.asn1.snap | 110 +- ...x520_2016_SelectedAttributeTypes.asn1.snap | 110 +- ...x520_2019_SelectedAttributeTypes.asn1.snap | 110 +- ...x_x692_2008_Example2-ASN1-Module.asn1.snap | 44 +- ..._2008_LegacyProtocol-ASN1-Module.asn1.snap | 27 +- ...746_2000_Schedulerev1-ASN1Module.asn1.snap | 10 +- rasn-compiler/src/generator/rasn/utils.rs | 9 + 20 files changed, 9503 insertions(+), 602 deletions(-) diff --git a/rasn-compiler-tests/tests/snapshots/parse_test__parses_modules@itu-t_f_f515_2003_Uds.asn1.snap b/rasn-compiler-tests/tests/snapshots/parse_test__parses_modules@itu-t_f_f515_2003_Uds.asn1.snap index c40bac07..55409335 100644 --- a/rasn-compiler-tests/tests/snapshots/parse_test__parses_modules@itu-t_f_f515_2003_Uds.asn1.snap +++ b/rasn-compiler-tests/tests/snapshots/parse_test__parses_modules@itu-t_f_f515_2003_Uds.asn1.snap @@ -1,42 +1,8 @@ --- source: rasn-compiler-tests/tests/parse_test.rs +assertion_line: 33 input_file: rasn-compiler-tests/tests/modules/itu-t_f_f515_2003_Uds.asn1 --- -Warnings: -Not yet implemented error while generating bindings: Enumerated values are currently unsupported! -Not yet implemented error while generating bindings: Enumerated values are currently unsupported! -Not yet implemented error while generating bindings: Enumerated values are currently unsupported! -Not yet implemented error while generating bindings: Enumerated values are currently unsupported! -Not yet implemented error while generating bindings: Enumerated values are currently unsupported! -Not yet implemented error while generating bindings: Enumerated values are currently unsupported! -Not yet implemented error while generating bindings: Enumerated values are currently unsupported! -Not yet implemented error while generating bindings: Enumerated values are currently unsupported! -Not yet implemented error while generating bindings: Enumerated values are currently unsupported! -Not yet implemented error while generating bindings: Enumerated values are currently unsupported! -Not yet implemented error while generating bindings: Enumerated values are currently unsupported! -Not yet implemented error while generating bindings: Enumerated values are currently unsupported! -Not yet implemented error while generating bindings: Enumerated values are currently unsupported! -Not yet implemented error while generating bindings: Enumerated values are currently unsupported! -Not yet implemented error while generating bindings: Enumerated values are currently unsupported! -Not yet implemented error while generating bindings: Enumerated values are currently unsupported! -Not yet implemented error while generating bindings: Enumerated values are currently unsupported! -Not yet implemented error while generating bindings: Enumerated values are currently unsupported! -Not yet implemented error while generating bindings: Enumerated values are currently unsupported! -Not yet implemented error while generating bindings: Enumerated values are currently unsupported! -Not yet implemented error while generating bindings: Enumerated values are currently unsupported! -Not yet implemented error while generating bindings: Enumerated values are currently unsupported! -Not yet implemented error while generating bindings: Enumerated values are currently unsupported! -Not yet implemented error while generating bindings: Enumerated values are currently unsupported! -Not yet implemented error while generating bindings: Enumerated values are currently unsupported! -Not yet implemented error while generating bindings: Enumerated values are currently unsupported! -Not yet implemented error while generating bindings: Enumerated values are currently unsupported! -Not yet implemented error while generating bindings: Enumerated values are currently unsupported! -Not yet implemented error while generating bindings: Enumerated values are currently unsupported! -Not yet implemented error while generating bindings: Enumerated values are currently unsupported! -Not yet implemented error while generating bindings: Enumerated values are currently unsupported! -Not yet implemented error while generating bindings: Enumerated values are currently unsupported! - - Generated: #[allow( non_camel_case_types, @@ -55,6 +21,28 @@ pub mod uds { #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)] #[rasn(delegate)] pub struct AddrCoverage(pub AddrCoverageType); + #[doc = " Inner type "] + #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash, Copy)] + #[rasn(enumerated)] + pub enum AddrCoverageAsWeight { + low = 0, + high = 1, + } + #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)] + #[rasn(automatic_tags)] + pub struct AddrCoverageAs { + pub base: AddrCoverageType, + #[rasn(default = "addr_coverage_as_weight_default")] + pub weight: AddrCoverageAsWeight, + } + impl AddrCoverageAs { + pub fn new(base: AddrCoverageType, weight: AddrCoverageAsWeight) -> Self { + Self { base, weight } + } + } + fn addr_coverage_as_weight_default() -> AddrCoverageAsWeight { + HIGH + } #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash, Copy)] #[rasn(enumerated)] pub enum AddrCoverageType { @@ -66,6 +54,28 @@ pub mod uds { #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)] #[rasn(delegate)] pub struct AddrRestriction(pub AddrRestrictionType); + #[doc = " Inner type "] + #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash, Copy)] + #[rasn(enumerated)] + pub enum AddrRestrictionAsWeight { + low = 0, + high = 1, + } + #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)] + #[rasn(automatic_tags)] + pub struct AddrRestrictionAs { + pub base: AddrRestrictionType, + #[rasn(default = "addr_restriction_as_weight_default")] + pub weight: AddrRestrictionAsWeight, + } + impl AddrRestrictionAs { + pub fn new(base: AddrRestrictionType, weight: AddrRestrictionAsWeight) -> Self { + Self { base, weight } + } + } + fn addr_restriction_as_weight_default() -> AddrRestrictionAsWeight { + HIGH + } #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash, Copy)] #[rasn(enumerated)] pub enum AddrRestrictionType { @@ -81,6 +91,28 @@ pub mod uds { #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)] #[rasn(delegate)] pub struct AddrTariff(pub AddrTariffType); + #[doc = " Inner type "] + #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash, Copy)] + #[rasn(enumerated)] + pub enum AddrTariffAsWeight { + low = 0, + high = 1, + } + #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)] + #[rasn(automatic_tags)] + pub struct AddrTariffAs { + pub base: AddrTariffType, + #[rasn(default = "addr_tariff_as_weight_default")] + pub weight: AddrTariffAsWeight, + } + impl AddrTariffAs { + pub fn new(base: AddrTariffType, weight: AddrTariffAsWeight) -> Self { + Self { base, weight } + } + } + fn addr_tariff_as_weight_default() -> AddrTariffAsWeight { + HIGH + } #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash, Copy)] #[rasn(enumerated)] pub enum AddrTariffType { @@ -98,6 +130,28 @@ pub mod uds { #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)] #[rasn(delegate)] pub struct AddrValidity(pub AddrValidityType); + #[doc = " Inner type "] + #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash, Copy)] + #[rasn(enumerated)] + pub enum AddrValidityAsWeight { + low = 0, + high = 1, + } + #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)] + #[rasn(automatic_tags)] + pub struct AddrValidityAs { + pub base: AddrValidityType, + #[rasn(default = "addr_validity_as_weight_default")] + pub weight: AddrValidityAsWeight, + } + impl AddrValidityAs { + pub fn new(base: AddrValidityType, weight: AddrValidityAsWeight) -> Self { + Self { base, weight } + } + } + fn addr_validity_as_weight_default() -> AddrValidityAsWeight { + HIGH + } #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash, Copy)] #[rasn(enumerated)] pub enum AddrValidityType { @@ -120,6 +174,34 @@ pub mod uds { addrTariffAs(AddrTariffAs), addrRestrictionAs(AddrRestrictionAs), } + #[doc = " Inner type "] + #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash, Copy)] + #[rasn(enumerated)] + pub enum AssertionAttrWeight { + low = 0, + high = 1, + } + #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)] + #[rasn(automatic_tags)] + pub struct AssertionAttr { + #[rasn(default = "assertion_attr_weight_default")] + pub weight: AssertionAttrWeight, + } + impl AssertionAttr { + pub fn new(weight: AssertionAttrWeight) -> Self { + Self { weight } + } + } + impl std::default::Default for AssertionAttr { + fn default() -> Self { + Self { + weight: assertion_attr_weight_default(), + } + } + } + fn assertion_attr_weight_default() -> AssertionAttrWeight { + HIGH + } #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)] #[rasn(choice, automatic_tags)] pub enum Attribute { @@ -218,6 +300,109 @@ pub mod uds { Self { lang, base } } } + #[doc = " Inner type "] + #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash, Copy)] + #[rasn(enumerated)] + pub enum AnonymousBusinessCategorySubValueWordMatch { + exact = 0, + truncated = 1, + phonetic = 2, + } + #[doc = " Inner type "] + #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash, Copy)] + #[rasn(enumerated)] + pub enum AnonymousBusinessCategorySubValueCharacterMatch { + exact = 0, + caseIgnore = 1, + mapped = 2, + } + #[doc = " Anonymous SEQUENCE OF member "] + #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)] + #[rasn(automatic_tags, identifier = "SEQUENCE")] + pub struct AnonymousBusinessCategorySubValue { + pub base: Ub128, + #[rasn( + default = "anonymous_business_category_sub_value_word_match_default", + identifier = "wordMatch" + )] + pub word_match: AnonymousBusinessCategorySubValueWordMatch, + #[rasn( + default = "anonymous_business_category_sub_value_character_match_default", + identifier = "characterMatch" + )] + pub character_match: AnonymousBusinessCategorySubValueCharacterMatch, + } + impl AnonymousBusinessCategorySubValue { + pub fn new( + base: Ub128, + word_match: AnonymousBusinessCategorySubValueWordMatch, + character_match: AnonymousBusinessCategorySubValueCharacterMatch, + ) -> Self { + Self { + base, + word_match, + character_match, + } + } + } + fn anonymous_business_category_sub_value_word_match_default( + ) -> AnonymousBusinessCategorySubValueWordMatch { + CharacterMatchType::exact + } + fn anonymous_business_category_sub_value_character_match_default( + ) -> AnonymousBusinessCategorySubValueCharacterMatch { + CharacterMatchType::caseIgnore + } + #[doc = " Inner type "] + #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)] + #[rasn(delegate, size("1.."))] + pub struct BusinessCategorySubValue(pub SequenceOf); + #[doc = " Inner type "] + #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash, Copy)] + #[rasn(enumerated)] + pub enum BusinessCategorySubString { + exact = 0, + deletion = 1, + restrDeletion = 2, + permutation = 3, + permutationAndDeletion = 4, + providerDefined = 5, + } + #[doc = " Inner type "] + #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash, Copy)] + #[rasn(enumerated)] + pub enum BusinessCategorySubWeight { + low = 0, + high = 1, + } + #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)] + #[rasn(automatic_tags)] + pub struct BusinessCategorySub { + pub value: BusinessCategorySubValue, + #[rasn(default = "business_category_sub_string_default")] + pub string: BusinessCategorySubString, + #[rasn(default = "business_category_sub_weight_default")] + pub weight: BusinessCategorySubWeight, + } + impl BusinessCategorySub { + pub fn new( + value: BusinessCategorySubValue, + string: BusinessCategorySubString, + weight: BusinessCategorySubWeight, + ) -> Self { + Self { + value, + string, + weight, + } + } + } + fn business_category_sub_string_default() -> BusinessCategorySubString { + CharacterMatchType::exact + } + fn business_category_sub_weight_default() -> BusinessCategorySubWeight { + HIGH + } #[doc = " Anonymous SEQUENCE OF member "] #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)] #[rasn(choice, automatic_tags, identifier = "CHOICE")] @@ -260,9 +445,53 @@ pub mod uds { #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)] #[rasn(delegate)] pub struct CommNetwork(pub NetworkType); + #[doc = " Inner type "] + #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash, Copy)] + #[rasn(enumerated)] + pub enum CommNetworkAsWeight { + low = 0, + high = 1, + } + #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)] + #[rasn(automatic_tags)] + pub struct CommNetworkAs { + pub base: NetworkType, + #[rasn(default = "comm_network_as_weight_default")] + pub weight: CommNetworkAsWeight, + } + impl CommNetworkAs { + pub fn new(base: NetworkType, weight: CommNetworkAsWeight) -> Self { + Self { base, weight } + } + } + fn comm_network_as_weight_default() -> CommNetworkAsWeight { + HIGH + } #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)] #[rasn(delegate)] pub struct CommService(pub ComServiceTypes); + #[doc = " Inner type "] + #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash, Copy)] + #[rasn(enumerated)] + pub enum CommServiceAsWeight { + low = 0, + high = 1, + } + #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)] + #[rasn(automatic_tags)] + pub struct CommServiceAs { + pub base: ComServiceType, + #[rasn(default = "comm_service_as_weight_default")] + pub weight: CommServiceAsWeight, + } + impl CommServiceAs { + pub fn new(base: ComServiceType, weight: CommServiceAsWeight) -> Self { + Self { base, weight } + } + } + fn comm_service_as_weight_default() -> CommServiceAsWeight { + HIGH + } #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)] #[rasn(automatic_tags)] pub struct CommsAddress { @@ -288,6 +517,28 @@ pub mod uds { #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)] #[rasn(delegate)] pub struct Country(pub NMTOKEN); + #[doc = " Inner type "] + #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash, Copy)] + #[rasn(enumerated)] + pub enum CountryAsWeight { + low = 0, + high = 1, + } + #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)] + #[rasn(automatic_tags)] + pub struct CountryAs { + pub base: NMTOKEN, + #[rasn(default = "country_as_weight_default")] + pub weight: CountryAsWeight, + } + impl CountryAs { + pub fn new(base: NMTOKEN, weight: CountryAsWeight) -> Self { + Self { base, weight } + } + } + fn country_as_weight_default() -> CountryAsWeight { + HIGH + } #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)] #[rasn(automatic_tags)] pub struct Description { @@ -302,6 +553,108 @@ pub mod uds { #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)] #[rasn(delegate)] pub struct DmdName(pub Ub64); + #[doc = " Inner type "] + #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash, Copy)] + #[rasn(enumerated)] + pub enum AnonymousDmdNameSubValueWordMatch { + exact = 0, + truncated = 1, + phonetic = 2, + } + #[doc = " Inner type "] + #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash, Copy)] + #[rasn(enumerated)] + pub enum AnonymousDmdNameSubValueCharacterMatch { + exact = 0, + caseIgnore = 1, + mapped = 2, + } + #[doc = " Anonymous SEQUENCE OF member "] + #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)] + #[rasn(automatic_tags, identifier = "SEQUENCE")] + pub struct AnonymousDmdNameSubValue { + pub base: Ub64, + #[rasn( + default = "anonymous_dmd_name_sub_value_word_match_default", + identifier = "wordMatch" + )] + pub word_match: AnonymousDmdNameSubValueWordMatch, + #[rasn( + default = "anonymous_dmd_name_sub_value_character_match_default", + identifier = "characterMatch" + )] + pub character_match: AnonymousDmdNameSubValueCharacterMatch, + } + impl AnonymousDmdNameSubValue { + pub fn new( + base: Ub64, + word_match: AnonymousDmdNameSubValueWordMatch, + character_match: AnonymousDmdNameSubValueCharacterMatch, + ) -> Self { + Self { + base, + word_match, + character_match, + } + } + } + fn anonymous_dmd_name_sub_value_word_match_default() -> AnonymousDmdNameSubValueWordMatch { + CharacterMatchType::exact + } + fn anonymous_dmd_name_sub_value_character_match_default( + ) -> AnonymousDmdNameSubValueCharacterMatch { + CharacterMatchType::caseIgnore + } + #[doc = " Inner type "] + #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)] + #[rasn(delegate, size("1.."))] + pub struct DmdNameSubValue(pub SequenceOf); + #[doc = " Inner type "] + #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash, Copy)] + #[rasn(enumerated)] + pub enum DmdNameSubString { + exact = 0, + deletion = 1, + restrDeletion = 2, + permutation = 3, + permutationAndDeletion = 4, + providerDefined = 5, + } + #[doc = " Inner type "] + #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash, Copy)] + #[rasn(enumerated)] + pub enum DmdNameSubWeight { + low = 0, + high = 1, + } + #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)] + #[rasn(automatic_tags)] + pub struct DmdNameSub { + pub value: DmdNameSubValue, + #[rasn(default = "dmd_name_sub_string_default")] + pub string: DmdNameSubString, + #[rasn(default = "dmd_name_sub_weight_default")] + pub weight: DmdNameSubWeight, + } + impl DmdNameSub { + pub fn new( + value: DmdNameSubValue, + string: DmdNameSubString, + weight: DmdNameSubWeight, + ) -> Self { + Self { + value, + string, + weight, + } + } + } + fn dmd_name_sub_string_default() -> DmdNameSubString { + CharacterMatchType::exact + } + fn dmd_name_sub_weight_default() -> DmdNameSubWeight { + HIGH + } #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)] #[rasn(choice, automatic_tags)] pub enum Family { @@ -333,243 +686,1105 @@ pub mod uds { #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)] #[rasn(delegate)] pub struct GivenName(pub Ub64); - #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)] - #[rasn(delegate)] - pub struct HierarchySelectList(pub HierarchySelections); + #[doc = " Inner type "] #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash, Copy)] #[rasn(enumerated)] - pub enum HierarchySelection { - #[rasn(identifier = "self")] - R_self = 0, - children = 1, - parent = 2, - hierarchy = 3, - top = 4, - subtree = 5, - all = 6, + pub enum AnonymousGivenNameSubValueWordMatch { + exact = 0, + truncated = 1, + phonetic = 2, } - #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)] - #[rasn(delegate)] - pub struct HierarchySelections(pub SequenceOf); - #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)] - #[rasn(delegate)] - pub struct HouseId(pub Ub64); - #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)] - #[rasn(delegate)] - pub struct Language(pub super::xsd::Language); + #[doc = " Inner type "] #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash, Copy)] #[rasn(enumerated)] - pub enum LimitProblem { - adminLimit = 0, - permanentRestriction = 1, + pub enum AnonymousGivenNameSubValueCharacterMatch { + exact = 0, + caseIgnore = 1, + mapped = 2, } + #[doc = " Anonymous SEQUENCE OF member "] #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)] - #[rasn(delegate)] - pub struct Locality(pub Ub128); - #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)] - #[rasn(delegate)] - pub struct LocalityCode(pub Ub64); + #[rasn(automatic_tags, identifier = "SEQUENCE")] + pub struct AnonymousGivenNameSubValue { + pub base: Ub64, + #[rasn( + default = "anonymous_given_name_sub_value_word_match_default", + identifier = "wordMatch" + )] + pub word_match: AnonymousGivenNameSubValueWordMatch, + #[rasn( + default = "anonymous_given_name_sub_value_character_match_default", + identifier = "characterMatch" + )] + pub character_match: AnonymousGivenNameSubValueCharacterMatch, + } + impl AnonymousGivenNameSubValue { + pub fn new( + base: Ub64, + word_match: AnonymousGivenNameSubValueWordMatch, + character_match: AnonymousGivenNameSubValueCharacterMatch, + ) -> Self { + Self { + base, + word_match, + character_match, + } + } + } + fn anonymous_given_name_sub_value_word_match_default() -> AnonymousGivenNameSubValueWordMatch { + CharacterMatchType::exact + } + fn anonymous_given_name_sub_value_character_match_default( + ) -> AnonymousGivenNameSubValueCharacterMatch { + CharacterMatchType::caseIgnore + } + #[doc = " Inner type "] #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)] - #[rasn(delegate)] - pub struct LocalityNDC(pub Ub16NumericString); - #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)] - #[rasn(delegate)] - pub struct Mail(pub Ub256); + #[rasn(delegate, size("1.."))] + pub struct GivenNameSubValue(pub SequenceOf); + #[doc = " Inner type "] #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash, Copy)] #[rasn(enumerated)] - pub enum NetworkType { - pstn = 0, - isdn = 1, - gsm = 2, - umts = 3, - internet = 4, + pub enum GivenNameSubString { + exact = 0, + deletion = 1, + restrDeletion = 2, + permutation = 3, + permutationAndDeletion = 4, + providerDefined = 5, + } + #[doc = " Inner type "] + #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash, Copy)] + #[rasn(enumerated)] + pub enum GivenNameSubWeight { + low = 0, + high = 1, } #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)] - #[rasn(delegate)] - pub struct NotSupported(pub Options); - #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)] - #[rasn(choice, automatic_tags)] - pub enum Notification { - limitProblem(LimitProblem), - serviceProblem(ServiceProblem), - searchType(SearchType), - attributeTypeList(AttributeTypeList), - filterNot(FilterNot), - filterItem(FilterItem), - providerName(ProviderName), - hierarchySelectList(HierarchySelectList), - searchControlOptionsList(SearchControlOptionsList), - attributeCombinations(AttributeCombinations), - wordRestriction(WordRestriction), - notSupported(NotSupported), + #[rasn(automatic_tags)] + pub struct GivenNameSub { + pub value: GivenNameSubValue, + #[rasn(default = "given_name_sub_string_default")] + pub string: GivenNameSubString, + #[rasn(default = "given_name_sub_weight_default")] + pub weight: GivenNameSubWeight, + } + impl GivenNameSub { + pub fn new( + value: GivenNameSubValue, + string: GivenNameSubString, + weight: GivenNameSubWeight, + ) -> Self { + Self { + value, + string, + weight, + } + } + } + fn given_name_sub_string_default() -> GivenNameSubString { + CharacterMatchType::exact + } + fn given_name_sub_weight_default() -> GivenNameSubWeight { + HIGH } #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)] - #[rasn(delegate, identifier = "NumericString-1", from("\u{30}..=\u{39}"))] - pub struct NumericString1(pub Ia5String); + #[rasn(delegate)] + pub struct HierarchySelectList(pub HierarchySelections); #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash, Copy)] #[rasn(enumerated)] - pub enum Option { - paging = 0, - weighting = 1, + pub enum HierarchySelection { + #[rasn(identifier = "self")] + R_self = 0, + children = 1, + parent = 2, + hierarchy = 3, + top = 4, + subtree = 5, + all = 6, } #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, Eq, Hash)] #[rasn(delegate)] - pub struct Options(pub SequenceOf