From cf4325ed4cd16f239e53aa4ac4b94351dad2bdf4 Mon Sep 17 00:00:00 2001 From: Niklas Saari Date: Sun, 6 Apr 2025 14:39:42 +0300 Subject: [PATCH] Change from TagTree in choice for Tag list most of the time --- macros/macros_impl/src/config.rs | 37 ++++++---- macros/macros_impl/src/enum.rs | 43 +++++++----- src/error/decode.rs | 10 ++- src/jer/de.rs | 17 +++-- src/jer/enc.rs | 6 +- src/oer/de.rs | 10 +-- src/oer/enc.rs | 24 +++---- src/per/de.rs | 6 +- src/per/enc.rs | 10 +-- src/types.rs | 5 +- src/types/variants.rs | 112 +++++++++++++++---------------- src/xer/de.rs | 9 ++- 12 files changed, 151 insertions(+), 138 deletions(-) diff --git a/macros/macros_impl/src/config.rs b/macros/macros_impl/src/config.rs index e071ec7d..874294a0 100644 --- a/macros/macros_impl/src/config.rs +++ b/macros/macros_impl/src/config.rs @@ -653,9 +653,16 @@ impl<'config> VariantConfig<'config> { }) } }; + let (tag_tokens, is_tag_tree) = tag_tree; + let if_check = if is_tag_tree { + quote!(#crate_root::types::TagTree::tag_contains(&tag, &[#tag_tokens])) + } else { + quote!(#tag_tokens.eq(&tag)) + }; Ok(quote! { - if #crate_root::types::TagTree::tag_contains(&tag, &[#tag_tree]) { + + if #if_check { #const_constraint return #decode_op } @@ -677,11 +684,14 @@ impl<'config> VariantConfig<'config> { }) } - pub fn tag_tree(&self) -> syn::Result { + /// Returns a tuple containing: + /// - The TokenStream representing the tag tree or a single tag + /// - A boolean indicating whether this is a complex tag tree (true) or a simple tag (false) + pub fn tag_tree(&self) -> syn::Result<(proc_macro2::TokenStream, bool)> { let crate_root = &self.container_config.crate_root; if self.tag.is_some() || self.container_config.automatic_tags { let tag = self.tag()?.to_tokens(crate_root); - Ok(quote!(#crate_root::types::TagTree::Leaf(#tag))) + Ok((quote!(#tag), false)) } else { let field_configs = self .variant @@ -697,9 +707,7 @@ impl<'config> VariantConfig<'config> { .map(|f| f.tag_tree()); Ok(match self.variant.fields { - syn::Fields::Unit => { - quote!(#crate_root::types::TagTree::Leaf(<() as #crate_root::AsnType>::TAG)) - } + syn::Fields::Unit => (quote!(<() as #crate_root::AsnType>::TAG), false), syn::Fields::Named(_) => { let error_message = format!( "{}'s fields is not a valid \ @@ -708,12 +716,15 @@ impl<'config> VariantConfig<'config> { self.variant.ident ); - quote!({ - const FIELD_LIST: &'static [#crate_root::types::TagTree] = &[#(#field_tags),*]; - const FIELD_TAG_TREE: #crate_root::types::TagTree = #crate_root::types::TagTree::Choice(FIELD_LIST); - const _: () = assert!(FIELD_TAG_TREE.is_unique(), #error_message); - #crate_root::types::TagTree::Leaf(#crate_root::types::Tag::SEQUENCE) - }) + ( + quote!({ + const FIELD_LIST: &'static [#crate_root::types::TagTree] = &[#(#field_tags),*]; + const FIELD_TAG_TREE: #crate_root::types::TagTree = #crate_root::types::TagTree::Choice(FIELD_LIST); + const _: () = assert!(FIELD_TAG_TREE.is_unique(), #error_message); + #crate_root::types::Tag::SEQUENCE + }), + false, + ) } syn::Fields::Unnamed(_) => { // Assert already checked in FieldConfig @@ -721,7 +732,7 @@ impl<'config> VariantConfig<'config> { let mut ty = self.variant.fields.iter().next().unwrap().ty.clone(); ty.strip_lifetimes(); - quote!(<#ty as #crate_root::AsnType>::TAG_TREE) + (quote!(<#ty as #crate_root::AsnType>::TAG_TREE), true) } }) } diff --git a/macros/macros_impl/src/enum.rs b/macros/macros_impl/src/enum.rs index de8e10c0..14ebd1e6 100644 --- a/macros/macros_impl/src/enum.rs +++ b/macros/macros_impl/src/enum.rs @@ -43,7 +43,15 @@ impl Enum<'_> { let field_tags = if self.config.choice { variant_configs .iter() - .map(super::config::VariantConfig::tag_tree) + .map(|config| { + config.tag_tree().map(|(tokens, is_tree)| { + if is_tree { + tokens + } else { + quote!(#crate_root::types::TagTree::Leaf(#tokens)) + } + }) + }) .collect::, _>>()? } else { Vec::new() @@ -83,25 +91,27 @@ impl Enum<'_> { let constraints_def = self.config.constraints.const_static_def(crate_root); - let (base_variants, extended_variants): (Vec<_>, Vec<_>) = variant_configs - .iter() - .zip(field_tags) - .partition_map(|(config, field_tag)| { + let extensible = self.config.constraints.extensible; + + let (variant_tags, extended_variant_tags): (Vec<_>, Vec<_>) = + variant_configs.iter().partition_map(|config| { if config.extension_addition { - either::Right(field_tag) + either::Right(config.tag().map(|tag| tag.to_tokens(crate_root)).unwrap()) } else { - either::Left(field_tag) + either::Left(config.tag().map(|tag| tag.to_tokens(crate_root)).unwrap()) } }); - let extensible = self.config.constraints.extensible; - let extended_const_variants = extensible - .then(|| quote!(Some(&[#(#extended_variants),*]))) + let extended_variant_tags = extensible + .then(|| { + if extended_variant_tags.is_empty() { + quote!(Some(&[])) + } else { + quote!(Some(&[#(#extended_variant_tags),*])) + } + }) .unwrap_or(quote!(None)); - // Check count of the root components in the choice - // https://github.com/XAMPPRocky/rasn/issues/168 - // Choice index starts from zero, so we need to reduce variance by one let variant_count = if self.variants.is_empty() { 0 } else { @@ -121,11 +131,9 @@ impl Enum<'_> { let choice_impl = self.config.choice.then(|| quote! { impl #impl_generics #crate_root::types::Choice for #name #ty_generics #where_clause { - const VARIANTS: &'static [#crate_root::types::TagTree] = &[ - #(#base_variants),* - ]; + const VARIANTS: &'static [#crate_root::types::Tag] = &[#(#variant_tags),*]; const VARIANCE_CONSTRAINT: #crate_root::types::Constraints = #variance_constraint; - const EXTENDED_VARIANTS: Option<&'static [#crate_root::types::TagTree]> = #extended_const_variants; + const EXTENDED_VARIANTS: Option<&'static [#crate_root::types::Tag]> = #extended_variant_tags; const IDENTIFIERS: &'static [&'static str] = &[ #(#identifiers),* ]; @@ -426,7 +434,6 @@ impl Enum<'_> { quote!(#name::#ident { #(#idents: #idents_prefixed),* } => { #encode_impl.map(|_| #tag_tokens) }) } syn::Fields::Unnamed(_) => { - // Assert already checked in FieldConfig assert_eq!(v.fields.len(), 1, "Tuple variants must contain only a single element."); let constraints = variant_config .constraints diff --git a/src/error/decode.rs b/src/error/decode.rs index ad529268..06be590e 100644 --- a/src/error/decode.rs +++ b/src/error/decode.rs @@ -10,7 +10,7 @@ use snafu::Snafu; use snafu::{Backtrace, GenerateImplicitData}; use crate::de::Error; -use crate::types::{constraints::Bounded, variants::Variants, Tag}; +use crate::types::{constraints::Bounded, Tag}; use crate::Codec; use num_bigint::BigInt; @@ -340,7 +340,11 @@ impl DecodeError { /// Creates a wrapper around a missing choice index error from a given codec. #[must_use] - pub fn choice_index_not_found(index: usize, variants: Variants, codec: Codec) -> Self { + pub fn choice_index_not_found( + index: usize, + variants: alloc::vec::Vec, + codec: Codec, + ) -> Self { Self::from_kind( DecodeErrorKind::ChoiceIndexNotFound { index, variants }, codec, @@ -498,7 +502,7 @@ pub enum DecodeErrorKind { /// The found index of the choice variant. index: usize, /// The variants checked for presence. - variants: Variants, + variants: alloc::vec::Vec, }, /// Choice index exceeds maximum possible address width. diff --git a/src/jer/de.rs b/src/jer/de.rs index ac7a76c4..db844397 100644 --- a/src/jer/de.rs +++ b/src/jer/de.rs @@ -6,10 +6,10 @@ use crate::{ de::Error, error::{DecodeError, JerDecodeErrorKind}, types::{ - variants, Any, BitString, BmpString, Constraints, Constructed, Date, DecodeChoice, - Enumerated, GeneralString, GeneralizedTime, GraphicString, Ia5String, NumericString, - ObjectIdentifier, Oid, PrintableString, SequenceOf, SetOf, Tag, TeletexString, UtcTime, - Utf8String, VisibleString, + Any, BitString, BmpString, Constraints, Constructed, Date, DecodeChoice, Enumerated, + GeneralString, GeneralizedTime, GraphicString, Ia5String, NumericString, ObjectIdentifier, + Oid, PrintableString, SequenceOf, SetOf, Tag, TeletexString, UtcTime, Utf8String, + VisibleString, }, Decode, }; @@ -660,14 +660,13 @@ impl Decoder { .map(|(i, _)| (i, v)) }) .map_or(Tag::EOC, |(i, v)| { - match variants::Variants::from_slice( - &[D::VARIANTS, D::EXTENDED_VARIANTS.unwrap_or(&[])].concat(), - ) - .get(i) + match &[D::VARIANTS, D::EXTENDED_VARIANTS.unwrap_or(&[])] + .concat() + .get(i) { Some(t) => { self.stack.push(v.clone()); - *t + **t } None => Tag::EOC, } diff --git a/src/jer/enc.rs b/src/jer/enc.rs index f6d8b8e3..b19117da 100644 --- a/src/jer/enc.rs +++ b/src/jer/enc.rs @@ -8,7 +8,7 @@ type ValueMap = Map; use crate::{ error::{EncodeError, JerEncodeErrorKind}, - types::{variants, Constraints, Identifier, IntegerType, Tag}, + types::{Constraints, Identifier, IntegerType, Tag}, }; use crate::types::RealType; @@ -487,9 +487,7 @@ impl crate::Encoder<'_> for Encoder { encode_fn: impl FnOnce(&mut Self) -> Result, _: Identifier, ) -> Result { - let variants = variants::Variants::from_slice( - &[E::VARIANTS, E::EXTENDED_VARIANTS.unwrap_or(&[])].concat(), - ); + let variants = &[E::VARIANTS, E::EXTENDED_VARIANTS.unwrap_or(&[])].concat(); let identifier = variants .iter() diff --git a/src/oer/de.rs b/src/oer/de.rs index 1c00cb7e..2f89931b 100644 --- a/src/oer/de.rs +++ b/src/oer/de.rs @@ -894,12 +894,12 @@ impl<'input, const RFC: usize, const EFC: usize> crate::Decoder for Decoder<'inp { let is_extensible = constraints.extensible(); let tag: Tag = self.parse_tag()?; - let is_root_extension = crate::types::TagTree::tag_contains(&tag, D::VARIANTS); - let is_extended_extension = - crate::types::TagTree::tag_contains(&tag, D::EXTENDED_VARIANTS.unwrap_or(&[])); + let is_root_extension = D::VARIANTS.contains(&tag); if is_root_extension { - D::from_tag(self, tag) - } else if is_extensible && is_extended_extension { + return D::from_tag(self, tag); + } + let is_extended_extension = D::EXTENDED_VARIANTS.unwrap_or(&[]).contains(&tag); + if is_extensible && is_extended_extension { let options = self.options; let length = self.decode_length()?; let bytes = self.extract_data_by_length(length)?; diff --git a/src/oer/enc.rs b/src/oer/enc.rs index a681aa0e..7516da9a 100644 --- a/src/oer/enc.rs +++ b/src/oer/enc.rs @@ -337,7 +337,8 @@ impl<'buffer, const RCL: usize, const ECL: usize> Encoder<'buffer, RCL, ECL> { // We must swap the first bit to show long form // It is always zero by default with u8 type when value being < 128 length |= 0b_1000_0000; - self.output.extend_from_slice(&length.to_be_bytes()); + self.output.reserve(1 + needed); + self.output.push(length); self.output.extend_from_slice(&bytes.as_ref()[..needed]); Ok(()) } @@ -349,7 +350,7 @@ impl<'buffer, const RCL: usize, const ECL: usize> Encoder<'buffer, RCL, ECL> { let (bytes, needed) = length.to_unsigned_bytes_be(); if length < 128 { // First bit should be always zero when below 128: ITU-T X.696 8.6.4 - buffer.extend_from_slice(&bytes.as_ref()[..needed]); + buffer.push(length as u8); return Ok(()); } let mut length_of_length = u8::try_from(needed).map_err(|err| { @@ -367,7 +368,8 @@ impl<'buffer, const RCL: usize, const ECL: usize> Encoder<'buffer, RCL, ECL> { // We must swap the first bit to show long form // It is always zero by default with u8 type when value being < 128 length_of_length |= 0b_1000_0000; - buffer.extend_from_slice(&length_of_length.to_be_bytes()); + buffer.reserve(1 + needed); + buffer.push(length_of_length); buffer.extend_from_slice(&bytes.as_ref()[..needed]); Ok(()) } @@ -591,8 +593,7 @@ impl<'buffer, const RCL: usize, const ECL: usize> Encoder<'buffer, RCL, ECL> { let mut cursor = self.cursor.extension_bitmap_cursor + self.worker.len(); self.output[self.cursor.extension_bitmap_cursor..cursor].copy_from_slice(self.worker); self.worker.clear(); - self.output[cursor..=cursor] - .copy_from_slice(&self.cursor.extension_missing_bits.to_be_bytes()); + self.output[cursor] = self.cursor.extension_missing_bits; cursor += 1; for (i, bit) in self.extension_bitfield.1.iter().enumerate() { extension_bitmap_buffer.set(i, *bit); @@ -647,8 +648,7 @@ impl<'buffer, const RFC: usize, const EFC: usize> crate::Encoder<'buffer> value: bool, _: Identifier, ) -> Result { - self.output - .extend_from_slice(if value { &[0xffu8] } else { &[0x00u8] }); + self.output.push(if value { 0xffu8 } else { 0x00u8 }); self.extend(tag); Ok(()) } @@ -698,7 +698,7 @@ impl<'buffer, const RFC: usize, const EFC: usize> crate::Encoder<'buffer> // If the BitString is empty, length is one and initial octet is zero if value.is_empty() { Self::encode_length(self.output, 1)?; - self.output.extend_from_slice(&[0x00u8]); + self.output.push(0x00u8); } else { // TODO 22.7 X.680, NamedBitString and COER // if self.options.encoding_rules.is_coer() @@ -979,9 +979,9 @@ impl<'buffer, const RFC: usize, const EFC: usize> crate::Encoder<'buffer> ); cursor.set_preamble_cursor(encoder.output.len()); // reserve bytes for preamble - for _ in 0..cursor.preamble_width { - encoder.output.push(0); - } + encoder + .output + .resize(encoder.output.len() + cursor.preamble_width, 0); encoder.cursor = cursor; encoder_scope(&mut encoder)?; @@ -1100,7 +1100,7 @@ impl<'buffer, const RFC: usize, const EFC: usize> crate::Encoder<'buffer> // Encode the value let _tag = encode_fn(self)?; debug_assert_eq!(_tag, tag); - let is_root_extension = crate::types::TagTree::tag_contains(&tag, E::VARIANTS); + let is_root_extension = E::VARIANTS.contains(&tag); if is_root_extension { // all good, correct data in the buffer already } else { diff --git a/src/per/de.rs b/src/per/de.rs index 0f5f459e..e73d177e 100644 --- a/src/per/de.rs +++ b/src/per/de.rs @@ -1048,11 +1048,11 @@ impl<'input, const RFC: usize, const EFC: usize> crate::Decoder for Decoder<'inp D: crate::types::DecodeChoice, { let is_extensible = self.parse_extensible_bit(&constraints)?; - let variants = crate::types::variants::Variants::from_static(if is_extensible { + let variants = if is_extensible { D::EXTENDED_VARIANTS.unwrap_or(&[]) } else { D::VARIANTS - }); + }; let index = if variants.len() != 1 || is_extensible { if is_extensible { @@ -1080,7 +1080,7 @@ impl<'input, const RFC: usize, const EFC: usize> crate::Decoder for Decoder<'inp }; let tag = variants.get(index).ok_or_else(|| { - DecodeError::choice_index_not_found(index, variants.clone(), self.codec()) + DecodeError::choice_index_not_found(index, variants.to_vec(), self.codec()) })?; if is_extensible { diff --git a/src/per/enc.rs b/src/per/enc.rs index f3dd26cf..86b36f65 100644 --- a/src/per/enc.rs +++ b/src/per/enc.rs @@ -1234,22 +1234,22 @@ impl crate::Encoder<'_> for Encoder Result { let mut buffer = BitString::new(); - let is_root_extension = crate::types::TagTree::tag_contains(&tag, E::VARIANTS); + let is_root_extension = E::VARIANTS.contains(&tag); self.encode_extensible_bit(&constraints, &mut buffer, || is_root_extension); - let variants = crate::types::variants::Variants::from_static(if is_root_extension { + let tags = if is_root_extension { E::VARIANTS } else { E::EXTENDED_VARIANTS.unwrap_or(&[]) - }); + }; - let index = variants + let index = tags .iter() .enumerate() .find_map(|(i, &variant_tag)| (tag == variant_tag).then_some(i)) .ok_or_else(|| Error::variant_not_in_choice(self.codec()))?; let bounds = if is_root_extension { - let variance = variants.len(); + let variance = tags.len(); debug_assert!(variance > 0); if variance == 1 { None diff --git a/src/types.rs b/src/types.rs index a51642d8..5b1b0e61 100644 --- a/src/types.rs +++ b/src/types.rs @@ -12,7 +12,6 @@ mod tag; pub mod constraints; pub mod fields; -pub mod variants; pub(crate) mod constructed; pub(crate) mod date; @@ -91,11 +90,11 @@ pub trait AsnType { /// A `CHOICE` value. pub trait Choice: Sized { /// Variants contained in the "root component list". - const VARIANTS: &'static [TagTree]; + const VARIANTS: &'static [Tag]; /// Constraint for the choice type, based on the number of root components. Used for PER encoding. const VARIANCE_CONSTRAINT: Constraints; /// Variants contained in the list of extensions. - const EXTENDED_VARIANTS: Option<&'static [TagTree]> = None; + const EXTENDED_VARIANTS: Option<&'static [Tag]> = None; /// Variant identifiers for text-based encoding rules const IDENTIFIERS: &'static [&'static str]; } diff --git a/src/types/variants.rs b/src/types/variants.rs index df8ad849..8c9e9385 100644 --- a/src/types/variants.rs +++ b/src/types/variants.rs @@ -1,71 +1,67 @@ -//! Representing all possible variants for a `CHOICE` type. +// //! Representing all possible variants for a `CHOICE` type. -use alloc::{borrow::Cow, vec, vec::Vec}; +// use alloc::{borrow::Cow, vec, vec::Vec}; -use crate::types::{Tag, TagTree}; +// use crate::types::{Tag, TagTree}; -/// A set of tags which represents all possible tags used in this field. -#[derive(Debug, Clone)] -pub struct Variants { - fields: Vec, -} +// /// A set of tags which represents all possible tags used in this field. +// #[derive(Debug, Clone)] +// pub struct Variants { +// fields: Vec, +// } -impl Variants { - /// Creates a new set of variants from a given set of tag trees. - #[must_use] - pub fn new(fields: Cow<'static, [TagTree]>) -> Self { - Self::flatten_tree((*fields).iter()) - } +// impl Variants { +// /// Creates a new set of variants from a given set of tag trees. +// pub fn new(fields: Cow<'static, [TagTree]>) -> Self { +// Self::flatten_tree((*fields).iter()) +// } - /// Returns an empty set of variants. - #[must_use] - pub const fn empty() -> Self { - Self { fields: Vec::new() } - } +// /// Returns an empty set of variants. +// pub const fn empty() -> Self { +// Self { fields: Vec::new() } +// } - /// Creates a new set of variants from a static set of tag trees. - #[must_use] - pub fn from_static(fields: &'static [TagTree]) -> Self { - Self::new(Cow::Borrowed(fields)) - } +// /// Creates a new set of variants from a static set of tag trees. +// pub fn from_static(fields: &'static [TagTree]) -> Self { +// Self::new(Cow::Borrowed(fields)) +// } - /// Creates a new set of variants a static set of tag trees. - #[must_use] - pub fn from_slice(fields: &[TagTree]) -> Self { - Self::flatten_tree(fields.iter()) - } +// /// Creates a new set of variants a static set of tag trees. +// pub fn from_slice(fields: &[TagTree]) -> Self { +// Self::flatten_tree(fields.iter()) +// } - fn flatten_tree<'a, I>(field_iter: I) -> Self - where - I: Iterator, - { - let fields = field_iter - .flat_map(|tree| { - fn flatten_tree(tree: &TagTree) -> Vec { - match tree { - TagTree::Leaf(tag) => vec![*tag], - TagTree::Choice(tree) => tree.iter().flat_map(flatten_tree).collect(), - } - } +// fn flatten_tree<'a, I>(field_iter: I) -> Self +// where +// I: Iterator, +// { +// let fields = field_iter +// .flat_map(|tree| { +// fn flatten_tree(tree: &TagTree) -> Vec { +// match tree { +// TagTree::Leaf(tag) => vec![*tag], +// TagTree::Choice(tree) => tree.iter().flat_map(flatten_tree).collect(), +// } +// } - flatten_tree(tree) - }) - .collect(); +// flatten_tree(tree) +// }) +// .collect(); - Self { fields } - } -} +// Self { fields } +// } +// } -impl From> for Variants { - fn from(fields: Cow<'static, [TagTree]>) -> Self { - Self::new(fields) - } -} +// impl From> for Variants { +// fn from(fields: Cow<'static, [TagTree]>) -> Self { +// Self::new(fields) +// } +// } -impl core::ops::Deref for Variants { - type Target = [Tag]; +// impl core::ops::Deref for Variants { +// type Target = [Tag]; - fn deref(&self) -> &Self::Target { - &self.fields - } -} +// fn deref(&self) -> &Self::Target { +// &self.fields +// } +// } diff --git a/src/xer/de.rs b/src/xer/de.rs index 379488e1..2b944b71 100644 --- a/src/xer/de.rs +++ b/src/xer/de.rs @@ -819,11 +819,10 @@ impl crate::Decoder for Decoder { .enumerate() .find(|(_, id)| id.eq_ignore_ascii_case(&name.local_name)) .and_then(|(i, _)| { - variants::Variants::from_slice( - &[D::VARIANTS, D::EXTENDED_VARIANTS.unwrap_or(&[])].concat(), - ) - .get(i) - .cloned() + [D::VARIANTS, D::EXTENDED_VARIANTS.unwrap_or(&[])] + .concat() + .get(i) + .copied() }) .unwrap_or(Tag::EOC); let events = self