diff --git a/imap-types/src/sequence.rs b/imap-types/src/sequence.rs index 95bee9f6..d513616c 100644 --- a/imap-types/src/sequence.rs +++ b/imap-types/src/sequence.rs @@ -1,4 +1,5 @@ use std::{ + fmt::{Debug, Formatter}, num::NonZeroU32, ops::{Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive}, str::FromStr, @@ -464,13 +465,22 @@ pub enum Strategy { Naive { largest: NonZeroU32 }, } -#[derive(Debug)] pub struct SequenceSetIterNaive<'a> { iter: core::slice::Iter<'a, Sequence>, - active_range: Option>, + active_range: Option>>, largest: NonZeroU32, } +impl<'a> Debug for SequenceSetIterNaive<'a> { + fn fmt(&self, f: &mut Formatter) -> std::fmt::Result { + f.debug_struct("SequenceSetIterNaive") + .field("iter", &self.iter) + .field("active_range", &"") + .field("largest", &self.largest) + .finish() + } +} + impl<'a> Iterator for SequenceSetIterNaive<'a> { type Item = NonZeroU32; @@ -492,7 +502,11 @@ impl<'a> Iterator for SequenceSetIterNaive<'a> { Sequence::Range(from, to) => { let from = from.expand(self.largest); let to = to.expand(self.largest); - self.active_range = Some(u32::from(from)..=u32::from(to)); + self.active_range = if from <= to { + Some(Box::new(u32::from(from)..=u32::from(to))) + } else { + Some(Box::new((u32::from(to)..=u32::from(from)).rev())) + }; } }, None => return None, @@ -701,7 +715,7 @@ mod tests { ("*", vec![3]), ("1:*", vec![1, 2, 3]), ("5,1:*,2:*", vec![5, 1, 2, 3, 2, 3]), - ("*:2", vec![]), + ("*:2", vec![3, 2]), ("*:*", vec![3]), ("4:6,*", vec![4, 5, 6, 3]), ] @@ -726,4 +740,18 @@ mod tests { assert_eq!(*expected, got); } } + + /// See https://github.com/duesee/imap-codec/issues/411 + #[test] + fn test_issue_411() { + let seq = SequenceSet::try_from("22,21,22,*:20").unwrap(); + let largest = NonZeroU32::new(23).unwrap(); + + let expected = [22, 21, 22, 23, 22, 21, 20] + .map(|n| NonZeroU32::new(n).unwrap()) + .to_vec(); + let got: Vec<_> = seq.iter(Strategy::Naive { largest }).collect(); + + assert_eq!(expected, got); + } }