Skip to content

Commit

Permalink
refactor!: Align CommandBody::{Search,Sort} with RFC
Browse files Browse the repository at this point in the history
  • Loading branch information
duesee committed Jan 16, 2024
1 parent 73f4040 commit 30ff8c3
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 41 deletions.
4 changes: 2 additions & 2 deletions imap-codec/src/codec/encode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -441,7 +441,7 @@ impl<'a> EncodeIntoContext for CommandBody<'a> {
charset.encode_ctx(ctx)?;
}
ctx.write_all(b" ")?;
criteria.encode_ctx(ctx)
join_serializable(criteria.as_ref(), b" ", ctx)
}
#[cfg(feature = "ext_sort_thread")]
CommandBody::Sort {
Expand All @@ -459,7 +459,7 @@ impl<'a> EncodeIntoContext for CommandBody<'a> {
ctx.write_all(b") ")?;
charset.encode_ctx(ctx)?;
ctx.write_all(b" ")?;
search_criteria.encode_ctx(ctx)
join_serializable(search_criteria.as_ref(), b" ", ctx)
}
CommandBody::Fetch {
sequence_set,
Expand Down
45 changes: 20 additions & 25 deletions imap-codec/src/search.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ use abnf_core::streaming::sp;
use imap_types::core::Charset;
use imap_types::{command::CommandBody, core::NonEmptyVec, search::SearchKey};
#[cfg(feature = "ext_sort_thread")]
use nom::sequence::pair;
use nom::sequence::separated_pair;
use nom::{
branch::alt,
bytes::streaming::{tag, tag_no_case},
combinator::{map, map_opt, opt, value},
multi::{many1, separated_list1},
sequence::{delimited, preceded, tuple},
multi::separated_list1,
sequence::{delimited, tuple},
};

use crate::{
Expand All @@ -32,16 +32,11 @@ pub(crate) fn search(input: &[u8]) -> IMAPResult<&[u8], CommandBody> {
tuple((sp, tag_no_case(b"CHARSET"), sp, charset)),
|(_, _, _, charset)| charset,
)),
many1(preceded(sp, search_key(9))),
sp,
map(separated_list1(sp, search_key(9)), NonEmptyVec::unvalidated),
));

let (remaining, (_, charset, mut criteria)) = parser(input)?;

let criteria = match criteria.len() {
0 => unreachable!(),
1 => criteria.pop().unwrap(),
_ => SearchKey::And(NonEmptyVec::unvalidated(criteria)),
};
let (remaining, (_, charset, _, criteria)) = parser(input)?;

