1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
use nom::{
    branch::alt,
    bytes::streaming::tag,
    combinator::{map, value},
    multi::separated_list1,
    sequence::tuple,
    IResult,
};

use crate::{
    parse::core::nz_number,
    types::sequence::{SeqNo, Sequence, SequenceSet},
};

/// Set of seq-number values, regardless of order.
/// Servers MAY coalesce overlaps and/or execute the sequence in any order.
///
/// Example: a message sequence number set of
/// 2,4:7,9,12:* for a mailbox with 15 messages is
/// equivalent to 2,4,5,6,7,9,12,13,14,15
///
/// Example: a message sequence number set of *:4,5:7
/// for a mailbox with 10 messages is equivalent to
/// 10,9,8,7,6,5,4,5,6,7 and MAY be reordered and
/// overlap coalesced to be 4,5,6,7,8,9,10.
///
/// ; errata id: 261
/// sequence-set = (seq-number / seq-range) ["," sequence-set]
///
/// Simplified:
///
/// sequence-set = (seq-number / seq-range) *("," (seq-number / seq-range))
///
/// TODO: Why the errata?
pub(crate) fn sequence_set(input: &[u8]) -> IResult<&[u8], SequenceSet> {
    map(
        separated_list1(
            tag(b","),
            alt((
                // Ordering is important!
                map(seq_range, |(from, to)| Sequence::Range(from, to)),
                map(seq_number, Sequence::Single),
            )),
        ),
        |sequence_set| SequenceSet(sequence_set),
    )(input)
}

/// Two seq-number values and all values between these two regardless of order.
///
/// Example: 2:4 and 4:2 are equivalent and indicate values 2, 3, and 4.
///
/// Example: a unique identifier sequence range of 3291:* includes the UID
///          of the last message in the mailbox, even if that value is less than 3291.
///
/// seq-range = seq-number ":" seq-number
fn seq_range(input: &[u8]) -> IResult<&[u8], (SeqNo, SeqNo)> {
    let mut parser = tuple((seq_number, tag(b":"), seq_number));

    let (remaining, (from, _, to)) = parser(input)?;

    Ok((remaining, (from, to)))
}

/// Message sequence number (COPY, FETCH, STORE commands) or unique
/// identifier (UID COPY, UID FETCH, UID STORE commands).
///
/// * represents the largest number in use.
/// In the case of message sequence numbers, it is the number of messages in a non-empty mailbox.
/// In the case of unique identifiers, it is the unique identifier of the last message in the mailbox or,
/// if the mailbox is empty, the mailbox's current UIDNEXT value.
///
/// The server should respond with a tagged BAD response to a command that uses a message
/// sequence number greater than the number of messages in the selected mailbox.
/// This includes "*" if the selected mailbox is empty.
///
/// seq-number = nz-number / "*"
fn seq_number(input: &[u8]) -> IResult<&[u8], SeqNo> {
    alt((
        map(nz_number, SeqNo::Value),
        value(SeqNo::Largest, tag(b"*")),
    ))(input)
}

#[cfg(test)]
mod test {
    use std::convert::TryInto;

    use super::*;

    #[test]
    fn test_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_seq_number() {
        // Must not be 0.
        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_seq_range() {
        // Must not be 0.
        assert!(seq_range(b"0:1?").is_err());

        assert_eq!(
            (
                SeqNo::Value(1.try_into().unwrap()),
                SeqNo::Value(2.try_into().unwrap())
            ),
            seq_range(b"1:2?").unwrap().1
        );
        assert_eq!(
            (SeqNo::Value(1.try_into().unwrap()), SeqNo::Largest),
            seq_range(b"1:*?").unwrap().1
        );
        assert_eq!(
            (SeqNo::Largest, SeqNo::Value(10.try_into().unwrap())),
            seq_range(b"*:10?").unwrap().1
        );
    }
}