use abnf_core::streaming::sp;
use imap_types::flag::{Flag, FlagFetch, FlagNameAttribute, FlagPerm};
use nom::{
branch::alt,
bytes::streaming::tag,
character::streaming::char,
combinator::{map, recognize, value},
multi::{separated_list0, separated_list1},
sequence::{delimited, preceded, tuple},
};
use crate::{core::atom, decode::IMAPResult};
pub(crate) fn flag(input: &[u8]) -> IMAPResult<&[u8], Flag> {
alt((
map(preceded(char('\\'), atom), Flag::system),
map(atom, Flag::Keyword),
))(input)
}
pub(crate) fn flag_list(input: &[u8]) -> IMAPResult<&[u8], Vec<Flag>> {
delimited(tag(b"("), separated_list0(sp, flag), tag(b")"))(input)
}
pub(crate) fn flag_fetch(input: &[u8]) -> IMAPResult<&[u8], FlagFetch> {
if let Ok((rem, peek)) = recognize(tuple((char('\\'), atom)))(input) {
if peek.to_ascii_lowercase() == b"\\recent" {
return Ok((rem, FlagFetch::Recent));
}
}
map(flag, FlagFetch::Flag)(input)
}
pub(crate) fn flag_perm(input: &[u8]) -> IMAPResult<&[u8], FlagPerm> {
alt((
value(FlagPerm::Asterisk, tag("\\*")),
map(flag, FlagPerm::Flag),
))(input)
}
pub(crate) fn mbx_list_flags(input: &[u8]) -> IMAPResult<&[u8], Vec<FlagNameAttribute>> {
let (remaining, flags) =
separated_list1(sp, map(preceded(char('\\'), atom), FlagNameAttribute::from))(input)?;
Ok((remaining, flags))
}
#[cfg(test)]
mod tests {
use imap_types::{
core::Atom,
flag::{Flag, FlagFetch, FlagNameAttribute, FlagPerm},
};
use super::*;
#[test]
fn test_parse_flag_fetch() {
let tests = [(
"iS)",
FlagFetch::Flag(Flag::Keyword(Atom::try_from("iS").unwrap())),
)];
for (test, expected) in tests {
let (rem, got) = flag_fetch(test.as_bytes()).unwrap();
assert_eq!(rem.len(), 1);
assert_eq!(expected, got);
}
}
#[test]
fn test_parse_flag_perm() {
let tests = [
("\\Deleted)", FlagPerm::Flag(Flag::Deleted)),
(
"\\Deletedx)",
FlagPerm::Flag(Flag::system(Atom::try_from("Deletedx").unwrap())),
),
("\\Seen ", FlagPerm::Flag(Flag::Seen)),
("\\*)", FlagPerm::Asterisk),
];
for (test, expected) in tests {
let (rem, got) = flag_perm(test.as_bytes()).unwrap();
assert_eq!(rem.len(), 1);
assert_eq!(expected, got);
}
}
#[test]
fn test_parse_mbx_list_flags() {
let tests = [
(
"\\Markedm)",
vec![FlagNameAttribute::from(Atom::try_from("Markedm").unwrap())],
),
("\\Marked)", vec![FlagNameAttribute::Marked]),
];
for (test, expected) in tests {
let (rem, got) = mbx_list_flags(test.as_bytes()).unwrap();
assert_eq!(expected, got);
assert_eq!(rem.len(), 1);
}
}
}