Skip to main content

rasn/types/
constraints.rs

1//! Constraints of values on a given type.
2
3use super::IntegerType;
4use num_bigint::BigInt;
5
6/// A marker trait with validation methods for types that have ASN.1 inner subtype constraints.
7pub trait InnerSubtypeConstraint: Sized {
8    /// Validates the inner subtype constraints and returns the type on success.
9    /// Does not attempt to decode internal ASN.1 `CONTAINING` constraints as a marked type. See `validate_and_decode_containing` for CONTAINING validation.
10    fn validate_components(self) -> Result<Self, crate::error::InnerSubtypeConstraintError> {
11        self.validate_and_decode_containing(None)
12    }
13
14    /// Validates the inner subtype constraints and attempts to decode internal ASN.1 `CONTAINING` constraints as a marked type.
15    /// Usually this means that some field has `OPAQUE` data, and we need to decode it further as a specific type, as defined in the inner subtype constraint.
16    /// Manual implementation of this function is required for all types that have inner subtype constraints.
17    /// # Arguments
18    /// * `decode_containing_with` - the codec to validate and decode the containing data with when ASN.1 type definiton has `CONTAINING`.
19    fn validate_and_decode_containing(
20        self,
21        decode_containing_with: Option<crate::Codec>,
22    ) -> Result<Self, crate::error::InnerSubtypeConstraintError>;
23}
24
25/// A set of constraints for a given type on what kinds of values are allowed.
26/// Used in certain codecs to optimise encoding and decoding values.
27///
28/// The effective constraint is typically the intersection or union among other constraints.
29/// As a result, we can store one constraint of each kind, updated with the latest constraint.
30///
31/// TODO architecture needs a re-design - multiple constraints with same type are allowed forming on non-contiguous set of values.
32/// We can't currently present this.
33/// 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.
34/// This is challenging to implement in compile-time, and we may need to use runtime checks.
35/// E.g effective constraint can have up to infinite single value constraints, and overall constraint value is not continuous.
36#[derive(Debug, Copy, Clone)]
37#[non_exhaustive]
38pub struct Constraints {
39    value: Option<Extensible<Value>>,
40    size: Option<Extensible<Size>>,
41    permitted_alphabet: Option<Extensible<PermittedAlphabet>>,
42    extensible: bool,
43}
44
45impl Constraints {
46    /// Empty constraints.
47    pub const NONE: Self = Self {
48        value: None,
49        size: None,
50        permitted_alphabet: None,
51        extensible: false,
52    };
53
54    /// Creates a new set of constraints from a given slice.
55    #[must_use]
56    pub const fn new(constraints: &[Constraint]) -> Self {
57        let mut value: Option<Extensible<Value>> = None;
58        let mut size: Option<Extensible<Size>> = None;
59        let mut permitted_alphabet: Option<Extensible<PermittedAlphabet>> = None;
60        let mut extensible = false;
61        let mut i = 0;
62        while i < constraints.len() {
63            match constraints[i] {
64                Constraint::Value(v) => {
65                    value = match value {
66                        Some(value) => Some(value.intersect(&v)),
67                        None => Some(v),
68                    };
69                }
70                Constraint::Size(s) => {
71                    size = if let Some(size) = size {
72                        Some(size.intersect(&s))
73                    } else {
74                        Some(s)
75                    };
76                }
77                Constraint::PermittedAlphabet(p) => {
78                    permitted_alphabet = if let Some(perm) = permitted_alphabet {
79                        Some(perm.intersect(&p))
80                    } else {
81                        Some(p)
82                    };
83                }
84                Constraint::Extensible => {
85                    extensible = true;
86                }
87            }
88            i += 1;
89        }
90        Self {
91            value,
92            size,
93            permitted_alphabet,
94            extensible,
95        }
96    }
97
98    /// A const variant of the default function.
99    #[must_use]
100    pub const fn default() -> Self {
101        Self::NONE
102    }
103
104    /// Creates an intersection of two constraint sets.
105    #[must_use]
106    pub const fn intersect(&self, rhs: Constraints) -> Self {
107        let value = match (self.value, rhs.value) {
108            (Some(value), Some(rhs_value)) => Some(value.intersect(&rhs_value)),
109            (Some(value), None) => Some(value),
110            (None, Some(rhs_value)) => Some(rhs_value),
111            (None, None) => None,
112        };
113        let size = match (self.size, rhs.size) {
114            (Some(size), Some(rhs_size)) => Some(size.intersect(&rhs_size)),
115            (Some(size), None) => Some(size),
116            (None, Some(rhs_size)) => Some(rhs_size),
117            (None, None) => None,
118        };
119        let permitted_alphabet = match (self.permitted_alphabet, rhs.permitted_alphabet) {
120            (Some(perm), Some(rhs_perm)) => Some(perm.intersect(&rhs_perm)),
121            (Some(perm), None) => Some(perm),
122            (None, Some(rhs_perm)) => Some(rhs_perm),
123            (None, None) => None,
124        };
125        let extensible = self.extensible || rhs.extensible;
126
127        Self {
128            value,
129            size,
130            permitted_alphabet,
131            extensible,
132        }
133    }
134
135    /// Returns the effective size constraint, if available.
136    #[must_use]
137    pub const fn size(&self) -> Option<&Extensible<Size>> {
138        self.size.as_ref()
139    }
140
141    /// Returns the effective permitted alphabet constraint, if available.
142    #[must_use]
143    pub const fn permitted_alphabet(&self) -> Option<&Extensible<PermittedAlphabet>> {
144        self.permitted_alphabet.as_ref()
145    }
146
147    /// Returns whether any of the constraints are extensible.
148    #[must_use]
149    pub const fn extensible(&self) -> bool {
150        if self.extensible {
151            return true;
152        }
153        if let Some(value) = &self.value
154            && value.extensible.is_some()
155        {
156            return true;
157        }
158        if let Some(size) = &self.size
159            && size.extensible.is_some()
160        {
161            return true;
162        }
163        if let Some(permitted_alphabet) = &self.permitted_alphabet
164            && permitted_alphabet.extensible.is_some()
165        {
166            return true;
167        }
168        false
169    }
170
171    /// Returns the value constraint from the set, if available.
172    #[must_use]
173    pub const fn value(&self) -> Option<&Extensible<Value>> {
174        self.value.as_ref()
175    }
176}
177
178/// The set of possible constraints a given value can have.
179#[derive(Debug, Copy, Clone, PartialEq)]
180pub enum Constraint {
181    /// A set of possible values which the type can be.
182    Value(Extensible<Value>),
183    /// The amount of possible values the type can have.
184    Size(Extensible<Size>),
185    /// The set of possible characters the type can have.
186    PermittedAlphabet(Extensible<PermittedAlphabet>),
187    /// The value itself is extensible, only valid for constructed types,
188    /// choices, or enumerated values.
189    Extensible,
190}
191
192/// The discriminant of [Constraint] values.
193#[derive(Debug, Clone, Copy, PartialEq)]
194#[allow(missing_docs)]
195pub enum ConstraintDiscriminant {
196    Value,
197    Size,
198    PermittedAlphabet,
199    Extensible,
200}
201impl ConstraintDiscriminant {
202    /// Constant equality check.
203    #[must_use]
204    pub const fn eq(&self, other: &ConstraintDiscriminant) -> bool {
205        *self as isize == *other as isize
206    }
207}
208
209impl Constraint {
210    /// Returns the discriminant of the value.
211    #[must_use]
212    pub const fn kind(&self) -> ConstraintDiscriminant {
213        match self {
214            Self::Value(_) => ConstraintDiscriminant::Value,
215            Self::Size(_) => ConstraintDiscriminant::Size,
216            Self::PermittedAlphabet(_) => ConstraintDiscriminant::PermittedAlphabet,
217            Self::Extensible => ConstraintDiscriminant::Extensible,
218        }
219    }
220    /// Returns the discriminant as an `isize` integer.
221    #[must_use]
222    pub const fn variant_as_isize(&self) -> isize {
223        match self {
224            Self::Value(_) => 0,
225            Self::Size(_) => 1,
226            Self::PermittedAlphabet(_) => 2,
227            Self::Extensible => 3,
228        }
229    }
230
231    /// Returns the value constraint, if set.
232    #[must_use]
233    pub const fn as_value(&self) -> Option<&Extensible<Value>> {
234        match self {
235            Self::Value(integer) => Some(integer),
236            _ => None,
237        }
238    }
239
240    /// Returns the permitted alphabet constraint, if set.
241    #[must_use]
242    pub const fn as_permitted_alphabet(&self) -> Option<&Extensible<PermittedAlphabet>> {
243        match self {
244            Self::PermittedAlphabet(alphabet) => Some(alphabet),
245            _ => None,
246        }
247    }
248
249    /// Returns the size constraint, if set.
250    #[must_use]
251    pub const fn to_size(&self) -> Option<&Extensible<Size>> {
252        match self {
253            Self::Size(size) => Some(size),
254            _ => None,
255        }
256    }
257
258    /// Returns the value constraint, if set.
259    #[must_use]
260    pub const fn to_value(&self) -> Option<&Extensible<Value>> {
261        match self {
262            Self::Value(integer) => Some(integer),
263            _ => None,
264        }
265    }
266
267    /// Returns whether the type is extensible.
268    #[must_use]
269    pub const fn is_extensible(&self) -> bool {
270        match self {
271            Self::Value(value) => value.extensible.is_some(),
272            Self::Size(size) => size.extensible.is_some(),
273            Self::PermittedAlphabet(alphabet) => alphabet.extensible.is_some(),
274            Self::Extensible => true,
275        }
276    }
277}
278
279/// A wrapper around [Constraint] covering whether the constraint is "extensible".
280///
281/// Extensible means that it can have values outside of its constraints, and what possible
282/// constraints thosevalues in the extended set can have, if any.
283#[derive(Debug, Default, Copy, Clone, PartialEq)]
284pub struct Extensible<T: 'static> {
285    /// The underlying constraint type.
286    pub constraint: T,
287    /// Whether the constraint is extensible, and if it is, a list of extensible
288    /// constraints.
289    /// Extensibility means that the allowed constraint values can change, not type of the constraint itself.
290    pub extensible: Option<&'static [T]>,
291}
292
293impl<T> Extensible<T> {
294    /// Creates a new wrapper around a given constraint, by default this means
295    /// that the underlying constraint is not extensible.
296    pub const fn new(constraint: T) -> Self {
297        Self {
298            constraint,
299            extensible: None,
300        }
301    }
302
303    /// Creates a new extensible constraint with a given set of constraints
304    /// on the extended values.
305    pub const fn new_extensible(constraint: T, constraints: &'static [T]) -> Self {
306        Self {
307            constraint,
308            extensible: Some(constraints),
309        }
310    }
311
312    /// Sets the constraint to be extensible with no constraints on extended
313    /// values.
314    #[must_use]
315    pub const fn set_extensible(self, extensible: bool) -> Self {
316        let extensible = if extensible {
317            let empty: &[T] = &[];
318            Some(empty)
319        } else {
320            None
321        };
322
323        self.extensible_with_constraints(extensible)
324    }
325
326    /// Sets the constraint to either not be extended or extensible with a set
327    /// of constraints.
328    #[must_use]
329    pub const fn extensible_with_constraints(mut self, constraints: Option<&'static [T]>) -> Self {
330        self.extensible = constraints;
331        self
332    }
333}
334
335macro_rules! impl_extensible {
336    ($($type:ty),+) => {
337        $(
338            impl Extensible<$type> {
339                /// Intersects two extensible constraints.
340                #[must_use] pub const fn intersect(&self, other: &Self) -> Self {
341                    // All lost in our use case? https://stackoverflow.com/questions/33524834/whats-the-result-set-operation-of-extensible-constraints-in-asn-1
342                    // ASN.1 treats serially applied constraints differently from nested extensible constraints?
343                    // We currently support only serially applied constraints.
344                    let extensible = match (self.extensible, other.extensible) {
345                        (Some(a), Some(_)) => Some(a),
346                        (Some(_), None) => None,
347                        (None, Some(_)) => None,
348                        (None, None) => None,
349                    };
350                    let constraint = self.constraint.intersect(&other.constraint);
351                    match extensible {
352                        Some(ext_ref) => Self::new_extensible(constraint, ext_ref),
353                        None => Self::new(constraint),
354                    }
355                }
356            }
357            impl From<$type> for Extensible<$type> {
358                fn from(value: $type) -> Self {
359                    Self {
360                        constraint: value,
361                        extensible: None,
362                    }
363                }
364            }
365        )+
366    };
367}
368impl_extensible!(Value, Size, PermittedAlphabet);
369
370/// A single or range of numeric values a type can be.
371#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
372pub struct Value {
373    /// Bound of the value
374    pub(crate) value: Bounded<i128>,
375    /// Sign of the bound, used for numeric values
376    pub(crate) signed: bool,
377    /// Range of the bound in bytes, used for numeric values
378    pub(crate) range: Option<u8>,
379}
380
381impl Value {
382    /// Creates a new value constraint from a given bound.
383    #[must_use]
384    pub const fn new(value: Bounded<i128>) -> Self {
385        let (signed, range) = value.range_in_bytes();
386        Self {
387            value,
388            signed,
389            range,
390        }
391    }
392    /// Gets the sign of the value constraint.
393    #[must_use]
394    pub const fn get_sign(&self) -> bool {
395        self.signed
396    }
397    /// Gets the range of the value constraint.
398    #[must_use]
399    pub const fn get_range(&self) -> Option<u8> {
400        self.range
401    }
402    /// Intersect between two `Value` constraints
403    #[must_use]
404    pub const fn intersect(&self, other: &Self) -> Self {
405        let value = match self.value.intersect(other.value) {
406            Some(value) => value,
407            // if the intersection is empty, return impossible range
408            None => Bounded::Range {
409                start: Some(1),
410                end: Some(-1),
411            },
412        };
413        let (signed, range) = value.range_in_bytes();
414        Self {
415            value,
416            signed,
417            range,
418        }
419    }
420}
421
422impl core::ops::Deref for Value {
423    type Target = Bounded<i128>;
424
425    fn deref(&self) -> &Self::Target {
426        &self.value
427    }
428}
429
430macro_rules! from_primitives {
431    ($($int:ty),+ $(,)?) => {
432        $(
433            impl From<Bounded<$int>> for Value {
434                fn from(bounded: Bounded<$int>) -> Self {
435                    Self::new(match bounded {
436                        Bounded::Range { start, end } => Bounded::Range {
437                            start: start.map(From::from),
438                            end: end.map(From::from),
439                        },
440                        Bounded::Single(value) => Bounded::Single(value.into()),
441                        Bounded::None => Bounded::None,
442                    })
443                }
444            }
445        )+
446    }
447}
448
449from_primitives! {
450    u8, u16, u32, u64,
451    i8, i16, i32, i64, i128,
452}
453
454impl TryFrom<Bounded<usize>> for Value {
455    type Error = <i128 as TryFrom<usize>>::Error;
456
457    fn try_from(bounded: Bounded<usize>) -> Result<Self, Self::Error> {
458        Ok(Self::new(match bounded {
459            Bounded::Range { start, end } => Bounded::Range {
460                start: start.map(TryFrom::try_from).transpose()?,
461                end: end.map(TryFrom::try_from).transpose()?,
462            },
463            Bounded::Single(value) => Bounded::Single(value.try_into()?),
464            Bounded::None => Bounded::None,
465        }))
466    }
467}
468
469/// A single or range of length values a type can have.
470#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
471pub struct Size(pub(crate) Bounded<usize>);
472
473impl Size {
474    /// Creates a varying range constraint.
475    #[must_use]
476    pub const fn new(range: Bounded<usize>) -> Self {
477        Self(range)
478    }
479
480    /// Creates a fixed size constraint.
481    #[must_use]
482    pub const fn fixed(length: usize) -> Self {
483        Self(Bounded::Single(length))
484    }
485
486    /// Returns whether the size is fixed.
487    #[must_use]
488    pub const fn is_fixed(&self) -> bool {
489        matches!(self.0, Bounded::Single(_))
490    }
491    /// Returns whether the size has a varying range.
492    #[must_use]
493    pub const fn is_range(&self) -> bool {
494        matches!(self.0, Bounded::Range { .. })
495    }
496    /// Intersect between two `Size` constraints
497    #[must_use]
498    pub const fn intersect(&self, other: &Self) -> Self {
499        match self.0.intersect(other.0) {
500            Some(value) => Self(value),
501            // if the intersection is empty, return a zero size
502            None => Self(Bounded::Single(0)),
503        }
504    }
505}
506
507impl core::ops::Deref for Size {
508    type Target = Bounded<usize>;
509
510    fn deref(&self) -> &Self::Target {
511        &self.0
512    }
513}
514
515impl core::ops::DerefMut for Size {
516    fn deref_mut(&mut self) -> &mut Self::Target {
517        &mut self.0
518    }
519}
520
521/// A range of alphabet characters a type can have.
522#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
523pub struct PermittedAlphabet(&'static [u32]);
524
525impl PermittedAlphabet {
526    /// Creates a new constraint from a given range.
527    #[must_use]
528    pub const fn new(range: &'static [u32]) -> Self {
529        Self(range)
530    }
531
532    /// Returns the range of allowed possible values.
533    #[must_use]
534    pub const fn as_inner(&self) -> &'static [u32] {
535        self.0
536    }
537    /// Intersect between two `PermittedAlphabet` constraints.
538    ///
539    /// TODO not currently possible to intersect
540    /// because new instance requires a static lifetime,
541    /// so we just override for now.
542    #[must_use]
543    pub const fn intersect(&self, other: &Self) -> Self {
544        Self(other.0)
545    }
546}
547
548impl core::ops::Deref for PermittedAlphabet {
549    type Target = [u32];
550
551    fn deref(&self) -> &Self::Target {
552        self.0
553    }
554}
555
556/// A set of potential bounded values.
557#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
558pub enum Bounded<T> {
559    /// No bounds on a given type.
560    #[default]
561    None,
562    /// A single value is permitted for a given type.
563    Single(T),
564    /// the range of values permitted for a given type.
565    Range {
566        /// The lower bound of the range, if any.
567        start: Option<T>,
568        /// The upper bound of the range, if any.
569        end: Option<T>,
570    },
571}
572
573impl<T> Bounded<T> {
574    /// Calculates the the amount of bytes that are required to represent unsigned integer `value`.
575    /// Particularly useful for OER codec
576    const fn unsigned_octet_size_by_range(value: u128) -> Option<u8> {
577        match value {
578            x if x <= u8::MAX as u128 => Some(1),
579            x if x <= u16::MAX as u128 => Some(2),
580            x if x <= u32::MAX as u128 => Some(4),
581            x if x <= u64::MAX as u128 => Some(8),
582            _ => None,
583        }
584    }
585    /// Calculates the the amount of bytes that are required to represent signed integer `value`.
586    /// Particularly useful for OER codec
587    const fn signed_octet_size_by_range(value: i128) -> Option<u8> {
588        match value {
589            x if x >= i8::MIN as i128 && x <= i8::MAX as i128 => Some(1),
590            x if x >= i16::MIN as i128 && x <= i16::MAX as i128 => Some(2),
591            x if x >= i32::MIN as i128 && x <= i32::MAX as i128 => Some(4),
592            x if x >= i64::MIN as i128 && x <= i64::MAX as i128 => Some(8),
593            _ => None,
594        }
595    }
596    /// Creates a bounded range that starts from value and has no end.
597    pub const fn start_from(value: T) -> Self {
598        Self::Range {
599            start: Some(value),
600            end: None,
601        }
602    }
603
604    /// Creates a bounded range that ends at value and has no defined start.
605    pub const fn up_to(value: T) -> Self {
606        Self::Range {
607            start: None,
608            end: Some(value),
609        }
610    }
611
612    /// Creates new bound from a single value.
613    pub const fn single_value(value: T) -> Self {
614        Self::Single(value)
615    }
616
617    /// Returns the lower bound of a given range, if any.
618    pub const fn as_start(&self) -> Option<&T> {
619        match &self {
620            Self::Range { start, .. } => start.as_ref(),
621            Self::Single(value) => Some(value),
622            _ => None,
623        }
624    }
625
626    /// Returns the upper bound of a given range, if any.
627    pub const fn as_end(&self) -> Option<&T> {
628        match &self {
629            Self::Range { end, .. } => end.as_ref(),
630            Self::Single(value) => Some(value),
631            _ => None,
632        }
633    }
634
635    /// Returns the bounds of a given range, if any.
636    pub const fn start_and_end(&self) -> (Option<&T>, Option<&T>) {
637        match &self {
638            Self::Range { start, end } => (start.as_ref(), end.as_ref()),
639            Self::Single(value) => (Some(value), Some(value)),
640            _ => (None, None),
641        }
642    }
643}
644
645impl<T: Copy + IntegerType> Bounded<T> {
646    /// Assuming T is an integer, returns the minimum possible bound, or zero
647    /// if not present.
648    pub const fn minimum(&self) -> T {
649        match self.as_start() {
650            Some(value) => *value,
651            None => T::ZERO,
652        }
653    }
654}
655
656macro_rules! impl_bounded_range {
657    ($($type:ty),+) => {
658        $(
659            impl Bounded<$type> {
660                /// Returns the number representing the difference between the lower and upper bound.
661                pub const fn range(&self) -> Option<$type> {
662                    match self {
663                        Self::Single(_) => Some(1),
664                        Self::Range {
665                            start: Some(start),
666                            end: Some(end),
667                        } => Some(end.wrapping_sub(*start).saturating_add(1)),
668                        _ => None,
669                    }
670                }
671                /// Returns the effective value which is either the number, or the positive
672                /// offset of that number from the start of the value range. `Either::Left`
673                /// represents the positive offset, and `Either::Right` represents
674                /// the number.
675                pub const fn effective_value(&self, value: $type) -> either::Either<$type, $type> {
676                    match self {
677                        Self::Range {
678                            start: Some(start), ..
679                        } => {
680                            debug_assert!(value >= *start);
681                            either::Left(value - *start)
682                        }
683                        _ => either::Right(value),
684                    }
685                }
686                /// Intersect the values of two bounded ranges.
687                ///
688                /// # Returns
689                ///
690                /// Returns the intersection of two bounded ranges, if any.
691                /// If the values do not intersect, returns `None`.
692                ///
693                /// ## Intersection Matrix
694                ///
695                /// | First \ Second | None | Single | Range(s,e) | Range(s,-) | Range(-,e) | Range(-,-) |
696                /// |----------------|------|--------|------------|------------|------------|------------|
697                /// | None           | ✓    | ✓      | ✓          | ✓          | ✓          | ✓          |
698                /// | Single         | ✓    | ✓      | ✓          | ✓          | ✓          | ✓          |
699                /// | Range(s,e)     | ✓    | ✓      | ✓          | ✓          | ✓          | ✓          |
700                /// | Range(s,-)     | ✓    | ✓      | ✓          | ✓          | ✓          | ✓          |
701                /// | Range(-,e)     | ✓    | ✓      | ✓          | ✓          | ✓          | ✓          |
702                /// | Range(-,-)     | ✓    | ✓      | ✓          | ✓          | ✓          | ✓          |
703                pub const fn intersect(&self, other: Self) -> Option<Self> {
704                    match self {
705                        Self::None => Some(other),
706                        Self::Single(a) => match other {
707                            Self::None => Some(Self::Single(*a)),
708                            Self::Single(b) => if *a == b { Some(Self::Single(*a)) } else { None },
709                            Self::Range { start, end } => {
710                                let within_start = if let Some(s) = start.as_ref() {
711                                    *a >= *s
712                                } else {
713                                    true
714                                };
715                                let within_end = if let Some(e) = end.as_ref() {
716                                    *a <= *e
717                                } else {
718                                    true
719                                };
720                                if within_start && within_end {
721                                    Some(Self::Single(*a))
722                                } else {
723                                    None
724                                }
725                            },
726                        },
727                        Self::Range { start: self_start, end: self_end } => match other {
728                            Self::None => Some(*self),
729
730                            Self::Single(b) => {
731                                let within_start = match self_start.as_ref() {
732                                    Some(s) => b >= *s,
733                                    None => true,
734                                };
735                                let within_end = match self_end.as_ref() {
736                                    Some(e) => b <= *e,
737                                    None => true,
738                                };
739                                if within_start && within_end {
740                                    Some(Self::Single(b))
741                                } else {
742                                    None
743                                }
744                            },
745
746                            Self::Range { start: other_start, end: other_end } => {
747                                // Determine the effective start bound (maximum of the two starts)
748                                let new_start = match (self_start, other_start) {
749                                    (None, None) => None,
750                                    (Some(a), None) => Some(*a),
751                                    (None, Some(b)) => Some(b),
752                                    (Some(a), Some(b)) => Some(max(*a as i128, b as i128) as $type),
753                                };
754
755                                // Determine the effective end bound (minimum of the two ends)
756                                let new_end = match (self_end, other_end) {
757                                    (None, None) => None,
758                                    (Some(a), None) => Some(*a),
759                                    (None, Some(b)) => Some(b),
760                                    (Some(a), Some(b)) => Some(min(*a as i128, b as i128) as $type),
761                                };
762
763                                match (new_start, new_end) {
764                                    (Some(start), Some(end)) => {
765                                        if start <= end {
766                                            Some(Self::Range { start: Some(start), end: Some(end) })
767                                        } else {
768                                            // No intersection
769                                           None
770                                        }
771                                    },
772                                    _ => Some(Self::Range { start: new_start, end: new_end }),
773                                }
774                            },
775                        },
776                    }
777                }
778            }
779        )+
780    };
781}
782impl_bounded_range!(i128, usize);
783
784impl From<Value> for Constraint {
785    fn from(size: Value) -> Self {
786        Self::Value(size.into())
787    }
788}
789
790impl From<Extensible<Value>> for Constraint {
791    fn from(size: Extensible<Value>) -> Self {
792        Self::Value(size)
793    }
794}
795
796impl From<Size> for Constraint {
797    fn from(size: Size) -> Self {
798        Self::Size(size.into())
799    }
800}
801
802impl From<Extensible<Size>> for Constraint {
803    fn from(size: Extensible<Size>) -> Self {
804        Self::Size(size)
805    }
806}
807
808impl From<PermittedAlphabet> for Constraint {
809    fn from(size: PermittedAlphabet) -> Self {
810        Self::PermittedAlphabet(size.into())
811    }
812}
813
814impl From<Extensible<PermittedAlphabet>> for Constraint {
815    fn from(size: Extensible<PermittedAlphabet>) -> Self {
816        Self::PermittedAlphabet(size)
817    }
818}
819const fn max(a: i128, b: i128) -> i128 {
820    [a, b][(a < b) as usize]
821}
822
823const fn max_unsigned(a: u128, b: u128) -> u128 {
824    [a, b][(a < b) as usize]
825}
826const fn min(a: i128, b: i128) -> i128 {
827    [a, b][(a > b) as usize]
828}
829
830impl Bounded<i128> {
831    /// Returns the sign and the range in bytes of the constraint.
832    #[must_use]
833    pub const fn range_in_bytes(&self) -> (bool, Option<u8>) {
834        match self {
835            Self::Single(value) => {
836                let is_signed = *value < 0;
837                let octet_size = if is_signed {
838                    Self::signed_octet_size_by_range(*value)
839                } else {
840                    Self::unsigned_octet_size_by_range(*value as u128)
841                };
842                (is_signed, octet_size)
843            }
844            Self::Range {
845                start: Some(start),
846                end: Some(end),
847            } => {
848                let is_signed = *start < 0;
849                let (octets_start, octets_end) = if is_signed {
850                    (
851                        Self::signed_octet_size_by_range(*start),
852                        Self::signed_octet_size_by_range(*end),
853                    )
854                } else {
855                    (
856                        Self::unsigned_octet_size_by_range(*start as u128),
857                        Self::unsigned_octet_size_by_range(*end as u128),
858                    )
859                };
860
861                let octets = match (octets_start, octets_end) {
862                    (Some(start), Some(end)) => {
863                        Some(max_unsigned(start as u128, end as u128) as u8)
864                    }
865                    (_, None) | (None, _) => None,
866                };
867
868                (is_signed, octets)
869            }
870            Self::Range {
871                start: Some(start),
872                end: None,
873            } => (*start < 0, None),
874            Self::Range { start: None, .. } | Self::None => (true, None),
875        }
876    }
877    /// Returns `true` if the given element is within the bounds of the constraint.
878    /// Constraint type is `i128` here, so we can make checks based on that.
879    #[inline(always)]
880    pub fn in_bound<I: IntegerType>(&self, element: &I) -> bool {
881        match &self {
882            Self::Range { start, end } => {
883                start.as_ref().is_none_or(|&start| {
884                    if let Some(e) = element.to_i128() {
885                        e >= start
886                    } else if let Some(e) = element.to_bigint() {
887                        e >= BigInt::from(start)
888                    } else {
889                        false
890                    }
891                }) && end.as_ref().is_none_or(|&end| {
892                    if let Some(e) = element.to_i128() {
893                        e <= end
894                    } else if let Some(e) = element.to_bigint() {
895                        e <= BigInt::from(end)
896                    } else {
897                        false
898                    }
899                })
900            }
901            Self::Single(value) => {
902                if let Some(e) = element.to_i128() {
903                    e == *value
904                } else {
905                    false
906                }
907            }
908            Self::None => true,
909        }
910    }
911}
912
913impl<T: PartialEq + PartialOrd> Bounded<T> {
914    /// Creates a new range from `start` to `end`.
915    ///
916    /// # Panics
917    /// When `start > end`.
918    pub fn new(start: T, end: T) -> Self {
919        debug_assert!(start <= end);
920        Self::const_new(start, end)
921    }
922
923    /// Const compatible range constructor.
924    ///
925    /// # Safety
926    /// Requires `start <= end` otherwise functions will return incorrect results..
927    /// In general you should prefer [`Self::new`] which has debug assertions
928    /// to ensure this.
929    pub const fn const_new(start: T, end: T) -> Self {
930        Self::Range {
931            start: Some(start),
932            end: Some(end),
933        }
934    }
935
936    /// Returns whether a given element is contained within a bound.
937    pub fn contains(&self, element: &T) -> bool {
938        match &self {
939            Self::Single(value) => value == element,
940            Self::Range { start, end } => {
941                start.as_ref().is_none_or(|start| element >= start)
942                    && end.as_ref().is_none_or(|end| element <= end)
943            }
944            Self::None => true,
945        }
946    }
947
948    /// Returns whether a given element is contained within a bound, returning
949    /// an error if not.
950    pub fn contains_or<E>(&self, element: &T, error: E) -> Result<(), E> {
951        self.contains_or_else(element, || error)
952    }
953
954    /// Returns whether a given element is contained within a bound, returning
955    /// an error if not.
956    pub fn contains_or_else<E>(&self, element: &T, error: impl FnOnce() -> E) -> Result<(), E> {
957        if self.contains(element) {
958            Ok(())
959        } else {
960            Err((error)())
961        }
962    }
963}
964
965impl<T: core::fmt::Display> core::fmt::Display for Bounded<T> {
966    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
967        match self {
968            Self::Range { start, end } => match (start.as_ref(), end.as_ref()) {
969                (Some(start), Some(end)) => write!(f, "{start}..{end}"),
970                (Some(start), None) => write!(f, "{start}.."),
971                (None, Some(end)) => write!(f, "..{end}"),
972                (None, None) => write!(f, ".."),
973            },
974            Self::Single(value) => value.fmt(f),
975            Self::None => write!(f, ".."),
976        }
977    }
978}
979
980#[cfg(test)]
981mod tests {
982    use super::*;
983
984    #[test]
985    fn range() {
986        let constraints = Bounded::new(0, 255usize);
987        assert_eq!(256, constraints.range().unwrap());
988    }
989
990    #[test]
991    #[allow(clippy::too_many_lines)]
992    fn test_bounded_intersections() {
993        // None intersections
994        let none = Bounded::<i128>::None;
995        let single = Bounded::<i128>::Single(5);
996        let range_both = Bounded::<i128>::Range {
997            start: Some(1),
998            end: Some(10),
999        };
1000        let range_start = Bounded::<i128>::Range {
1001            start: Some(1),
1002            end: None,
1003        };
1004        let range_end = Bounded::<i128>::Range {
1005            start: None,
1006            end: Some(10),
1007        };
1008        let range_none = Bounded::<i128>::Range {
1009            start: None,
1010            end: None,
1011        };
1012
1013        // None ∩ X cases
1014        assert_eq!(none.intersect(none), Some(none));
1015        assert_eq!(none.intersect(single), Some(single));
1016        assert_eq!(none.intersect(range_both), Some(range_both));
1017        assert_eq!(none.intersect(range_start), Some(range_start));
1018        assert_eq!(none.intersect(range_end), Some(range_end));
1019        assert_eq!(none.intersect(range_none), Some(range_none));
1020
1021        // Single ∩ X cases
1022        assert_eq!(single.intersect(none), Some(single));
1023        assert_eq!(single.intersect(single), Some(single));
1024        assert_eq!(single.intersect(Bounded::<i128>::Single(6)), None);
1025
1026        // Single in range
1027        assert_eq!(
1028            single.intersect(Bounded::<i128>::Range {
1029                start: Some(1),
1030                end: Some(10)
1031            }),
1032            Some(single)
1033        );
1034        // Single below range
1035        assert_eq!(
1036            single.intersect(Bounded::<i128>::Range {
1037                start: Some(6),
1038                end: Some(10)
1039            }),
1040            None
1041        );
1042        // Single above range
1043        assert_eq!(
1044            single.intersect(Bounded::<i128>::Range {
1045                start: Some(1),
1046                end: Some(4)
1047            }),
1048            None
1049        );
1050
1051        // Single ∩ Range(s,-)
1052        assert_eq!(
1053            single.intersect(Bounded::<i128>::Range {
1054                start: Some(1),
1055                end: None
1056            }),
1057            Some(single)
1058        );
1059        assert_eq!(
1060            single.intersect(Bounded::<i128>::Range {
1061                start: Some(6),
1062                end: None
1063            }),
1064            None
1065        );
1066
1067        // Single ∩ Range(-,e)
1068        assert_eq!(
1069            single.intersect(Bounded::<i128>::Range {
1070                start: None,
1071                end: Some(10)
1072            }),
1073            Some(single)
1074        );
1075        assert_eq!(
1076            single.intersect(Bounded::<i128>::Range {
1077                start: None,
1078                end: Some(4)
1079            }),
1080            None
1081        );
1082
1083        // Single ∩ Range(-,-)
1084        assert_eq!(single.intersect(range_none), Some(single));
1085
1086        // Range(s,e) ∩ X cases
1087        assert_eq!(range_both.intersect(none), Some(range_both));
1088
1089        // Range(s,e) ∩ Single
1090        assert_eq!(
1091            range_both.intersect(Bounded::<i128>::Single(5)),
1092            Some(Bounded::<i128>::Single(5))
1093        );
1094        assert_eq!(range_both.intersect(Bounded::<i128>::Single(0)), None);
1095        assert_eq!(range_both.intersect(Bounded::<i128>::Single(11)), None);
1096
1097        // Range(s,e) ∩ Range(s,e) - overlapping cases
1098        assert_eq!(
1099            Bounded::<i128>::Range {
1100                start: Some(1),
1101                end: Some(10)
1102            }
1103            .intersect(Bounded::<i128>::Range {
1104                start: Some(5),
1105                end: Some(15)
1106            }),
1107            Some(Bounded::<i128>::Range {
1108                start: Some(5),
1109                end: Some(10)
1110            })
1111        );
1112        assert_eq!(
1113            Bounded::<i128>::Range {
1114                start: Some(1),
1115                end: Some(10)
1116            }
1117            .intersect(Bounded::<i128>::Range {
1118                start: Some(0),
1119                end: Some(5)
1120            }),
1121            Some(Bounded::<i128>::Range {
1122                start: Some(1),
1123                end: Some(5)
1124            })
1125        );
1126
1127        // Range(s,e) ∩ Range(s,e) - non-overlapping
1128        assert_eq!(
1129            Bounded::<i128>::Range {
1130                start: Some(1),
1131                end: Some(5)
1132            }
1133            .intersect(Bounded::<i128>::Range {
1134                start: Some(6),
1135                end: Some(10)
1136            }),
1137            None
1138        );
1139
1140        // Range(s,e) ∩ Range(s,-)
1141        assert_eq!(
1142            Bounded::<i128>::Range {
1143                start: Some(1),
1144                end: Some(10)
1145            }
1146            .intersect(Bounded::<i128>::Range {
1147                start: Some(5),
1148                end: None
1149            }),
1150            Some(Bounded::<i128>::Range {
1151                start: Some(5),
1152                end: Some(10)
1153            })
1154        );
1155        assert_eq!(
1156            Bounded::<i128>::Range {
1157                start: Some(1),
1158                end: Some(10)
1159            }
1160            .intersect(Bounded::<i128>::Range {
1161                start: Some(11),
1162                end: None
1163            }),
1164            None
1165        );
1166
1167        // Range(s,e) ∩ Range(-,e)
1168        assert_eq!(
1169            Bounded::<i128>::Range {
1170                start: Some(1),
1171                end: Some(10)
1172            }
1173            .intersect(Bounded::<i128>::Range {
1174                start: None,
1175                end: Some(5)
1176            }),
1177            Some(Bounded::<i128>::Range {
1178                start: Some(1),
1179                end: Some(5)
1180            })
1181        );
1182        assert_eq!(
1183            Bounded::<i128>::Range {
1184                start: Some(6),
1185                end: Some(10)
1186            }
1187            .intersect(Bounded::<i128>::Range {
1188                start: None,
1189                end: Some(5)
1190            }),
1191            None
1192        );
1193
1194        // Range(s,e) ∩ Range(-,-)
1195        assert_eq!(range_both.intersect(range_none), Some(range_both));
1196
1197        // Range(s,-) ∩ X cases
1198        assert_eq!(range_start.intersect(none), Some(range_start));
1199
1200        // Range(s,-) ∩ Single
1201        assert_eq!(
1202            Bounded::<i128>::Range {
1203                start: Some(1),
1204                end: None
1205            }
1206            .intersect(Bounded::<i128>::Single(5)),
1207            Some(Bounded::<i128>::Single(5))
1208        );
1209        assert_eq!(
1210            Bounded::<i128>::Range {
1211                start: Some(6),
1212                end: None
1213            }
1214            .intersect(Bounded::<i128>::Single(5)),
1215            None
1216        );
1217
1218        // Range(s,-) ∩ Range(s,-)
1219        assert_eq!(
1220            Bounded::<i128>::Range {
1221                start: Some(1),
1222                end: None
1223            }
1224            .intersect(Bounded::<i128>::Range {
1225                start: Some(5),
1226                end: None
1227            }),
1228            Some(Bounded::<i128>::Range {
1229                start: Some(5),
1230                end: None
1231            })
1232        );
1233
1234        // Range(s,-) ∩ Range(-,e)
1235        assert_eq!(
1236            Bounded::<i128>::Range {
1237                start: Some(1),
1238                end: None
1239            }
1240            .intersect(Bounded::<i128>::Range {
1241                start: None,
1242                end: Some(10)
1243            }),
1244            Some(Bounded::<i128>::Range {
1245                start: Some(1),
1246                end: Some(10)
1247            })
1248        );
1249
1250        // Range(s,-) ∩ Range(-,-)
1251        assert_eq!(range_start.intersect(range_none), Some(range_start));
1252
1253        // Range(-,e) ∩ X cases
1254        assert_eq!(range_end.intersect(none), Some(range_end));
1255
1256        // Range(-,e) ∩ Single
1257        assert_eq!(
1258            Bounded::<i128>::Range {
1259                start: None,
1260                end: Some(10)
1261            }
1262            .intersect(Bounded::<i128>::Single(5)),
1263            Some(Bounded::<i128>::Single(5))
1264        );
1265        assert_eq!(
1266            Bounded::<i128>::Range {
1267                start: None,
1268                end: Some(5)
1269            }
1270            .intersect(Bounded::<i128>::Single(10)),
1271            None
1272        );
1273
1274        // Range(-,e) ∩ Range(-,e)
1275        assert_eq!(
1276            Bounded::<i128>::Range {
1277                start: None,
1278                end: Some(10)
1279            }
1280            .intersect(Bounded::<i128>::Range {
1281                start: None,
1282                end: Some(5)
1283            }),
1284            Some(Bounded::<i128>::Range {
1285                start: None,
1286                end: Some(5)
1287            })
1288        );
1289
1290        // Range(-,-) ∩ X cases
1291        assert_eq!(range_none.intersect(none), Some(range_none));
1292        assert_eq!(range_none.intersect(single), Some(single));
1293        assert_eq!(range_none.intersect(range_both), Some(range_both));
1294        assert_eq!(range_none.intersect(range_start), Some(range_start));
1295        assert_eq!(range_none.intersect(range_end), Some(range_end));
1296        assert_eq!(range_none.intersect(range_none), Some(range_none));
1297
1298        // Add couple tests for usize type just in case
1299        let u_single = Bounded::<usize>::Single(5);
1300        let u_range = Bounded::<usize>::Range {
1301            start: Some(1),
1302            end: Some(10),
1303        };
1304
1305        assert_eq!(
1306            u_range.intersect(Bounded::<usize>::Range {
1307                start: Some(5),
1308                end: Some(15),
1309            }),
1310            Some(Bounded::<usize>::Range {
1311                start: Some(5),
1312                end: Some(10),
1313            })
1314        );
1315
1316        assert_eq!(
1317            Bounded::<usize>::Range {
1318                start: Some(1),
1319                end: Some(5)
1320            }
1321            .intersect(Bounded::<usize>::Range {
1322                start: Some(6),
1323                end: Some(10)
1324            }),
1325            None
1326        );
1327
1328        assert_eq!(u_range.intersect(u_single), Some(u_single));
1329    }
1330    #[test]
1331    fn range_in_bytes_none() {
1332        let bounded = Bounded::<i128>::None;
1333        assert_eq!(bounded.range_in_bytes(), (true, None));
1334    }
1335    #[test]
1336    fn range_in_bytes_range() {
1337        let bounded = Bounded::<i128>::Range {
1338            start: Some(0i128),
1339            end: Some(0i128),
1340        };
1341        assert_eq!(bounded.range_in_bytes(), (false, Some(1u8)));
1342
1343        let bounded = Bounded::<i128>::Range {
1344            start: Some(-1i128),
1345            end: Some(-1i128),
1346        };
1347        assert_eq!(bounded.range_in_bytes(), (true, Some(1u8)));
1348
1349        let boundary_test_values = [
1350            (
1351                i8::MIN as i128,
1352                i8::MAX as i128,
1353                (true, Some(1u8)),
1354                (true, Some(2u8)),
1355                (true, Some(2u8)),
1356                "i8 range",
1357            ),
1358            (
1359                i16::MIN as i128,
1360                i16::MAX as i128,
1361                (true, Some(2u8)),
1362                (true, Some(4u8)),
1363                (true, Some(4u8)),
1364                "i16 range",
1365            ),
1366            (
1367                i32::MIN as i128,
1368                i32::MAX as i128,
1369                (true, Some(4u8)),
1370                (true, Some(8u8)),
1371                (true, Some(8u8)),
1372                "i32 range",
1373            ),
1374            (
1375                i64::MIN as i128,
1376                i64::MAX as i128,
1377                (true, Some(8u8)),
1378                (true, None),
1379                (true, None),
1380                "i64 range",
1381            ),
1382            (
1383                u8::MIN as i128,
1384                u8::MAX as i128,
1385                (false, Some(1u8)),
1386                (true, Some(2u8)),
1387                (false, Some(2u8)),
1388                "u8 range",
1389            ),
1390            (
1391                u16::MIN as i128,
1392                u16::MAX as i128,
1393                (false, Some(2u8)),
1394                (true, Some(4u8)),
1395                (false, Some(4u8)),
1396                "u16 range",
1397            ),
1398            (
1399                u32::MIN as i128,
1400                u32::MAX as i128,
1401                (false, Some(4u8)),
1402                (true, Some(8u8)),
1403                (false, Some(8u8)),
1404                "u32 range",
1405            ),
1406            (
1407                u64::MIN as i128,
1408                u64::MAX as i128,
1409                (false, Some(8u8)),
1410                (true, None),
1411                (false, None),
1412                "u64 range",
1413            ),
1414        ];
1415
1416        for (lower, upper, expected, expected_one_down, expected_one_up, name) in
1417            boundary_test_values.into_iter()
1418        {
1419            // test regular case
1420            let bounded = Bounded::<i128>::Range {
1421                start: Some(lower),
1422                end: Some(upper),
1423            };
1424            assert_eq!(bounded.range_in_bytes(), expected, "testing {}", name);
1425
1426            // test with lower bound decreased by 1 ("one down")
1427            let bounded = Bounded::<i128>::Range {
1428                start: Some(lower - 1),
1429                end: Some(upper),
1430            };
1431            assert_eq!(
1432                bounded.range_in_bytes(),
1433                expected_one_down,
1434                "testing {}, one down",
1435                name
1436            );
1437
1438            // test with upper bound increased by 1 ("one up")
1439            let bounded = Bounded::<i128>::Range {
1440                start: Some(lower),
1441                end: Some(upper + 1),
1442            };
1443            assert_eq!(
1444                bounded.range_in_bytes(),
1445                expected_one_up,
1446                "testing {}, one up",
1447                name
1448            );
1449        }
1450    }
1451    #[test]
1452    fn range_in_bytes_range_with_none() {
1453        let test_values = [
1454            (None, None, true),
1455            (Some(-1i128), None, true),
1456            (Some(0i128), None, false),
1457            (Some(1i128), None, false),
1458            (None, Some(-1i128), true),
1459            (None, Some(0i128), true),
1460            (None, Some(1i128), true),
1461        ];
1462
1463        for (lower, upper, expected_signedness) in test_values.into_iter() {
1464            let bounded = Bounded::<i128>::Range {
1465                start: lower,
1466                end: upper,
1467            };
1468            assert_eq!(
1469                bounded.range_in_bytes(),
1470                (expected_signedness, None),
1471                "testing lower={:?} upper={:?}",
1472                lower,
1473                upper
1474            );
1475        }
1476    }
1477    #[test]
1478    fn range_in_bytes_single() {
1479        let test_values = [
1480            (-1i128, (true, Some(1u8))),
1481            (0i128, (false, Some(1u8))),
1482            (1i128, (false, Some(1u8))),
1483            (i8::MIN as i128, (true, Some(1u8))),
1484            (i8::MAX as i128, (false, Some(1u8))),
1485            (u8::MAX as i128, (false, Some(1u8))),
1486            ((i8::MIN as i128) - 1, (true, Some(2u8))),
1487            ((u8::MAX as i128) + 1, (false, Some(2u8))),
1488            (i16::MIN as i128, (true, Some(2u8))),
1489            (i16::MAX as i128, (false, Some(2u8))),
1490            (u16::MAX as i128, (false, Some(2u8))),
1491            ((i16::MIN as i128) - 1, (true, Some(4u8))),
1492            ((u16::MAX as i128) + 1, (false, Some(4u8))),
1493            (i32::MIN as i128, (true, Some(4u8))),
1494            (i32::MAX as i128, (false, Some(4u8))),
1495            (u32::MAX as i128, (false, Some(4u8))),
1496            ((i32::MIN as i128) - 1, (true, Some(8u8))),
1497            ((u32::MAX as i128) + 1, (false, Some(8u8))),
1498            (i64::MIN as i128, (true, Some(8u8))),
1499            (i64::MAX as i128, (false, Some(8u8))),
1500            (u64::MAX as i128, (false, Some(8u8))),
1501            ((i64::MIN as i128) - 1, (true, None)),
1502            ((u64::MAX as i128) + 1, (false, None)),
1503        ];
1504
1505        for (value, expected) in test_values.into_iter() {
1506            let bounded = Bounded::<i128>::Single(value);
1507            assert_eq!(bounded.range_in_bytes(), expected, "testing {}", value);
1508        }
1509    }
1510}