use imap_types::{
core::NonEmptyVec,
sequence::{SeqOrUid, Sequence, SequenceSet},
};
use nom::{
branch::alt,
bytes::streaming::tag,
combinator::{map, value},
multi::separated_list1,
sequence::tuple,
};
use crate::{core::nz_number, decode::IMAPResult};
pub(crate) fn sequence_set(input: &[u8]) -> IMAPResult<&[u8], SequenceSet> {
map(
separated_list1(
tag(b","),
alt((
map(seq_range, |(from, to)| Sequence::Range(from, to)),
map(seq_number, Sequence::Single),
)),
),
|set| SequenceSet(NonEmptyVec::unvalidated(set)),
)(input)
}
pub(crate) fn seq_range(input: &[u8]) -> IMAPResult<&[u8], (SeqOrUid, SeqOrUid)> {
let mut parser = tuple((seq_number, tag(b":"), seq_number));
let (remaining, (from, _, to)) = parser(input)?;
Ok((remaining, (from, to)))
}
pub(crate) fn seq_number(input: &[u8]) -> IMAPResult<&[u8], SeqOrUid> {
alt((
map(nz_number, SeqOrUid::Value),
value(SeqOrUid::Asterisk, tag(b"*")),
))(input)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::encode::{EncodeContext, EncodeIntoContext};
#[test]
fn test_encode_of_some_sequence_sets() {
let tests = [
(
Sequence::Single(SeqOrUid::Value(1.try_into().unwrap())),
b"1".as_ref(),
),
(Sequence::Single(SeqOrUid::Asterisk), b"*".as_ref()),
(
Sequence::Range(SeqOrUid::Value(1.try_into().unwrap()), SeqOrUid::Asterisk),
b"1:*".as_ref(),
),
];
for (test, expected) in tests {
let mut ctx = EncodeContext::new();
test.encode_ctx(&mut ctx).unwrap();
let out = ctx.dump();
assert_eq!(*expected, out);
}
}
#[test]
fn test_parse_sequence_set() {
let (rem, val) = sequence_set(b"1:*?").unwrap();
println!("{:?}, {:?}", rem, val);
let (rem, val) = sequence_set(b"1:*,5?").unwrap();
println!("{:?}, {:?}", rem, val);
}
#[test]
fn test_parse_seq_number() {
assert!(seq_number(b"0?").is_err());
let (rem, val) = seq_number(b"1?").unwrap();
println!("{:?}, {:?}", rem, val);
let (rem, val) = seq_number(b"*?").unwrap();
println!("{:?}, {:?}", rem, val);
}
#[test]
fn test_parse_seq_range() {
assert!(seq_range(b"0:1?").is_err());
assert_eq!(
(
SeqOrUid::Value(1.try_into().unwrap()),
SeqOrUid::Value(2.try_into().unwrap())
),
seq_range(b"1:2?").unwrap().1
);
assert_eq!(
(SeqOrUid::Value(1.try_into().unwrap()), SeqOrUid::Asterisk),
seq_range(b"1:*?").unwrap().1
);
assert_eq!(
(SeqOrUid::Asterisk, SeqOrUid::Value(10.try_into().unwrap())),
seq_range(b"*:10?").unwrap().1
);
}
}