rasn/types/
constraints.rs

1use alloc::borrow::Cow;
2
3#[derive(Debug, Default, Clone)]
4pub struct Constraints<'constraint>(pub Cow<'constraint, [Constraint]>);
5
6impl<'r> Constraints<'r> {
7    pub const NONE: Self = Self(Cow::Borrowed(&[]));
8
9    pub const fn new(constraints: &'r [Constraint]) -> Self {
10        Self(Cow::Borrowed(constraints))
11    }
12
13    /// Overrides a set of constraints with another set.
14    pub fn override_constraints(self, mut rhs: Constraints) -> Constraints {
15        for parent in self.0.iter() {
16            if !rhs.0.iter().any(|child| child.kind() == parent.kind()) {
17                rhs.0.to_mut().push(parent.clone());
18            }
19        }
20
21        rhs
22    }
23
24    pub fn size(&self) -> Option<&Extensible<Size>> {
25        self.0.iter().find_map(|constraint| constraint.to_size())
26    }
27
28    pub fn permitted_alphabet(&self) -> Option<&Extensible<PermittedAlphabet>> {
29        self.0
30            .iter()
31            .find_map(|constraint| constraint.as_permitted_alphabet())
32    }
33
34    pub fn extensible(&self) -> bool {
35        self.0.iter().any(|constraint| constraint.is_extensible())
36    }
37
38    pub fn value(&self) -> Option<Extensible<Value>> {
39        self.0.iter().find_map(|constraint| constraint.to_value())
40    }
41}
42
43impl<'r> From<&'r [Constraint]> for Constraints<'r> {
44    fn from(constraints: &'r [Constraint]) -> Self {
45        Self::new(constraints)
46    }
47}
48
49impl<'r, const N: usize> From<&'r [Constraint; N]> for Constraints<'r> {
50    fn from(constraints: &'r [Constraint; N]) -> Self {
51        Self::new(constraints)
52    }
53}
54
55#[derive(Debug, Clone, PartialEq)]
56pub enum Constraint {
57    Value(Extensible<Value>),
58    Size(Extensible<Size>),
59    PermittedAlphabet(Extensible<PermittedAlphabet>),
60    /// The value itself is extensible, only valid for constructed types,
61    /// choices, or enumerated values.
62    Extensible,
63}
64
65#[derive(Debug, Clone, Copy, PartialEq)]
66pub enum ConstraintDiscriminant {
67    Value,
68    Size,
69    PermittedAlphabet,
70    Extensible,
71}
72
73impl Constraint {
74    pub const fn kind(&self) -> ConstraintDiscriminant {
75        match self {
76            Self::Value(_) => ConstraintDiscriminant::Value,
77            Self::Size(_) => ConstraintDiscriminant::Size,
78            Self::PermittedAlphabet(_) => ConstraintDiscriminant::PermittedAlphabet,
79            Self::Extensible => ConstraintDiscriminant::Extensible,
80        }
81    }
82
83    pub const fn as_value(&self) -> Option<&Extensible<Value>> {
84        match self {
85            Self::Value(integer) => Some(integer),
86            _ => None,
87        }
88    }
89
90    pub fn as_permitted_alphabet(&self) -> Option<&Extensible<PermittedAlphabet>> {
91        match self {
92            Self::PermittedAlphabet(alphabet) => Some(alphabet),
93            _ => None,
94        }
95    }
96
97    pub fn to_size(&self) -> Option<&Extensible<Size>> {
98        match self {
99            Self::Size(size) => Some(size),
100            _ => None,
101        }
102    }
103
104    pub fn to_value(&self) -> Option<Extensible<Value>> {
105        match self {
106            Self::Value(integer) => Some(integer.clone()),
107            _ => None,
108        }
109    }
110
111    /// Returns whether the type is extensible.
112    pub const fn is_extensible(&self) -> bool {
113        match self {
114            Self::Value(value) => value.extensible.is_some(),
115            Self::Size(size) => size.extensible.is_some(),
116            Self::PermittedAlphabet(alphabet) => alphabet.extensible.is_some(),
117            Self::Extensible => true,
118        }
119    }
120}
121
122#[derive(Debug, Default, Clone, PartialEq)]
123pub struct Extensible<T: 'static> {
124    pub constraint: T,
125    /// Whether the constraint is extensible, and if it is, a list of extensible
126    /// constraints.
127    pub extensible: Option<&'static [T]>,
128}
129
130impl<T> Extensible<T> {
131    pub const fn new(constraint: T) -> Self {
132        Self {
133            constraint,
134            extensible: None,
135        }
136    }
137
138    pub const fn new_extensible(constraint: T, constraints: &'static [T]) -> Self {
139        Self {
140            constraint,
141            extensible: Some(constraints),
142        }
143    }
144
145    pub const fn set_extensible(self, extensible: bool) -> Self {
146        let extensible = if extensible {
147            let empty: &[T] = &[];
148            Some(empty)
149        } else {
150            None
151        };
152
153        self.extensible_with_constraints(extensible)
154    }
155
156    pub const fn extensible_with_constraints(mut self, constraints: Option<&'static [T]>) -> Self {
157        self.extensible = constraints;
158        self
159    }
160}
161
162impl From<Value> for Extensible<Value> {
163    fn from(value: Value) -> Self {
164        Self {
165            constraint: value,
166            extensible: None,
167        }
168    }
169}
170
171impl From<Size> for Extensible<Size> {
172    fn from(size: Size) -> Self {
173        Self {
174            constraint: size,
175            extensible: None,
176        }
177    }
178}
179
180impl From<PermittedAlphabet> for Extensible<PermittedAlphabet> {
181    fn from(alphabet: PermittedAlphabet) -> Self {
182        Self {
183            constraint: alphabet,
184            extensible: None,
185        }
186    }
187}
188
189#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
190pub struct Value(pub(crate) Bounded<i128>);
191
192impl Value {
193    pub const fn new(value: Bounded<i128>) -> Self {
194        Self(value)
195    }
196}
197
198impl core::ops::Deref for Value {
199    type Target = Bounded<i128>;
200
201    fn deref(&self) -> &Self::Target {
202        &self.0
203    }
204}
205
206impl core::ops::DerefMut for Value {
207    fn deref_mut(&mut self) -> &mut Self::Target {
208        &mut self.0
209    }
210}
211
212macro_rules! from_primitives {
213    ($($int:ty),+ $(,)?) => {
214        $(
215            impl From<Bounded<$int>> for Value {
216                fn from(bounded: Bounded<$int>) -> Self {
217                    Self(match bounded {
218                        Bounded::Range { start, end } => Bounded::Range {
219                            start: start.map(From::from),
220                            end: end.map(From::from),
221                        },
222                        Bounded::Single(value) => Bounded::Single(value.into()),
223                        Bounded::None => Bounded::None,
224                    })
225                }
226            }
227        )+
228    }
229}
230
231from_primitives! {
232    u8, u16, u32, u64,
233    i8, i16, i32, i64, i128,
234}
235
236impl TryFrom<Bounded<usize>> for Value {
237    type Error = <i128 as TryFrom<usize>>::Error;
238
239    fn try_from(bounded: Bounded<usize>) -> Result<Self, Self::Error> {
240        Ok(Self(match bounded {
241            Bounded::Range { start, end } => Bounded::Range {
242                start: start.map(TryFrom::try_from).transpose()?,
243                end: end.map(TryFrom::try_from).transpose()?,
244            },
245            Bounded::Single(value) => Bounded::Single(value.try_into()?),
246            Bounded::None => Bounded::None,
247        }))
248    }
249}
250
251#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
252pub struct Size(pub(crate) Bounded<usize>);
253
254impl Size {
255    #[must_use]
256    /// Creates a varying range constraint.
257    pub const fn new(range: Bounded<usize>) -> Self {
258        Self(range)
259    }
260
261    #[must_use]
262    /// Creates a fixed size constraint.
263    pub const fn fixed(length: usize) -> Self {
264        Self(Bounded::Single(length))
265    }
266
267    #[must_use]
268    /// Returns whether the size is fixed.
269    pub fn is_fixed(&self) -> bool {
270        matches!(self.0, Bounded::Single(_))
271    }
272    /// Returns whether the size has a varying range.
273    #[must_use]
274    pub fn is_range(&self) -> bool {
275        matches!(self.0, Bounded::Range { .. })
276    }
277}
278
279impl core::ops::Deref for Size {
280    type Target = Bounded<usize>;
281
282    fn deref(&self) -> &Self::Target {
283        &self.0
284    }
285}
286
287impl core::ops::DerefMut for Size {
288    fn deref_mut(&mut self) -> &mut Self::Target {
289        &mut self.0
290    }
291}
292
293#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
294pub struct PermittedAlphabet(&'static [u32]);
295
296impl PermittedAlphabet {
297    pub const fn new(range: &'static [u32]) -> Self {
298        Self(range)
299    }
300
301    pub fn as_inner(&self) -> &'static [u32] {
302        self.0
303    }
304}
305
306impl core::ops::Deref for PermittedAlphabet {
307    type Target = [u32];
308
309    fn deref(&self) -> &Self::Target {
310        self.0
311    }
312}
313
314#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
315pub enum Bounded<T> {
316    #[default]
317    None,
318    Single(T),
319    Range {
320        start: Option<T>,
321        end: Option<T>,
322    },
323}
324
325impl<T> Bounded<T> {
326    pub const fn start_from(value: T) -> Self {
327        Self::Range {
328            start: Some(value),
329            end: None,
330        }
331    }
332
333    pub const fn up_to(value: T) -> Self {
334        Self::Range {
335            start: None,
336            end: Some(value),
337        }
338    }
339
340    pub const fn as_start(&self) -> Option<&T> {
341        match &self {
342            Self::Range { start, .. } => start.as_ref(),
343            Self::Single(value) => Some(value),
344            _ => None,
345        }
346    }
347
348    pub const fn as_end(&self) -> Option<&T> {
349        match &self {
350            Self::Range { end, .. } => end.as_ref(),
351            Self::Single(value) => Some(value),
352            _ => None,
353        }
354    }
355
356    pub const fn start_and_end(&self) -> (Option<&T>, Option<&T>) {
357        match &self {
358            Self::Range { start, end } => (start.as_ref(), end.as_ref()),
359            Self::Single(value) => (Some(value), Some(value)),
360            _ => (None, None),
361        }
362    }
363
364    pub const fn single_value(value: T) -> Self {
365        Self::Single(value)
366    }
367}
368
369impl<T: Default + Clone> Bounded<T> {
370    pub fn as_minimum(&self) -> Option<&T> {
371        match self {
372            Self::Single(value) => Some(value),
373            Self::Range {
374                start: Some(start), ..
375            } => Some(start),
376            _ => None,
377        }
378    }
379
380    pub fn minimum(&self) -> T {
381        self.as_minimum().cloned().unwrap_or_default()
382    }
383}
384
385impl<T: num_traits::WrappingSub<Output = T> + num_traits::SaturatingAdd<Output = T> + From<u8>>
386    Bounded<T>
387{
388    pub fn range(&self) -> Option<T> {
389        match self {
390            Self::Single(_) => Some(T::from(1u8)),
391            Self::Range {
392                start: Some(start),
393                end: Some(end),
394            } => Some(end.wrapping_sub(start).saturating_add(&1.into())),
395            _ => None,
396        }
397    }
398}
399
400impl<T: core::ops::Sub<Output = T> + core::fmt::Debug + Default + Clone + PartialOrd> Bounded<T> {
401    /// Returns the effective value which is either the number, or the positive
402    /// offset of that number from the start of the value range. `Either::Left`
403    /// represents the positive offset, and `Either::Right` represents
404    /// the number.
405    pub fn effective_value(&self, value: T) -> either::Either<T, T> {
406        match &self {
407            Self::Range {
408                start: Some(start), ..
409            } => {
410                debug_assert!(&value >= start);
411                either::Left(value - start.clone())
412            }
413            _ => either::Right(value),
414        }
415    }
416}
417
418impl<T: core::ops::Sub<Output = T> + core::fmt::Debug + Default + Clone + PartialOrd<T>> Bounded<T>
419where
420    crate::types::Integer: From<T>,
421{
422    /// The same as [`effective_value`] except using [`crate::types::Integer`].
423    pub fn effective_bigint_value(
424        &self,
425        value: crate::types::Integer,
426    ) -> either::Either<crate::types::Integer, crate::types::Integer> {
427        if let Bounded::Range {
428            start: Some(start), ..
429        } = self
430        {
431            let start = crate::types::Integer::from(start.clone());
432            debug_assert!(value >= start);
433            either::Left(value - start)
434        } else {
435            either::Right(value)
436        }
437    }
438}
439
440impl From<Value> for Constraint {
441    fn from(size: Value) -> Self {
442        Self::Value(size.into())
443    }
444}
445
446impl From<Extensible<Value>> for Constraint {
447    fn from(size: Extensible<Value>) -> Self {
448        Self::Value(size)
449    }
450}
451
452impl From<Size> for Constraint {
453    fn from(size: Size) -> Self {
454        Self::Size(size.into())
455    }
456}
457
458impl From<Extensible<Size>> for Constraint {
459    fn from(size: Extensible<Size>) -> Self {
460        Self::Size(size)
461    }
462}
463
464impl From<PermittedAlphabet> for Constraint {
465    fn from(size: PermittedAlphabet) -> Self {
466        Self::PermittedAlphabet(size.into())
467    }
468}
469
470impl From<Extensible<PermittedAlphabet>> for Constraint {
471    fn from(size: Extensible<PermittedAlphabet>) -> Self {
472        Self::PermittedAlphabet(size)
473    }
474}
475
476impl Bounded<i128> {
477    pub fn bigint_contains(&self, element: &crate::types::Integer) -> bool {
478        match &self {
479            Self::Single(value) => crate::types::Integer::from(*value) == *element,
480            Self::Range { start, end } => {
481                start
482                    .as_ref()
483                    .map_or(true, |&start| element >= &start.into())
484                    && end.as_ref().map_or(true, |&end| element <= &end.into())
485            }
486            Self::None => true,
487        }
488    }
489}
490
491impl<T: PartialEq + PartialOrd> Bounded<T> {
492    /// Creates a new range from `start` to `end`.
493    ///
494    /// # Panics
495    /// When `start > end`.
496    pub fn new(start: T, end: T) -> Self {
497        debug_assert!(start <= end);
498        Self::const_new(start, end)
499    }
500
501    /// Const compatible range constructor.
502    ///
503    /// # Safety
504    /// Requires `start <= end` otherwise functions will return incorrect results..
505    /// In general you should prefer [`Self::new`] which has debug assertions
506    /// to ensure this.
507    pub const fn const_new(start: T, end: T) -> Self {
508        Self::Range {
509            start: Some(start),
510            end: Some(end),
511        }
512    }
513
514    pub fn contains(&self, element: &T) -> bool {
515        match &self {
516            Self::Single(value) => value == element,
517            Self::Range { start, end } => {
518                start.as_ref().map_or(true, |start| element >= start)
519                    && end.as_ref().map_or(true, |end| element <= end)
520            }
521            Self::None => true,
522        }
523    }
524
525    pub fn contains_or<E>(&self, element: &T, error: E) -> Result<(), E> {
526        self.contains_or_else(element, || error)
527    }
528
529    pub fn contains_or_else<E>(&self, element: &T, error: impl FnOnce() -> E) -> Result<(), E> {
530        match self.contains(element) {
531            true => Ok(()),
532            false => Err((error)()),
533        }
534    }
535}
536
537impl<T: core::fmt::Display> core::fmt::Display for Bounded<T> {
538    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
539        match self {
540            Self::Range { start, end } => match (start.as_ref(), end.as_ref()) {
541                (Some(start), Some(end)) => write!(f, "{start}..{end}"),
542                (Some(start), None) => write!(f, "{start}.."),
543                (None, Some(end)) => write!(f, "..{end}"),
544                (None, None) => write!(f, ".."),
545            },
546            Self::Single(value) => value.fmt(f),
547            Self::None => write!(f, ".."),
548        }
549    }
550}
551
552#[cfg(test)]
553mod tests {
554    use super::*;
555
556    #[test]
557    fn range() {
558        let constraints = Bounded::new(0, 255);
559        assert_eq!(256, constraints.range().unwrap());
560    }
561}