imap_types/
sequence.rs

1use std::{
2    num::NonZeroU32,
3    ops::{Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive},
4    str::FromStr,
5};
6
7#[cfg(feature = "arbitrary")]
8use arbitrary::Arbitrary;
9#[cfg(feature = "bounded-static")]
10use bounded_static::ToStatic;
11#[cfg(feature = "serde")]
12use serde::{Deserialize, Serialize};
13
14use crate::{
15    core::NonEmptyVec,
16    error::{ValidationError, ValidationErrorKind},
17};
18
19pub const ONE: NonZeroU32 = match NonZeroU32::new(1) {
20    Some(one) => one,
21    None => panic!(),
22};
23pub const MIN: NonZeroU32 = ONE;
24pub const MAX: NonZeroU32 = match NonZeroU32::new(u32::MAX) {
25    Some(max) => max,
26    None => panic!(),
27};
28
29#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
30#[cfg_attr(feature = "bounded-static", derive(ToStatic))]
31#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
32#[derive(Debug, Clone, PartialEq, Eq, Hash)]
33pub struct SequenceSet(pub NonEmptyVec<Sequence>);
34
35impl From<Sequence> for SequenceSet {
36    fn from(sequence: Sequence) -> Self {
37        Self(NonEmptyVec::from(sequence))
38    }
39}
40
41macro_rules! impl_from_t_for_sequence_set {
42    ($thing:ty) => {
43        impl From<$thing> for SequenceSet {
44            fn from(value: $thing) -> Self {
45                Self::from(Sequence::from(value))
46            }
47        }
48    };
49}
50
51macro_rules! impl_try_from_t_for_sequence_set {
52    ($thing:ty) => {
53        impl TryFrom<$thing> for SequenceSet {
54            type Error = ValidationError;
55
56            fn try_from(value: $thing) -> Result<Self, Self::Error> {
57                Ok(Self::from(Sequence::try_from(value)?))
58            }
59        }
60    };
61}
62
63impl_from_t_for_sequence_set!(SeqOrUid);
64impl_from_t_for_sequence_set!(NonZeroU32);
65impl_from_t_for_sequence_set!(RangeFull);
66impl_from_t_for_sequence_set!(RangeFrom<NonZeroU32>);
67impl_try_from_t_for_sequence_set!(RangeTo<NonZeroU32>);
68impl_from_t_for_sequence_set!(RangeToInclusive<NonZeroU32>);
69impl_try_from_t_for_sequence_set!(Range<NonZeroU32>);
70impl_from_t_for_sequence_set!(RangeInclusive<NonZeroU32>);
71
72// `SequenceSet::try_from` implementations.
73
74impl TryFrom<Vec<Sequence>> for SequenceSet {
75    type Error = ValidationError;
76
77    fn try_from(sequences: Vec<Sequence>) -> Result<Self, Self::Error> {
78        Ok(Self(NonEmptyVec::try_from(sequences).map_err(|_| {
79            ValidationError::new(ValidationErrorKind::Empty)
80        })?))
81    }
82}
83
84impl TryFrom<Vec<NonZeroU32>> for SequenceSet {
85    type Error = ValidationError;
86
87    fn try_from(sequences: Vec<NonZeroU32>) -> Result<Self, Self::Error> {
88        Ok(Self(
89            NonEmptyVec::try_from(
90                sequences
91                    .into_iter()
92                    .map(Sequence::from)
93                    .collect::<Vec<_>>(),
94            )
95            .map_err(|_| ValidationError::new(ValidationErrorKind::Empty))?,
96        ))
97    }
98}
99
100impl TryFrom<&str> for SequenceSet {
101    type Error = ValidationError;
102
103    fn try_from(value: &str) -> Result<Self, Self::Error> {
104        value.parse()
105    }
106}
107
108impl FromStr for SequenceSet {
109    type Err = ValidationError;
110
111    fn from_str(value: &str) -> Result<Self, Self::Err> {
112        let mut results = vec![];
113
114        for seq in value.split(',') {
115            results.push(Sequence::try_from(seq)?);
116        }
117
118        Ok(SequenceSet(NonEmptyVec::try_from(results).map_err(
119            |_| ValidationError::new(ValidationErrorKind::Empty),
120        )?))
121    }
122}
123
124#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
125#[cfg_attr(feature = "bounded-static", derive(ToStatic))]
126#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
127#[derive(Debug, Clone, PartialEq, Eq, Hash)]
128pub enum Sequence {
129    Single(SeqOrUid),
130    Range(SeqOrUid, SeqOrUid),
131}
132
133impl From<SeqOrUid> for Sequence {
134    fn from(value: SeqOrUid) -> Self {
135        Self::Single(value)
136    }
137}
138
139impl From<NonZeroU32> for Sequence {
140    fn from(value: NonZeroU32) -> Self {
141        Self::Single(SeqOrUid::from(value))
142    }
143}
144
145impl TryFrom<&str> for Sequence {
146    type Error = ValidationError;
147
148    fn try_from(value: &str) -> Result<Self, Self::Error> {
149        value.parse()
150    }
151}
152
153impl FromStr for Sequence {
154    type Err = ValidationError;
155
156    fn from_str(value: &str) -> Result<Self, Self::Err> {
157        match value.split(':').count() {
158            0 => Err(ValidationError::new(ValidationErrorKind::Empty)),
159            1 => Ok(Sequence::Single(SeqOrUid::try_from(value)?)),
160            2 => {
161                let mut split = value.split(':');
162
163                let start = split.next().unwrap();
164                let end = split.next().unwrap();
165
166                Ok(Sequence::Range(
167                    SeqOrUid::try_from(start)?,
168                    SeqOrUid::try_from(end)?,
169                ))
170            }
171            _ => Err(ValidationError::new(ValidationErrorKind::Invalid)),
172        }
173    }
174}
175
176#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
177#[cfg_attr(feature = "bounded-static", derive(ToStatic))]
178#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
179#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy)]
180pub enum SeqOrUid {
181    Value(NonZeroU32),
182    Asterisk,
183}
184
185impl From<NonZeroU32> for SeqOrUid {
186    fn from(value: NonZeroU32) -> Self {
187        Self::Value(value)
188    }
189}
190
191macro_rules! impl_try_from_num {
192    ($num:ty) => {
193        impl TryFrom<&[$num]> for SequenceSet {
194            type Error = ValidationError;
195
196            fn try_from(values: &[$num]) -> Result<Self, Self::Error> {
197                let mut checked = Vec::new();
198
199                for value in values {
200                    checked.push(Sequence::try_from(*value)?);
201                }
202
203                Self::try_from(checked)
204            }
205        }
206
207        impl TryFrom<$num> for SequenceSet {
208            type Error = ValidationError;
209
210            fn try_from(value: $num) -> Result<Self, Self::Error> {
211                Ok(Self::from(Sequence::try_from(value)?))
212            }
213        }
214
215        impl TryFrom<$num> for Sequence {
216            type Error = ValidationError;
217
218            fn try_from(value: $num) -> Result<Self, Self::Error> {
219                Ok(Self::from(SeqOrUid::try_from(value)?))
220            }
221        }
222
223        impl TryFrom<$num> for SeqOrUid {
224            type Error = ValidationError;
225
226            fn try_from(value: $num) -> Result<Self, Self::Error> {
227                if let Ok(value) = u32::try_from(value) {
228                    if let Ok(value) = NonZeroU32::try_from(value) {
229                        return Ok(Self::Value(value));
230                    }
231                }
232
233                Err(ValidationError::new(ValidationErrorKind::Invalid))
234            }
235        }
236    };
237}
238
239impl_try_from_num!(i8);
240impl_try_from_num!(i16);
241impl_try_from_num!(i32);
242impl_try_from_num!(i64);
243impl_try_from_num!(isize);
244impl_try_from_num!(u8);
245impl_try_from_num!(u16);
246impl_try_from_num!(u32);
247impl_try_from_num!(u64);
248impl_try_from_num!(usize);
249
250impl TryFrom<&str> for SeqOrUid {
251    type Error = ValidationError;
252
253    fn try_from(value: &str) -> Result<Self, Self::Error> {
254        value.parse()
255    }
256}
257
258impl FromStr for SeqOrUid {
259    type Err = ValidationError;
260
261    fn from_str(value: &str) -> Result<Self, Self::Err> {
262        if value == "*" {
263            Ok(SeqOrUid::Asterisk)
264        } else {
265            // This is to align parsing here with the IMAP grammar:
266            // Rust's `parse::<NonZeroU32>` function accepts numbers that start with 0.
267            // For example, 00001, is interpreted as 1. But this is not allowed in IMAP.
268            if value.starts_with('0') {
269                Err(ValidationError::new(ValidationErrorKind::Invalid))
270            } else {
271                Ok(SeqOrUid::Value(NonZeroU32::from_str(value).map_err(
272                    |_| ValidationError::new(ValidationErrorKind::Invalid),
273                )?))
274            }
275        }
276    }
277}
278
279// -------------------------------------------------------------------------------------------------
280
281macro_rules! impl_try_from_num_range {
282    ($num:ty) => {
283        impl TryFrom<RangeFrom<$num>> for SequenceSet {
284            type Error = ValidationError;
285
286            fn try_from(range: RangeFrom<$num>) -> Result<Self, Self::Error> {
287                Ok(Self::from(Sequence::try_from(range)?))
288            }
289        }
290
291        impl TryFrom<RangeTo<$num>> for SequenceSet {
292            type Error = ValidationError;
293
294            fn try_from(range: RangeTo<$num>) -> Result<Self, Self::Error> {
295                Ok(Self::from(Sequence::try_from(range)?))
296            }
297        }
298
299        impl TryFrom<RangeToInclusive<$num>> for SequenceSet {
300            type Error = ValidationError;
301
302            fn try_from(range: RangeToInclusive<$num>) -> Result<Self, Self::Error> {
303                Ok(Self::from(Sequence::try_from(range)?))
304            }
305        }
306
307        impl TryFrom<Range<$num>> for SequenceSet {
308            type Error = ValidationError;
309
310            fn try_from(range: Range<$num>) -> Result<Self, Self::Error> {
311                Ok(Self::from(Sequence::try_from(range)?))
312            }
313        }
314
315        impl TryFrom<RangeInclusive<$num>> for SequenceSet {
316            type Error = ValidationError;
317
318            fn try_from(range: RangeInclusive<$num>) -> Result<Self, Self::Error> {
319                Ok(Self::from(Sequence::try_from(range)?))
320            }
321        }
322
323        // -----------------------------------------------------------------------------------------
324
325        impl TryFrom<RangeFrom<$num>> for Sequence {
326            type Error = ValidationError;
327
328            fn try_from(range: RangeFrom<$num>) -> Result<Self, Self::Error> {
329                Ok(Self::Range(
330                    SeqOrUid::try_from(range.start)?,
331                    SeqOrUid::Asterisk,
332                ))
333            }
334        }
335
336        impl TryFrom<RangeTo<$num>> for Sequence {
337            type Error = ValidationError;
338
339            fn try_from(range: RangeTo<$num>) -> Result<Self, Self::Error> {
340                Ok(Self::Range(
341                    SeqOrUid::from(ONE),
342                    SeqOrUid::try_from(range.end.saturating_sub(1))?,
343                ))
344            }
345        }
346
347        impl TryFrom<RangeToInclusive<$num>> for Sequence {
348            type Error = ValidationError;
349
350            fn try_from(range: RangeToInclusive<$num>) -> Result<Self, Self::Error> {
351                Ok(Self::Range(
352                    SeqOrUid::from(ONE),
353                    SeqOrUid::try_from(range.end)?,
354                ))
355            }
356        }
357
358        impl TryFrom<Range<$num>> for Sequence {
359            type Error = ValidationError;
360
361            fn try_from(range: Range<$num>) -> Result<Self, Self::Error> {
362                Ok(Self::Range(
363                    SeqOrUid::try_from(range.start)?,
364                    SeqOrUid::try_from(range.end.saturating_sub(1))?,
365                ))
366            }
367        }
368
369        impl TryFrom<RangeInclusive<$num>> for Sequence {
370            type Error = ValidationError;
371
372            fn try_from(range: RangeInclusive<$num>) -> Result<Self, Self::Error> {
373                Ok(Self::Range(
374                    SeqOrUid::try_from(*range.start())?,
375                    SeqOrUid::try_from(*range.end())?,
376                ))
377            }
378        }
379    };
380}
381
382impl_try_from_num_range!(i8);
383impl_try_from_num_range!(i16);
384impl_try_from_num_range!(i32);
385impl_try_from_num_range!(i64);
386impl_try_from_num_range!(isize);
387impl_try_from_num_range!(u8);
388impl_try_from_num_range!(u16);
389impl_try_from_num_range!(u32);
390impl_try_from_num_range!(u64);
391impl_try_from_num_range!(usize);
392
393impl From<RangeFull> for Sequence {
394    fn from(_: RangeFull) -> Self {
395        Self::from(MIN..)
396    }
397}
398
399impl From<RangeFrom<NonZeroU32>> for Sequence {
400    fn from(range: RangeFrom<NonZeroU32>) -> Self {
401        Self::Range(SeqOrUid::from(range.start), SeqOrUid::Asterisk)
402    }
403}
404
405impl TryFrom<RangeTo<NonZeroU32>> for Sequence {
406    type Error = ValidationError;
407
408    fn try_from(range: RangeTo<NonZeroU32>) -> Result<Self, Self::Error> {
409        Self::try_from(MIN..range.end)
410    }
411}
412
413impl From<RangeToInclusive<NonZeroU32>> for Sequence {
414    fn from(range: RangeToInclusive<NonZeroU32>) -> Self {
415        Self::from(MIN..=range.end)
416    }
417}
418
419impl TryFrom<Range<NonZeroU32>> for Sequence {
420    type Error = ValidationError;
421
422    fn try_from(range: Range<NonZeroU32>) -> Result<Self, Self::Error> {
423        Ok(Self::Range(
424            SeqOrUid::from(MIN),
425            SeqOrUid::try_from(range.end.get().saturating_sub(1))?,
426        ))
427    }
428}
429
430impl From<RangeInclusive<NonZeroU32>> for Sequence {
431    fn from(range: RangeInclusive<NonZeroU32>) -> Self {
432        Self::Range(SeqOrUid::from(*range.start()), SeqOrUid::from(*range.end()))
433    }
434}
435
436// -------------------------------------------------------------------------------------------------
437
438impl<'a> SequenceSet {
439    pub fn iter(&'a self, strategy: Strategy) -> impl Iterator<Item = NonZeroU32> + 'a {
440        match strategy {
441            Strategy::Naive { largest } => SequenceSetIterNaive {
442                iter: self.0.as_ref().iter(),
443                active_range: None,
444                largest,
445            },
446        }
447    }
448}
449
450impl SeqOrUid {
451    pub fn expand(&self, largest: NonZeroU32) -> NonZeroU32 {
452        match self {
453            SeqOrUid::Value(value) => *value,
454            SeqOrUid::Asterisk => largest,
455        }
456    }
457}
458
459// -------------------------------------------------------------------------------------------------
460
461#[derive(Debug)]
462#[non_exhaustive]
463pub enum Strategy {
464    Naive { largest: NonZeroU32 },
465}
466
467#[derive(Debug)]
468pub struct SequenceSetIterNaive<'a> {
469    iter: core::slice::Iter<'a, Sequence>,
470    active_range: Option<RangeInclusive<u32>>,
471    largest: NonZeroU32,
472}
473
474impl<'a> Iterator for SequenceSetIterNaive<'a> {
475    type Item = NonZeroU32;
476
477    fn next(&mut self) -> Option<Self::Item> {
478        loop {
479            if let Some(ref mut range) = self.active_range {
480                if let Some(seq_or_uid) = range.next() {
481                    return Some(NonZeroU32::try_from(seq_or_uid).unwrap());
482                } else {
483                    self.active_range = None;
484                }
485            }
486
487            match self.iter.next() {
488                Some(seq) => match seq {
489                    Sequence::Single(seq_no) => {
490                        return Some(seq_no.expand(self.largest));
491                    }
492                    Sequence::Range(from, to) => {
493                        let from = from.expand(self.largest);
494                        let to = to.expand(self.largest);
495                        self.active_range = Some(u32::from(from)..=u32::from(to));
496                    }
497                },
498                None => return None,
499            }
500        }
501    }
502}
503
504#[cfg(test)]
505mod tests {
506    use std::num::NonZeroU32;
507
508    use super::*;
509    use crate::core::NonEmptyVec;
510
511    #[test]
512    fn test_creation_of_sequence_from_u32() {
513        assert_eq!(
514            SequenceSet::try_from(1),
515            Ok(SequenceSet(NonEmptyVec::from(Sequence::Single(
516                SeqOrUid::Value(NonZeroU32::new(1).unwrap())
517            ))))
518        );
519        assert_eq!(
520            SequenceSet::try_from(0),
521            Err(ValidationError::new(ValidationErrorKind::Invalid))
522        );
523    }
524
525    #[test]
526    fn test_creation_of_sequence_from_range() {
527        // 1:*
528        let range = ..;
529        let seq = Sequence::from(range);
530        assert_eq!(
531            seq,
532            Sequence::Range(
533                SeqOrUid::Value(NonZeroU32::new(1).unwrap()),
534                SeqOrUid::Asterisk
535            )
536        );
537
538        // 1:*
539        let range = 1..;
540        let seq = Sequence::try_from(range).unwrap();
541        assert_eq!(
542            seq,
543            Sequence::Range(
544                SeqOrUid::Value(NonZeroU32::new(1).unwrap()),
545                SeqOrUid::Asterisk
546            )
547        );
548
549        // 1337:*
550        let range = 1337..;
551        let seq = Sequence::try_from(range).unwrap();
552        assert_eq!(
553            seq,
554            Sequence::Range(
555                SeqOrUid::Value(NonZeroU32::new(1337).unwrap()),
556                SeqOrUid::Asterisk
557            )
558        );
559
560        // 1:1336
561        let range = 1..1337;
562        let seq = Sequence::try_from(range).unwrap();
563        assert_eq!(
564            seq,
565            Sequence::Range(
566                SeqOrUid::Value(NonZeroU32::new(1).unwrap()),
567                SeqOrUid::Value(NonZeroU32::new(1336).unwrap())
568            )
569        );
570
571        // 1:1337
572        let range = 1..=1337;
573        let seq = Sequence::try_from(range).unwrap();
574        assert_eq!(
575            seq,
576            Sequence::Range(
577                SeqOrUid::Value(NonZeroU32::new(1).unwrap()),
578                SeqOrUid::Value(NonZeroU32::new(1337).unwrap())
579            )
580        );
581
582        // 1:1336
583        let range = ..1337;
584        let seq = Sequence::try_from(range).unwrap();
585        assert_eq!(
586            seq,
587            Sequence::Range(
588                SeqOrUid::Value(NonZeroU32::new(1).unwrap()),
589                SeqOrUid::Value(NonZeroU32::new(1336).unwrap())
590            )
591        );
592
593        // 1:1337
594        let range = ..=1337;
595        let seq = Sequence::try_from(range).unwrap();
596        assert_eq!(
597            seq,
598            Sequence::Range(
599                SeqOrUid::Value(NonZeroU32::new(1).unwrap()),
600                SeqOrUid::Value(NonZeroU32::new(1337).unwrap())
601            )
602        );
603    }
604
605    #[test]
606    fn test_creation_of_sequence_set_from_str_positive() {
607        let tests = &[
608            (
609                "1",
610                SequenceSet(
611                    vec![Sequence::Single(SeqOrUid::Value(1.try_into().unwrap()))]
612                        .try_into()
613                        .unwrap(),
614                ),
615            ),
616            (
617                "1,2,3",
618                SequenceSet(
619                    vec![
620                        Sequence::Single(SeqOrUid::Value(1.try_into().unwrap())),
621                        Sequence::Single(SeqOrUid::Value(2.try_into().unwrap())),
622                        Sequence::Single(SeqOrUid::Value(3.try_into().unwrap())),
623                    ]
624                    .try_into()
625                    .unwrap(),
626                ),
627            ),
628            (
629                "*",
630                SequenceSet(
631                    vec![Sequence::Single(SeqOrUid::Asterisk)]
632                        .try_into()
633                        .unwrap(),
634                ),
635            ),
636            (
637                "1:2",
638                SequenceSet(
639                    vec![Sequence::Range(
640                        SeqOrUid::Value(1.try_into().unwrap()),
641                        SeqOrUid::Value(2.try_into().unwrap()),
642                    )]
643                    .try_into()
644                    .unwrap(),
645                ),
646            ),
647            (
648                "1:2,3",
649                SequenceSet(
650                    vec![
651                        Sequence::Range(
652                            SeqOrUid::Value(1.try_into().unwrap()),
653                            SeqOrUid::Value(2.try_into().unwrap()),
654                        ),
655                        Sequence::Single(SeqOrUid::Value(3.try_into().unwrap())),
656                    ]
657                    .try_into()
658                    .unwrap(),
659                ),
660            ),
661            (
662                "1:2,3,*",
663                SequenceSet(
664                    vec![
665                        Sequence::Range(
666                            SeqOrUid::Value(1.try_into().unwrap()),
667                            SeqOrUid::Value(2.try_into().unwrap()),
668                        ),
669                        Sequence::Single(SeqOrUid::Value(3.try_into().unwrap())),
670                        Sequence::Single(SeqOrUid::Asterisk),
671                    ]
672                    .try_into()
673                    .unwrap(),
674                ),
675            ),
676        ];
677
678        for (test, expected) in tests.iter() {
679            let got = SequenceSet::try_from(*test).unwrap();
680            assert_eq!(*expected, got);
681        }
682    }
683
684    #[test]
685    fn test_creation_of_sequence_set_from_str_negative() {
686        let tests = &[
687            "", "* ", " *", " * ", "1 ", " 1", " 1 ", "01", " 01", "01 ", " 01 ", "*1", ":", ":*",
688            "*:", "*: ", "1:2:3",
689        ];
690
691        for test in tests {
692            let got = SequenceSet::try_from(*test);
693            print!("\"{}\" | {:?} | ", test, got.clone().unwrap_err());
694            println!("{}", got.unwrap_err());
695        }
696    }
697
698    #[test]
699    fn test_iteration_over_some_sequence_sets() {
700        let tests = vec![
701            ("*", vec![3]),
702            ("1:*", vec![1, 2, 3]),
703            ("5,1:*,2:*", vec![5, 1, 2, 3, 2, 3]),
704            ("*:2", vec![]),
705            ("*:*", vec![3]),
706            ("4:6,*", vec![4, 5, 6, 3]),
707        ]
708        .into_iter()
709        .map(|(raw, vec)| {
710            (
711                raw,
712                vec.into_iter()
713                    .map(|num| num.try_into().unwrap())
714                    .collect::<Vec<NonZeroU32>>(),
715            )
716        })
717        .collect::<Vec<(&str, Vec<NonZeroU32>)>>();
718
719        for (test, expected) in tests {
720            let seq_set = SequenceSet::try_from(test).unwrap();
721            let got: Vec<NonZeroU32> = seq_set
722                .iter(Strategy::Naive {
723                    largest: 3.try_into().unwrap(),
724                })
725                .collect();
726            assert_eq!(*expected, got);
727        }
728    }
729}