Ok((
remaining,
Expand Down Expand Up @@ -230,18 +225,18 @@ fn search_key_limited<'a>(
/// ```abnf
/// search-criteria = charset 1*(SP search-key)
/// ```
pub(crate) fn search_criteria(input: &[u8]) -> IMAPResult<&[u8], (Charset, SearchKey)> {
let mut parser = pair(charset, many1(preceded(sp, search_key(9))));
pub(crate) fn search_criteria(
input: &[u8],
) -> IMAPResult<&[u8], (Charset, NonEmptyVec<SearchKey>)> {
let mut parser = separated_pair(
charset,
sp,
map(separated_list1(sp, search_key(9)), NonEmptyVec::unvalidated),
);

let (remaining, (charset, mut search_key)) = parser(input)?;
let (remaining, (charset, search_keys)) = parser(input)?;

let search_key = match search_key.len() {
0 => unreachable!(),
1 => search_key.pop().unwrap(),
_ => SearchKey::And(NonEmptyVec::unvalidated(search_key)),
};

Ok((remaining, (charset, search_key)))
Ok((remaining, (charset, search_keys)))
}

#[cfg(test)]
Expand All @@ -267,19 +262,19 @@ mod tests {
val,
CommandBody::Search {
charset: None,
criteria: And(NonEmptyVec::from(Uid(SequenceSetData(
criteria: NonEmptyVec::from(And(NonEmptyVec::from(Uid(SequenceSetData(
vec![Single(Value(5.try_into().unwrap()))]
.try_into()
.unwrap()
)))),
))))),
uid: false,
}
);

let (_rem, val) = search(b"search (uid 5 or uid 5 (uid 1 uid 2) not uid 5)???").unwrap();
let expected = CommandBody::Search {
charset: None,
criteria: And(vec![
criteria: NonEmptyVec::from(And(vec![
Uid(SequenceSetData(
vec![Single(Value(5.try_into().unwrap()))]
.try_into()
Expand Down Expand Up @@ -313,7 +308,7 @@ mod tests {
)))),
]
.try_into()
.unwrap()),
.unwrap())),
uid: false,
};
assert_eq!(val, expected);
Expand Down
46 changes: 32 additions & 14 deletions imap-types/src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1015,7 +1015,7 @@ pub enum CommandBody<'a> {
/// Charset.
charset: Option<Charset<'a>>,
/// Criteria.
criteria: SearchKey<'a>,
criteria: NonEmptyVec<SearchKey<'a>>,
/// Use UID variant.
uid: bool,
},
Expand All @@ -1038,7 +1038,7 @@ pub enum CommandBody<'a> {
/// Charset.
charset: Charset<'a>,
/// Search criteria.
search_criteria: SearchKey<'a>,
search_criteria: NonEmptyVec<SearchKey<'a>>,
/// Use UID variant.
uid: bool,
},
Expand Down Expand Up @@ -1581,7 +1581,11 @@ impl<'a> CommandBody<'a> {
}

/// Construct a SEARCH command.
pub fn search(charset: Option<Charset<'a>>, criteria: SearchKey<'a>, uid: bool) -> Self {
pub fn search(
charset: Option<Charset<'a>>,
criteria: NonEmptyVec<SearchKey<'a>>,
uid: bool,
) -> Self {
CommandBody::Search {
charset,
criteria,
Expand Down Expand Up @@ -1836,45 +1840,59 @@ mod tests {
CommandBody::Expunge,
CommandBody::search(
None,
SearchKey::And(
NonEmptyVec::from(SearchKey::And(
vec![SearchKey::All, SearchKey::New, SearchKey::Unseen]
.try_into()
.unwrap(),
),
)),
false,
),
CommandBody::search(
None,
SearchKey::And(
NonEmptyVec::from(SearchKey::And(
vec![SearchKey::All, SearchKey::New, SearchKey::Unseen]
.try_into()
.unwrap(),
),
)),
true,
),
CommandBody::search(
None,
SearchKey::And(
NonEmptyVec::from(SearchKey::And(
vec![SearchKey::SequenceSet(SequenceSet(
vec![Sequence::Single(SeqOrUid::Value(42.try_into().unwrap()))]
.try_into()
.unwrap(),
))]
.try_into()
.unwrap(),
),
)),
true,
),
CommandBody::search(
None,
NonEmptyVec::from(SearchKey::SequenceSet("42".try_into().unwrap())),
true,
),
CommandBody::search(None, SearchKey::SequenceSet("42".try_into().unwrap()), true),
CommandBody::search(None, SearchKey::SequenceSet("*".try_into().unwrap()), true),
CommandBody::search(
None,
SearchKey::Or(Box::new(SearchKey::Draft), Box::new(SearchKey::All)),
NonEmptyVec::from(SearchKey::SequenceSet("*".try_into().unwrap())),
true,
),
CommandBody::search(
None,
NonEmptyVec::from(SearchKey::Or(
Box::new(SearchKey::Draft),
Box::new(SearchKey::All),
)),
true,
),
CommandBody::search(
Some(Charset::try_from("UTF-8").unwrap()),
SearchKey::Or(Box::new(SearchKey::Draft), Box::new(SearchKey::All)),
NonEmptyVec::from(SearchKey::Or(
Box::new(SearchKey::Draft),
Box::new(SearchKey::All),
)),
true,
),
CommandBody::fetch(
Expand Down Expand Up @@ -2021,7 +2039,7 @@ mod tests {
(
CommandBody::Search {
charset: None,
criteria: SearchKey::Recent,
criteria: NonEmptyVec::from(SearchKey::Recent),
uid: true,
},
"SEARCH",
Expand Down

0 comments on commit 30ff8c3

Please sign in to comment.