use std::ops::RangeInclusive;
use nom::{
branch::alt,
bytes::streaming::{tag, tag_no_case},
combinator::map,
multi::separated_list1,
sequence::preceded,
IResult, Parser,
};
use crate::core::number;
use crate::rfc3501::ResponseCode;
pub(crate) fn resp_text_code_append_uid(i: &[u8]) -> IResult<&[u8], ResponseCode<'_>> {
map(
preceded(tag_no_case("APPENDUID "), (number, tag(" "), uid_set)),
|(fst, _, snd)| ResponseCode::AppendUid(fst, snd),
)
.parse(i)
}
pub(crate) fn resp_text_code_copy_uid(i: &[u8]) -> IResult<&[u8], ResponseCode<'_>> {
map(
preceded(
tag_no_case("COPYUID "),
(number, tag(" "), uid_set, tag(" "), uid_set),
),
|(fst, _, snd, _, trd)| ResponseCode::CopyUid(fst, snd, trd),
)
.parse(i)
}
pub(crate) fn resp_text_code_uid_not_sticky(i: &[u8]) -> IResult<&[u8], ResponseCode<'_>> {
map(tag_no_case("UIDNOTSTICKY"), |_| ResponseCode::UidNotSticky).parse(i)
}
fn uid_set(i: &[u8]) -> IResult<&[u8], Vec<UidSetMember>> {
separated_list1(tag(","), UidSetMember::parse).parse(i)
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum UidSetMember {
UidRange(RangeInclusive<u32>),
Uid(u32),
}
impl UidSetMember {
fn parse(i: &[u8]) -> IResult<&[u8], Self> {
alt((uid_range, map(number, From::from))).parse(i)
}
}
impl From<RangeInclusive<u32>> for UidSetMember {
fn from(x: RangeInclusive<u32>) -> Self {
UidSetMember::UidRange(x)
}
}
impl From<u32> for UidSetMember {
fn from(x: u32) -> Self {
UidSetMember::Uid(x)
}
}
fn uid_range(i: &[u8]) -> IResult<&[u8], UidSetMember> {
map(
nom::sequence::separated_pair(number, tag(":"), number),
|(fst, snd)| if fst <= snd { fst..=snd } else { snd..=fst }.into(),
)
.parse(i)
}