diff --git a/rasn-compiler-tests/tests/edge_cases.rs b/rasn-compiler-tests/tests/edge_cases.rs index 3b4752b..f14469d 100644 --- a/rasn-compiler-tests/tests/edge_cases.rs +++ b/rasn-compiler-tests/tests/edge_cases.rs @@ -55,6 +55,46 @@ e2e_pdu!( } "# ); +e2e_pdu!( + distinguished_value_range_in_choice_from_impl, + rasn_compiler::prelude::RasnConfig { + generate_from_impls: true, + ..Default::default() + }, + r#" + TestChoice ::= CHOICE { + restricted Distinguished (second|fourth..sixth|eighth), + ... + } + Distinguished ::= INTEGER { + first(1), + second(2), + third(3), + fourth(4), + fifth(5), + sixth(6), + seventh(7), + eighth(8), + ninth(9), + tenth(10), + } (1..10)"#, + r#" #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq, PartialOrd, Eq, Ord, Hash)] + #[rasn(delegate, value("1..=10"))] + pub struct Distinguished(pub u8); + #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq)] + #[rasn(choice, automatic_tags)] + #[non_exhaustive] + pub enum TestChoice { + #[rasn(value("2..=8"))] + restricted(Distinguished), + } + impl From for TestChoice { + fn from(value: Distinguished) -> Self { + Self::restricted(value) + } + } "# +); + e2e_pdu!( enum_and_distinguished_defaults, r#" diff --git a/rasn-compiler-tests/tests/structured_types.rs b/rasn-compiler-tests/tests/structured_types.rs index de2ea28..20a0b7d 100644 --- a/rasn-compiler-tests/tests/structured_types.rs +++ b/rasn-compiler-tests/tests/structured_types.rs @@ -97,3 +97,55 @@ e2e_pdu!( pub static ref NESTED_TYPE_VAL: NestedType = NestedType::new(NestedTypeChoiceField::one(Integer::from(4))); } "# ); + +e2e_pdu!( + nested_choice_value_from_impl, + rasn_compiler::prelude::RasnConfig { + generate_from_impls: true, + ..Default::default() + }, + r#" + NestedType ::= SEQUENCE { + choiceField CHOICE { + one INTEGER, + two BOOLEAN + } + } + + nestedTypeVal NestedType ::= { choiceField one:4 } + "#, + r#" + #[doc = "Inner type"] + #[derive(AsnType,Debug,Clone,Decode,Encode,PartialEq)] + #[rasn(choice, automatic_tags)] + pub enum NestedTypeChoiceField { + one(Integer), + two(bool), + } + impl From for NestedTypeChoiceField { + fn from(value: Integer) -> Self { + Self::one(value) + } + } + impl From for NestedTypeChoiceField { + fn from(value: bool) -> Self { + Self::two(value) + } + } + + #[derive(AsnType,Debug,Clone,Decode,Encode,PartialEq)] + #[rasn(automatic_tags)] + pub struct NestedType{ + #[rasn(identifier="choiceField")] + pub choice_field: NestedTypeChoiceField, + } + impl NestedType { + pub fn new(choice_field: NestedTypeChoiceField) -> Self { + Self { choice_field } + } + } + + lazy_static! { + pub static ref NESTED_TYPE_VAL: NestedType = NestedType::new(NestedTypeChoiceField::one(Integer::from(4))); + } "# +); diff --git a/rasn-compiler/src/generator/rasn/builder.rs b/rasn-compiler/src/generator/rasn/builder.rs index 80159c5..6c991e6 100644 --- a/rasn-compiler/src/generator/rasn/builder.rs +++ b/rasn-compiler/src/generator/rasn/builder.rs @@ -725,14 +725,31 @@ impl Rasn { &tld.ty, )); } - Ok(choice_template( + let mut choice_str = choice_template( self.format_comments(&tld.comments)?, - name.clone(), + &name, extensible, self.format_choice_options(choice, &name.to_string())?, inner_options, self.join_annotations(annotations), - )) + ); + if self.config.generate_from_impls { + choice_str = std::iter::once(choice_str) + .map(|x| Ok(x)) + .chain(choice.options.iter().map(|o| { + let (_, formatted_type_name) = + self.constraints_and_type_name(&o.ty, &o.name, &name.to_string())?; + + let o_name = self.to_rust_enum_identifier(&o.name); + Ok::<_, GeneratorError>(choice_from_impl_template( + &name, + o_name, + formatted_type_name, + )) + })) + .collect::>()?; + } + Ok(choice_str) } else { Err(GeneratorError::new( Some(ToplevelDefinition::Type(tld)), diff --git a/rasn-compiler/src/generator/rasn/mod.rs b/rasn-compiler/src/generator/rasn/mod.rs index 04011b1..d4e131a 100644 --- a/rasn-compiler/src/generator/rasn/mod.rs +++ b/rasn-compiler/src/generator/rasn/mod.rs @@ -46,6 +46,11 @@ pub struct Config { /// is set to `true` , the compiler will import the entire module using /// the wildcard `*` for each module that the input ASN.1 module imports from. pub default_wildcard_imports: bool, + /// To make working with the generated types a bit more ergonomic, the compiler + /// can generate `From` impls for a `CHOICE`. This is disabled by default to + /// generate less code, but can be enabled with `generate_from_impls` set to + /// `true`. + pub generate_from_impls: bool, } #[cfg(target_family = "wasm")] @@ -65,6 +70,7 @@ impl Default for Config { Self { opaque_open_types: true, default_wildcard_imports: false, + generate_from_impls: false, } } } diff --git a/rasn-compiler/src/generator/rasn/template.rs b/rasn-compiler/src/generator/rasn/template.rs index 72b961a..ea2e0ca 100644 --- a/rasn-compiler/src/generator/rasn/template.rs +++ b/rasn-compiler/src/generator/rasn/template.rs @@ -312,7 +312,7 @@ pub fn const_choice_value_template( pub fn choice_template( comments: TokenStream, - name: TokenStream, + name: &TokenStream, extensible: TokenStream, options: TokenStream, nested_options: Vec, @@ -329,3 +329,17 @@ pub fn choice_template( } } } + +pub fn choice_from_impl_template( + name: &TokenStream, + variant: Ident, + wrapped: TokenStream, +) -> TokenStream { + quote! { + impl From<#wrapped> for #name { + fn from(value: #wrapped) -> Self { + Self::#variant(value) + } + } + } +}