From f83d410099c0a6dc474a104678aa633434fff7fa Mon Sep 17 00:00:00 2001 From: Niklas Saari Date: Sat, 7 Sep 2024 16:52:18 +0300 Subject: [PATCH 01/22] Improve range computation --- src/oer/ranges.rs | 154 +++++++++++++++++++++++++++------------------- 1 file changed, 92 insertions(+), 62 deletions(-) diff --git a/src/oer/ranges.rs b/src/oer/ranges.rs index 1d57fa8a..4b7c8b29 100644 --- a/src/oer/ranges.rs +++ b/src/oer/ranges.rs @@ -2,80 +2,110 @@ use crate::types::constraints::{Bounded, Extensible, Value}; /// ITU-T X.696 (02/2021) 10.0 /// -/// Number of octets by value ranges for unsigned integers +/// Number of octets by value ranges for unsigned and signed integers /// 1, 2, 4 or 8 octets -const UNSIGNED_RANGES: [(i128, i128, u8); 4] = [ - (0i128, u8::MAX as i128, 1), - (0i128, u16::MAX as i128, 2), - (0i128, u32::MAX as i128, 4), - (0i128, u64::MAX as i128, 8), -]; -/// Number of octets by value ranges for signed integers -/// 1, 2, 4 or 8 octets -const SIGNED_RANGES: [(i128, i128, u8); 4] = [ - (i8::MIN as i128, i8::MAX as i128, 1), - (i16::MIN as i128, i16::MAX as i128, 2), - (i32::MIN as i128, i32::MAX as i128, 4), - (i64::MIN as i128, i64::MAX as i128, 8), -]; pub fn octet_size_by_range(value: i128) -> Option { - for i in [UNSIGNED_RANGES, SIGNED_RANGES] { - if let Some(octets) = i - .iter() - .find(|&&(min, max, _)| value >= min && value <= max) - .map(|&(_, _, octets)| octets) - { - return Some(octets); - } + let range = if value >= 0 { + // For unsigned values + Some(((128 - value.leading_zeros() + 7) / 8) as u8) + } else { + // For signed values + Some(((128 - (value + 1).leading_zeros() + 7) / 8) as u8) + }; + match range { + Some(1) => Some(1), + Some(2) => Some(2), + Some(3..5) => Some(4), + Some(5..=8) => Some(8), + _ => None, } - None } -// Constraints limit Bound to i128 in Value type (see Value struct) -// Only Value constraint is OER visible (range, single value) -// TODO - maybe use BigInt instead of i128 some day? + +// // Constraints limit Bound to i128 in Value type (see Value struct) +// // Only Value constraint is OER visible (range, single value) +// // TODO - maybe use BigInt instead of i128 some day? +// pub fn determine_integer_size_and_sign( +// value_constraint: &Extensible, +// data: U, +// // transform_fn takes data, integers' signed status, and octet number required to contain integer +// // based on the constraints +// mut transform_fn: impl FnMut(U, bool, Option) -> Result, +// ) -> Result { +// // Ignore constraints if extension marker is present +// if value_constraint.extensible.is_some() { +// return transform_fn(data, true, None); +// } +// match value_constraint.constraint.0 { +// Bounded::Range { +// start: Some(start), +// end: Some(end), +// } => { +// if start >= 0 { +// for (min, max, octets) in UNSIGNED_RANGES { +// if min <= start && end <= max { +// return transform_fn(data, false, Some(octets)); +// } +// } +// // Upper bound is out of range, use length determinant +// return transform_fn(data, false, None); +// } +// for (min, max, octets) in SIGNED_RANGES { +// if min <= start && end <= max { +// return transform_fn(data, true, Some(octets)); +// } +// } +// // Negative lower bound, and out of range, use length determinant and signed integers +// transform_fn(data, true, None) +// } +// Bounded::Range { +// start: Some(start), +// end: None, +// } => transform_fn(data, start < 0, None), +// Bounded::Range { +// start: None, +// end: Some(_) | None, +// } +// | Bounded::None => transform_fn(data, true, None), +// // TODO - check if this is correct way instead of not encoding at all, or true/false +// Bounded::Single(value) => transform_fn(data, value < 0, octet_size_by_range(value)), +// } +// } + pub fn determine_integer_size_and_sign( value_constraint: &Extensible, data: U, - // transform_fn takes data, integers' signed status, and octet number required to contain integer - // based on the constraints mut transform_fn: impl FnMut(U, bool, Option) -> Result, ) -> Result { - // Ignore constraints if extension marker is present if value_constraint.extensible.is_some() { return transform_fn(data, true, None); } - match value_constraint.constraint.0 { - Bounded::Range { - start: Some(start), - end: Some(end), - } => { - if start >= 0 { - for (min, max, octets) in UNSIGNED_RANGES { - if min <= start && end <= max { - return transform_fn(data, false, Some(octets)); - } - } - // Upper bound is out of range, use length determinant - return transform_fn(data, false, None); - } - for (min, max, octets) in SIGNED_RANGES { - if min <= start && end <= max { - return transform_fn(data, true, Some(octets)); - } + + match &value_constraint.constraint.0 { + Bounded::Range { start, end } => match (start, end) { + (Some(start), Some(end)) => { + let is_signed = *start < 0; + let octets = if is_signed { + get_signed_octets(*start, *end) + } else { + get_unsigned_octets(*start, *end) + }; + transform_fn(data, is_signed, octets) } - // Negative lower bound, and out of range, use length determinant and signed integers - transform_fn(data, true, None) - } - Bounded::Range { - start: Some(start), - end: None, - } => transform_fn(data, start < 0, None), - Bounded::Range { - start: None, - end: Some(_) | None, - } - | Bounded::None => transform_fn(data, true, None), - // TODO - check if this is correct way instead of not encoding at all, or true/false - Bounded::Single(value) => transform_fn(data, value < 0, octet_size_by_range(value)), + (Some(start), None) => transform_fn(data, *start < 0, None), + _ => transform_fn(data, true, None), + }, + Bounded::Single(value) => transform_fn(data, *value < 0, octet_size_by_range(*value)), + Bounded::None => transform_fn(data, true, None), } } + +fn get_unsigned_octets(start: i128, end: i128) -> Option { + let max_value = end.max(start); + octet_size_by_range(max_value) +} + +fn get_signed_octets(start: i128, end: i128) -> Option { + let min_value = start.min(end); + let max_value = start.max(end); + octet_size_by_range(min_value.abs().max(max_value.abs())) +} From f344aff38fa36e27e9bbdff9f5bbbf8b1116eb68 Mon Sep 17 00:00:00 2001 From: Niklas Saari Date: Mon, 9 Sep 2024 20:40:32 +0300 Subject: [PATCH 02/22] Make constraints explicitly constant --- macros/macros_impl/src/config.rs | 38 +++++++---- src/oer/de.rs | 35 +++++----- src/oer/enc.rs | 35 +++++----- src/oer/ranges.rs | 111 ------------------------------- src/types/constraints.rs | 90 ++++++++++++++++++++++--- 5 files changed, 141 insertions(+), 168 deletions(-) delete mode 100644 src/oer/ranges.rs diff --git a/macros/macros_impl/src/config.rs b/macros/macros_impl/src/config.rs index dc025cc4..09a99ea7 100644 --- a/macros/macros_impl/src/config.rs +++ b/macros/macros_impl/src/config.rs @@ -751,6 +751,7 @@ impl<'a> FieldConfig<'a> { pub fn encode(&self, context: usize, use_self: bool) -> proc_macro2::TokenStream { let this = use_self.then(|| quote!(self.)); let tag = self.tag(context); + let constraint_name = format_ident!("CONSTRAINT_{}", context); let i = syn::Index::from(context); let field = self .field @@ -773,9 +774,10 @@ impl<'a> FieldConfig<'a> { .const_expr(&self.container_config.crate_root) .unwrap_or_else(|| quote!(#crate_root::types::Constraints::default())); quote!( + const #constraint_name : #crate_root::types::Constraints = #constraints; encoder.encode_extension_addition( #tag, - <#ty as #crate_root::AsnType>::CONSTRAINTS.override_constraints(#constraints), + <#ty as #crate_root::AsnType>::CONSTRAINTS.override_constraints(#constraint_name), &#this #field )?; ) @@ -789,9 +791,10 @@ impl<'a> FieldConfig<'a> { match (self.constraints.has_constraints(), self.default.is_some()) { (true, true) => { quote!( + const #constraint_name : #crate_root::types::Constraints = #constraints; encoder.encode_default_with_tag_and_constraints( #tag, - <#ty as #crate_root::AsnType>::CONSTRAINTS.override_constraints(#constraints), + <#ty as #crate_root::AsnType>::CONSTRAINTS.override_constraints(#constraint_name), &#this #field, #default_fn )?; @@ -799,10 +802,11 @@ impl<'a> FieldConfig<'a> { } (true, false) => { quote!( + const #constraint_name : #crate_root::types::Constraints = #constraints; #this #field.encode_with_tag_and_constraints( encoder, #tag, - <#ty as #crate_root::AsnType>::CONSTRAINTS.override_constraints(#constraints), + <#ty as #crate_root::AsnType>::CONSTRAINTS.override_constraints(#constraint_name), #default_fn )?; ) @@ -819,9 +823,10 @@ impl<'a> FieldConfig<'a> { .const_expr(&self.container_config.crate_root) .unwrap_or_else(|| quote!(#crate_root::types::Constraints::default())); quote!( + const #constraint_name : #crate_root::types::Constraints = #constraints; encoder.encode_extension_addition( #tag, - <#ty as #crate_root::AsnType>::CONSTRAINTS.override_constraints(#constraints), + <#ty as #crate_root::AsnType>::CONSTRAINTS.override_constraints(#constraint_name), &#this #field )?; ) @@ -834,8 +839,9 @@ impl<'a> FieldConfig<'a> { .constraints .const_expr(&self.container_config.crate_root); quote!( + const #constraint_name : #crate_root::types::Constraints = #constraints; encoder.encode_default_with_constraints( - <#ty as #crate_root::AsnType>::CONSTRAINTS.override_constraints(#constraints), + <#ty as #crate_root::AsnType>::CONSTRAINTS.override_constraints(#constraint_name), &#this #field, #default_fn )?; @@ -846,9 +852,10 @@ impl<'a> FieldConfig<'a> { .constraints .const_expr(&self.container_config.crate_root); quote!( + const #constraint_name : rasn::types::Constraints = #constraints; #this #field.encode_with_constraints( encoder, - <#ty as #crate_root::AsnType>::CONSTRAINTS.override_constraints(#constraints), + <#ty as #crate_root::AsnType>::CONSTRAINTS.override_constraints(#constraint_name), )?; ) } @@ -885,6 +892,7 @@ impl<'a> FieldConfig<'a> { let default_fn = self.default_fn(); let tag = self.tag(context); + let constraint_name = format_ident!("CONSTRAINT_{}", context); let constraints = self.constraints.const_expr(crate_root); let handle_extension = if self.is_not_option_or_default_type() { quote!(.ok_or_else(|| { @@ -923,10 +931,11 @@ impl<'a> FieldConfig<'a> { } (Some(false), Some(path), true) => { quote!( + const #constraint_name : #crate_root::types::Constraints = #constraints; decoder.decode_default_with_tag_and_constraints( #tag, #path, - <#ty as #crate_root::AsnType>::CONSTRAINTS.override_constraints(#constraints), + <#ty as #crate_root::AsnType>::CONSTRAINTS.override_constraints(#constraint_name), ) #or_else ) } @@ -935,10 +944,11 @@ impl<'a> FieldConfig<'a> { } (Some(false), None, true) => { quote!( + const #constraint_name : #crate_root::types::Constraints = #constraints; <_>::decode_with_tag_and_constraints( decoder, #tag, - <#ty as #crate_root::AsnType>::CONSTRAINTS.override_constraints(#constraints), + <#ty as #crate_root::AsnType>::CONSTRAINTS.override_constraints(#constraint_name), ) #or_else ) } @@ -947,9 +957,10 @@ impl<'a> FieldConfig<'a> { } (None, Some(path), true) => { quote!( + const #constraint_name : #crate_root::types::Constraints = #constraints; decoder.decode_default_with_constraints( #path, - <#ty as #crate_root::AsnType>::CONSTRAINTS.override_constraints(#constraints), + <#ty as #crate_root::AsnType>::CONSTRAINTS.override_constraints(#constraint_name), ) #or_else ) } @@ -958,9 +969,10 @@ impl<'a> FieldConfig<'a> { } (None, None, true) => { quote!( + const #constraint_name : #crate_root::types::Constraints = #constraints; <_>::decode_with_constraints( decoder, - <#ty as #crate_root::AsnType>::CONSTRAINTS.override_constraints(#constraints), + <#ty as #crate_root::AsnType>::CONSTRAINTS.override_constraints(#constraint_name), ) #or_else ) } @@ -1028,9 +1040,10 @@ impl<'a> FieldConfig<'a> { } (None, Some(path), true) => { quote!( + const #constraint_name : #crate_root::types::Constraints = #constraints; decoder.decode_extension_addition_with_default_and_constraints( #path, - <#ty as #crate_root::AsnType>::CONSTRAINTS.override_constraints(#constraints), + <#ty as #crate_root::AsnType>::CONSTRAINTS.override_constraints(#constraint_name), ) #or_else ) } @@ -1043,8 +1056,9 @@ impl<'a> FieldConfig<'a> { } (None, None, true) => { quote!( + const #constraint_name : #crate_root::types::Constraints = #constraints; decoder.decode_extension_addition_with_constraints( - <#ty as #crate_root::AsnType>::CONSTRAINTS.override_constraints(#constraints), + <#ty as #crate_root::AsnType>::CONSTRAINTS.override_constraints(#constraint_name), ) #or_else ) } diff --git a/src/oer/de.rs b/src/oer/de.rs index b95798ee..4a9d57f3 100644 --- a/src/oer/de.rs +++ b/src/oer/de.rs @@ -12,7 +12,6 @@ use alloc::{ }; use crate::{ - oer::{ranges, EncodingRules}, types::{ self, fields::{Field, Fields}, @@ -270,27 +269,31 @@ impl<'input, const RFC: usize, const EFC: usize> Decoder<'input, RFC, EFC> { ) -> Result { // Only 'value' constraint is OER visible for integer if let Some(value) = constraints.value() { - ranges::determine_integer_size_and_sign(value, self.input, |_, sign, octets| { - let integer = self.decode_integer_from_bytes::(sign, octets.map(usize::from))?; - // if the value is too large for a i128, the constraint isn't satisfied - if let Some(constraint_integer) = integer.to_i128() { - if value.constraint.contains(&constraint_integer) { - Ok(integer) - } else { - Err(DecodeError::value_constraint_not_satisfied( - integer.to_bigint().unwrap_or_default(), - value.constraint.0, - self.codec(), - )) - } + let (sign, octets) = if value.extensible.is_some() { + (true, None) + } else { + (value.constraint.get_sign(), value.constraint.get_range()) + }; + let integer = self.decode_integer_from_bytes::(sign, octets.map(usize::from))?; + // if the value is too large for a i128, the constraint isn't satisfied + if let Some(constraint_integer) = integer.to_i128() { + if value.constraint.contains(&constraint_integer) { + Ok(integer) } else { Err(DecodeError::value_constraint_not_satisfied( integer.to_bigint().unwrap_or_default(), - value.constraint.0, + value.constraint.value, self.codec(), )) } - }) + } else { + Err(DecodeError::value_constraint_not_satisfied( + integer.to_bigint().unwrap_or_default(), + value.constraint.value, + self.codec(), + )) + } + // }) } else { // No constraints self.decode_integer_from_bytes::(true, None) diff --git a/src/oer/enc.rs b/src/oer/enc.rs index ccd9934e..471b0de2 100644 --- a/src/oer/enc.rs +++ b/src/oer/enc.rs @@ -6,7 +6,6 @@ use core::cell::RefCell; use num_traits::ToPrimitive; use crate::{ - oer::{ranges, EncodingRules}, types::{ Any, BitStr, BmpString, Choice, Constraints, Constructed, Date, Enumerated, GeneralString, GeneralizedTime, Ia5String, IntegerType, NumericString, PrintableString, SetOf, Tag, @@ -358,29 +357,27 @@ impl<'a, const RCL: usize, const ECL: usize> Encoder<'a, RCL, ECL> { value_to_enc: &I, ) -> Result<(), EncodeError> { if let Some(value) = constraints.value() { - if !value.constraint.0.in_bound(value_to_enc) && value.extensible.is_none() { + if !value.constraint.value.in_bound(value_to_enc) && value.extensible.is_none() { return Err(EncodeError::value_constraint_not_satisfied( value_to_enc.to_bigint().unwrap_or_default(), - &value.constraint.0, + &value.constraint.value, self.codec(), )); } - ranges::determine_integer_size_and_sign( - value, - value_to_enc, - |value_to_enc, sign, octets| -> Result<(), EncodeError> { - if let Some(octets) = octets { - self.encode_constrained_integer_with_padding( - usize::from(octets), - value_to_enc, - sign, - )?; - } else { - self.encode_unconstrained_integer(value_to_enc, sign)?; - } - Ok(()) - }, - )?; + let (sign, octets) = if value.extensible.is_some() { + (true, None) + } else { + (value.constraint.get_sign(), value.constraint.get_range()) + }; + if let Some(octets) = octets { + self.encode_constrained_integer_with_padding( + usize::from(octets), + value_to_enc, + sign, + )?; + } else { + self.encode_unconstrained_integer(value_to_enc, sign)?; + } } else { self.encode_unconstrained_integer(value_to_enc, true)?; } diff --git a/src/oer/ranges.rs b/src/oer/ranges.rs deleted file mode 100644 index 4b7c8b29..00000000 --- a/src/oer/ranges.rs +++ /dev/null @@ -1,111 +0,0 @@ -use crate::types::constraints::{Bounded, Extensible, Value}; - -/// ITU-T X.696 (02/2021) 10.0 -/// -/// Number of octets by value ranges for unsigned and signed integers -/// 1, 2, 4 or 8 octets -pub fn octet_size_by_range(value: i128) -> Option { - let range = if value >= 0 { - // For unsigned values - Some(((128 - value.leading_zeros() + 7) / 8) as u8) - } else { - // For signed values - Some(((128 - (value + 1).leading_zeros() + 7) / 8) as u8) - }; - match range { - Some(1) => Some(1), - Some(2) => Some(2), - Some(3..5) => Some(4), - Some(5..=8) => Some(8), - _ => None, - } -} - -// // Constraints limit Bound to i128 in Value type (see Value struct) -// // Only Value constraint is OER visible (range, single value) -// // TODO - maybe use BigInt instead of i128 some day? -// pub fn determine_integer_size_and_sign( -// value_constraint: &Extensible, -// data: U, -// // transform_fn takes data, integers' signed status, and octet number required to contain integer -// // based on the constraints -// mut transform_fn: impl FnMut(U, bool, Option) -> Result, -// ) -> Result { -// // Ignore constraints if extension marker is present -// if value_constraint.extensible.is_some() { -// return transform_fn(data, true, None); -// } -// match value_constraint.constraint.0 { -// Bounded::Range { -// start: Some(start), -// end: Some(end), -// } => { -// if start >= 0 { -// for (min, max, octets) in UNSIGNED_RANGES { -// if min <= start && end <= max { -// return transform_fn(data, false, Some(octets)); -// } -// } -// // Upper bound is out of range, use length determinant -// return transform_fn(data, false, None); -// } -// for (min, max, octets) in SIGNED_RANGES { -// if min <= start && end <= max { -// return transform_fn(data, true, Some(octets)); -// } -// } -// // Negative lower bound, and out of range, use length determinant and signed integers -// transform_fn(data, true, None) -// } -// Bounded::Range { -// start: Some(start), -// end: None, -// } => transform_fn(data, start < 0, None), -// Bounded::Range { -// start: None, -// end: Some(_) | None, -// } -// | Bounded::None => transform_fn(data, true, None), -// // TODO - check if this is correct way instead of not encoding at all, or true/false -// Bounded::Single(value) => transform_fn(data, value < 0, octet_size_by_range(value)), -// } -// } - -pub fn determine_integer_size_and_sign( - value_constraint: &Extensible, - data: U, - mut transform_fn: impl FnMut(U, bool, Option) -> Result, -) -> Result { - if value_constraint.extensible.is_some() { - return transform_fn(data, true, None); - } - - match &value_constraint.constraint.0 { - Bounded::Range { start, end } => match (start, end) { - (Some(start), Some(end)) => { - let is_signed = *start < 0; - let octets = if is_signed { - get_signed_octets(*start, *end) - } else { - get_unsigned_octets(*start, *end) - }; - transform_fn(data, is_signed, octets) - } - (Some(start), None) => transform_fn(data, *start < 0, None), - _ => transform_fn(data, true, None), - }, - Bounded::Single(value) => transform_fn(data, *value < 0, octet_size_by_range(*value)), - Bounded::None => transform_fn(data, true, None), - } -} - -fn get_unsigned_octets(start: i128, end: i128) -> Option { - let max_value = end.max(start); - octet_size_by_range(max_value) -} - -fn get_signed_octets(start: i128, end: i128) -> Option { - let min_value = start.min(end); - let max_value = start.max(end); - octet_size_by_range(min_value.abs().max(max_value.abs())) -} diff --git a/src/types/constraints.rs b/src/types/constraints.rs index 4132bc67..cda437fe 100644 --- a/src/types/constraints.rs +++ b/src/types/constraints.rs @@ -234,12 +234,30 @@ impl From for Extensible { /// A single or range of numeric values a type can be. #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct Value(pub(crate) Bounded); +pub struct Value { + /// Bound of the value + pub(crate) value: Bounded, + /// Sign of the bound, used for numeric values + pub(crate) signed: bool, + /// Range of the bound in bytes, used for numeric values + pub(crate) range: Option, +} impl Value { /// Creates a new value constraint from a given bound. pub const fn new(value: Bounded) -> Self { - Self(value) + let (signed, range) = value.range_in_bytes(); + Self { + value, + signed, + range, + } + } + pub const fn get_sign(&self) -> bool { + self.signed + } + pub const fn get_range(&self) -> Option { + self.range } } @@ -247,22 +265,22 @@ impl core::ops::Deref for Value { type Target = Bounded; fn deref(&self) -> &Self::Target { - &self.0 + &self.value } } -impl core::ops::DerefMut for Value { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} +// impl core::ops::DerefMut for Value { +// fn deref_mut(&mut self) -> &mut Self::Target { +// &mut self.value +// } +// } macro_rules! from_primitives { ($($int:ty),+ $(,)?) => { $( impl From> for Value { fn from(bounded: Bounded<$int>) -> Self { - Self(match bounded { + Self::new(match bounded { Bounded::Range { start, end } => Bounded::Range { start: start.map(From::from), end: end.map(From::from), @@ -285,7 +303,7 @@ impl TryFrom> for Value { type Error = >::Error; fn try_from(bounded: Bounded) -> Result { - Ok(Self(match bounded { + Ok(Self::new(match bounded { Bounded::Range { start, end } => Bounded::Range { start: start.map(TryFrom::try_from).transpose()?, end: end.map(TryFrom::try_from).transpose()?, @@ -381,6 +399,23 @@ pub enum Bounded { } impl Bounded { + /// Calculates the the amount of bytes that are required to represent integer `value`. + /// Particularly useful for OER codec + #[inline(always)] + const fn octet_size_by_range(value: i128) -> Option { + let abs_value = value.unsigned_abs(); + Some(if abs_value <= u8::MAX as u128 { + 1 + } else if abs_value <= u16::MAX as u128 { + 2 + } else if abs_value <= u32::MAX as u128 { + 4 + } else if abs_value <= u64::MAX as u128 { + 8 + } else { + return None; + }) + } /// Creates a bounded range that starts from value and has no end. pub const fn start_from(value: T) -> Self { Self::Range { @@ -538,6 +573,30 @@ impl From> for Constraint { } impl Bounded { + const fn max(&self, a: u128, b: u128) -> u128 { + [a, b][(a < b) as usize] + } + pub const fn range_in_bytes(&self) -> (bool, Option) { + match self { + Self::Single(value) => (*value < 0, Self::octet_size_by_range(*value)), + Self::Range { + start: Some(start), + end: Some(end), + } => { + let is_signed = *start < 0; + let end_abs = end.unsigned_abs(); + let start_abs = start.unsigned_abs(); + let max = self.max(start_abs, end_abs); + let octets = Self::octet_size_by_range(max as i128); + (is_signed, octets) + } + Self::Range { + start: Some(start), + end: None, + } => (*start < 0, None), + Self::Range { start: None, .. } | Self::None => (true, None), + } + } /// Returns `true` if the given element is within the bounds of the constraint. /// Constraint type is `i128` here, so we can make checks based on that. pub fn in_bound(&self, element: &I) -> bool { @@ -648,4 +707,15 @@ mod tests { let constraints = Bounded::new(0, 255); assert_eq!(256, constraints.range().unwrap()); } + #[test] + fn check_const_validity() { + const MY_CONST: Constraints = Constraints::new(&[Constraint::Value( + Extensible::new(Value::new(Bounded::const_new( + 0i128 as i128, + 255i128 as i128, + ))) + .set_extensible(false), + )]); + dbg!(MY_CONST); + } } From a9f27273f4d12f5092bd93ccd91be065184bcebe Mon Sep 17 00:00:00 2001 From: Niklas Saari Date: Mon, 9 Sep 2024 22:25:45 +0300 Subject: [PATCH 03/22] Fix constraints default --- macros/macros_impl/src/config.rs | 4 +++- src/jer/enc.rs | 12 ++++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/macros/macros_impl/src/config.rs b/macros/macros_impl/src/config.rs index 09a99ea7..26d25ccb 100644 --- a/macros/macros_impl/src/config.rs +++ b/macros/macros_impl/src/config.rs @@ -852,7 +852,7 @@ impl<'a> FieldConfig<'a> { .constraints .const_expr(&self.container_config.crate_root); quote!( - const #constraint_name : rasn::types::Constraints = #constraints; + const #constraint_name : #crate_root::types::Constraints = #constraints; #this #field.encode_with_constraints( encoder, <#ty as #crate_root::AsnType>::CONSTRAINTS.override_constraints(#constraint_name), @@ -1040,11 +1040,13 @@ impl<'a> FieldConfig<'a> { } (None, Some(path), true) => { quote!( + { const #constraint_name : #crate_root::types::Constraints = #constraints; decoder.decode_extension_addition_with_default_and_constraints( #path, <#ty as #crate_root::AsnType>::CONSTRAINTS.override_constraints(#constraint_name), ) #or_else + } ) } (None, Some(path), false) => { diff --git a/src/jer/enc.rs b/src/jer/enc.rs index 7fc35921..56e2e427 100644 --- a/src/jer/enc.rs +++ b/src/jer/enc.rs @@ -71,8 +71,16 @@ impl crate::Encoder for Encoder { type Error = EncodeError; type AnyEncoder = Encoder; - fn encode_any(&mut self, t: Tag, value: &crate::types::Any) -> Result { - self.encode_octet_string(t, Constraints::default(), &value.contents) + fn encode_any( + &mut self, + t: crate::types::Tag, + value: &crate::types::Any, + ) -> Result { + self.encode_octet_string( + t, + crate::types::constraints::Constraints::default(), + &value.contents, + ) } fn encode_bool(&mut self, _: Tag, value: bool) -> Result { From 865752096e846344c779109e22d48daccaee80fb Mon Sep 17 00:00:00 2001 From: Niklas Saari Date: Thu, 12 Sep 2024 00:54:04 +0300 Subject: [PATCH 04/22] Initial 'static constraints --- macros/macros_impl/src/config.rs | 20 ++- macros/macros_impl/src/decode.rs | 2 +- macros/macros_impl/src/encode.rs | 2 +- macros/macros_impl/src/enum.rs | 19 ++- src/aper.rs | 6 + src/lib.rs | 1 + src/per/de.rs | 4 +- src/types.rs | 9 +- src/types/constraints.rs | 218 ++++++++++++++++++++++++++----- src/types/integer.rs | 2 +- src/types/strings/octet.rs | 6 +- src/uper.rs | 1 + standards/pkix/src/lib.rs | 2 +- 13 files changed, 237 insertions(+), 55 deletions(-) diff --git a/macros/macros_impl/src/config.rs b/macros/macros_impl/src/config.rs index 26d25ccb..11f14cce 100644 --- a/macros/macros_impl/src/config.rs +++ b/macros/macros_impl/src/config.rs @@ -15,9 +15,8 @@ pub struct Constraints { impl Constraints { pub fn const_static_def(&self, crate_root: &syn::Path) -> Option { - self.const_expr(crate_root).map( - |expr| quote!(const CONSTRAINTS: #crate_root::types::Constraints<'static> = #expr;), - ) + self.const_expr(crate_root) + .map(|expr| quote!(const CONSTRAINTS: #crate_root::types::Constraints = #expr;)) } pub fn attribute_tokens(&self) -> Option { @@ -505,6 +504,8 @@ impl<'config> VariantConfig<'config> { let tag_tree = self.tag_tree(context); let ident = &self.variant.ident; let is_explicit = self.has_explicit_tag(); + let constraint_name = format_ident!("DECODE_CONSTRAINT_{}", context); + let mut const_constraint = quote! {}; let decode_op = match &self.variant.fields { syn::Fields::Unit => { @@ -536,12 +537,18 @@ impl<'config> VariantConfig<'config> { .map(|path| quote!(#path)) .unwrap_or_else(|| quote!(<_>::default)); if let Some(constraints) = constraints { - quote!(decoder.decode_default_with_tag_and_constraints(tag, #path, #constraints)) + const_constraint = quote! { + const #constraint_name: #crate_root::types::constraints::Constraints = #constraints; + }; + quote!(decoder.decode_default_with_tag_and_constraints(tag, #path, #constraint_name)) } else { quote!(decoder.decode_default_with_tag(tag, #path)) } } else if let Some(constraints) = constraints { - quote!(<_>::decode_with_tag_and_constraints(decoder, tag, #constraints)) + const_constraint = quote! { + const #constraint_name: #crate_root::types::constraints::Constraints = #constraints; + }; + quote!(<_>::decode_with_tag_and_constraints(decoder, tag, #constraint_name)) } else { quote!(<_>::decode_with_tag(decoder, tag)) } @@ -587,6 +594,7 @@ impl<'config> VariantConfig<'config> { quote! { if #crate_root::types::TagTree::tag_contains(&tag, &[#tag_tree]) { + #const_constraint return #decode_op } } @@ -751,7 +759,7 @@ impl<'a> FieldConfig<'a> { pub fn encode(&self, context: usize, use_self: bool) -> proc_macro2::TokenStream { let this = use_self.then(|| quote!(self.)); let tag = self.tag(context); - let constraint_name = format_ident!("CONSTRAINT_{}", context); + let constraint_name = format_ident!("FIELD_CONSTRAINT_{}", context); let i = syn::Index::from(context); let field = self .field diff --git a/macros/macros_impl/src/decode.rs b/macros/macros_impl/src/decode.rs index cd52392a..3ab118e6 100644 --- a/macros/macros_impl/src/decode.rs +++ b/macros/macros_impl/src/decode.rs @@ -254,7 +254,7 @@ pub fn derive_struct_impl( quote! { impl #impl_generics #crate_root::Decode for #name #ty_generics #where_clause { - fn decode_with_tag_and_constraints<'constraints, D: #crate_root::Decoder>(decoder: &mut D, tag: #crate_root::types::Tag, constraints: #crate_root::types::Constraints<'constraints>) -> core::result::Result { + fn decode_with_tag_and_constraints(decoder: &mut D, tag: #crate_root::types::Tag, constraints: #crate_root::types::Constraints) -> core::result::Result { #decode_impl } } diff --git a/macros/macros_impl/src/encode.rs b/macros/macros_impl/src/encode.rs index b9d3414d..3364596b 100644 --- a/macros/macros_impl/src/encode.rs +++ b/macros/macros_impl/src/encode.rs @@ -87,7 +87,7 @@ pub fn derive_struct_impl( quote! { #[allow(clippy::mutable_key_type)] impl #impl_generics #crate_root::Encode for #name #ty_generics #where_clause { - fn encode_with_tag_and_constraints<'constraints, EN: #crate_root::Encoder>(&self, encoder: &mut EN, tag: #crate_root::types::Tag, constraints: #crate_root::types::Constraints<'constraints>) -> core::result::Result<(), EN::Error> { + fn encode_with_tag_and_constraints(&self, encoder: &mut EN, tag: #crate_root::types::Tag, constraints: #crate_root::types::Constraints) -> core::result::Result<(), EN::Error> { #(#vars)* #encode_impl diff --git a/macros/macros_impl/src/enum.rs b/macros/macros_impl/src/enum.rs index 295bc6ae..4ee0d7ad 100644 --- a/macros/macros_impl/src/enum.rs +++ b/macros/macros_impl/src/enum.rs @@ -90,6 +90,7 @@ impl Enum { let extended_const_variants = extensible .then(|| quote!(Some(&[#(#extended_variants),*]))) .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 @@ -308,7 +309,7 @@ impl Enum { #[automatically_derived] impl #impl_generics #crate_root::Decode for #name #ty_generics #where_clause { - fn decode_with_tag_and_constraints<'constraints, D: #crate_root::Decoder>(decoder: &mut D, tag: #crate_root::types::Tag, constraints: #crate_root::types::Constraints<'constraints>) -> core::result::Result { + fn decode_with_tag_and_constraints(decoder: &mut D, tag: #crate_root::types::Tag, constraints: #crate_root::types::Constraints) -> core::result::Result { #decode_with_tag } @@ -330,7 +331,7 @@ impl Enum { }; quote! { - fn encode_with_tag_and_constraints<'constraints, EN: #crate_root::Encoder>(&self, encoder: &mut EN, tag: #crate_root::types::Tag, constraints: #crate_root::types::Constraints<'constraints>) -> core::result::Result<(), EN::Error> { + fn encode_with_tag_and_constraints(&self, encoder: &mut EN, tag: #crate_root::types::Tag, constraints: #crate_root::types::Constraints) -> core::result::Result<(), EN::Error> { #operation } } @@ -361,7 +362,7 @@ impl Enum { syn::Fields::Unit => quote!(#name::#ident => #tag_tokens), } }); - + let mut variant_constraints: Vec = vec![]; let variants = self.variants.iter().enumerate().map(|(i, v)| { let ident = &v.ident; let name = &self.name; @@ -397,17 +398,24 @@ impl Enum { let constraints = variant_config .constraints .const_expr(&self.config.crate_root); + let constraint_name = format_ident!("VARIANT_CONSTRAINT_{}", i); let variant_tag = variant_tag.to_tokens(crate_root); let encode_operation = if variant_config.has_explicit_tag() { quote!(encoder.encode_explicit_prefix(#variant_tag, value)) } else if variant_config.tag.is_some() || self.config.automatic_tags { if let Some(constraints) = constraints { - quote!(#crate_root::Encode::encode_with_tag_and_constraints(value, encoder, #variant_tag, #constraints)) + variant_constraints.push(quote! { + const #constraint_name: #crate_root::types::constraints::Constraints = #constraints; + }); + quote!(#crate_root::Encode::encode_with_tag_and_constraints(value, encoder, #variant_tag, #constraint_name)) } else { quote!(#crate_root::Encode::encode_with_tag(value, encoder, #variant_tag)) } } else if let Some(constraints) = constraints { - quote!(#crate_root::Encode::encode_with_constraints(value, encoder, #constraints)) + variant_constraints.push(quote! { + const #constraint_name: #crate_root::types::constraints::Constraints = #constraints; + }); + quote!(#crate_root::Encode::encode_with_constraints(value, encoder, #constraint_name)) } else { quote!(#crate_root::Encode::encode(value, encoder)) }; @@ -510,6 +518,7 @@ impl Enum { quote! { fn encode(&self, encoder: &mut E) -> core::result::Result<(), E::Error> { + #(#variant_constraints)* #encode_impl.map(drop) } } diff --git a/src/aper.rs b/src/aper.rs index ffa55c8c..275afd22 100644 --- a/src/aper.rs +++ b/src/aper.rs @@ -416,6 +416,12 @@ mod tests { ]), size_constraint!(1, 255) ); + const PERMITTED_CONSTRAINT_2: Constraints = + Constraints::new( + &[Constraint::PermittedAlphabet(constraints::Extensible::new( + PermittedAlphabet::new(&[b'a' as u32]), + ))], + ); round_trip_with_constraints!( aper, VisibleString, diff --git a/src/lib.rs b/src/lib.rs index 4ad924fe..c4b2357b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -47,6 +47,7 @@ pub mod prelude { pub use crate::{ de::{Decode, Decoder}, enc::{Encode, Encoder}, + macros, types::*, }; } diff --git a/src/per/de.rs b/src/per/de.rs index 8194d948..de813753 100644 --- a/src/per/de.rs +++ b/src/per/de.rs @@ -7,7 +7,7 @@ use super::{ FOURTY_EIGHT_K, LARGE_UNSIGNED_CONSTRAINT, SIXTEEN_K, SIXTY_FOUR_K, SMALL_UNSIGNED_CONSTRAINT, THIRTY_TWO_K, }; -use crate::types::{IntegerType, SetOf}; +pub use crate::error::DecodeError; use crate::{ de::Error as _, types::{ @@ -15,7 +15,7 @@ use crate::{ constraints::{self, Extensible}, fields::{Field, Fields}, strings::{should_be_indexed, StaticPermittedAlphabet}, - Constraints, Enumerated, Tag, + Constraints, Enumerated, IntegerType, SetOf, Tag, }, Decode, }; diff --git a/src/types.rs b/src/types.rs index b967caf3..f22fb3c8 100644 --- a/src/types.rs +++ b/src/types.rs @@ -63,8 +63,7 @@ pub trait AsnType { /// `Leaf` that points [`Self::TAG`]. const TAG_TREE: TagTree = TagTree::Leaf(Self::TAG); - /// The set of constraints for values of the given type. - const CONSTRAINTS: Constraints<'static> = Constraints::NONE; + const CONSTRAINTS: Constraints = Constraints::NONE; /// Identifier of an ASN.1 type as specified in the original specification /// if not identical with the identifier of `Self` @@ -83,7 +82,7 @@ pub trait Choice: Sized { /// Variants contained in the "root component list". const VARIANTS: &'static [TagTree]; /// Constraint for the choice type, based on the number of root components. Used for PER encoding. - const VARIANCE_CONSTRAINT: Constraints<'static>; + const VARIANCE_CONSTRAINT: Constraints; /// Variants contained in the list of extensions. const EXTENDED_VARIANTS: Option<&'static [TagTree]> = None; /// Variant identifiers for text-based encoding rules @@ -248,7 +247,7 @@ macro_rules! asn_integer_type { $( impl AsnType for $int { const TAG: Tag = Tag::INTEGER; - const CONSTRAINTS: Constraints<'static> = constraints!(value_constraint!((<$int>::MIN as i128), (<$int>::MAX as i128))); + const CONSTRAINTS: Constraints = constraints!(value_constraint!((<$int>::MIN as i128), (<$int>::MAX as i128))); } )+ } @@ -309,7 +308,7 @@ impl AsnType for SetOf { impl AsnType for [T; N] { const TAG: Tag = Tag::SEQUENCE; - const CONSTRAINTS: Constraints<'static> = constraints!(size_constraint!(N)); + const CONSTRAINTS: Constraints = constraints!(size_constraint!(N)); } impl AsnType for &'_ [T] { diff --git a/src/types/constraints.rs b/src/types/constraints.rs index cda437fe..93e2c607 100644 --- a/src/types/constraints.rs +++ b/src/types/constraints.rs @@ -1,21 +1,18 @@ //! Constraints of values on a given type. use super::IntegerType; -use alloc::borrow::Cow; use num_bigint::BigInt; /// A set of constraints for a given type on what kinds of values are allowed. /// Used in certain codecs to optimise encoding and decoding values. #[derive(Debug, Clone)] -pub struct Constraints<'constraint>(pub Cow<'constraint, [Constraint]>); +pub struct Constraints(pub &'static [Constraint]); -impl<'r> Constraints<'r> { - /// No constraints on a given type. - pub const NONE: Self = Self(Cow::Borrowed(&[])); +impl Constraints { + pub const NONE: Self = Self(&[]); - /// Creates a set of constraints from a set of values. - pub const fn new(constraints: &'r [Constraint]) -> Self { - Self(Cow::Borrowed(constraints)) + pub const fn new(constraints: &'static [Constraint]) -> Self { + Self(constraints) } /// A const variant of the default function. @@ -25,21 +22,31 @@ impl<'r> Constraints<'r> { /// Overrides a set of constraints with another set. #[inline(always)] - pub fn override_constraints(mut self, mut rhs: Constraints) -> Constraints { - let mut i = 0; - while i < self.0.len() { - if !rhs.0.iter().any(|child| child.kind() == self.0[i].kind()) { - // No matching constraint in rhs, so move it - let parent = self.0.to_mut().swap_remove(i); - rhs.0.to_mut().push(parent); - } else { - i += 1; + pub const fn override_constraints(mut self, mut rhs: Constraints) -> Constraints { + let mut si = 0; + let mut ri = 0; + while si < self.0.len() { + while ri < rhs.0.len() { + if self.0[si].kind().eq(&rhs.0[ri].kind()) { + // No matching constraint in rhs, so move it + // let parent = self.0.swap_remove(i); + // dbg!(si); + ri += 1; + } else { + ri += 1; + break; + } + si += 1; } } rhs } /// Returns the size constraint from the set, if available. + // pub fn override_constraints(self, rhs: Constraints) -> Constraints { + // rhs + // } + pub fn size(&self) -> Option<&Extensible> { self.0.iter().find_map(|constraint| constraint.to_size()) } @@ -62,14 +69,14 @@ impl<'r> Constraints<'r> { } } -impl<'r> From<&'r [Constraint]> for Constraints<'r> { - fn from(constraints: &'r [Constraint]) -> Self { +impl From<&'static [Constraint]> for Constraints { + fn from(constraints: &'static [Constraint]) -> Self { Self::new(constraints) } } -impl<'r, const N: usize> From<&'r [Constraint; N]> for Constraints<'r> { - fn from(constraints: &'r [Constraint; N]) -> Self { +impl From<&'static [Constraint; N]> for Constraints { + fn from(constraints: &'static [Constraint; N]) -> Self { Self::new(constraints) } } @@ -97,6 +104,11 @@ pub enum ConstraintDiscriminant { PermittedAlphabet, Extensible, } +impl ConstraintDiscriminant { + pub const fn eq(&self, other: &ConstraintDiscriminant) -> bool { + *self as isize == *other as isize + } +} impl Constraint { /// Returns the discriminant of the value. @@ -697,6 +709,153 @@ impl core::fmt::Display for Bounded { } } } +/// Helper macro to create constant value constraints. +/// +/// Usage: +/// ```rust +// Full range +// let full_range = value_constraint!(0, 100); +// Only start specified +// let start_only = value_constraint!(start: 0); +// Only end specified +// let end_only = value_constraint!(end: 100); +// Single value +// let single = value_constraint!(42); +// Full range with extensibility +// let ext_full_range = value_constraint!(0, 100, true); +// Only start with extensibility +// let ext_start_only = value_constraint!(start: 0, true); +// Only end with extensibility +// let ext_end_only = value_constraint!(end: 100, false); +// Single value with extensibility +/// let ext_single = value_constraint!(42, true); +/// ``` +#[macro_export] +macro_rules! value_constraint { + ($($args:tt)*) => { + $crate::bounded_constraint!(Value, $($args)*) + }; +} + +#[macro_export] +macro_rules! size_constraint { + ($($args:tt)*) => { + $crate::bounded_constraint!(Size, $($args)*) + }; +} + +#[macro_export] +macro_rules! constraints { + ($($constraint:expr),+ $(,)?) => { + $crate::types::constraints::Constraints(&[$($constraint),+]) + }; +} + +#[macro_export] +macro_rules! permitted_alphabet_constraint { + ( $alphabet:expr) => { + $crate::types::constraints::Constraint::PermittedAlphabet( + $crate::types::constraints::Extensible::new( + $crate::types::constraints::PermittedAlphabet::new($alphabet), + ), + ) + }; +} + +#[macro_export] +macro_rules! bounded_constraint { + // Start and end + ($constraint_type:ident, $start:expr, $end:expr) => { + $crate::types::constraints::Constraint::$constraint_type( + $crate::types::constraints::Extensible::new( + $crate::types::constraints::$constraint_type::new( + $crate::types::constraints::Bounded::const_new($start, $end), + ), + ), + ) + }; + + // Only start provided + ($constraint_type:ident, start: $start:expr) => { + $crate::types::constraints::Constraint::$constraint_type( + $crate::types::constraints::Extensible::new( + $crate::types::constraints::$constraint_type::new( + $crate::types::constraints::Bounded::start_from($start), + ), + ), + ) + }; + + // Only end provided + ($constraint_type:ident, end: $end:expr) => { + $crate::types::constraints::Constraint::$constraint_type( + $crate::types::constraints::Extensible::new( + $crate::types::constraints::$constraint_type::new( + $crate::types::constraints::Bounded::up_to($end), + ), + ), + ) + }; + + // Single value + ($constraint_type:ident, $single:expr) => { + $crate::types::constraints::Constraint::$constraint_type( + $crate::types::constraints::Extensible::new( + $crate::types::constraints::$constraint_type::new( + $crate::types::constraints::Bounded::Single($single), + ), + ), + ) + }; + + // Range with extensibility + ($constraint_type:ident, $start:expr, $end:expr, $extensible:expr) => { + $crate::types::constraints::Constraint::$constraint_type( + $crate::types::constraints::Extensible::new( + $crate::types::constraints::$constraint_type::new( + $crate::types::constraints::Bounded::const_new($start, $end), + ), + ) + .set_extensible($extensible), + ) + }; + + // Only start with extensibility + ($constraint_type:ident, start: $start:expr, $extensible:expr) => { + $crate::types::constraints::Constraint::$constraint_type( + $crate::types::constraints::Extensible::new( + $crate::types::constraints::$constraint_type::new( + $crate::types::constraints::Bounded::start_from($start), + ), + ) + .set_extensible($extensible), + ) + }; + + // Only end with extensibility + ($constraint_type:ident, end: $end:expr, $extensible:expr) => { + $crate::types::constraints::Constraint::$constraint_type( + $crate::types::constraints::Extensible::new( + $crate::types::constraints::$constraint_type::new( + $crate::types::constraints::Bounded::up_to($end), + ), + ) + .set_extensible($extensible), + ) + }; + + // Single value with extensibility + ($constraint_type:ident, $single:expr, $extensible:expr) => { + $crate::types::constraints::Constraint::$constraint_type( + $crate::types::constraints::Extensible::new( + $crate::types::constraints::$constraint_type::new( + $crate::types::constraints::Bounded::Single($single), + ), + ) + .set_extensible($extensible), + ) + }; +} #[cfg(test)] mod tests { @@ -708,14 +867,13 @@ mod tests { assert_eq!(256, constraints.range().unwrap()); } #[test] - fn check_const_validity() { - const MY_CONST: Constraints = Constraints::new(&[Constraint::Value( - Extensible::new(Value::new(Bounded::const_new( - 0i128 as i128, - 255i128 as i128, - ))) - .set_extensible(false), - )]); - dbg!(MY_CONST); + fn test_concat_constraints() { + let a = [Constraint::Value(Extensible::new(Value::new(Bounded::Single(0)))); 1]; + let b = [Constraint::Size(Extensible::new(Size::new(Bounded::Single(0)))); 1]; + let c = concat_constraints(a, b); + + const COMBINED_CONSTRAINTS: [Constraint; 2] = concat_constraints(a, b); + + const RESULT: &'static [Constraint] = &COMBINED_CONSTRAINTS; } } diff --git a/src/types/integer.rs b/src/types/integer.rs index 0beea5a6..5c85c082 100644 --- a/src/types/integer.rs +++ b/src/types/integer.rs @@ -355,7 +355,7 @@ pub struct ConstrainedInteger(pub(crate) Int impl AsnType for ConstrainedInteger { const TAG: Tag = Tag::INTEGER; - const CONSTRAINTS: Constraints<'static> = + const CONSTRAINTS: Constraints = Constraints::new(&[constraints::Constraint::Value(Extensible::new( constraints::Value::new(constraints::Bounded::const_new(START, END)), ))]); diff --git a/src/types/strings/octet.rs b/src/types/strings/octet.rs index bddde642..24caf976 100644 --- a/src/types/strings/octet.rs +++ b/src/types/strings/octet.rs @@ -63,9 +63,9 @@ impl core::ops::DerefMut for FixedOctetString { impl AsnType for FixedOctetString { const TAG: Tag = Tag::OCTET_STRING; - const CONSTRAINTS: Constraints<'static> = Constraints::new(&[Constraint::Size( - Extensible::new(constraints::Size::fixed(N)), - )]); + const CONSTRAINTS: Constraints = Constraints::new(&[Constraint::Size(Extensible::new( + constraints::Size::fixed(N), + ))]); } impl Decode for FixedOctetString { diff --git a/src/uper.rs b/src/uper.rs index e8318ce2..1c995e4f 100644 --- a/src/uper.rs +++ b/src/uper.rs @@ -41,6 +41,7 @@ mod tests { use crate::{ macros::{constraints, permitted_alphabet_constraint, size_constraint}, prelude::*, + size_constraint, types::{constraints::*, *}, }; diff --git a/standards/pkix/src/lib.rs b/standards/pkix/src/lib.rs index 928de981..2b3e3338 100644 --- a/standards/pkix/src/lib.rs +++ b/standards/pkix/src/lib.rs @@ -429,7 +429,7 @@ pub struct BuiltInDomainDefinedAttribute { pub value: PrintableString, } -#[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(AsnType, Clone, Debug, Encode, Decode, PartialEq, Eq, PartialOrd, Ord, Hash)] #[rasn(tag(explicit(application, 1)))] #[rasn(choice)] pub enum CountryName { From e9700039183e057aeeb2d7ec9627a6f7a5bf5340 Mon Sep 17 00:00:00 2001 From: Niklas Saari Date: Thu, 12 Sep 2024 11:27:59 +0300 Subject: [PATCH 05/22] More const functions --- src/types/constraints.rs | 116 +++++++++++++++++++++++++-------------- 1 file changed, 75 insertions(+), 41 deletions(-) diff --git a/src/types/constraints.rs b/src/types/constraints.rs index 93e2c607..613b9c5d 100644 --- a/src/types/constraints.rs +++ b/src/types/constraints.rs @@ -6,7 +6,7 @@ use num_bigint::BigInt; /// A set of constraints for a given type on what kinds of values are allowed. /// Used in certain codecs to optimise encoding and decoding values. #[derive(Debug, Clone)] -pub struct Constraints(pub &'static [Constraint]); +pub struct Constraints(pub &'static [Constraint]); impl Constraints { pub const NONE: Self = Self(&[]); @@ -21,51 +21,85 @@ impl Constraints { } /// Overrides a set of constraints with another set. - #[inline(always)] - pub const fn override_constraints(mut self, mut rhs: Constraints) -> Constraints { - let mut si = 0; - let mut ri = 0; - while si < self.0.len() { - while ri < rhs.0.len() { - if self.0[si].kind().eq(&rhs.0[ri].kind()) { - // No matching constraint in rhs, so move it - // let parent = self.0.swap_remove(i); - // dbg!(si); - ri += 1; - } else { - ri += 1; - break; - } - si += 1; - } - } + // #[inline(always)] + // pub fn const override_constraints(mut self, mut rhs: Constraints) -> [Constraint; 4] { + // let + // let mut si = 0; + // let mut ri = 0; + // let mut lhs = self.0.as_mut(); + // let mut rrhs = rhs.0.as_mut(); + // while si < self.0.len() { + // while ri < rrhs.len() { + // if lhs[si].kind().eq(&rrhs[ri].kind()) { + // // No matching constraint in rhs, so move it + // unsafe { + // core::ptr::swap( + // &mut lhs[si] as *mut Constraint, + // &mut rrhs[ri] as *mut Constraint, + // ); + // } + // ri += 1; + // } else { + // ri += 1; + // break; + // } + // si += 1; + // } + // } + // rhs + // } + // } + + pub fn override_constraints(self, rhs: Constraints) -> Constraints { rhs } /// Returns the size constraint from the set, if available. - // pub fn override_constraints(self, rhs: Constraints) -> Constraints { - // rhs - // } - - pub fn size(&self) -> Option<&Extensible> { - self.0.iter().find_map(|constraint| constraint.to_size()) + pub const fn size(&self) -> Option<&Extensible> { + let mut i = 0; + while i < self.0.len() { + if let Some(size) = self.0[i].to_size() { + return Some(size); + } + i += 1; + } + None } /// Returns the permitted alphabet constraint from the set, if available. - pub fn permitted_alphabet(&self) -> Option<&Extensible> { - self.0 - .iter() - .find_map(|constraint| constraint.as_permitted_alphabet()) + pub const fn permitted_alphabet(&self) -> Option<&Extensible> { + let mut i = 0; + while i < self.0.len() { + if let Some(alpha) = self.0[i].as_permitted_alphabet() { + return Some(alpha); + } + i += 1; + } + None } /// Returns whether any of the constraints are extensible. - pub fn extensible(&self) -> bool { - self.0.iter().any(|constraint| constraint.is_extensible()) + pub const fn extensible(&self) -> bool { + let mut i = 0; + while i < self.0.len() { + if self.0[i].is_extensible() { + return true; + } + i += 1; + } + false } /// Returns the value constraint from the set, if available. - pub fn value(&self) -> Option<&Extensible> { - self.0.iter().find_map(|constraint| constraint.to_value()) + pub const fn value(&self) -> Option<&Extensible> { + let mut i = 0; + while i < self.0.len() { + if let Some(value) = self.0[i].as_value() { + return Some(value); + } + i += 1; + } + None } } @@ -866,14 +900,14 @@ mod tests { let constraints = Bounded::new(0, 255); assert_eq!(256, constraints.range().unwrap()); } - #[test] - fn test_concat_constraints() { - let a = [Constraint::Value(Extensible::new(Value::new(Bounded::Single(0)))); 1]; - let b = [Constraint::Size(Extensible::new(Size::new(Bounded::Single(0)))); 1]; - let c = concat_constraints(a, b); + // #[test] + // fn test_concat_constraints() { + // let a = [Constraint::Value(Extensible::new(Value::new(Bounded::Single(0)))); 1]; + // let b = [Constraint::Size(Extensible::new(Size::new(Bounded::Single(0)))); 1]; + // let c = concat_constraints(a, b); - const COMBINED_CONSTRAINTS: [Constraint; 2] = concat_constraints(a, b); + // const COMBINED_CONSTRAINTS: [Constraint; 2] = concat_constraints(a, b); - const RESULT: &'static [Constraint] = &COMBINED_CONSTRAINTS; - } + // const RESULT: &'static [Constraint] = &COMBINED_CONSTRAINTS; + // } } From 8cdecff6425168cbf9bc65e091ca2cdd7030b95f Mon Sep 17 00:00:00 2001 From: Niklas Saari Date: Thu, 12 Sep 2024 15:34:21 +0300 Subject: [PATCH 06/22] Merge method --- src/types/constraints.rs | 88 ++++++++++++++++++++++++++-------------- 1 file changed, 58 insertions(+), 30 deletions(-) diff --git a/src/types/constraints.rs b/src/types/constraints.rs index 613b9c5d..206fdc7a 100644 --- a/src/types/constraints.rs +++ b/src/types/constraints.rs @@ -21,34 +21,46 @@ impl Constraints { } /// Overrides a set of constraints with another set. - // #[inline(always)] - // pub fn const override_constraints(mut self, mut rhs: Constraints) -> [Constraint; 4] { - // let - // let mut si = 0; - // let mut ri = 0; - // let mut lhs = self.0.as_mut(); - // let mut rrhs = rhs.0.as_mut(); - // while si < self.0.len() { - // while ri < rrhs.len() { - // if lhs[si].kind().eq(&rrhs[ri].kind()) { - // // No matching constraint in rhs, so move it - // unsafe { - // core::ptr::swap( - // &mut lhs[si] as *mut Constraint, - // &mut rrhs[ri] as *mut Constraint, - // ); - // } - // ri += 1; - // } else { - // ri += 1; - // break; - // } - // si += 1; - // } - // } - // rhs - // } - // } + /// This function is used only on compile-time. + #[inline(always)] + pub(crate) const fn merge(self, rhs: Self) -> ([Constraint; 5], usize) { + let mut si = 0; + let mut ri = 0; + // Count of the variants in Constraint + const N: usize = 5; + let mut array: [Constraint; N] = [Constraint::Empty; N]; + if rhs.0.len() > N || rhs.0.is_empty() { + panic!("rhs is smaller than N or rhs is empty") + } + // Copy rhs first to the array + let mut copy_index = 0; + while copy_index < rhs.0.len() { + unsafe { + let data: Constraint = core::mem::transmute_copy(&rhs.0[copy_index]); + array[copy_index] = data; + } + copy_index += 1; + } + while si < self.0.len() { + while ri < rhs.0.len() { + if !self.0[si].kind().eq(&rhs.0[ri].kind()) { + if copy_index > N { + panic!("copy_index is greater than N") + } + unsafe { + let data: Constraint = core::mem::transmute_copy(&self.0[si]); + array[copy_index] = data; + } + copy_index += 1; + ri += 1; + } else { + ri += 1; + } + si += 1; + } + } + (array, copy_index) + } pub fn override_constraints(self, rhs: Constraints) -> Constraints { rhs @@ -127,6 +139,7 @@ pub enum Constraint { /// The value itself is extensible, only valid for constructed types, /// choices, or enumerated values. Extensible, + Empty, } /// The discriminant of [Constraint] values. @@ -137,6 +150,7 @@ pub enum ConstraintDiscriminant { Size, PermittedAlphabet, Extensible, + Empty, } impl ConstraintDiscriminant { pub const fn eq(&self, other: &ConstraintDiscriminant) -> bool { @@ -152,6 +166,19 @@ impl Constraint { Self::Size(_) => ConstraintDiscriminant::Size, Self::PermittedAlphabet(_) => ConstraintDiscriminant::PermittedAlphabet, Self::Extensible => ConstraintDiscriminant::Extensible, + Self::Empty => ConstraintDiscriminant::Empty, + } + } + pub const fn default() -> Self { + Self::Empty + } + pub const fn variant_as_isize(&self) -> isize { + match self { + Self::Value(_) => 0, + Self::Size(_) => 1, + Self::PermittedAlphabet(_) => 2, + Self::Extensible => 3, + Self::Empty => 4, } } @@ -194,6 +221,7 @@ impl Constraint { Self::Size(size) => size.extensible.is_some(), Self::PermittedAlphabet(alphabet) => alphabet.extensible.is_some(), Self::Extensible => true, + Self::Empty => false, } } } @@ -202,7 +230,7 @@ impl Constraint { /// /// Extensible means that it can have values outside of its constraints, and what possible /// constraints thosevalues in the extended set can have, if any. -#[derive(Debug, Copy, Default, Clone, PartialEq)] +#[derive(Debug, Default, Copy, Clone, PartialEq)] pub struct Extensible { /// The underlying constraint type. pub constraint: T, @@ -404,7 +432,7 @@ impl core::ops::DerefMut for Size { } /// A range of alphabet characters a type can have. -#[derive(Clone, Debug, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct PermittedAlphabet(&'static [u32]); impl PermittedAlphabet { From 281d41fcbb304caf237b5152e7e5a2f4c8d031f3 Mon Sep 17 00:00:00 2001 From: Niklas Saari Date: Thu, 12 Sep 2024 15:46:48 +0300 Subject: [PATCH 07/22] Undo unintended pkix change --- standards/pkix/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/standards/pkix/src/lib.rs b/standards/pkix/src/lib.rs index 2b3e3338..928de981 100644 --- a/standards/pkix/src/lib.rs +++ b/standards/pkix/src/lib.rs @@ -429,7 +429,7 @@ pub struct BuiltInDomainDefinedAttribute { pub value: PrintableString, } -#[derive(AsnType, Clone, Debug, Encode, Decode, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq, Eq, PartialOrd, Ord, Hash)] #[rasn(tag(explicit(application, 1)))] #[rasn(choice)] pub enum CountryName { From 7e3fd41dca0694efb4ebc4fc5556425f0bdc9812 Mon Sep 17 00:00:00 2001 From: Niklas Saari Date: Thu, 12 Sep 2024 15:47:10 +0300 Subject: [PATCH 08/22] doc --- src/types/constraints.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/types/constraints.rs b/src/types/constraints.rs index 206fdc7a..5fb35f80 100644 --- a/src/types/constraints.rs +++ b/src/types/constraints.rs @@ -21,7 +21,7 @@ impl Constraints { } /// Overrides a set of constraints with another set. - /// This function is used only on compile-time. + /// This function should be only used on compile-time. #[inline(always)] pub(crate) const fn merge(self, rhs: Self) -> ([Constraint; 5], usize) { let mut si = 0; From 1fa0456d0f1a56826e32154eff76f66733f4e242 Mon Sep 17 00:00:00 2001 From: Niklas Saari Date: Thu, 12 Sep 2024 20:48:07 +0300 Subject: [PATCH 09/22] Delegate struct remains as problem --- macros/macros_impl/src/config.rs | 72 +++++++++++++++++++++----------- src/types/constraints.rs | 64 ++++++++++++++++++---------- 2 files changed, 90 insertions(+), 46 deletions(-) diff --git a/macros/macros_impl/src/config.rs b/macros/macros_impl/src/config.rs index 11f14cce..7a2949d2 100644 --- a/macros/macros_impl/src/config.rs +++ b/macros/macros_impl/src/config.rs @@ -782,10 +782,12 @@ impl<'a> FieldConfig<'a> { .const_expr(&self.container_config.crate_root) .unwrap_or_else(|| quote!(#crate_root::types::Constraints::default())); quote!( - const #constraint_name : #crate_root::types::Constraints = #constraints; + const #constraint_name : #crate_root::types::Constraints = #crate_root::types::Constraints::from_fixed_size(&<#ty as #crate_root::AsnType>::CONSTRAINTS.merge( + #constraints + )); encoder.encode_extension_addition( #tag, - <#ty as #crate_root::AsnType>::CONSTRAINTS.override_constraints(#constraint_name), + #constraint_name, &#this #field )?; ) @@ -799,10 +801,12 @@ impl<'a> FieldConfig<'a> { match (self.constraints.has_constraints(), self.default.is_some()) { (true, true) => { quote!( - const #constraint_name : #crate_root::types::Constraints = #constraints; + const #constraint_name : #crate_root::types::Constraints = #crate_root::types::Constraints::from_fixed_size(&<#ty as #crate_root::AsnType>::CONSTRAINTS.merge( + #constraints + )); encoder.encode_default_with_tag_and_constraints( #tag, - <#ty as #crate_root::AsnType>::CONSTRAINTS.override_constraints(#constraint_name), + #constraint_name, &#this #field, #default_fn )?; @@ -810,11 +814,13 @@ impl<'a> FieldConfig<'a> { } (true, false) => { quote!( - const #constraint_name : #crate_root::types::Constraints = #constraints; + const #constraint_name : #crate_root::types::Constraints = #crate_root::types::Constraints::from_fixed_size(&<#ty as #crate_root::AsnType>::CONSTRAINTS.merge( + #constraints + )); #this #field.encode_with_tag_and_constraints( encoder, #tag, - <#ty as #crate_root::AsnType>::CONSTRAINTS.override_constraints(#constraint_name), + #constraint_name, #default_fn )?; ) @@ -831,10 +837,12 @@ impl<'a> FieldConfig<'a> { .const_expr(&self.container_config.crate_root) .unwrap_or_else(|| quote!(#crate_root::types::Constraints::default())); quote!( - const #constraint_name : #crate_root::types::Constraints = #constraints; + const #constraint_name : #crate_root::types::Constraints = #crate_root::types::Constraints::from_fixed_size(&<#ty as #crate_root::AsnType>::CONSTRAINTS.merge( + #constraints + )); encoder.encode_extension_addition( #tag, - <#ty as #crate_root::AsnType>::CONSTRAINTS.override_constraints(#constraint_name), + #constraint_name, &#this #field )?; ) @@ -847,9 +855,11 @@ impl<'a> FieldConfig<'a> { .constraints .const_expr(&self.container_config.crate_root); quote!( - const #constraint_name : #crate_root::types::Constraints = #constraints; + const #constraint_name : #crate_root::types::Constraints = #crate_root::types::Constraints::from_fixed_size(&<#ty as #crate_root::AsnType>::CONSTRAINTS.merge( + #constraints + )); encoder.encode_default_with_constraints( - <#ty as #crate_root::AsnType>::CONSTRAINTS.override_constraints(#constraint_name), + #constraint_name, &#this #field, #default_fn )?; @@ -860,10 +870,12 @@ impl<'a> FieldConfig<'a> { .constraints .const_expr(&self.container_config.crate_root); quote!( - const #constraint_name : #crate_root::types::Constraints = #constraints; + const #constraint_name : #crate_root::types::Constraints = #crate_root::types::Constraints::from_fixed_size(&<#ty as #crate_root::AsnType>::CONSTRAINTS.merge( + #constraints + )); #this #field.encode_with_constraints( encoder, - <#ty as #crate_root::AsnType>::CONSTRAINTS.override_constraints(#constraint_name), + #constraint_name, )?; ) } @@ -939,11 +951,13 @@ impl<'a> FieldConfig<'a> { } (Some(false), Some(path), true) => { quote!( - const #constraint_name : #crate_root::types::Constraints = #constraints; + const #constraint_name : #crate_root::types::Constraints = #crate_root::types::Constraints::from_fixed_size(&<#ty as #crate_root::AsnType>::CONSTRAINTS.merge( + #constraints + )); decoder.decode_default_with_tag_and_constraints( #tag, #path, - <#ty as #crate_root::AsnType>::CONSTRAINTS.override_constraints(#constraint_name), + #constraint_name, ) #or_else ) } @@ -952,11 +966,13 @@ impl<'a> FieldConfig<'a> { } (Some(false), None, true) => { quote!( - const #constraint_name : #crate_root::types::Constraints = #constraints; + const #constraint_name : #crate_root::types::Constraints = #crate_root::types::Constraints::from_fixed_size(&<#ty as #crate_root::AsnType>::CONSTRAINTS.merge( + #constraints + )); <_>::decode_with_tag_and_constraints( decoder, #tag, - <#ty as #crate_root::AsnType>::CONSTRAINTS.override_constraints(#constraint_name), + #constraint_name, ) #or_else ) } @@ -965,10 +981,12 @@ impl<'a> FieldConfig<'a> { } (None, Some(path), true) => { quote!( - const #constraint_name : #crate_root::types::Constraints = #constraints; + const #constraint_name : #crate_root::types::Constraints = #crate_root::types::Constraints::from_fixed_size(&<#ty as #crate_root::AsnType>::CONSTRAINTS.merge( + #constraints + )); decoder.decode_default_with_constraints( #path, - <#ty as #crate_root::AsnType>::CONSTRAINTS.override_constraints(#constraint_name), + #constraint_name, ) #or_else ) } @@ -977,10 +995,12 @@ impl<'a> FieldConfig<'a> { } (None, None, true) => { quote!( - const #constraint_name : #crate_root::types::Constraints = #constraints; + const #constraint_name : #crate_root::types::Constraints = #crate_root::types::Constraints::from_fixed_size(&<#ty as #crate_root::AsnType>::CONSTRAINTS.merge( + #constraints + )); <_>::decode_with_constraints( decoder, - <#ty as #crate_root::AsnType>::CONSTRAINTS.override_constraints(#constraint_name), + #constraint_name, ) #or_else ) } @@ -1049,10 +1069,12 @@ impl<'a> FieldConfig<'a> { (None, Some(path), true) => { quote!( { - const #constraint_name : #crate_root::types::Constraints = #constraints; + const #constraint_name : #crate_root::types::Constraints = #crate_root::types::Constraints::from_fixed_size(&<#ty as #crate_root::AsnType>::CONSTRAINTS.merge( + #constraints + )); decoder.decode_extension_addition_with_default_and_constraints( #path, - <#ty as #crate_root::AsnType>::CONSTRAINTS.override_constraints(#constraint_name), + #constraint_name, ) #or_else } ) @@ -1066,9 +1088,11 @@ impl<'a> FieldConfig<'a> { } (None, None, true) => { quote!( - const #constraint_name : #crate_root::types::Constraints = #constraints; + const #constraint_name : #crate_root::types::Constraints = #crate_root::types::Constraints::from_fixed_size(&<#ty as #crate_root::AsnType>::CONSTRAINTS.merge( + #constraints + )); decoder.decode_extension_addition_with_constraints( - <#ty as #crate_root::AsnType>::CONSTRAINTS.override_constraints(#constraint_name), + #constraint_name, ) #or_else ) } diff --git a/src/types/constraints.rs b/src/types/constraints.rs index 5fb35f80..c3ef492b 100644 --- a/src/types/constraints.rs +++ b/src/types/constraints.rs @@ -3,6 +3,9 @@ use super::IntegerType; use num_bigint::BigInt; +const SUPPORTED_CONSTRAINTS_COUNT: usize = 5; +pub const DEFAULT_CONSTRAINTS: Constraints = Constraints::NONE; + /// A set of constraints for a given type on what kinds of values are allowed. /// Used in certain codecs to optimise encoding and decoding values. #[derive(Debug, Clone)] @@ -15,54 +18,69 @@ impl Constraints { Self(constraints) } + pub const fn inner(&self) -> &'static [Constraint] { + self.0 + } + /// We currently only support 5 different constraint types, which includes the empty constraint. + /// `usize` is used to drop the empty ones, which are needed to initialize the array. + pub const fn from_fixed_size( + merged: &'static ([Constraint; SUPPORTED_CONSTRAINTS_COUNT], usize), + ) -> Self { + struct ConstraintArray(&'static [Constraint; N]); + + impl ConstraintArray { + const fn as_slice(&self) -> &'static [Constraint] { + self.0 + } + } + let array = ConstraintArray(&merged.0); + Self::new(array.as_slice()) + } + /// A const variant of the default function. pub const fn default() -> Self { Self::NONE } - /// Overrides a set of constraints with another set. + /// Merges a set of constraints with another set, if they don't exist. /// This function should be only used on compile-time. #[inline(always)] - pub(crate) const fn merge(self, rhs: Self) -> ([Constraint; 5], usize) { + pub const fn merge(self, rhs: Self) -> ([Constraint; SUPPORTED_CONSTRAINTS_COUNT], usize) { let mut si = 0; + let rhs = rhs.0; let mut ri = 0; - // Count of the variants in Constraint - const N: usize = 5; - let mut array: [Constraint; N] = [Constraint::Empty; N]; - if rhs.0.len() > N || rhs.0.is_empty() { - panic!("rhs is smaller than N or rhs is empty") + let mut array: [Constraint; SUPPORTED_CONSTRAINTS_COUNT] = + [Constraint::Empty; SUPPORTED_CONSTRAINTS_COUNT]; + if rhs.len() > SUPPORTED_CONSTRAINTS_COUNT { + panic!("Overriding constraint is larger than we have different constraint types") } // Copy rhs first to the array let mut copy_index = 0; - while copy_index < rhs.0.len() { - unsafe { - let data: Constraint = core::mem::transmute_copy(&rhs.0[copy_index]); - array[copy_index] = data; - } + while copy_index < rhs.len() { + array[copy_index] = rhs[copy_index]; copy_index += 1; } while si < self.0.len() { - while ri < rhs.0.len() { - if !self.0[si].kind().eq(&rhs.0[ri].kind()) { - if copy_index > N { - panic!("copy_index is greater than N") - } - unsafe { - let data: Constraint = core::mem::transmute_copy(&self.0[si]); - array[copy_index] = data; + while ri < rhs.len() { + if !self.0[si].kind().eq(&rhs[ri].kind()) { + if copy_index > SUPPORTED_CONSTRAINTS_COUNT { + panic!("attempting to copy into greater index than we have different constraint types") } + array[copy_index] = self.0[si]; copy_index += 1; ri += 1; } else { ri += 1; } - si += 1; } + si += 1; } (array, copy_index) } - + /// Overrides a set of constraints with another set. + #[inline(always)] pub fn override_constraints(self, rhs: Constraints) -> Constraints { + // self.merge(rhs) rhs } @@ -128,6 +146,8 @@ impl From<&'static [Constraint; N]> for Constraints { } /// The set of possible constraints a given value can have. +/// +/// Do not change the amount of variants in this enum without changing the `SUPPORTED_CONSTRAINTS_COUNT` constant. #[derive(Debug, Copy, Clone, PartialEq)] pub enum Constraint { /// A set of possible values which the type can be. From e5040c02b6b6b6be53d3a0b31c253cc2c9cb3baa Mon Sep 17 00:00:00 2001 From: Niklas Saari Date: Fri, 13 Sep 2024 11:18:05 +0300 Subject: [PATCH 10/22] Initial working version --- macros/macros_impl/src/config.rs | 28 ++--- macros/macros_impl/src/decode.rs | 10 +- macros/macros_impl/src/encode.rs | 35 +++++- src/lib.rs | 4 +- src/types.rs | 8 +- src/types/constraints.rs | 177 ++++++++++++++++++++++++------- src/types/integer.rs | 2 +- src/types/strings/octet.rs | 2 +- tests/personnel.rs | 2 + 9 files changed, 204 insertions(+), 64 deletions(-) diff --git a/macros/macros_impl/src/config.rs b/macros/macros_impl/src/config.rs index 7a2949d2..8a9a2eb8 100644 --- a/macros/macros_impl/src/config.rs +++ b/macros/macros_impl/src/config.rs @@ -15,8 +15,9 @@ pub struct Constraints { impl Constraints { pub fn const_static_def(&self, crate_root: &syn::Path) -> Option { - self.const_expr(crate_root) - .map(|expr| quote!(const CONSTRAINTS: #crate_root::types::Constraints = #expr;)) + self.const_expr(crate_root).map( + |expr| quote!(const CONSTRAINTS: #crate_root::types::Constraints<'static> = #expr;), + ) } pub fn attribute_tokens(&self) -> Option { @@ -950,7 +951,7 @@ impl<'a> FieldConfig<'a> { } } (Some(false), Some(path), true) => { - quote!( + quote!({ const #constraint_name : #crate_root::types::Constraints = #crate_root::types::Constraints::from_fixed_size(&<#ty as #crate_root::AsnType>::CONSTRAINTS.merge( #constraints )); @@ -958,14 +959,14 @@ impl<'a> FieldConfig<'a> { #tag, #path, #constraint_name, - ) #or_else + ) #or_else } ) } (Some(false), Some(path), false) => { quote!(decoder.decode_default_with_tag(#tag, #path) #or_else) } (Some(false), None, true) => { - quote!( + quote!({ const #constraint_name : #crate_root::types::Constraints = #crate_root::types::Constraints::from_fixed_size(&<#ty as #crate_root::AsnType>::CONSTRAINTS.merge( #constraints )); @@ -973,35 +974,35 @@ impl<'a> FieldConfig<'a> { decoder, #tag, #constraint_name, - ) #or_else + ) #or_else } ) } (Some(false), None, false) => { quote!(<_>::decode_with_tag(decoder, #tag) #or_else) } (None, Some(path), true) => { - quote!( + quote!({ const #constraint_name : #crate_root::types::Constraints = #crate_root::types::Constraints::from_fixed_size(&<#ty as #crate_root::AsnType>::CONSTRAINTS.merge( #constraints )); decoder.decode_default_with_constraints( #path, #constraint_name, - ) #or_else + ) #or_else } ) } (None, Some(path), false) => { quote!(decoder.decode_default(#path) #or_else) } (None, None, true) => { - quote!( + quote!({ const #constraint_name : #crate_root::types::Constraints = #crate_root::types::Constraints::from_fixed_size(&<#ty as #crate_root::AsnType>::CONSTRAINTS.merge( #constraints )); <_>::decode_with_constraints( decoder, #constraint_name, - ) #or_else + ) #or_else } ) } (None, None, false) => { @@ -1075,8 +1076,7 @@ impl<'a> FieldConfig<'a> { decoder.decode_extension_addition_with_default_and_constraints( #path, #constraint_name, - ) #or_else - } + ) #or_else } ) } (None, Some(path), false) => { @@ -1087,13 +1087,13 @@ impl<'a> FieldConfig<'a> { ) } (None, None, true) => { - quote!( + quote!({ const #constraint_name : #crate_root::types::Constraints = #crate_root::types::Constraints::from_fixed_size(&<#ty as #crate_root::AsnType>::CONSTRAINTS.merge( #constraints )); decoder.decode_extension_addition_with_constraints( #constraint_name, - ) #or_else + ) #or_else } ) } (None, None, false) => { diff --git a/macros/macros_impl/src/decode.rs b/macros/macros_impl/src/decode.rs index 3ab118e6..673814c7 100644 --- a/macros/macros_impl/src/decode.rs +++ b/macros/macros_impl/src/decode.rs @@ -27,7 +27,15 @@ pub fn derive_struct_impl( decoder.decode_explicit_prefix::<#ty>(tag).map(Self) } } else { + let constraint_name = format_ident!("DELEGATE_DECODE_CONSTRAINT"); + let constraints = config + .constraints + .const_expr(crate_root) + .unwrap_or_else(|| quote!(#crate_root::types::Constraints::default())); quote! { + const #constraint_name : #crate_root::types::Constraints = #constraints; + let merged = #constraint_name.merge(constraints); + let constraints : #crate_root::types::Constraints = #crate_root::types::Constraints::from_fixed_size(&merged); match tag { #crate_root::types::Tag::EOC => { Ok(Self(<#ty>::decode(decoder)?)) @@ -36,7 +44,7 @@ pub fn derive_struct_impl( <#ty as #crate_root::Decode>::decode_with_tag_and_constraints( decoder, tag, - <#ty as #crate_root::AsnType>::CONSTRAINTS.override_constraints(constraints), + constraints ).map(Self) } } diff --git a/macros/macros_impl/src/encode.rs b/macros/macros_impl/src/encode.rs index 3364596b..5f8555db 100644 --- a/macros/macros_impl/src/encode.rs +++ b/macros/macros_impl/src/encode.rs @@ -39,7 +39,34 @@ pub fn derive_struct_impl( // 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.0).map(drop)) } else { + // let constraint_name = format_ident!("ENCODE_DELEGATE_CONSTRAINTS"); + // let constraints = config + // .constraints + // .const_expr(crate_root) + // .unwrap_or_else(|| quote!(#crate_root::types::Constraints::default())); + // print!("{:?}", config.identifier); + // print!("{:?}", config); + // println!("{}", quote!(#constraints)); quote!( + // const #constraint_name : #crate_root::types::Constraints = #crate_root::types::Constraints::from_fixed_size(&<#ty as #crate_root::AsnType>::CONSTRAINTS.merge( + // #constraints + // )); + // let (data, test) = <#ty as #crate_root::AsnType>::CONSTRAINTS.merge( + // constraints + // ); + let merged = <#ty as #crate_root::AsnType>::CONSTRAINTS.merge( + constraints + ); + // dbg!(&data[..test]); + // dbg!(&test); + // let constraint : #crate_root::types::Constraints = #crate_root::types::Constraints::new(&data[..test]); + // dbg!(&constraint); + // let merged = <#ty as #crate_root::AsnType>::CONSTRAINTS.merge(constraint); + let merged_constraints : #crate_root::types::Constraints = #crate_root::types::Constraints::from_fixed_size(&merged); + // dbg!(constraintts); + // dbg!(#constraint_name); + // dbg!(&constraints); + // dbg!(<#ty as #crate_root::AsnType>::CONSTRAINTS); match tag { #crate_root::types::Tag::EOC => { self.0.encode(encoder) @@ -49,7 +76,13 @@ pub fn derive_struct_impl( &self.0, encoder, tag, - <#ty as #crate_root::AsnType>::CONSTRAINTS.override_constraints(constraints) + // data, + // constraints + // Correct but misses override.. + // #constraint_name + merged_constraints + // Empty + // <#ty as #crate_root::AsnType>::CONSTRAINTS, ) } } diff --git a/src/lib.rs b/src/lib.rs index c4b2357b..be364ad4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -141,8 +141,8 @@ mod tests { impl crate::AsnType for CustomInt { const TAG: Tag = Tag::INTEGER; - const CONSTRAINTS: Constraints<'static> = - crate::macros::constraints!(crate::macros::value_constraint!(start: 127)); + const CONSTRAINTS: Constraints = + macros::constraints!(macros::value_constraint!(start: 127)); } impl crate::Encode for CustomInt { diff --git a/src/types.rs b/src/types.rs index f22fb3c8..dfdce04d 100644 --- a/src/types.rs +++ b/src/types.rs @@ -63,7 +63,7 @@ pub trait AsnType { /// `Leaf` that points [`Self::TAG`]. const TAG_TREE: TagTree = TagTree::Leaf(Self::TAG); - const CONSTRAINTS: Constraints = Constraints::NONE; + const CONSTRAINTS: Constraints<'static> = Constraints::NONE; /// Identifier of an ASN.1 type as specified in the original specification /// if not identical with the identifier of `Self` @@ -82,7 +82,7 @@ pub trait Choice: Sized { /// Variants contained in the "root component list". const VARIANTS: &'static [TagTree]; /// Constraint for the choice type, based on the number of root components. Used for PER encoding. - const VARIANCE_CONSTRAINT: Constraints; + const VARIANCE_CONSTRAINT: Constraints<'static>; /// Variants contained in the list of extensions. const EXTENDED_VARIANTS: Option<&'static [TagTree]> = None; /// Variant identifiers for text-based encoding rules @@ -247,7 +247,7 @@ macro_rules! asn_integer_type { $( impl AsnType for $int { const TAG: Tag = Tag::INTEGER; - const CONSTRAINTS: Constraints = constraints!(value_constraint!((<$int>::MIN as i128), (<$int>::MAX as i128))); + const CONSTRAINTS: Constraints<'static> = constraints!(value_constraint!((<$int>::MIN as i128), (<$int>::MAX as i128))); } )+ } @@ -308,7 +308,7 @@ impl AsnType for SetOf { impl AsnType for [T; N] { const TAG: Tag = Tag::SEQUENCE; - const CONSTRAINTS: Constraints = constraints!(size_constraint!(N)); + const CONSTRAINTS: Constraints<'static> = constraints!(size_constraint!(N)); } impl AsnType for &'_ [T] { diff --git a/src/types/constraints.rs b/src/types/constraints.rs index c3ef492b..f5709490 100644 --- a/src/types/constraints.rs +++ b/src/types/constraints.rs @@ -9,27 +9,29 @@ pub const DEFAULT_CONSTRAINTS: Constraints = Constraints::NONE; /// A set of constraints for a given type on what kinds of values are allowed. /// Used in certain codecs to optimise encoding and decoding values. #[derive(Debug, Clone)] -pub struct Constraints(pub &'static [Constraint]); +pub struct Constraints<'constraint>(pub &'constraint [Constraint]); -impl Constraints { +impl<'constraint> Constraints<'constraint> { pub const NONE: Self = Self(&[]); - pub const fn new(constraints: &'static [Constraint]) -> Self { + pub const fn new(constraints: &'constraint [Constraint]) -> Self { Self(constraints) } - - pub const fn inner(&self) -> &'static [Constraint] { + pub const fn inner(&self) -> &'constraint [Constraint] { self.0 } /// We currently only support 5 different constraint types, which includes the empty constraint. /// `usize` is used to drop the empty ones, which are needed to initialize the array. pub const fn from_fixed_size( - merged: &'static ([Constraint; SUPPORTED_CONSTRAINTS_COUNT], usize), + merged: &'constraint ([Constraint; SUPPORTED_CONSTRAINTS_COUNT], usize), ) -> Self { - struct ConstraintArray(&'static [Constraint; N]); + if merged.1 == 0 { + return Self::NONE; + } + struct ConstraintArray<'a, const N: usize>(&'a [Constraint; N]); - impl ConstraintArray { - const fn as_slice(&self) -> &'static [Constraint] { + impl<'a, const N: usize> ConstraintArray<'a, N> { + const fn as_slice(&self) -> &'a [Constraint] { self.0 } } @@ -46,43 +48,45 @@ impl Constraints { /// This function should be only used on compile-time. #[inline(always)] pub const fn merge(self, rhs: Self) -> ([Constraint; SUPPORTED_CONSTRAINTS_COUNT], usize) { - let mut si = 0; let rhs = rhs.0; - let mut ri = 0; let mut array: [Constraint; SUPPORTED_CONSTRAINTS_COUNT] = [Constraint::Empty; SUPPORTED_CONSTRAINTS_COUNT]; + if rhs.len() > SUPPORTED_CONSTRAINTS_COUNT { panic!("Overriding constraint is larger than we have different constraint types") } + // Copy rhs first to the array let mut copy_index = 0; while copy_index < rhs.len() { array[copy_index] = rhs[copy_index]; copy_index += 1; } + let mut si = 0; while si < self.0.len() { + let mut found = false; + let mut ri = 0; while ri < rhs.len() { - if !self.0[si].kind().eq(&rhs[ri].kind()) { - if copy_index > SUPPORTED_CONSTRAINTS_COUNT { - panic!("attempting to copy into greater index than we have different constraint types") - } - array[copy_index] = self.0[si]; - copy_index += 1; - ri += 1; - } else { - ri += 1; + if self.0[si].kind().eq(&rhs[ri].kind()) { + found = true; + break; + } + ri += 1; + } + + if !found { + if copy_index >= SUPPORTED_CONSTRAINTS_COUNT { + panic!("attempting to copy into greater index than we have different constraint types") } + array[copy_index] = self.0[si]; + copy_index += 1; } + si += 1; } + (array, copy_index) } - /// Overrides a set of constraints with another set. - #[inline(always)] - pub fn override_constraints(self, rhs: Constraints) -> Constraints { - // self.merge(rhs) - rhs - } /// Returns the size constraint from the set, if available. pub const fn size(&self) -> Option<&Extensible> { @@ -363,12 +367,6 @@ impl core::ops::Deref for Value { } } -// impl core::ops::DerefMut for Value { -// fn deref_mut(&mut self) -> &mut Self::Target { -// &mut self.value -// } -// } - macro_rules! from_primitives { ($($int:ty),+ $(,)?) => { $( @@ -942,20 +940,119 @@ macro_rules! bounded_constraint { #[cfg(test)] mod tests { use super::*; + use crate as rasn; + use crate::prelude::*; #[test] fn range() { let constraints = Bounded::new(0, 255); assert_eq!(256, constraints.range().unwrap()); } + #[test] + fn test_merge_constraints() { + #[derive(AsnType, Decode, Debug, PartialEq)] + #[rasn(delegate, from("a..=z", "A..=Z", "-", "."), size("1..=64"))] + pub struct NameString(pub VisibleString); + + #[derive(AsnType, Decode, Debug, PartialEq)] + #[rasn(tag(application, 1))] + pub struct InitialString { + #[rasn(size(1))] + pub initial: NameString, + } + const INNER: Constraint = rasn::types::Constraint::Size( + rasn::types::constraints::Extensible::new(rasn::types::constraints::Size::new( + rasn::types::constraints::Bounded::single_value(1i128 as usize), + )) + .set_extensible(false), + ); + const LESS_INNER: Constraints = rasn::types::Constraints::new(&[INNER]); + dbg!(LESS_INNER); + dbg!(::CONSTRAINTS); + const MERGED: ([Constraint; SUPPORTED_CONSTRAINTS_COUNT], usize) = + ::CONSTRAINTS.merge(rasn::types::Constraints::new(&[ + rasn::types::Constraint::Size( + rasn::types::constraints::Extensible::new(rasn::types::constraints::Size::new( + rasn::types::constraints::Bounded::single_value(1i128 as usize), + )) + .set_extensible(false), + ), + ])); + dbg!(MERGED); + + const FIELD_CONSTRAINT_0: rasn::types::Constraints = + rasn::types::Constraints::from_fixed_size( + &::CONSTRAINTS.merge(rasn::types::Constraints::new( + &[rasn::types::Constraint::Size( + rasn::types::constraints::Extensible::new( + rasn::types::constraints::Size::new( + rasn::types::constraints::Bounded::single_value(1i128 as usize), + ), + ) + .set_extensible(false), + )], + )), + ); + dbg!(FIELD_CONSTRAINT_0); + } // #[test] - // fn test_concat_constraints() { - // let a = [Constraint::Value(Extensible::new(Value::new(Bounded::Single(0)))); 1]; - // let b = [Constraint::Size(Extensible::new(Size::new(Bounded::Single(0)))); 1]; - // let c = concat_constraints(a, b); - - // const COMBINED_CONSTRAINTS: [Constraint; 2] = concat_constraints(a, b); - - // const RESULT: &'static [Constraint] = &COMBINED_CONSTRAINTS; + // fn test_nested_extensible() { + // #[derive(AsnType, Encode, Decode, Debug, PartialEq)] + // #[rasn(tag(application, 2), delegate, value("0..=9999", extensible))] + // pub struct ExtensibleEmployeeNumber(pub Integer); + + // #[derive(AsnType, Decode, Encode, Debug, PartialEq)] + // #[rasn( + // tag(application, 3), + // delegate, + // from("0..=9"), + // size(8, extensible, "9..=20") + // )] + // pub struct ExtensibleDate(pub VisibleString); + + // #[derive(AsnType, Decode, Encode, Debug, PartialEq)] + // #[rasn(delegate, from("a..=z", "A..=Z", "-", "."), size("1..=64", extensible))] + // pub struct ExtensibleNameString(pub VisibleString); + + // #[derive(AsnType, Decode, Encode, Debug, PartialEq)] + // #[rasn(tag(application, 1))] + // #[non_exhaustive] + // pub struct ExtensibleName { + // pub given_name: ExtensibleNameString, + // #[rasn(size(1))] + // pub initial: ExtensibleNameString, + // pub family_name: ExtensibleNameString, + // } + // #[derive(AsnType, Decode, Encode, Debug, PartialEq)] + // #[rasn(set)] + // #[non_exhaustive] + // pub struct ExtensibleChildInformation { + // name: ExtensibleName, + // #[rasn(tag(explicit(0)))] + // date_of_birth: ExtensibleDate, + // } + + // #[derive(AsnType, Encode, Decode, Debug, PartialEq)] + // #[rasn(set, tag(application, 0))] + // #[non_exhaustive] + // pub struct ExtensiblePersonnelRecord { + // pub name: ExtensibleName, + // #[rasn(tag(explicit(0)))] + // pub title: VisibleString, + // pub number: ExtensibleEmployeeNumber, + // #[rasn(tag(explicit(1)))] + // pub date_of_hire: ExtensibleDate, + // #[rasn(tag(explicit(2)))] + // pub name_of_spouse: ExtensibleName, + // #[rasn(tag(3), default, size(2, extensible))] + // pub children: Option>, + // } + // #[derive(AsnType, Decode, Encode, Debug, PartialEq)] + // #[rasn(set)] + // #[non_exhaustive] + // pub struct ExtensibleTest { + // name: ExtensibleName, + // #[rasn(tag(1), size(1, extensible))] + // record: ExtensiblePersonnelRecord, // } } diff --git a/src/types/integer.rs b/src/types/integer.rs index 5c85c082..0beea5a6 100644 --- a/src/types/integer.rs +++ b/src/types/integer.rs @@ -355,7 +355,7 @@ pub struct ConstrainedInteger(pub(crate) Int impl AsnType for ConstrainedInteger { const TAG: Tag = Tag::INTEGER; - const CONSTRAINTS: Constraints = + const CONSTRAINTS: Constraints<'static> = Constraints::new(&[constraints::Constraint::Value(Extensible::new( constraints::Value::new(constraints::Bounded::const_new(START, END)), ))]); diff --git a/src/types/strings/octet.rs b/src/types/strings/octet.rs index 24caf976..f75fd8ed 100644 --- a/src/types/strings/octet.rs +++ b/src/types/strings/octet.rs @@ -63,7 +63,7 @@ impl core::ops::DerefMut for FixedOctetString { impl AsnType for FixedOctetString { const TAG: Tag = Tag::OCTET_STRING; - const CONSTRAINTS: Constraints = Constraints::new(&[Constraint::Size(Extensible::new( + const CONSTRAINTS: Constraints<'static> = Constraints::new(&[Constraint::Size(Extensible::new( constraints::Size::fixed(N), ))]); } diff --git a/tests/personnel.rs b/tests/personnel.rs index 17245ecc..d808e4ec 100644 --- a/tests/personnel.rs +++ b/tests/personnel.rs @@ -518,6 +518,8 @@ test! { constrained_uper_initial(uper): InitialString = InitialString { initial: VisibleString::try_from("P").unwrap().into(), } => &[0x44]; + constrained_uper_number(uper): ExtensibleEmployeeNumber = ExtensibleEmployeeNumber(51.into()) + => &[0x0, 0x66]; constrained_uper(uper): PersonnelRecordWithConstraints = <_>::default() => &[ 0x86, 0x5D, 0x51, 0xD2, 0x88, 0x8A, 0x51, 0x25, 0xF1, 0x80, 0x99, 0x84, From 56d5d77c064ce40686dd92e8346a892abd31601e Mon Sep 17 00:00:00 2001 From: Niklas Saari Date: Tue, 17 Sep 2024 19:21:25 +0300 Subject: [PATCH 11/22] Rebase fixes --- src/aper.rs | 6 ------ src/jer/enc.rs | 6 +----- src/lib.rs | 2 +- src/per/de.rs | 1 - src/types/strings/octet.rs | 9 +++++---- src/uper.rs | 1 - 6 files changed, 7 insertions(+), 18 deletions(-) diff --git a/src/aper.rs b/src/aper.rs index 275afd22..ffa55c8c 100644 --- a/src/aper.rs +++ b/src/aper.rs @@ -416,12 +416,6 @@ mod tests { ]), size_constraint!(1, 255) ); - const PERMITTED_CONSTRAINT_2: Constraints = - Constraints::new( - &[Constraint::PermittedAlphabet(constraints::Extensible::new( - PermittedAlphabet::new(&[b'a' as u32]), - ))], - ); round_trip_with_constraints!( aper, VisibleString, diff --git a/src/jer/enc.rs b/src/jer/enc.rs index 56e2e427..2604b606 100644 --- a/src/jer/enc.rs +++ b/src/jer/enc.rs @@ -76,11 +76,7 @@ impl crate::Encoder for Encoder { t: crate::types::Tag, value: &crate::types::Any, ) -> Result { - self.encode_octet_string( - t, - crate::types::constraints::Constraints::default(), - &value.contents, - ) + self.encode_octet_string(t, Constraints::default(), &value.contents) } fn encode_bool(&mut self, _: Tag, value: bool) -> Result { diff --git a/src/lib.rs b/src/lib.rs index be364ad4..3e8d309e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -141,7 +141,7 @@ mod tests { impl crate::AsnType for CustomInt { const TAG: Tag = Tag::INTEGER; - const CONSTRAINTS: Constraints = + const CONSTRAINTS: Constraints<'static> = macros::constraints!(macros::value_constraint!(start: 127)); } diff --git a/src/per/de.rs b/src/per/de.rs index de813753..b19e048e 100644 --- a/src/per/de.rs +++ b/src/per/de.rs @@ -7,7 +7,6 @@ use super::{ FOURTY_EIGHT_K, LARGE_UNSIGNED_CONSTRAINT, SIXTEEN_K, SIXTY_FOUR_K, SMALL_UNSIGNED_CONSTRAINT, THIRTY_TWO_K, }; -pub use crate::error::DecodeError; use crate::{ de::Error as _, types::{ diff --git a/src/types/strings/octet.rs b/src/types/strings/octet.rs index f75fd8ed..b3c121a5 100644 --- a/src/types/strings/octet.rs +++ b/src/types/strings/octet.rs @@ -1,4 +1,7 @@ -use crate::prelude::*; +use crate::{ + macros::{constraints, size_constraint}, + prelude::*, +}; use alloc::vec::Vec; @@ -63,9 +66,7 @@ impl core::ops::DerefMut for FixedOctetString { impl AsnType for FixedOctetString { const TAG: Tag = Tag::OCTET_STRING; - const CONSTRAINTS: Constraints<'static> = Constraints::new(&[Constraint::Size(Extensible::new( - constraints::Size::fixed(N), - ))]); + const CONSTRAINTS: Constraints<'static> = constraints!(size_constraint!(N)); } impl Decode for FixedOctetString { diff --git a/src/uper.rs b/src/uper.rs index 1c995e4f..e8318ce2 100644 --- a/src/uper.rs +++ b/src/uper.rs @@ -41,7 +41,6 @@ mod tests { use crate::{ macros::{constraints, permitted_alphabet_constraint, size_constraint}, prelude::*, - size_constraint, types::{constraints::*, *}, }; From 164848a930b17d3a0b74b4d67d3a696003b9e407 Mon Sep 17 00:00:00 2001 From: Niklas Saari Date: Thu, 24 Oct 2024 19:14:32 +0300 Subject: [PATCH 12/22] Rebase cleanup --- src/oer.rs | 2 - src/oer/de.rs | 1 + src/oer/enc.rs | 1 + src/types/constraints.rs | 169 +++------------------------------------ 4 files changed, 12 insertions(+), 161 deletions(-) diff --git a/src/oer.rs b/src/oer.rs index 36e9dc27..c65f83e1 100644 --- a/src/oer.rs +++ b/src/oer.rs @@ -1,8 +1,6 @@ //! Codec for Octet Encoding Rules (OER). //! Encodes in canonical format (COER), and decodes in more versatile format (OER). -mod ranges; - pub mod de; pub mod enc; diff --git a/src/oer/de.rs b/src/oer/de.rs index 4a9d57f3..10d2738d 100644 --- a/src/oer/de.rs +++ b/src/oer/de.rs @@ -12,6 +12,7 @@ use alloc::{ }; use crate::{ + oer::EncodingRules, types::{ self, fields::{Field, Fields}, diff --git a/src/oer/enc.rs b/src/oer/enc.rs index 471b0de2..4e07ad1b 100644 --- a/src/oer/enc.rs +++ b/src/oer/enc.rs @@ -6,6 +6,7 @@ use core::cell::RefCell; use num_traits::ToPrimitive; use crate::{ + oer::EncodingRules, types::{ Any, BitStr, BmpString, Choice, Constraints, Constructed, Date, Enumerated, GeneralString, GeneralizedTime, Ia5String, IntegerType, NumericString, PrintableString, SetOf, Tag, diff --git a/src/types/constraints.rs b/src/types/constraints.rs index f5709490..4132163b 100644 --- a/src/types/constraints.rs +++ b/src/types/constraints.rs @@ -4,6 +4,7 @@ use super::IntegerType; use num_bigint::BigInt; const SUPPORTED_CONSTRAINTS_COUNT: usize = 5; +/// The default empty constraints. pub const DEFAULT_CONSTRAINTS: Constraints = Constraints::NONE; /// A set of constraints for a given type on what kinds of values are allowed. @@ -12,11 +13,14 @@ pub const DEFAULT_CONSTRAINTS: Constraints = Constraints::NONE; pub struct Constraints<'constraint>(pub &'constraint [Constraint]); impl<'constraint> Constraints<'constraint> { + /// Empty constraints. pub const NONE: Self = Self(&[]); + /// Creates a new set of constraints from a given slice. pub const fn new(constraints: &'constraint [Constraint]) -> Self { Self(constraints) } + /// Returns the inner constraints. pub const fn inner(&self) -> &'constraint [Constraint] { self.0 } @@ -137,18 +141,6 @@ impl<'constraint> Constraints<'constraint> { } } -impl From<&'static [Constraint]> for Constraints { - fn from(constraints: &'static [Constraint]) -> Self { - Self::new(constraints) - } -} - -impl From<&'static [Constraint; N]> for Constraints { - fn from(constraints: &'static [Constraint; N]) -> Self { - Self::new(constraints) - } -} - /// The set of possible constraints a given value can have. /// /// Do not change the amount of variants in this enum without changing the `SUPPORTED_CONSTRAINTS_COUNT` constant. @@ -177,6 +169,7 @@ pub enum ConstraintDiscriminant { Empty, } impl ConstraintDiscriminant { + /// Constant equality check. pub const fn eq(&self, other: &ConstraintDiscriminant) -> bool { *self as isize == *other as isize } @@ -193,9 +186,11 @@ impl Constraint { Self::Empty => ConstraintDiscriminant::Empty, } } + /// Returns the default constraint, which is an empty constraint. pub const fn default() -> Self { Self::Empty } + /// Returns the discriminant as an `isize` integer. pub const fn variant_as_isize(&self) -> isize { match self { Self::Value(_) => 0, @@ -351,9 +346,11 @@ impl Value { range, } } + /// Gets the sign of the value constraint. pub const fn get_sign(&self) -> bool { self.signed } + /// Gets the range of the value constraint. pub const fn get_range(&self) -> Option { self.range } @@ -668,6 +665,7 @@ impl Bounded { const fn max(&self, a: u128, b: u128) -> u128 { [a, b][(a < b) as usize] } + /// Returns the sign and the range in bytes of the constraint. pub const fn range_in_bytes(&self) -> (bool, Option) { match self { Self::Single(value) => (*value < 0, Self::octet_size_by_range(*value)), @@ -789,153 +787,6 @@ impl core::fmt::Display for Bounded { } } } -/// Helper macro to create constant value constraints. -/// -/// Usage: -/// ```rust -// Full range -// let full_range = value_constraint!(0, 100); -// Only start specified -// let start_only = value_constraint!(start: 0); -// Only end specified -// let end_only = value_constraint!(end: 100); -// Single value -// let single = value_constraint!(42); -// Full range with extensibility -// let ext_full_range = value_constraint!(0, 100, true); -// Only start with extensibility -// let ext_start_only = value_constraint!(start: 0, true); -// Only end with extensibility -// let ext_end_only = value_constraint!(end: 100, false); -// Single value with extensibility -/// let ext_single = value_constraint!(42, true); -/// ``` -#[macro_export] -macro_rules! value_constraint { - ($($args:tt)*) => { - $crate::bounded_constraint!(Value, $($args)*) - }; -} - -#[macro_export] -macro_rules! size_constraint { - ($($args:tt)*) => { - $crate::bounded_constraint!(Size, $($args)*) - }; -} - -#[macro_export] -macro_rules! constraints { - ($($constraint:expr),+ $(,)?) => { - $crate::types::constraints::Constraints(&[$($constraint),+]) - }; -} - -#[macro_export] -macro_rules! permitted_alphabet_constraint { - ( $alphabet:expr) => { - $crate::types::constraints::Constraint::PermittedAlphabet( - $crate::types::constraints::Extensible::new( - $crate::types::constraints::PermittedAlphabet::new($alphabet), - ), - ) - }; -} - -#[macro_export] -macro_rules! bounded_constraint { - // Start and end - ($constraint_type:ident, $start:expr, $end:expr) => { - $crate::types::constraints::Constraint::$constraint_type( - $crate::types::constraints::Extensible::new( - $crate::types::constraints::$constraint_type::new( - $crate::types::constraints::Bounded::const_new($start, $end), - ), - ), - ) - }; - - // Only start provided - ($constraint_type:ident, start: $start:expr) => { - $crate::types::constraints::Constraint::$constraint_type( - $crate::types::constraints::Extensible::new( - $crate::types::constraints::$constraint_type::new( - $crate::types::constraints::Bounded::start_from($start), - ), - ), - ) - }; - - // Only end provided - ($constraint_type:ident, end: $end:expr) => { - $crate::types::constraints::Constraint::$constraint_type( - $crate::types::constraints::Extensible::new( - $crate::types::constraints::$constraint_type::new( - $crate::types::constraints::Bounded::up_to($end), - ), - ), - ) - }; - - // Single value - ($constraint_type:ident, $single:expr) => { - $crate::types::constraints::Constraint::$constraint_type( - $crate::types::constraints::Extensible::new( - $crate::types::constraints::$constraint_type::new( - $crate::types::constraints::Bounded::Single($single), - ), - ), - ) - }; - - // Range with extensibility - ($constraint_type:ident, $start:expr, $end:expr, $extensible:expr) => { - $crate::types::constraints::Constraint::$constraint_type( - $crate::types::constraints::Extensible::new( - $crate::types::constraints::$constraint_type::new( - $crate::types::constraints::Bounded::const_new($start, $end), - ), - ) - .set_extensible($extensible), - ) - }; - - // Only start with extensibility - ($constraint_type:ident, start: $start:expr, $extensible:expr) => { - $crate::types::constraints::Constraint::$constraint_type( - $crate::types::constraints::Extensible::new( - $crate::types::constraints::$constraint_type::new( - $crate::types::constraints::Bounded::start_from($start), - ), - ) - .set_extensible($extensible), - ) - }; - - // Only end with extensibility - ($constraint_type:ident, end: $end:expr, $extensible:expr) => { - $crate::types::constraints::Constraint::$constraint_type( - $crate::types::constraints::Extensible::new( - $crate::types::constraints::$constraint_type::new( - $crate::types::constraints::Bounded::up_to($end), - ), - ) - .set_extensible($extensible), - ) - }; - - // Single value with extensibility - ($constraint_type:ident, $single:expr, $extensible:expr) => { - $crate::types::constraints::Constraint::$constraint_type( - $crate::types::constraints::Extensible::new( - $crate::types::constraints::$constraint_type::new( - $crate::types::constraints::Bounded::Single($single), - ), - ) - .set_extensible($extensible), - ) - }; -} #[cfg(test)] mod tests { From 6fd03d83b909079467085d1eac0495d712133823 Mon Sep 17 00:00:00 2001 From: Niklas Saari Date: Thu, 24 Oct 2024 20:06:22 +0300 Subject: [PATCH 13/22] Missing overrides, docs --- src/types.rs | 1 + src/types/constraints.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/src/types.rs b/src/types.rs index dfdce04d..5a276cc6 100644 --- a/src/types.rs +++ b/src/types.rs @@ -63,6 +63,7 @@ pub trait AsnType { /// `Leaf` that points [`Self::TAG`]. const TAG_TREE: TagTree = TagTree::Leaf(Self::TAG); + /// The constraints for this type. const CONSTRAINTS: Constraints<'static> = Constraints::NONE; /// Identifier of an ASN.1 type as specified in the original specification diff --git a/src/types/constraints.rs b/src/types/constraints.rs index 4132163b..2a4de631 100644 --- a/src/types/constraints.rs +++ b/src/types/constraints.rs @@ -155,6 +155,7 @@ pub enum Constraint { /// The value itself is extensible, only valid for constructed types, /// choices, or enumerated values. Extensible, + /// Empty constraint. Empty, } From ef4c35c68c64c8b975ed68e1ba28749d45e1afc7 Mon Sep 17 00:00:00 2001 From: Niklas Saari Date: Thu, 24 Oct 2024 21:54:33 +0300 Subject: [PATCH 14/22] Missing macros --- macros/macros_impl/src/config.rs | 37 +++++++++++++++++++++----------- src/types.rs | 2 +- src/types/constraints.rs | 3 +-- 3 files changed, 27 insertions(+), 15 deletions(-) diff --git a/macros/macros_impl/src/config.rs b/macros/macros_impl/src/config.rs index 8a9a2eb8..e6a1ec5d 100644 --- a/macros/macros_impl/src/config.rs +++ b/macros/macros_impl/src/config.rs @@ -1032,11 +1032,16 @@ impl<'a> FieldConfig<'a> { or_else.clone() }; if constraints { - quote!( - decoder.decode_extension_addition_with_explicit_tag_and_constraints( - #tag, - <#ty as #crate_root::AsnType>::CONSTRAINTS.override_constraints(#constraints), - ) #or_else #handle_extension) + { + quote!( + const #constraint_name : #crate_root::types::Constraints = #crate_root::types::Constraints::from_fixed_size(&<#ty as #crate_root::AsnType>::CONSTRAINTS.merge( + #constraints + )); + decoder.decode_extension_addition_with_explicit_tag_and_constraints( + #tag, + #constraint_name + ) #or_else #handle_extension) + } } else { quote!(decoder.decode_extension_addition_with_explicit_tag_and_constraints( #tag, @@ -1045,20 +1050,28 @@ impl<'a> FieldConfig<'a> { } (Some(false), Some(path), true) => { quote!( + const #constraint_name : #crate_root::types::Constraints = #crate_root::types::Constraints::from_fixed_size(&<#ty as #crate_root::AsnType>::CONSTRAINTS.merge( + #constraints + )); decoder.decode_extension_addition_with_default_and_tag_and_constraints( #tag, #path, - <#ty as #crate_root::AsnType>::CONSTRAINTS.override_constraints(#constraints), - ) #or_else + #constraint_name + ) #or_else ) } (Some(false), None, true) => { quote!( - <_>::decode_extension_addition_with_tag_and_constraints( - decoder, - #tag, - <#ty as #crate_root::AsnType>::CONSTRAINTS.override_constraints(#constraints), - ) #or_else #handle_extension + { + const #constraint_name : #crate_root::types::Constraints = #crate_root::types::Constraints::from_fixed_size(&<#ty as #crate_root::AsnType>::CONSTRAINTS.merge( + #constraints + )); + <_>::decode_extension_addition_with_tag_and_constraints( + decoder, + #tag, + #constraint_name + ) #or_else #handle_extension + } ) } (Some(false), Some(path), false) => { diff --git a/src/types.rs b/src/types.rs index 5a276cc6..b967caf3 100644 --- a/src/types.rs +++ b/src/types.rs @@ -63,7 +63,7 @@ pub trait AsnType { /// `Leaf` that points [`Self::TAG`]. const TAG_TREE: TagTree = TagTree::Leaf(Self::TAG); - /// The constraints for this type. + /// The set of constraints for values of the given type. const CONSTRAINTS: Constraints<'static> = Constraints::NONE; /// Identifier of an ASN.1 type as specified in the original specification diff --git a/src/types/constraints.rs b/src/types/constraints.rs index 2a4de631..a00f5a1b 100644 --- a/src/types/constraints.rs +++ b/src/types/constraints.rs @@ -3,9 +3,8 @@ use super::IntegerType; use num_bigint::BigInt; +// TODO type can have multiple constraints of same kind, up to infinite const SUPPORTED_CONSTRAINTS_COUNT: usize = 5; -/// The default empty constraints. -pub const DEFAULT_CONSTRAINTS: Constraints = Constraints::NONE; /// A set of constraints for a given type on what kinds of values are allowed. /// Used in certain codecs to optimise encoding and decoding values. From 2f577fcde7011cc137dbfbe84cd06bb12d18db90 Mon Sep 17 00:00:00 2001 From: Niklas Saari Date: Mon, 28 Oct 2024 15:45:00 +0200 Subject: [PATCH 15/22] Docs, rm unnecessary inline --- src/types/constraints.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/types/constraints.rs b/src/types/constraints.rs index a00f5a1b..bd9e0084 100644 --- a/src/types/constraints.rs +++ b/src/types/constraints.rs @@ -408,20 +408,20 @@ impl TryFrom> for Value { pub struct Size(pub(crate) Bounded); impl Size { - #[must_use] /// Creates a varying range constraint. + #[must_use] pub const fn new(range: Bounded) -> Self { Self(range) } - #[must_use] /// Creates a fixed size constraint. + #[must_use] pub const fn fixed(length: usize) -> Self { Self(Bounded::Single(length)) } - #[must_use] /// Returns whether the size is fixed. + #[must_use] pub const fn is_fixed(&self) -> bool { matches!(self.0, Bounded::Single(_)) } @@ -490,7 +490,6 @@ pub enum Bounded { impl Bounded { /// Calculates the the amount of bytes that are required to represent integer `value`. /// Particularly useful for OER codec - #[inline(always)] const fn octet_size_by_range(value: i128) -> Option { let abs_value = value.unsigned_abs(); Some(if abs_value <= u8::MAX as u128 { From ea20d65a4265540ab606a588cdee04be1b081cd1 Mon Sep 17 00:00:00 2001 From: Niklas Saari Date: Thu, 21 Nov 2024 00:56:41 +0200 Subject: [PATCH 16/22] Ldap rustfmt --- standards/ldap/src/lib.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/standards/ldap/src/lib.rs b/standards/ldap/src/lib.rs index 6c478188..3eb7e193 100644 --- a/standards/ldap/src/lib.rs +++ b/standards/ldap/src/lib.rs @@ -65,11 +65,7 @@ impl rasn::Encode for LdapString { tag: rasn::types::Tag, constraints: rasn::types::Constraints, ) -> core::result::Result<(), EN::Error> { - encoder.encode_octet_string( - tag, - constraints, - self.0.as_bytes(), - )?; + encoder.encode_octet_string(tag, constraints, self.0.as_bytes())?; Ok(()) } } From 50c784f3b9536f138da8b5f4d145bcf6e11ee67f Mon Sep 17 00:00:00 2001 From: Niklas Saari Date: Thu, 21 Nov 2024 15:01:54 +0200 Subject: [PATCH 17/22] wip --- Cargo.toml | 13 +- macros/macros_impl/src/config.rs | 66 ++--- macros/macros_impl/src/decode.rs | 9 +- macros/macros_impl/src/encode.rs | 7 +- macros/macros_impl/src/enum.rs | 2 +- src/lib.rs | 4 +- src/per/enc.rs | 2 +- src/types.rs | 8 +- src/types/constraints.rs | 411 +++++++++++++++++++++++-------- src/types/integer.rs | 2 +- src/types/strings/octet.rs | 2 +- tests/generics.rs | 29 ++- 12 files changed, 389 insertions(+), 166 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 05ae703c..700086bf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,6 +32,12 @@ std = [] backtraces = ["std", "snafu/backtrace"] compiler = ["rasn-compiler"] +[profile.dev] +# debug = 0 + +[profile.bench] +debug = true + [profile.bench-lto] inherits = "bench" opt-level = 3 @@ -56,7 +62,7 @@ bench = false [[bench]] name = "criterion_integer" -path = "benches/integer.rs" +path = "benches/integer_basic.rs" harness = false test = true @@ -85,7 +91,10 @@ snafu = { version = "0.8.5", default-features = false, features = [ serde_json = { version = "1", default-features = false, features = ["alloc"] } [dev-dependencies] -criterion = { version = "0.5.1", default-features = false, features = ["plotters", "cargo_bench_support"] } +criterion = { version = "0.5.1", default-features = false, features = [ + "plotters", + "cargo_bench_support", +] } iai-callgrind = "0.14.0" once_cell = "1.20.2" pretty_assertions.workspace = true diff --git a/macros/macros_impl/src/config.rs b/macros/macros_impl/src/config.rs index e6a1ec5d..36d92f91 100644 --- a/macros/macros_impl/src/config.rs +++ b/macros/macros_impl/src/config.rs @@ -15,9 +15,8 @@ pub struct Constraints { impl Constraints { pub fn const_static_def(&self, crate_root: &syn::Path) -> Option { - self.const_expr(crate_root).map( - |expr| quote!(const CONSTRAINTS: #crate_root::types::Constraints<'static> = #expr;), - ) + self.const_expr(crate_root) + .map(|expr| quote!(const CONSTRAINTS: #crate_root::types::Constraints = #expr;)) } pub fn attribute_tokens(&self) -> Option { @@ -769,6 +768,7 @@ impl<'a> FieldConfig<'a> { .map(|name| quote!(#name)) .unwrap_or_else(|| quote!(#i)); let mut ty = self.field.ty.clone(); + // dbg!(&ty); let crate_root = &self.container_config.crate_root; ty.strip_lifetimes(); let default_fn = self.default_fn(); @@ -783,9 +783,9 @@ impl<'a> FieldConfig<'a> { .const_expr(&self.container_config.crate_root) .unwrap_or_else(|| quote!(#crate_root::types::Constraints::default())); quote!( - const #constraint_name : #crate_root::types::Constraints = #crate_root::types::Constraints::from_fixed_size(&<#ty as #crate_root::AsnType>::CONSTRAINTS.merge( + const #constraint_name : #crate_root::types::Constraints = <#ty as #crate_root::AsnType>::CONSTRAINTS.intersect( #constraints - )); + ); encoder.encode_extension_addition( #tag, #constraint_name, @@ -802,9 +802,9 @@ impl<'a> FieldConfig<'a> { match (self.constraints.has_constraints(), self.default.is_some()) { (true, true) => { quote!( - const #constraint_name : #crate_root::types::Constraints = #crate_root::types::Constraints::from_fixed_size(&<#ty as #crate_root::AsnType>::CONSTRAINTS.merge( + const #constraint_name : #crate_root::types::Constraints =<#ty as #crate_root::AsnType>::CONSTRAINTS.intersect( #constraints - )); + ); encoder.encode_default_with_tag_and_constraints( #tag, #constraint_name, @@ -815,9 +815,9 @@ impl<'a> FieldConfig<'a> { } (true, false) => { quote!( - const #constraint_name : #crate_root::types::Constraints = #crate_root::types::Constraints::from_fixed_size(&<#ty as #crate_root::AsnType>::CONSTRAINTS.merge( + const #constraint_name : #crate_root::types::Constraints =<#ty as #crate_root::AsnType>::CONSTRAINTS.intersect( #constraints - )); + ); #this #field.encode_with_tag_and_constraints( encoder, #tag, @@ -838,9 +838,9 @@ impl<'a> FieldConfig<'a> { .const_expr(&self.container_config.crate_root) .unwrap_or_else(|| quote!(#crate_root::types::Constraints::default())); quote!( - const #constraint_name : #crate_root::types::Constraints = #crate_root::types::Constraints::from_fixed_size(&<#ty as #crate_root::AsnType>::CONSTRAINTS.merge( + const #constraint_name : #crate_root::types::Constraints = <#ty as #crate_root::AsnType>::CONSTRAINTS.intersect( #constraints - )); + ); encoder.encode_extension_addition( #tag, #constraint_name, @@ -856,9 +856,9 @@ impl<'a> FieldConfig<'a> { .constraints .const_expr(&self.container_config.crate_root); quote!( - const #constraint_name : #crate_root::types::Constraints = #crate_root::types::Constraints::from_fixed_size(&<#ty as #crate_root::AsnType>::CONSTRAINTS.merge( + const #constraint_name : #crate_root::types::Constraints = <#ty as #crate_root::AsnType>::CONSTRAINTS.intersect( #constraints - )); + ); encoder.encode_default_with_constraints( #constraint_name, &#this #field, @@ -871,9 +871,9 @@ impl<'a> FieldConfig<'a> { .constraints .const_expr(&self.container_config.crate_root); quote!( - const #constraint_name : #crate_root::types::Constraints = #crate_root::types::Constraints::from_fixed_size(&<#ty as #crate_root::AsnType>::CONSTRAINTS.merge( + const #constraint_name : #crate_root::types::Constraints = <#ty as #crate_root::AsnType>::CONSTRAINTS.intersect( #constraints - )); + ); #this #field.encode_with_constraints( encoder, #constraint_name, @@ -952,9 +952,9 @@ impl<'a> FieldConfig<'a> { } (Some(false), Some(path), true) => { quote!({ - const #constraint_name : #crate_root::types::Constraints = #crate_root::types::Constraints::from_fixed_size(&<#ty as #crate_root::AsnType>::CONSTRAINTS.merge( + const #constraint_name : #crate_root::types::Constraints = <#ty as #crate_root::AsnType>::CONSTRAINTS.intersect( #constraints - )); + ); decoder.decode_default_with_tag_and_constraints( #tag, #path, @@ -967,9 +967,9 @@ impl<'a> FieldConfig<'a> { } (Some(false), None, true) => { quote!({ - const #constraint_name : #crate_root::types::Constraints = #crate_root::types::Constraints::from_fixed_size(&<#ty as #crate_root::AsnType>::CONSTRAINTS.merge( + const #constraint_name : #crate_root::types::Constraints = <#ty as #crate_root::AsnType>::CONSTRAINTS.intersect( #constraints - )); + ); <_>::decode_with_tag_and_constraints( decoder, #tag, @@ -982,9 +982,9 @@ impl<'a> FieldConfig<'a> { } (None, Some(path), true) => { quote!({ - const #constraint_name : #crate_root::types::Constraints = #crate_root::types::Constraints::from_fixed_size(&<#ty as #crate_root::AsnType>::CONSTRAINTS.merge( + const #constraint_name : #crate_root::types::Constraints = <#ty as #crate_root::AsnType>::CONSTRAINTS.intersect( #constraints - )); + ); decoder.decode_default_with_constraints( #path, #constraint_name, @@ -996,9 +996,9 @@ impl<'a> FieldConfig<'a> { } (None, None, true) => { quote!({ - const #constraint_name : #crate_root::types::Constraints = #crate_root::types::Constraints::from_fixed_size(&<#ty as #crate_root::AsnType>::CONSTRAINTS.merge( + const #constraint_name : #crate_root::types::Constraints = <#ty as #crate_root::AsnType>::CONSTRAINTS.intersect( #constraints - )); + ); <_>::decode_with_constraints( decoder, #constraint_name, @@ -1034,9 +1034,9 @@ impl<'a> FieldConfig<'a> { if constraints { { quote!( - const #constraint_name : #crate_root::types::Constraints = #crate_root::types::Constraints::from_fixed_size(&<#ty as #crate_root::AsnType>::CONSTRAINTS.merge( + const #constraint_name : #crate_root::types::Constraints = <#ty as #crate_root::AsnType>::CONSTRAINTS.intersect( #constraints - )); + ); decoder.decode_extension_addition_with_explicit_tag_and_constraints( #tag, #constraint_name @@ -1050,9 +1050,9 @@ impl<'a> FieldConfig<'a> { } (Some(false), Some(path), true) => { quote!( - const #constraint_name : #crate_root::types::Constraints = #crate_root::types::Constraints::from_fixed_size(&<#ty as #crate_root::AsnType>::CONSTRAINTS.merge( + const #constraint_name : #crate_root::types::Constraints = <#ty as #crate_root::AsnType>::CONSTRAINTS.intersect( #constraints - )); + ); decoder.decode_extension_addition_with_default_and_tag_and_constraints( #tag, #path, @@ -1063,9 +1063,9 @@ impl<'a> FieldConfig<'a> { (Some(false), None, true) => { quote!( { - const #constraint_name : #crate_root::types::Constraints = #crate_root::types::Constraints::from_fixed_size(&<#ty as #crate_root::AsnType>::CONSTRAINTS.merge( + const #constraint_name : #crate_root::types::Constraints = <#ty as #crate_root::AsnType>::CONSTRAINTS.intersect( #constraints - )); + ); <_>::decode_extension_addition_with_tag_and_constraints( decoder, #tag, @@ -1083,9 +1083,9 @@ impl<'a> FieldConfig<'a> { (None, Some(path), true) => { quote!( { - const #constraint_name : #crate_root::types::Constraints = #crate_root::types::Constraints::from_fixed_size(&<#ty as #crate_root::AsnType>::CONSTRAINTS.merge( + const #constraint_name : #crate_root::types::Constraints = <#ty as #crate_root::AsnType>::CONSTRAINTS.intersect( #constraints - )); + ); decoder.decode_extension_addition_with_default_and_constraints( #path, #constraint_name, @@ -1101,9 +1101,9 @@ impl<'a> FieldConfig<'a> { } (None, None, true) => { quote!({ - const #constraint_name : #crate_root::types::Constraints = #crate_root::types::Constraints::from_fixed_size(&<#ty as #crate_root::AsnType>::CONSTRAINTS.merge( + const #constraint_name : #crate_root::types::Constraints = <#ty as #crate_root::AsnType>::CONSTRAINTS.intersect( #constraints - )); + ); decoder.decode_extension_addition_with_constraints( #constraint_name, ) #or_else } diff --git a/macros/macros_impl/src/decode.rs b/macros/macros_impl/src/decode.rs index 673814c7..d913de46 100644 --- a/macros/macros_impl/src/decode.rs +++ b/macros/macros_impl/src/decode.rs @@ -33,9 +33,9 @@ pub fn derive_struct_impl( .const_expr(crate_root) .unwrap_or_else(|| quote!(#crate_root::types::Constraints::default())); quote! { - const #constraint_name : #crate_root::types::Constraints = #constraints; - let merged = #constraint_name.merge(constraints); - let constraints : #crate_root::types::Constraints = #crate_root::types::Constraints::from_fixed_size(&merged); + const #constraint_name : #crate_root::types::Constraints = <#ty as #crate_root::AsnType>::CONSTRAINTS; + let CONSTRAINTS: #crate_root::types::Constraints = #constraint_name.intersect(constraints); + // let constraints : #crate_root::types::Constraints = #crate_root::types::Constraints::from_fixed_size(&merged); match tag { #crate_root::types::Tag::EOC => { Ok(Self(<#ty>::decode(decoder)?)) @@ -44,7 +44,8 @@ pub fn derive_struct_impl( <#ty as #crate_root::Decode>::decode_with_tag_and_constraints( decoder, tag, - constraints + // constraints + CONSTRAINTS ).map(Self) } } diff --git a/macros/macros_impl/src/encode.rs b/macros/macros_impl/src/encode.rs index 5f8555db..2cbbfc30 100644 --- a/macros/macros_impl/src/encode.rs +++ b/macros/macros_impl/src/encode.rs @@ -54,7 +54,7 @@ pub fn derive_struct_impl( // let (data, test) = <#ty as #crate_root::AsnType>::CONSTRAINTS.merge( // constraints // ); - let merged = <#ty as #crate_root::AsnType>::CONSTRAINTS.merge( + let merged = <#ty as #crate_root::AsnType>::CONSTRAINTS.intersect( constraints ); // dbg!(&data[..test]); @@ -62,7 +62,7 @@ pub fn derive_struct_impl( // let constraint : #crate_root::types::Constraints = #crate_root::types::Constraints::new(&data[..test]); // dbg!(&constraint); // let merged = <#ty as #crate_root::AsnType>::CONSTRAINTS.merge(constraint); - let merged_constraints : #crate_root::types::Constraints = #crate_root::types::Constraints::from_fixed_size(&merged); + // let merged_constraints : #crate_root::types::Constraints = #crate_root::types::Constraints::from_fixed_size(&merged); // dbg!(constraintts); // dbg!(#constraint_name); // dbg!(&constraints); @@ -80,7 +80,8 @@ pub fn derive_struct_impl( // constraints // Correct but misses override.. // #constraint_name - merged_constraints + merged + // merged_constraints // Empty // <#ty as #crate_root::AsnType>::CONSTRAINTS, ) diff --git a/macros/macros_impl/src/enum.rs b/macros/macros_impl/src/enum.rs index 4ee0d7ad..00da738e 100644 --- a/macros/macros_impl/src/enum.rs +++ b/macros/macros_impl/src/enum.rs @@ -116,7 +116,7 @@ impl Enum { const VARIANTS: &'static [#crate_root::types::TagTree] = &[ #(#base_variants),* ]; - const VARIANCE_CONSTRAINT: #crate_root::types::Constraints<'static> = #variance_constraint; + const VARIANCE_CONSTRAINT: #crate_root::types::Constraints = #variance_constraint; const EXTENDED_VARIANTS: Option<&'static [#crate_root::types::TagTree]> = #extended_const_variants; const IDENTIFIERS: &'static [&'static str] = &[ #(#identifiers),* diff --git a/src/lib.rs b/src/lib.rs index 3e8d309e..e88a6e4b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,5 @@ #![doc = include_str!("../README.md")] -#![cfg_attr(not(test), no_std)] +// #![cfg_attr(not(test), no_std)] #![warn(missing_docs)] extern crate alloc; @@ -141,7 +141,7 @@ mod tests { impl crate::AsnType for CustomInt { const TAG: Tag = Tag::INTEGER; - const CONSTRAINTS: Constraints<'static> = + const CONSTRAINTS: Constraints = macros::constraints!(macros::value_constraint!(start: 127)); } diff --git a/src/per/enc.rs b/src/per/enc.rs index 9b544111..1a4724ec 100644 --- a/src/per/enc.rs +++ b/src/per/enc.rs @@ -1368,7 +1368,7 @@ mod tests { impl crate::AsnType for CustomInt { const TAG: Tag = Tag::INTEGER; - const CONSTRAINTS: Constraints<'static> = constraints!(value_constraint!(end: 65535)); + const CONSTRAINTS: Constraints = constraints!(value_constraint!(end: 65535)); } impl crate::Encode for CustomInt { diff --git a/src/types.rs b/src/types.rs index b967caf3..3d2a7696 100644 --- a/src/types.rs +++ b/src/types.rs @@ -64,7 +64,7 @@ pub trait AsnType { const TAG_TREE: TagTree = TagTree::Leaf(Self::TAG); /// The set of constraints for values of the given type. - const CONSTRAINTS: Constraints<'static> = Constraints::NONE; + const CONSTRAINTS: Constraints = Constraints::NONE; /// Identifier of an ASN.1 type as specified in the original specification /// if not identical with the identifier of `Self` @@ -83,7 +83,7 @@ pub trait Choice: Sized { /// Variants contained in the "root component list". const VARIANTS: &'static [TagTree]; /// Constraint for the choice type, based on the number of root components. Used for PER encoding. - const VARIANCE_CONSTRAINT: Constraints<'static>; + const VARIANCE_CONSTRAINT: Constraints; /// Variants contained in the list of extensions. const EXTENDED_VARIANTS: Option<&'static [TagTree]> = None; /// Variant identifiers for text-based encoding rules @@ -248,7 +248,7 @@ macro_rules! asn_integer_type { $( impl AsnType for $int { const TAG: Tag = Tag::INTEGER; - const CONSTRAINTS: Constraints<'static> = constraints!(value_constraint!((<$int>::MIN as i128), (<$int>::MAX as i128))); + const CONSTRAINTS: Constraints = constraints!(value_constraint!((<$int>::MIN as i128), (<$int>::MAX as i128))); } )+ } @@ -309,7 +309,7 @@ impl AsnType for SetOf { impl AsnType for [T; N] { const TAG: Tag = Tag::SEQUENCE; - const CONSTRAINTS: Constraints<'static> = constraints!(size_constraint!(N)); + const CONSTRAINTS: Constraints = constraints!(size_constraint!(N)); } impl AsnType for &'_ [T] { diff --git a/src/types/constraints.rs b/src/types/constraints.rs index bd9e0084..4fb0449a 100644 --- a/src/types/constraints.rs +++ b/src/types/constraints.rs @@ -4,42 +4,81 @@ use super::IntegerType; use num_bigint::BigInt; // TODO type can have multiple constraints of same kind, up to infinite -const SUPPORTED_CONSTRAINTS_COUNT: usize = 5; +// const SUPPORTED_CONSTRAINTS_COUNT: usize = 5; + +// ASN.1 has typically union and intersection constraints +// add union and intersection methods? +// Typically constraints must match all the constraints applied to them, so unless specified otherwise +// we should use intersection for these constraints. /// A set of constraints for a given type on what kinds of values are allowed. /// Used in certain codecs to optimise encoding and decoding values. +/// +/// The effective constraint is typically the intersection or union among other constraints. +/// As a result, we can store one constraint of each kind, updated with the latest constraint. +/// +/// TODO architecture needs a re-design - multple different-style value constraints are allowed +/// for example, value constraint can have multiple single values, or a range of values which do not overlap. #[derive(Debug, Clone)] -pub struct Constraints<'constraint>(pub &'constraint [Constraint]); +#[non_exhaustive] +pub struct Constraints { + value: Option>, + size: Option>, + permitted_alphabet: Option>, + extensible: bool, +} -impl<'constraint> Constraints<'constraint> { +impl<'constraint> Constraints { /// Empty constraints. - pub const NONE: Self = Self(&[]); + pub const NONE: Self = Self { + value: None, + size: None, + permitted_alphabet: None, + extensible: false, + }; /// Creates a new set of constraints from a given slice. pub const fn new(constraints: &'constraint [Constraint]) -> Self { - Self(constraints) - } - /// Returns the inner constraints. - pub const fn inner(&self) -> &'constraint [Constraint] { - self.0 - } - /// We currently only support 5 different constraint types, which includes the empty constraint. - /// `usize` is used to drop the empty ones, which are needed to initialize the array. - pub const fn from_fixed_size( - merged: &'constraint ([Constraint; SUPPORTED_CONSTRAINTS_COUNT], usize), - ) -> Self { - if merged.1 == 0 { - return Self::NONE; - } - struct ConstraintArray<'a, const N: usize>(&'a [Constraint; N]); - - impl<'a, const N: usize> ConstraintArray<'a, N> { - const fn as_slice(&self) -> &'a [Constraint] { - self.0 + let mut value: Option> = None; + let mut size: Option> = None; + let mut permitted_alphabet: Option> = None; + let mut extensible = false; + let mut i = 0; + while i < constraints.len() { + match constraints[i] { + Constraint::Value(v) => { + value = match value { + Some(value) => Some(value.intersect(&v)), + None => Some(v), + }; + } + Constraint::Size(s) => { + size = if let Some(size) = size { + Some(size.intersect(&s)) + } else { + Some(s) + }; + } + Constraint::PermittedAlphabet(p) => { + permitted_alphabet = if let Some(perm) = permitted_alphabet { + Some(perm.intersect(&p)) + } else { + Some(p) + }; + } + Constraint::Extensible => { + extensible = true; + } + Constraint::Empty => {} } + i += 1; + } + Self { + value, + size, + permitted_alphabet, + extensible, } - let array = ConstraintArray(&merged.0); - Self::new(array.as_slice()) } /// A const variant of the default function. @@ -49,94 +88,71 @@ impl<'constraint> Constraints<'constraint> { /// Merges a set of constraints with another set, if they don't exist. /// This function should be only used on compile-time. - #[inline(always)] - pub const fn merge(self, rhs: Self) -> ([Constraint; SUPPORTED_CONSTRAINTS_COUNT], usize) { - let rhs = rhs.0; - let mut array: [Constraint; SUPPORTED_CONSTRAINTS_COUNT] = - [Constraint::Empty; SUPPORTED_CONSTRAINTS_COUNT]; - - if rhs.len() > SUPPORTED_CONSTRAINTS_COUNT { - panic!("Overriding constraint is larger than we have different constraint types") - } - - // Copy rhs first to the array - let mut copy_index = 0; - while copy_index < rhs.len() { - array[copy_index] = rhs[copy_index]; - copy_index += 1; - } - let mut si = 0; - while si < self.0.len() { - let mut found = false; - let mut ri = 0; - while ri < rhs.len() { - if self.0[si].kind().eq(&rhs[ri].kind()) { - found = true; - break; - } - ri += 1; - } - - if !found { - if copy_index >= SUPPORTED_CONSTRAINTS_COUNT { - panic!("attempting to copy into greater index than we have different constraint types") - } - array[copy_index] = self.0[si]; - copy_index += 1; - } + pub const fn intersect(&self, rhs: Constraints) -> Self { + let value = match (self.value, rhs.value) { + (Some(value), Some(rhs_value)) => Some(value.intersect(&rhs_value)), + (Some(value), None) => Some(value), + (None, Some(rhs_value)) => Some(rhs_value), + (None, None) => None, + }; + let size = match (self.size, rhs.size) { + (Some(size), Some(rhs_size)) => Some(size.intersect(&rhs_size)), + (Some(size), None) => Some(size), + (None, Some(rhs_size)) => Some(rhs_size), + (None, None) => None, + }; + let permitted_alphabet = match (self.permitted_alphabet, rhs.permitted_alphabet) { + (Some(perm), Some(rhs_perm)) => Some(perm.intersect(&rhs_perm)), + (Some(perm), None) => Some(perm), + (None, Some(rhs_perm)) => Some(rhs_perm), + (None, None) => None, + }; + let extensible = self.extensible || rhs.extensible; - si += 1; + Self { + value, + size, + permitted_alphabet, + extensible, } - - (array, copy_index) } /// Returns the size constraint from the set, if available. pub const fn size(&self) -> Option<&Extensible> { - let mut i = 0; - while i < self.0.len() { - if let Some(size) = self.0[i].to_size() { - return Some(size); - } - i += 1; - } - None + self.size.as_ref() } /// Returns the permitted alphabet constraint from the set, if available. pub const fn permitted_alphabet(&self) -> Option<&Extensible> { - let mut i = 0; - while i < self.0.len() { - if let Some(alpha) = self.0[i].as_permitted_alphabet() { - return Some(alpha); - } - i += 1; - } - None + self.permitted_alphabet.as_ref() } /// Returns whether any of the constraints are extensible. pub const fn extensible(&self) -> bool { - let mut i = 0; - while i < self.0.len() { - if self.0[i].is_extensible() { + if self.extensible { + return true; + } + if let Some(value) = &self.value { + if value.extensible.is_some() { + return true; + } + } + if let Some(size) = &self.size { + if size.extensible.is_some() { + return true; + } + } + if let Some(permitted_alphabet) = &self.permitted_alphabet { + if permitted_alphabet.extensible.is_some() { return true; } - i += 1; } false } /// Returns the value constraint from the set, if available. pub const fn value(&self) -> Option<&Extensible> { - let mut i = 0; - while i < self.0.len() { - if let Some(value) = self.0[i].as_value() { - return Some(value); - } - i += 1; - } - None + self.value.as_ref() } } @@ -200,6 +216,29 @@ impl Constraint { Self::Empty => 4, } } + // pub const fn intersect(&self, other: &Self) -> Self { + // // TODO implement intersection of extensible constraints + // match (self, other) { + // (Self::Value(a), Self::Value(b)) => { + // let is_extensible = a.extensible.is_some() || b.extensible.is_some(); + // let a = a.constraint.intersect(&b.constraint); + // Self::Value(Extensible::new(a).set_extensible(is_extensible)) + // } + // (Self::Size(a), Self::Size(b)) => { + // let is_extensible = a.extensible.is_some() || b.extensible.is_some(); + // let a = a.constraint.intersect(&b.constraint); + // Self::Size(Extensible::new(a).set_extensible(is_extensible)) + // } + // (Self::PermittedAlphabet(a), Self::PermittedAlphabet(b)) => { + // let is_extensible = a.extensible.is_some() || b.extensible.is_some(); + // let a = a.constraint.intersect(&b.constraint); + // Self::PermittedAlphabet(Extensible::new(a).set_extensible(is_extensible)) + // } + // (Self::Extensible, Self::Extensible) => Self::Extensible, + // (Self::Empty, _) | (_, Self::Empty) => Self::Empty, + // _ => Self::Extensible, + // } + // } /// Returns the value constraint, if set. pub const fn as_value(&self) -> Option<&Extensible> { @@ -255,6 +294,7 @@ pub struct Extensible { pub constraint: T, /// Whether the constraint is extensible, and if it is, a list of extensible /// constraints. + /// Extensibility means that the allowed constraint values can change, not type of the constraint itself. pub extensible: Option<&'static [T]>, } @@ -298,6 +338,56 @@ impl Extensible { } } +impl Extensible { + /// Intersects two extensible value constraints. + pub const fn intersect(&self, other: &Self) -> Self { + let extensible = match (self.extensible, other.extensible) { + (Some(a), Some(_)) => Some(a), + (Some(a), None) => None, + (None, Some(b)) => None, + (None, None) => None, + }; + let constraint = self.constraint.intersect(&other.constraint); + match extensible { + Some(ext_ref) => Self::new_extensible(constraint, ext_ref), + None => Self::new(constraint), + } + } +} +impl Extensible { + /// Intersects two extensible size constraints. + pub const fn intersect(&self, other: &Self) -> Self { + let extensible = match (self.extensible, other.extensible) { + (Some(a), Some(_)) => Some(a), + (Some(_), None) => None, + (None, Some(_)) => None, + (None, None) => None, + }; + let constraint = self.constraint.intersect(&other.constraint); + match extensible { + Some(ext_ref) => Self::new_extensible(constraint, ext_ref), + None => Self::new(constraint), + } + } +} +impl Extensible { + /// Intersects two extensible permitted alphabet constraints. + pub const fn intersect(&self, other: &Self) -> Self { + // Extensiblity status might not be correct + let extensible = match (self.extensible, other.extensible) { + (Some(a), Some(_b)) => Some(a), + (Some(_), None) => None, + (None, Some(_)) => None, + (None, None) => None, + }; + let constraint = self.constraint.intersect(&other.constraint); + match extensible { + Some(ext_ref) => Self::new_extensible(constraint, ext_ref), + None => Self::new(constraint), + } + } +} + impl From for Extensible { fn from(value: Value) -> Self { Self { @@ -354,6 +444,16 @@ impl Value { pub const fn get_range(&self) -> Option { self.range } + /// Intersect between two `Value` constraints + pub const fn intersect(&self, other: &Self) -> Self { + let value = self.value.intersect(other.value); + let (signed, range) = value.range_in_bytes(); + Self { + value, + signed, + range, + } + } } impl core::ops::Deref for Value { @@ -430,6 +530,10 @@ impl Size { pub const fn is_range(&self) -> bool { matches!(self.0, Bounded::Range { .. }) } + #[must_use] + pub const fn intersect(&self, other: &Self) -> Self { + Self(self.0.intersect(other.0)) + } } impl core::ops::Deref for Size { @@ -460,6 +564,14 @@ impl PermittedAlphabet { pub const fn as_inner(&self) -> &'static [u32] { self.0 } + /// Intersect between two `PermittedAlphabet` constraints. + /// + /// TODO not currently possible to intersect + /// because new instance requires a static lifetime, + /// so we just override for now. + pub const fn intersect(&self, other: &Self) -> Self { + Self(other.0) + } } impl core::ops::Deref for PermittedAlphabet { @@ -553,6 +665,86 @@ impl Bounded { } } +impl Bounded { + /// Intersect the values of two bounded ranges. + pub const fn intersect(&self, other: Self) -> Self { + match (self, other) { + (Self::None, _) | (_, Self::None) => Self::None, + (Self::Single(a), Self::Single(b)) if *a == b => Self::Single(*a), + ( + Self::Single(a), + Self::Range { + start: Some(b), + end: Some(c), + }, + ) if *a >= b && *a <= c => Self::Single(*a), + ( + Self::Range { + start: Some(b), + end: Some(c), + }, + Self::Single(a), + ) if a >= *b && a <= *c => Self::Single(a), + ( + Self::Range { + start: Some(a), + end: Some(b), + }, + Self::Range { + start: Some(c), + end: Some(d), + }, + ) if *a <= d && *b >= c => Self::Range { + // usize is unsigned, so we can't have negative values + // usize always < i128::MAX + start: Some(max_signed(*a, c)), + end: Some(min(*b, d)), + }, + _ => Self::None, + } + } +} + +impl Bounded { + /// Intersect the values of two bounded ranges. + pub const fn intersect(&self, other: Self) -> Self { + match (self, other) { + (Self::None, _) | (_, Self::None) => Self::None, + (Self::Single(a), Self::Single(b)) if *a == b => Self::Single(*a), + ( + Self::Single(a), + Self::Range { + start: Some(b), + end: Some(c), + }, + ) if *a >= b && *a <= c => Self::Single(*a), + ( + Self::Range { + start: Some(b), + end: Some(c), + }, + Self::Single(a), + ) if a >= *b && a <= *c => Self::Single(a), + ( + Self::Range { + start: Some(a), + end: Some(b), + }, + Self::Range { + start: Some(c), + end: Some(d), + }, + ) if *a <= d && *b >= c => Self::Range { + // usize is unsigned, so we can't have negative values + // usize always < i128::MAX + start: Some(max_unsigned(*a as u128, c as u128) as usize), + end: Some(min(*b as i128, d as i128) as usize), + }, + _ => Self::None, + } + } +} + impl Bounded { /// Assuming T is an integer, returns the minimum possible bound, or zero /// if not present. @@ -659,11 +851,18 @@ impl From> for Constraint { Self::PermittedAlphabet(size) } } +const fn max_signed(a: i128, b: i128) -> i128 { + [a, b][(a < b) as usize] +} + +const fn max_unsigned(a: u128, b: u128) -> u128 { + [a, b][(a < b) as usize] +} +const fn min(a: i128, b: i128) -> i128 { + [a, b][(a > b) as usize] +} impl Bounded { - const fn max(&self, a: u128, b: u128) -> u128 { - [a, b][(a < b) as usize] - } /// Returns the sign and the range in bytes of the constraint. pub const fn range_in_bytes(&self) -> (bool, Option) { match self { @@ -675,8 +874,8 @@ impl Bounded { let is_signed = *start < 0; let end_abs = end.unsigned_abs(); let start_abs = start.unsigned_abs(); - let max = self.max(start_abs, end_abs); - let octets = Self::octet_size_by_range(max as i128); + let bound_max = max_unsigned(start_abs, end_abs); + let octets = Self::octet_size_by_range(bound_max as i128); (is_signed, octets) } Self::Range { @@ -817,10 +1016,8 @@ mod tests { .set_extensible(false), ); const LESS_INNER: Constraints = rasn::types::Constraints::new(&[INNER]); - dbg!(LESS_INNER); - dbg!(::CONSTRAINTS); - const MERGED: ([Constraint; SUPPORTED_CONSTRAINTS_COUNT], usize) = - ::CONSTRAINTS.merge(rasn::types::Constraints::new(&[ + const MERGED: Constraints = + ::CONSTRAINTS.intersect(Constraints::new(&[ rasn::types::Constraint::Size( rasn::types::constraints::Extensible::new(rasn::types::constraints::Size::new( rasn::types::constraints::Bounded::single_value(1i128 as usize), @@ -828,21 +1025,19 @@ mod tests { .set_extensible(false), ), ])); - dbg!(MERGED); - const FIELD_CONSTRAINT_0: rasn::types::Constraints = - rasn::types::Constraints::from_fixed_size( - &::CONSTRAINTS.merge(rasn::types::Constraints::new( - &[rasn::types::Constraint::Size( + // rasn::types::Constraints::from_fixed_size( + ::CONSTRAINTS.intersect(Constraints::new(&[ + rasn::types::Constraint::Size( rasn::types::constraints::Extensible::new( rasn::types::constraints::Size::new( rasn::types::constraints::Bounded::single_value(1i128 as usize), ), ) .set_extensible(false), - )], - )), - ); + ), + ])); + // ); dbg!(FIELD_CONSTRAINT_0); } // #[test] diff --git a/src/types/integer.rs b/src/types/integer.rs index 0beea5a6..5c85c082 100644 --- a/src/types/integer.rs +++ b/src/types/integer.rs @@ -355,7 +355,7 @@ pub struct ConstrainedInteger(pub(crate) Int impl AsnType for ConstrainedInteger { const TAG: Tag = Tag::INTEGER; - const CONSTRAINTS: Constraints<'static> = + const CONSTRAINTS: Constraints = Constraints::new(&[constraints::Constraint::Value(Extensible::new( constraints::Value::new(constraints::Bounded::const_new(START, END)), ))]); diff --git a/src/types/strings/octet.rs b/src/types/strings/octet.rs index b3c121a5..4ca7df54 100644 --- a/src/types/strings/octet.rs +++ b/src/types/strings/octet.rs @@ -66,7 +66,7 @@ impl core::ops::DerefMut for FixedOctetString { impl AsnType for FixedOctetString { const TAG: Tag = Tag::OCTET_STRING; - const CONSTRAINTS: Constraints<'static> = constraints!(size_constraint!(N)); + const CONSTRAINTS: Constraints = constraints!(size_constraint!(N)); } impl Decode for FixedOctetString { diff --git a/tests/generics.rs b/tests/generics.rs index 91eff18e..19832838 100644 --- a/tests/generics.rs +++ b/tests/generics.rs @@ -1,14 +1,13 @@ use rasn::prelude::*; +pub trait LeetTrait { + type Leet: Encode + Decode + core::fmt::Debug + Clone; + + fn leet(&self) -> Self::Leet; +} // https://github.com/librasn/rasn/issues/193 #[test] fn test_sequence_with_generics_issue_193() { - pub trait LeetTrait { - type Leet: Encode + Decode + core::fmt::Debug + Clone; - - fn leet(&self) -> Self::Leet; - } - #[derive(AsnType, Encode, Decode, Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] #[rasn(choice, automatic_tags)] pub enum Messages { @@ -39,4 +38,22 @@ fn test_sequence_with_generics_issue_193() { hello_selection, rasn::oer::decode::>(&encoded).unwrap() ) + + // #[derive(AsnType, Encode, Decode, Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] + // #[rasn(delegate, automatic_tags, size("1..", "-5"))] + // pub struct World(String); +} + +#[test] +fn test_sequence_with_generic_and_constraints() { + #[derive(AsnType, Debug, Encode, Decode, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] + #[rasn(automatic_tags)] + pub struct ConstrainedBlock + where + T: LeetTrait, + { + id: Integer, + #[rasn(size("1.."))] + extn: SequenceOf, + } } From 3260417fa08444548709958c30b6b8b421f27be2 Mon Sep 17 00:00:00 2001 From: Niklas Saari Date: Fri, 22 Nov 2024 03:43:25 +0200 Subject: [PATCH 18/22] OER: improve constraint use on decoding --- src/oer/de.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/oer/de.rs b/src/oer/de.rs index 10d2738d..5ffaeb29 100644 --- a/src/oer/de.rs +++ b/src/oer/de.rs @@ -270,12 +270,12 @@ impl<'input, const RFC: usize, const EFC: usize> Decoder<'input, RFC, EFC> { ) -> Result { // Only 'value' constraint is OER visible for integer if let Some(value) = constraints.value() { - let (sign, octets) = if value.extensible.is_some() { + let (signed, octets) = if value.extensible.is_some() { (true, None) } else { (value.constraint.get_sign(), value.constraint.get_range()) }; - let integer = self.decode_integer_from_bytes::(sign, octets.map(usize::from))?; + let integer = self.decode_integer_from_bytes::(signed, octets.map(usize::from))?; // if the value is too large for a i128, the constraint isn't satisfied if let Some(constraint_integer) = integer.to_i128() { if value.constraint.contains(&constraint_integer) { @@ -356,7 +356,7 @@ impl<'input, const RFC: usize, const EFC: usize> Decoder<'input, RFC, EFC> { fn parse_known_multiplier_string< T: crate::types::strings::StaticPermittedAlphabet + crate::types::AsnType - + TryFrom, Error = crate::error::strings::PermittedAlphabetError>, + + for<'a> TryFrom<&'a [u8], Error = crate::error::strings::PermittedAlphabetError>, >( &mut self, constraints: &Constraints, @@ -364,15 +364,13 @@ impl<'input, const RFC: usize, const EFC: usize> Decoder<'input, RFC, EFC> { if let Some(size) = constraints.size() { // Fixed size, only data is included if size.constraint.is_fixed() && size.extensible.is_none() { - let data = self - .extract_data_by_length(*size.constraint.as_start().unwrap()) - .map(|data| data.as_bytes().to_vec())?; - return T::try_from(data) + let data = self.extract_data_by_length(*size.constraint.as_start().unwrap())?; + return T::try_from(data.as_bytes()) .map_err(|e| DecodeError::permitted_alphabet_error(e, self.codec())); } } let length = self.decode_length()?; - T::try_from(self.extract_data_by_length(length)?.as_bytes().to_vec()) + T::try_from(self.extract_data_by_length(length)?.as_bytes()) .map_err(|e| DecodeError::permitted_alphabet_error(e, self.codec())) } From 213dbefc6f16bac6a9af262fe96d581b6f3b9005 Mon Sep 17 00:00:00 2001 From: Niklas Saari Date: Fri, 22 Nov 2024 06:17:21 +0200 Subject: [PATCH 19/22] Finish const (mostly) constraints --- macros/macros_impl/src/config.rs | 127 ++++---- macros/macros_impl/src/decode.rs | 18 +- macros/macros_impl/src/encode.rs | 47 +-- src/oer/enc.rs | 10 +- src/per/enc.rs | 17 +- src/types/constraints.rs | 497 ++++++++----------------------- 6 files changed, 216 insertions(+), 500 deletions(-) diff --git a/macros/macros_impl/src/config.rs b/macros/macros_impl/src/config.rs index 36d92f91..f30f92e2 100644 --- a/macros/macros_impl/src/config.rs +++ b/macros/macros_impl/src/config.rs @@ -1,7 +1,7 @@ use std::ops::Deref; use quote::ToTokens; -use syn::{parenthesized, LitStr, Path, Token, UnOp}; +use syn::{parenthesized, LitStr, Path, PathArguments, Token, Type, UnOp}; use crate::{ext::TypeExt, tag::Tag}; @@ -759,7 +759,6 @@ impl<'a> FieldConfig<'a> { pub fn encode(&self, context: usize, use_self: bool) -> proc_macro2::TokenStream { let this = use_self.then(|| quote!(self.)); let tag = self.tag(context); - let constraint_name = format_ident!("FIELD_CONSTRAINT_{}", context); let i = syn::Index::from(context); let field = self .field @@ -768,24 +767,42 @@ impl<'a> FieldConfig<'a> { .map(|name| quote!(#name)) .unwrap_or_else(|| quote!(#i)); let mut ty = self.field.ty.clone(); - // dbg!(&ty); + let has_generics = if let Type::Path(ty) = &ty { + ty.path + .segments + .last() + .map(|seg| !matches!(seg.arguments, PathArguments::None)) + .unwrap_or(false) + } else { + false + }; let crate_root = &self.container_config.crate_root; ty.strip_lifetimes(); let default_fn = self.default_fn(); + let constraint_name = format_ident!("FIELD_CONSTRAINT_{}", context); + let constraints = self + .constraints + .const_expr(&self.container_config.crate_root) + .unwrap_or_else(|| quote!(#crate_root::types::Constraints::default())); + let constraint_def = if has_generics { + quote! { + let #constraint_name: #crate_root::types::Constraints = <#ty as #crate_root::AsnType>::CONSTRAINTS.intersect(const {#constraints}); + } + } else { + quote! { + const #constraint_name : #crate_root::types::Constraints = <#ty as #crate_root::AsnType>::CONSTRAINTS.intersect( + #constraints + ); + } + }; let encode = if self.tag.is_some() || self.container_config.automatic_tags { if self.tag.as_ref().map_or(false, |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)?;) } else if self.extension_addition { - let constraints = self - .constraints - .const_expr(&self.container_config.crate_root) - .unwrap_or_else(|| quote!(#crate_root::types::Constraints::default())); quote!( - const #constraint_name : #crate_root::types::Constraints = <#ty as #crate_root::AsnType>::CONSTRAINTS.intersect( - #constraints - ); + #constraint_def encoder.encode_extension_addition( #tag, #constraint_name, @@ -795,16 +812,10 @@ impl<'a> FieldConfig<'a> { } else if self.extension_addition_group { quote!(encoder.encode_extension_addition_group(#this #field.as_ref())?;) } else { - let constraints = self - .constraints - .const_expr(&self.container_config.crate_root) - .unwrap_or_else(|| quote!(#crate_root::types::Constraints::default())); match (self.constraints.has_constraints(), self.default.is_some()) { (true, true) => { quote!( - const #constraint_name : #crate_root::types::Constraints =<#ty as #crate_root::AsnType>::CONSTRAINTS.intersect( - #constraints - ); + #constraint_def encoder.encode_default_with_tag_and_constraints( #tag, #constraint_name, @@ -815,9 +826,7 @@ impl<'a> FieldConfig<'a> { } (true, false) => { quote!( - const #constraint_name : #crate_root::types::Constraints =<#ty as #crate_root::AsnType>::CONSTRAINTS.intersect( - #constraints - ); + #constraint_def #this #field.encode_with_tag_and_constraints( encoder, #tag, @@ -833,14 +842,8 @@ impl<'a> FieldConfig<'a> { } } } else if self.extension_addition { - let constraints = self - .constraints - .const_expr(&self.container_config.crate_root) - .unwrap_or_else(|| quote!(#crate_root::types::Constraints::default())); quote!( - const #constraint_name : #crate_root::types::Constraints = <#ty as #crate_root::AsnType>::CONSTRAINTS.intersect( - #constraints - ); + #constraint_def encoder.encode_extension_addition( #tag, #constraint_name, @@ -852,13 +855,8 @@ impl<'a> FieldConfig<'a> { } else { match (self.constraints.has_constraints(), self.default.is_some()) { (true, true) => { - let constraints = self - .constraints - .const_expr(&self.container_config.crate_root); quote!( - const #constraint_name : #crate_root::types::Constraints = <#ty as #crate_root::AsnType>::CONSTRAINTS.intersect( - #constraints - ); + #constraint_def encoder.encode_default_with_constraints( #constraint_name, &#this #field, @@ -867,13 +865,8 @@ impl<'a> FieldConfig<'a> { ) } (true, false) => { - let constraints = self - .constraints - .const_expr(&self.container_config.crate_root); quote!( - const #constraint_name : #crate_root::types::Constraints = <#ty as #crate_root::AsnType>::CONSTRAINTS.intersect( - #constraints - ); + #constraint_def #this #field.encode_with_constraints( encoder, #constraint_name, @@ -913,8 +906,28 @@ impl<'a> FieldConfig<'a> { let default_fn = self.default_fn(); let tag = self.tag(context); + let has_generics = if let Type::Path(ty) = &ty { + ty.path + .segments + .last() + .map(|seg| !matches!(seg.arguments, PathArguments::None)) + .unwrap_or(false) + } else { + false + }; let constraint_name = format_ident!("CONSTRAINT_{}", context); let constraints = self.constraints.const_expr(crate_root); + let constraint_def = if has_generics { + quote! { + let #constraint_name: #crate_root::types::Constraints = <#ty as #crate_root::AsnType>::CONSTRAINTS.intersect(const {#constraints}); + } + } else { + quote! { + const #constraint_name : #crate_root::types::Constraints = <#ty as #crate_root::AsnType>::CONSTRAINTS.intersect( + #constraints + ); + } + }; let handle_extension = if self.is_not_option_or_default_type() { quote!(.ok_or_else(|| { #crate_root::de::Error::field_error(#ident, #crate_root::error::DecodeError::required_extension_not_present(#tag, decoder.codec()), decoder.codec())})?) @@ -952,9 +965,7 @@ impl<'a> FieldConfig<'a> { } (Some(false), Some(path), true) => { quote!({ - const #constraint_name : #crate_root::types::Constraints = <#ty as #crate_root::AsnType>::CONSTRAINTS.intersect( - #constraints - ); + #constraint_def decoder.decode_default_with_tag_and_constraints( #tag, #path, @@ -967,9 +978,7 @@ impl<'a> FieldConfig<'a> { } (Some(false), None, true) => { quote!({ - const #constraint_name : #crate_root::types::Constraints = <#ty as #crate_root::AsnType>::CONSTRAINTS.intersect( - #constraints - ); + #constraint_def <_>::decode_with_tag_and_constraints( decoder, #tag, @@ -982,9 +991,7 @@ impl<'a> FieldConfig<'a> { } (None, Some(path), true) => { quote!({ - const #constraint_name : #crate_root::types::Constraints = <#ty as #crate_root::AsnType>::CONSTRAINTS.intersect( - #constraints - ); + #constraint_def decoder.decode_default_with_constraints( #path, #constraint_name, @@ -996,9 +1003,7 @@ impl<'a> FieldConfig<'a> { } (None, None, true) => { quote!({ - const #constraint_name : #crate_root::types::Constraints = <#ty as #crate_root::AsnType>::CONSTRAINTS.intersect( - #constraints - ); + #constraint_def <_>::decode_with_constraints( decoder, #constraint_name, @@ -1034,9 +1039,7 @@ impl<'a> FieldConfig<'a> { if constraints { { quote!( - const #constraint_name : #crate_root::types::Constraints = <#ty as #crate_root::AsnType>::CONSTRAINTS.intersect( - #constraints - ); + #constraint_def decoder.decode_extension_addition_with_explicit_tag_and_constraints( #tag, #constraint_name @@ -1050,9 +1053,7 @@ impl<'a> FieldConfig<'a> { } (Some(false), Some(path), true) => { quote!( - const #constraint_name : #crate_root::types::Constraints = <#ty as #crate_root::AsnType>::CONSTRAINTS.intersect( - #constraints - ); + #constraint_def decoder.decode_extension_addition_with_default_and_tag_and_constraints( #tag, #path, @@ -1063,9 +1064,7 @@ impl<'a> FieldConfig<'a> { (Some(false), None, true) => { quote!( { - const #constraint_name : #crate_root::types::Constraints = <#ty as #crate_root::AsnType>::CONSTRAINTS.intersect( - #constraints - ); + #constraint_def <_>::decode_extension_addition_with_tag_and_constraints( decoder, #tag, @@ -1083,9 +1082,7 @@ impl<'a> FieldConfig<'a> { (None, Some(path), true) => { quote!( { - const #constraint_name : #crate_root::types::Constraints = <#ty as #crate_root::AsnType>::CONSTRAINTS.intersect( - #constraints - ); + #constraint_def decoder.decode_extension_addition_with_default_and_constraints( #path, #constraint_name, @@ -1101,9 +1098,7 @@ impl<'a> FieldConfig<'a> { } (None, None, true) => { quote!({ - const #constraint_name : #crate_root::types::Constraints = <#ty as #crate_root::AsnType>::CONSTRAINTS.intersect( - #constraints - ); + #constraint_def decoder.decode_extension_addition_with_constraints( #constraint_name, ) #or_else } diff --git a/macros/macros_impl/src/decode.rs b/macros/macros_impl/src/decode.rs index d913de46..2d76a27c 100644 --- a/macros/macros_impl/src/decode.rs +++ b/macros/macros_impl/src/decode.rs @@ -27,15 +27,22 @@ pub fn derive_struct_impl( decoder.decode_explicit_prefix::<#ty>(tag).map(Self) } } else { - let constraint_name = format_ident!("DELEGATE_DECODE_CONSTRAINT"); let constraints = config .constraints .const_expr(crate_root) .unwrap_or_else(|| quote!(#crate_root::types::Constraints::default())); + let constraint_name = format_ident!("DELEGATE_DECODE_CONSTRAINT"); + let constraint_def = if generics.params.is_empty() { + quote! { + let #constraint_name: #crate_root::types::Constraints = const {<#ty as #crate_root::AsnType>::CONSTRAINTS.intersect(#constraints)}.intersect(constraints); + } + } else { + quote! { + let #constraint_name: #crate_root::types::Constraints = <#ty as #crate_root::AsnType>::CONSTRAINTS.intersect(constraints).intersect(const {#constraints }); + } + }; quote! { - const #constraint_name : #crate_root::types::Constraints = <#ty as #crate_root::AsnType>::CONSTRAINTS; - let CONSTRAINTS: #crate_root::types::Constraints = #constraint_name.intersect(constraints); - // let constraints : #crate_root::types::Constraints = #crate_root::types::Constraints::from_fixed_size(&merged); + #constraint_def match tag { #crate_root::types::Tag::EOC => { Ok(Self(<#ty>::decode(decoder)?)) @@ -44,8 +51,7 @@ pub fn derive_struct_impl( <#ty as #crate_root::Decode>::decode_with_tag_and_constraints( decoder, tag, - // constraints - CONSTRAINTS + #constraint_name ).map(Self) } } diff --git a/macros/macros_impl/src/encode.rs b/macros/macros_impl/src/encode.rs index 2cbbfc30..751ac6ac 100644 --- a/macros/macros_impl/src/encode.rs +++ b/macros/macros_impl/src/encode.rs @@ -39,34 +39,18 @@ pub fn derive_struct_impl( // 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.0).map(drop)) } else { - // let constraint_name = format_ident!("ENCODE_DELEGATE_CONSTRAINTS"); - // let constraints = config - // .constraints - // .const_expr(crate_root) - // .unwrap_or_else(|| quote!(#crate_root::types::Constraints::default())); - // print!("{:?}", config.identifier); - // print!("{:?}", config); - // println!("{}", quote!(#constraints)); + let constraint_name = quote::format_ident!("effective_constraint"); + let constraint_def = if generics.params.is_empty() { + quote! { + let #constraint_name: #crate_root::types::Constraints = const {<#ty as #crate_root::AsnType>::CONSTRAINTS}.intersect(constraints); + } + } else { + quote! { + let #constraint_name: #crate_root::types::Constraints = <#ty as #crate_root::AsnType>::CONSTRAINTS.intersect(constraints); + } + }; quote!( - // const #constraint_name : #crate_root::types::Constraints = #crate_root::types::Constraints::from_fixed_size(&<#ty as #crate_root::AsnType>::CONSTRAINTS.merge( - // #constraints - // )); - // let (data, test) = <#ty as #crate_root::AsnType>::CONSTRAINTS.merge( - // constraints - // ); - let merged = <#ty as #crate_root::AsnType>::CONSTRAINTS.intersect( - constraints - ); - // dbg!(&data[..test]); - // dbg!(&test); - // let constraint : #crate_root::types::Constraints = #crate_root::types::Constraints::new(&data[..test]); - // dbg!(&constraint); - // let merged = <#ty as #crate_root::AsnType>::CONSTRAINTS.merge(constraint); - // let merged_constraints : #crate_root::types::Constraints = #crate_root::types::Constraints::from_fixed_size(&merged); - // dbg!(constraintts); - // dbg!(#constraint_name); - // dbg!(&constraints); - // dbg!(<#ty as #crate_root::AsnType>::CONSTRAINTS); + #constraint_def match tag { #crate_root::types::Tag::EOC => { self.0.encode(encoder) @@ -76,14 +60,7 @@ pub fn derive_struct_impl( &self.0, encoder, tag, - // data, - // constraints - // Correct but misses override.. - // #constraint_name - merged - // merged_constraints - // Empty - // <#ty as #crate_root::AsnType>::CONSTRAINTS, + #constraint_name ) } } diff --git a/src/oer/enc.rs b/src/oer/enc.rs index 4e07ad1b..a0c1feaa 100644 --- a/src/oer/enc.rs +++ b/src/oer/enc.rs @@ -365,7 +365,7 @@ impl<'a, const RCL: usize, const ECL: usize> Encoder<'a, RCL, ECL> { self.codec(), )); } - let (sign, octets) = if value.extensible.is_some() { + let (signed, octets) = if value.extensible.is_some() { (true, None) } else { (value.constraint.get_sign(), value.constraint.get_range()) @@ -374,10 +374,10 @@ impl<'a, const RCL: usize, const ECL: usize> Encoder<'a, RCL, ECL> { self.encode_constrained_integer_with_padding( usize::from(octets), value_to_enc, - sign, + signed, )?; } else { - self.encode_unconstrained_integer(value_to_enc, sign)?; + self.encode_unconstrained_integer(value_to_enc, signed)?; } } else { self.encode_unconstrained_integer(value_to_enc, true)?; @@ -455,8 +455,8 @@ impl<'a, const RCL: usize, const ECL: usize> Encoder<'a, RCL, ECL> { } } // Prior checks before encoding with length determinant - let max_permitted_length = usize::MAX / 8; // In compile time, no performance penalty? - if length > max_permitted_length { + const MAX_PERMITTED_LENGTH: usize = usize::MAX / 8; + if length > MAX_PERMITTED_LENGTH { return Err(EncodeError::length_exceeds_platform_size(self.codec())); } Ok(false) diff --git a/src/per/enc.rs b/src/per/enc.rs index 1a4724ec..05d2dff6 100644 --- a/src/per/enc.rs +++ b/src/per/enc.rs @@ -664,15 +664,14 @@ impl Encoder { )); } - let effective_range = - value_range - .constraint - .effective_integer_value(value.to_i128().ok_or_else(|| { - Error::integer_type_conversion_failed( - "Value too large for i128 type - outside of type constraint".to_string(), - self.codec(), - ) - })?); + let effective_range = value_range + .constraint + .effective_value(value.to_i128().ok_or_else(|| { + Error::integer_type_conversion_failed( + "Value too large for i128 type - outside of type constraint".to_string(), + self.codec(), + ) + })?); let unsigned_ref; let signed_ref; let needed: usize; diff --git a/src/types/constraints.rs b/src/types/constraints.rs index 4fb0449a..d2979993 100644 --- a/src/types/constraints.rs +++ b/src/types/constraints.rs @@ -3,14 +3,6 @@ use super::IntegerType; use num_bigint::BigInt; -// TODO type can have multiple constraints of same kind, up to infinite -// const SUPPORTED_CONSTRAINTS_COUNT: usize = 5; - -// ASN.1 has typically union and intersection constraints -// add union and intersection methods? -// Typically constraints must match all the constraints applied to them, so unless specified otherwise -// we should use intersection for these constraints. - /// A set of constraints for a given type on what kinds of values are allowed. /// Used in certain codecs to optimise encoding and decoding values. /// @@ -18,8 +10,10 @@ use num_bigint::BigInt; /// As a result, we can store one constraint of each kind, updated with the latest constraint. /// /// TODO architecture needs a re-design - multple different-style value constraints are allowed -/// for example, value constraint can have multiple single values, or a range of values which do not overlap. -#[derive(Debug, Clone)] +/// for example, value constraint can have multiple single values, or a range of values which do not overlap, and are effective at the same time. +/// This is challenging to implement in compile-time, and we may need to use runtime checks. +/// E.g effective constraint can have up to infinite single value constraints, and overal constraint value is not continuous. +#[derive(Debug, Copy, Clone)] #[non_exhaustive] pub struct Constraints { value: Option>, @@ -69,7 +63,6 @@ impl<'constraint> Constraints { Constraint::Extensible => { extensible = true; } - Constraint::Empty => {} } i += 1; } @@ -86,8 +79,7 @@ impl<'constraint> Constraints { Self::NONE } - /// Merges a set of constraints with another set, if they don't exist. - /// This function should be only used on compile-time. + /// Creates an intersection of two constraint sets. pub const fn intersect(&self, rhs: Constraints) -> Self { let value = match (self.value, rhs.value) { (Some(value), Some(rhs_value)) => Some(value.intersect(&rhs_value)), @@ -117,12 +109,12 @@ impl<'constraint> Constraints { } } - /// Returns the size constraint from the set, if available. + /// Returns the effective size constraint, if available. pub const fn size(&self) -> Option<&Extensible> { self.size.as_ref() } - /// Returns the permitted alphabet constraint from the set, if available. + /// Returns the effective permitted alphabet constraint, if available. pub const fn permitted_alphabet(&self) -> Option<&Extensible> { self.permitted_alphabet.as_ref() } @@ -170,8 +162,6 @@ pub enum Constraint { /// The value itself is extensible, only valid for constructed types, /// choices, or enumerated values. Extensible, - /// Empty constraint. - Empty, } /// The discriminant of [Constraint] values. @@ -182,7 +172,6 @@ pub enum ConstraintDiscriminant { Size, PermittedAlphabet, Extensible, - Empty, } impl ConstraintDiscriminant { /// Constant equality check. @@ -199,13 +188,8 @@ impl Constraint { Self::Size(_) => ConstraintDiscriminant::Size, Self::PermittedAlphabet(_) => ConstraintDiscriminant::PermittedAlphabet, Self::Extensible => ConstraintDiscriminant::Extensible, - Self::Empty => ConstraintDiscriminant::Empty, } } - /// Returns the default constraint, which is an empty constraint. - pub const fn default() -> Self { - Self::Empty - } /// Returns the discriminant as an `isize` integer. pub const fn variant_as_isize(&self) -> isize { match self { @@ -213,32 +197,8 @@ impl Constraint { Self::Size(_) => 1, Self::PermittedAlphabet(_) => 2, Self::Extensible => 3, - Self::Empty => 4, } } - // pub const fn intersect(&self, other: &Self) -> Self { - // // TODO implement intersection of extensible constraints - // match (self, other) { - // (Self::Value(a), Self::Value(b)) => { - // let is_extensible = a.extensible.is_some() || b.extensible.is_some(); - // let a = a.constraint.intersect(&b.constraint); - // Self::Value(Extensible::new(a).set_extensible(is_extensible)) - // } - // (Self::Size(a), Self::Size(b)) => { - // let is_extensible = a.extensible.is_some() || b.extensible.is_some(); - // let a = a.constraint.intersect(&b.constraint); - // Self::Size(Extensible::new(a).set_extensible(is_extensible)) - // } - // (Self::PermittedAlphabet(a), Self::PermittedAlphabet(b)) => { - // let is_extensible = a.extensible.is_some() || b.extensible.is_some(); - // let a = a.constraint.intersect(&b.constraint); - // Self::PermittedAlphabet(Extensible::new(a).set_extensible(is_extensible)) - // } - // (Self::Extensible, Self::Extensible) => Self::Extensible, - // (Self::Empty, _) | (_, Self::Empty) => Self::Empty, - // _ => Self::Extensible, - // } - // } /// Returns the value constraint, if set. pub const fn as_value(&self) -> Option<&Extensible> { @@ -279,7 +239,6 @@ impl Constraint { Self::Size(size) => size.extensible.is_some(), Self::PermittedAlphabet(alphabet) => alphabet.extensible.is_some(), Self::Extensible => true, - Self::Empty => false, } } } @@ -338,82 +297,40 @@ impl Extensible { } } -impl Extensible { - /// Intersects two extensible value constraints. - pub const fn intersect(&self, other: &Self) -> Self { - let extensible = match (self.extensible, other.extensible) { - (Some(a), Some(_)) => Some(a), - (Some(a), None) => None, - (None, Some(b)) => None, - (None, None) => None, - }; - let constraint = self.constraint.intersect(&other.constraint); - match extensible { - Some(ext_ref) => Self::new_extensible(constraint, ext_ref), - None => Self::new(constraint), - } - } -} -impl Extensible { - /// Intersects two extensible size constraints. - pub const fn intersect(&self, other: &Self) -> Self { - let extensible = match (self.extensible, other.extensible) { - (Some(a), Some(_)) => Some(a), - (Some(_), None) => None, - (None, Some(_)) => None, - (None, None) => None, - }; - let constraint = self.constraint.intersect(&other.constraint); - match extensible { - Some(ext_ref) => Self::new_extensible(constraint, ext_ref), - None => Self::new(constraint), - } - } -} -impl Extensible { - /// Intersects two extensible permitted alphabet constraints. - pub const fn intersect(&self, other: &Self) -> Self { - // Extensiblity status might not be correct - let extensible = match (self.extensible, other.extensible) { - (Some(a), Some(_b)) => Some(a), - (Some(_), None) => None, - (None, Some(_)) => None, - (None, None) => None, - }; - let constraint = self.constraint.intersect(&other.constraint); - match extensible { - Some(ext_ref) => Self::new_extensible(constraint, ext_ref), - None => Self::new(constraint), - } - } -} - -impl From for Extensible { - fn from(value: Value) -> Self { - Self { - constraint: value, - extensible: None, - } - } -} - -impl From for Extensible { - fn from(size: Size) -> Self { - Self { - constraint: size, - extensible: None, - } - } -} - -impl From for Extensible { - fn from(alphabet: PermittedAlphabet) -> Self { - Self { - constraint: alphabet, - extensible: None, - } - } +macro_rules! impl_extensible { + ($($type:ty),+) => { + $( + impl Extensible<$type> { + /// Intersects two extensible constraints. + pub const fn intersect(&self, other: &Self) -> Self { + // All lost in our use case? https://stackoverflow.com/questions/33524834/whats-the-result-set-operation-of-extensible-constraints-in-asn-1 + // ASN.1 treats serially applied constraints differently from nested extensible constraints? + // We currently support only serially applied constraints. + let extensible = match (self.extensible, other.extensible) { + (Some(a), Some(_)) => Some(a), + (Some(_), None) => None, + (None, Some(_)) => None, + (None, None) => None, + }; + let constraint = self.constraint.intersect(&other.constraint); + match extensible { + Some(ext_ref) => Self::new_extensible(constraint, ext_ref), + None => Self::new(constraint), + } + } + } + impl From<$type> for Extensible<$type> { + fn from(value: $type) -> Self { + Self { + constraint: value, + extensible: None, + } + } + } + )+ + }; } +impl_extensible!(Value, Size, PermittedAlphabet); /// A single or range of numeric values a type can be. #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -530,6 +447,7 @@ impl Size { pub const fn is_range(&self) -> bool { matches!(self.0, Bounded::Range { .. }) } + /// Intersect between two `Size` constraints #[must_use] pub const fn intersect(&self, other: &Self) -> Self { Self(self.0.intersect(other.0)) @@ -603,18 +521,13 @@ impl Bounded { /// Calculates the the amount of bytes that are required to represent integer `value`. /// Particularly useful for OER codec const fn octet_size_by_range(value: i128) -> Option { - let abs_value = value.unsigned_abs(); - Some(if abs_value <= u8::MAX as u128 { - 1 - } else if abs_value <= u16::MAX as u128 { - 2 - } else if abs_value <= u32::MAX as u128 { - 4 - } else if abs_value <= u64::MAX as u128 { - 8 - } else { - return None; - }) + match value.unsigned_abs() { + x if x <= u8::MAX as u128 => Some(1), + x if x <= u16::MAX as u128 => Some(2), + x if x <= u32::MAX as u128 => Some(4), + x if x <= u64::MAX as u128 => Some(8), + _ => None, + } } /// Creates a bounded range that starts from value and has no end. pub const fn start_from(value: T) -> Self { @@ -665,86 +578,6 @@ impl Bounded { } } -impl Bounded { - /// Intersect the values of two bounded ranges. - pub const fn intersect(&self, other: Self) -> Self { - match (self, other) { - (Self::None, _) | (_, Self::None) => Self::None, - (Self::Single(a), Self::Single(b)) if *a == b => Self::Single(*a), - ( - Self::Single(a), - Self::Range { - start: Some(b), - end: Some(c), - }, - ) if *a >= b && *a <= c => Self::Single(*a), - ( - Self::Range { - start: Some(b), - end: Some(c), - }, - Self::Single(a), - ) if a >= *b && a <= *c => Self::Single(a), - ( - Self::Range { - start: Some(a), - end: Some(b), - }, - Self::Range { - start: Some(c), - end: Some(d), - }, - ) if *a <= d && *b >= c => Self::Range { - // usize is unsigned, so we can't have negative values - // usize always < i128::MAX - start: Some(max_signed(*a, c)), - end: Some(min(*b, d)), - }, - _ => Self::None, - } - } -} - -impl Bounded { - /// Intersect the values of two bounded ranges. - pub const fn intersect(&self, other: Self) -> Self { - match (self, other) { - (Self::None, _) | (_, Self::None) => Self::None, - (Self::Single(a), Self::Single(b)) if *a == b => Self::Single(*a), - ( - Self::Single(a), - Self::Range { - start: Some(b), - end: Some(c), - }, - ) if *a >= b && *a <= c => Self::Single(*a), - ( - Self::Range { - start: Some(b), - end: Some(c), - }, - Self::Single(a), - ) if a >= *b && a <= *c => Self::Single(a), - ( - Self::Range { - start: Some(a), - end: Some(b), - }, - Self::Range { - start: Some(c), - end: Some(d), - }, - ) if *a <= d && *b >= c => Self::Range { - // usize is unsigned, so we can't have negative values - // usize always < i128::MAX - start: Some(max_unsigned(*a as u128, c as u128) as usize), - end: Some(min(*b as i128, d as i128) as usize), - }, - _ => Self::None, - } - } -} - impl Bounded { /// Assuming T is an integer, returns the minimum possible bound, or zero /// if not present. @@ -756,65 +589,76 @@ impl Bounded { } } -impl + num_traits::SaturatingAdd + From> - Bounded -{ - /// Returns the number representing the difference between the lower and upper bound. - pub fn range(&self) -> Option { - match self { - Self::Single(_) => Some(T::from(1u8)), - Self::Range { - start: Some(start), - end: Some(end), - } => Some(end.wrapping_sub(start).saturating_add(&1.into())), - _ => None, - } - } -} - -impl + core::fmt::Debug + Default + core::cmp::PartialOrd> Bounded -where - for<'a> &'a T: core::ops::Sub, -{ - /// Returns the effective value which is either the number, or the positive - /// offset of that number from the start of the value range. `Either::Left` - /// represents the positive offset, and `Either::Right` represents - /// the number. - pub fn effective_value(&self, value: T) -> either::Either { - match self { - Self::Range { - start: Some(start), .. - } => { - debug_assert!(&value >= start); - either::Left(&value - start) +macro_rules! impl_bounded_range { + ($($type:ty),+) => { + $( + impl Bounded<$type> { + /// Returns the number representing the difference between the lower and upper bound. + pub const fn range(&self) -> Option<$type> { + match self { + Self::Single(_) => Some(1), + Self::Range { + start: Some(start), + end: Some(end), + } => Some(end.wrapping_sub(*start).saturating_add(1)), + _ => None, + } + } + /// Returns the effective value which is either the number, or the positive + /// offset of that number from the start of the value range. `Either::Left` + /// represents the positive offset, and `Either::Right` represents + /// the number. + pub const fn effective_value(&self, value: $type) -> either::Either<$type, $type> { + match self { + Self::Range { + start: Some(start), .. + } => { + debug_assert!(value >= *start); + either::Left(value - *start) + } + _ => either::Right(value), + } + } + /// Intersect the values of two bounded ranges. + pub const fn intersect(&self, other: Self) -> Self { + match (self, other) { + (Self::None, _) | (_, Self::None) => Self::None, + (Self::Single(a), Self::Single(b)) if *a == b => Self::Single(*a), + ( + Self::Single(a), + Self::Range { + start: Some(b), + end: Some(c), + }, + ) if *a >= b && *a <= c => Self::Single(*a), + ( + Self::Range { + start: Some(b), + end: Some(c), + }, + Self::Single(a), + ) if a >= *b && a <= *c => Self::Single(a), + ( + Self::Range { + start: Some(a), + end: Some(b), + }, + Self::Range { + start: Some(c), + end: Some(d), + }, + ) if *a <= d && *b >= c => Self::Range { + start: Some(max(*a as i128, c as i128) as $type), + end: Some(min(*b as i128, d as i128) as $type), + }, + _ => Self::None, + } + } } - _ => either::Right(value), - } - } -} - -impl Bounded -where - T: core::ops::Sub + core::fmt::Debug + Default + PartialOrd, -{ - /// The same as [`Self::effective_value`] except using [`crate::types::Integer`]. - pub fn effective_integer_value(self, value: I) -> either::Either - where - I: IntegerType + core::ops::Sub, - I: From + PartialOrd, - { - if let Bounded::Range { - start: Some(start), .. - } = self - { - let start = I::from(start); - debug_assert!(value >= start); - either::Left(value - start) - } else { - either::Right(value) - } - } + )+ + }; } +impl_bounded_range!(i128, usize); impl From for Constraint { fn from(size: Value) -> Self { @@ -851,7 +695,7 @@ impl From> for Constraint { Self::PermittedAlphabet(size) } } -const fn max_signed(a: i128, b: i128) -> i128 { +const fn max(a: i128, b: i128) -> i128 { [a, b][(a < b) as usize] } @@ -989,115 +833,10 @@ impl core::fmt::Display for Bounded { #[cfg(test)] mod tests { use super::*; - use crate as rasn; - use crate::prelude::*; #[test] fn range() { - let constraints = Bounded::new(0, 255); + let constraints = Bounded::new(0, 255usize); assert_eq!(256, constraints.range().unwrap()); } - #[test] - fn test_merge_constraints() { - #[derive(AsnType, Decode, Debug, PartialEq)] - #[rasn(delegate, from("a..=z", "A..=Z", "-", "."), size("1..=64"))] - pub struct NameString(pub VisibleString); - - #[derive(AsnType, Decode, Debug, PartialEq)] - #[rasn(tag(application, 1))] - pub struct InitialString { - #[rasn(size(1))] - pub initial: NameString, - } - const INNER: Constraint = rasn::types::Constraint::Size( - rasn::types::constraints::Extensible::new(rasn::types::constraints::Size::new( - rasn::types::constraints::Bounded::single_value(1i128 as usize), - )) - .set_extensible(false), - ); - const LESS_INNER: Constraints = rasn::types::Constraints::new(&[INNER]); - const MERGED: Constraints = - ::CONSTRAINTS.intersect(Constraints::new(&[ - rasn::types::Constraint::Size( - rasn::types::constraints::Extensible::new(rasn::types::constraints::Size::new( - rasn::types::constraints::Bounded::single_value(1i128 as usize), - )) - .set_extensible(false), - ), - ])); - const FIELD_CONSTRAINT_0: rasn::types::Constraints = - // rasn::types::Constraints::from_fixed_size( - ::CONSTRAINTS.intersect(Constraints::new(&[ - rasn::types::Constraint::Size( - rasn::types::constraints::Extensible::new( - rasn::types::constraints::Size::new( - rasn::types::constraints::Bounded::single_value(1i128 as usize), - ), - ) - .set_extensible(false), - ), - ])); - // ); - dbg!(FIELD_CONSTRAINT_0); - } - // #[test] - // fn test_nested_extensible() { - // #[derive(AsnType, Encode, Decode, Debug, PartialEq)] - // #[rasn(tag(application, 2), delegate, value("0..=9999", extensible))] - // pub struct ExtensibleEmployeeNumber(pub Integer); - - // #[derive(AsnType, Decode, Encode, Debug, PartialEq)] - // #[rasn( - // tag(application, 3), - // delegate, - // from("0..=9"), - // size(8, extensible, "9..=20") - // )] - // pub struct ExtensibleDate(pub VisibleString); - - // #[derive(AsnType, Decode, Encode, Debug, PartialEq)] - // #[rasn(delegate, from("a..=z", "A..=Z", "-", "."), size("1..=64", extensible))] - // pub struct ExtensibleNameString(pub VisibleString); - - // #[derive(AsnType, Decode, Encode, Debug, PartialEq)] - // #[rasn(tag(application, 1))] - // #[non_exhaustive] - // pub struct ExtensibleName { - // pub given_name: ExtensibleNameString, - // #[rasn(size(1))] - // pub initial: ExtensibleNameString, - // pub family_name: ExtensibleNameString, - // } - // #[derive(AsnType, Decode, Encode, Debug, PartialEq)] - // #[rasn(set)] - // #[non_exhaustive] - // pub struct ExtensibleChildInformation { - // name: ExtensibleName, - // #[rasn(tag(explicit(0)))] - // date_of_birth: ExtensibleDate, - // } - - // #[derive(AsnType, Encode, Decode, Debug, PartialEq)] - // #[rasn(set, tag(application, 0))] - // #[non_exhaustive] - // pub struct ExtensiblePersonnelRecord { - // pub name: ExtensibleName, - // #[rasn(tag(explicit(0)))] - // pub title: VisibleString, - // pub number: ExtensibleEmployeeNumber, - // #[rasn(tag(explicit(1)))] - // pub date_of_hire: ExtensibleDate, - // #[rasn(tag(explicit(2)))] - // pub name_of_spouse: ExtensibleName, - // #[rasn(tag(3), default, size(2, extensible))] - // pub children: Option>, - // } - // #[derive(AsnType, Decode, Encode, Debug, PartialEq)] - // #[rasn(set)] - // #[non_exhaustive] - // pub struct ExtensibleTest { - // name: ExtensibleName, - // #[rasn(tag(1), size(1, extensible))] - // record: ExtensiblePersonnelRecord, - // } } From a6156d23c5e03a5c9a8d54b548179da75e489475 Mon Sep 17 00:00:00 2001 From: Niklas Saari Date: Fri, 22 Nov 2024 08:33:23 +0200 Subject: [PATCH 20/22] Improved generic detection, cleanup --- Cargo.toml | 8 +--- macros/macros_impl/src/config.rs | 68 +++++++++++++++++++++----------- macros/macros_impl/src/decode.rs | 13 +++++- macros/macros_impl/src/encode.rs | 13 +++++- src/lib.rs | 2 +- tests/generics.rs | 21 ++++++++-- 6 files changed, 88 insertions(+), 37 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 700086bf..e359ebee 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,12 +32,6 @@ std = [] backtraces = ["std", "snafu/backtrace"] compiler = ["rasn-compiler"] -[profile.dev] -# debug = 0 - -[profile.bench] -debug = true - [profile.bench-lto] inherits = "bench" opt-level = 3 @@ -62,7 +56,7 @@ bench = false [[bench]] name = "criterion_integer" -path = "benches/integer_basic.rs" +path = "benches/integer.rs" harness = false test = true diff --git a/macros/macros_impl/src/config.rs b/macros/macros_impl/src/config.rs index f30f92e2..644cf551 100644 --- a/macros/macros_impl/src/config.rs +++ b/macros/macros_impl/src/config.rs @@ -1,7 +1,7 @@ use std::ops::Deref; use quote::ToTokens; -use syn::{parenthesized, LitStr, Path, PathArguments, Token, Type, UnOp}; +use syn::{parenthesized, Ident, LitStr, Path, Token, Type, UnOp}; use crate::{ext::TypeExt, tag::Tag}; @@ -756,7 +756,12 @@ impl<'a> FieldConfig<'a> { } } - pub fn encode(&self, context: usize, use_self: bool) -> proc_macro2::TokenStream { + pub fn encode( + &self, + context: usize, + use_self: bool, + type_params: &[Ident], + ) -> proc_macro2::TokenStream { let this = use_self.then(|| quote!(self.)); let tag = self.tag(context); let i = syn::Index::from(context); @@ -767,18 +772,22 @@ impl<'a> FieldConfig<'a> { .map(|name| quote!(#name)) .unwrap_or_else(|| quote!(#i)); let mut ty = self.field.ty.clone(); - let has_generics = if let Type::Path(ty) = &ty { - ty.path - .segments - .last() - .map(|seg| !matches!(seg.arguments, PathArguments::None)) - .unwrap_or(false) - } else { - false - }; let crate_root = &self.container_config.crate_root; ty.strip_lifetimes(); let default_fn = self.default_fn(); + let has_generics = !type_params.is_empty() && { + if let Type::Path(ref ty) = ty { + ty.path.segments.iter().any(|seg| { + let type_string = seg.into_token_stream().to_string(); + let type_parts: Vec<&str> = type_string.split(" ").collect(); + type_params + .iter() + .any(|param| type_parts.contains(¶m.to_string().as_str())) + }) + } else { + false + } + }; let constraint_name = format_ident!("FIELD_CONSTRAINT_{}", context); let constraints = self .constraints @@ -883,13 +892,23 @@ impl<'a> FieldConfig<'a> { } } - pub fn decode_field_def(&self, name: &syn::Ident, context: usize) -> proc_macro2::TokenStream { + pub fn decode_field_def( + &self, + name: &syn::Ident, + context: usize, + type_params: &[Ident], + ) -> proc_macro2::TokenStream { let lhs = self.field.ident.as_ref().map(|i| quote!(#i :)); - let decode_op = self.decode(name, context); + let decode_op = self.decode(name, context, type_params); quote!(#lhs #decode_op) } - pub fn decode(&self, name: &syn::Ident, context: usize) -> proc_macro2::TokenStream { + pub fn decode( + &self, + name: &syn::Ident, + context: usize, + type_params: &[Ident], + ) -> proc_macro2::TokenStream { let crate_root = &self.container_config.crate_root; let ty = &self.field.ty; let ident = format!( @@ -901,19 +920,22 @@ impl<'a> FieldConfig<'a> { .map(|ident| ident.to_string()) .unwrap_or_else(|| context.to_string()) ); - let or_else = quote!(.map_err(|error| #crate_root::de::Error::field_error(#ident, error.into(), decoder.codec()))?); let default_fn = self.default_fn(); let tag = self.tag(context); - let has_generics = if let Type::Path(ty) = &ty { - ty.path - .segments - .last() - .map(|seg| !matches!(seg.arguments, PathArguments::None)) - .unwrap_or(false) - } else { - false + let has_generics = !type_params.is_empty() && { + if let Type::Path(ty) = ty { + ty.path.segments.iter().any(|seg| { + let type_string = seg.into_token_stream().to_string(); + let type_parts: Vec<&str> = type_string.split(" ").collect(); + type_params + .iter() + .any(|param| type_parts.contains(¶m.to_string().as_str())) + }) + } else { + false + } }; let constraint_name = format_ident!("CONSTRAINT_{}", context); let constraints = self.constraints.const_expr(crate_root); diff --git a/macros/macros_impl/src/decode.rs b/macros/macros_impl/src/decode.rs index 2d76a27c..33c5703c 100644 --- a/macros/macros_impl/src/decode.rs +++ b/macros/macros_impl/src/decode.rs @@ -201,7 +201,18 @@ pub fn derive_struct_impl( count_root_fields += 1; } - list.push(field_config.decode_field_def(&name, i)); + let type_params: Vec<_> = generics + .params + .iter() + .filter_map(|param| { + if let syn::GenericParam::Type(type_param) = param { + Some(type_param.ident.clone()) + } else { + None + } + }) + .collect(); + list.push(field_config.decode_field_def(&name, i, &type_params)); } let fields = match container.fields { diff --git a/macros/macros_impl/src/encode.rs b/macros/macros_impl/src/encode.rs index 751ac6ac..e4b5816d 100644 --- a/macros/macros_impl/src/encode.rs +++ b/macros/macros_impl/src/encode.rs @@ -11,11 +11,22 @@ pub fn derive_struct_impl( let mut field_encodings = Vec::with_capacity(container.fields.len()); let mut number_root_fields: usize = 0; let mut number_extended_fields: usize = 0; + let type_params: Vec<_> = generics + .params + .iter() + .filter_map(|param| { + if let syn::GenericParam::Type(type_param) = param { + Some(type_param.ident.clone()) + } else { + None + } + }) + .collect(); // Count the number of root and extended fields so that encoder can know the number of fields in advance for (i, field) in container.fields.iter().enumerate() { let field_config = FieldConfig::new(field, config); - let field_encoding = field_config.encode(i, true); + let field_encoding = field_config.encode(i, true, &type_params); if field_config.is_extension() { number_extended_fields += 1; diff --git a/src/lib.rs b/src/lib.rs index e88a6e4b..be364ad4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,5 @@ #![doc = include_str!("../README.md")] -// #![cfg_attr(not(test), no_std)] +#![cfg_attr(not(test), no_std)] #![warn(missing_docs)] extern crate alloc; diff --git a/tests/generics.rs b/tests/generics.rs index 19832838..03728cdb 100644 --- a/tests/generics.rs +++ b/tests/generics.rs @@ -38,12 +38,9 @@ fn test_sequence_with_generics_issue_193() { hello_selection, rasn::oer::decode::>(&encoded).unwrap() ) - - // #[derive(AsnType, Encode, Decode, Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] - // #[rasn(delegate, automatic_tags, size("1..", "-5"))] - // pub struct World(String); } +// This test is just for checking that generics will compile #[test] fn test_sequence_with_generic_and_constraints() { #[derive(AsnType, Debug, Encode, Decode, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] @@ -56,4 +53,20 @@ fn test_sequence_with_generic_and_constraints() { #[rasn(size("1.."))] extn: SequenceOf, } + #[derive(AsnType, Debug, Encode, Decode, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] + #[rasn(automatic_tags)] + #[rasn(delegate)] + #[rasn(size("4"))] + pub struct ConstrainedDelegateBlock(T); + + #[derive(AsnType, Debug, Encode, Decode, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] + #[rasn(automatic_tags)] + #[rasn(choice)] + enum ConstrainedBlockEnum { + First(Integer), + #[rasn(size("1.."))] + Second(T), + #[rasn(value("5"))] + Third(T), + } } From f6bf6239d912169bcf33f589801bb2c03c39596f Mon Sep 17 00:00:00 2001 From: Niklas Saari Date: Fri, 22 Nov 2024 08:40:17 +0200 Subject: [PATCH 21/22] Cleanup --- src/types/constraints.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/types/constraints.rs b/src/types/constraints.rs index d2979993..eca787ef 100644 --- a/src/types/constraints.rs +++ b/src/types/constraints.rs @@ -9,10 +9,11 @@ use num_bigint::BigInt; /// The effective constraint is typically the intersection or union among other constraints. /// As a result, we can store one constraint of each kind, updated with the latest constraint. /// -/// TODO architecture needs a re-design - multple different-style value constraints are allowed -/// for example, value constraint can have multiple single values, or a range of values which do not overlap, and are effective at the same time. +/// TODO architecture needs a re-design - multiple constraints with same type are allowed forming on non-contiguous set of values. +/// We can't currently present this. +/// For example, value constraint can have multiple single values, or a range of values which do not overlap, and are effective at the same time. /// This is challenging to implement in compile-time, and we may need to use runtime checks. -/// E.g effective constraint can have up to infinite single value constraints, and overal constraint value is not continuous. +/// E.g effective constraint can have up to infinite single value constraints, and overall constraint value is not continuous. #[derive(Debug, Copy, Clone)] #[non_exhaustive] pub struct Constraints { @@ -149,8 +150,6 @@ impl<'constraint> Constraints { } /// The set of possible constraints a given value can have. -/// -/// Do not change the amount of variants in this enum without changing the `SUPPORTED_CONSTRAINTS_COUNT` constant. #[derive(Debug, Copy, Clone, PartialEq)] pub enum Constraint { /// A set of possible values which the type can be. From de352311b7432027fca64dc39d99b01a072d196f Mon Sep 17 00:00:00 2001 From: Niklas Saari Date: Fri, 22 Nov 2024 08:49:42 +0200 Subject: [PATCH 22/22] clippy --- src/types/constraints.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/types/constraints.rs b/src/types/constraints.rs index eca787ef..b321d733 100644 --- a/src/types/constraints.rs +++ b/src/types/constraints.rs @@ -23,7 +23,7 @@ pub struct Constraints { extensible: bool, } -impl<'constraint> Constraints { +impl Constraints { /// Empty constraints. pub const NONE: Self = Self { value: None, @@ -33,7 +33,7 @@ impl<'constraint> Constraints { }; /// Creates a new set of constraints from a given slice. - pub const fn new(constraints: &'constraint [Constraint]) -> Self { + pub const fn new(constraints: &[Constraint]) -> Self { let mut value: Option> = None; let mut size: Option> = None; let mut permitted_alphabet: Option> = None;