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 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 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 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 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 pub const fn new(range: Bounded<usize>) -> Self {
258 Self(range)
259 }
260
261 #[must_use]
262 pub const fn fixed(length: usize) -> Self {
264 Self(Bounded::Single(length))
265 }
266
267 #[must_use]
268 pub fn is_fixed(&self) -> bool {
270 matches!(self.0, Bounded::Single(_))
271 }
272 #[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 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 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 pub fn new(start: T, end: T) -> Self {
497 debug_assert!(start <= end);
498 Self::const_new(start, end)
499 }
500
501 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}