fixup! adjust parse_until_done to return an Option so it is more versatile
This commit is contained in:
parent
6146e0c399
commit
b3529a058f
3 changed files with 55 additions and 40 deletions
82
src/parse.rs
82
src/parse.rs
|
|
@ -63,37 +63,6 @@ where
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse and return an expected single `T` Response with `F`.
|
|
||||||
/// Responses other than `T` go into the `unsolicited` channel.
|
|
||||||
///
|
|
||||||
/// If more than one `T` are found then [`Error::Parse`] is returned
|
|
||||||
/// If zero `T` are found and optional is false then [`Error::Parse`] is returned, otherwise None is
|
|
||||||
pub(crate) fn parse_until_done<'input, T, F>(
|
|
||||||
input: &'input [u8],
|
|
||||||
optional: bool,
|
|
||||||
unsolicited: &mut mpsc::Sender<UnsolicitedResponse>,
|
|
||||||
map: F,
|
|
||||||
) -> Result<Option<T>>
|
|
||||||
where
|
|
||||||
F: FnMut(Response<'input>) -> Result<MapOrNot<'input, T>>,
|
|
||||||
{
|
|
||||||
let mut temp_output = Vec::<T>::new();
|
|
||||||
|
|
||||||
parse_many_into(input, &mut temp_output, unsolicited, map)?;
|
|
||||||
|
|
||||||
match temp_output.len() {
|
|
||||||
1 => Ok(Some(temp_output.remove(0))),
|
|
||||||
0 => {
|
|
||||||
if optional {
|
|
||||||
Ok(None)
|
|
||||||
} else {
|
|
||||||
Err(Error::Parse(ParseError::Invalid(input.to_vec())))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => Err(Error::Parse(ParseError::Invalid(input.to_vec()))),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) enum MapOrNot2<'a, T, U> {
|
pub(crate) enum MapOrNot2<'a, T, U> {
|
||||||
Map1(T),
|
Map1(T),
|
||||||
Map2(U),
|
Map2(U),
|
||||||
|
|
@ -101,7 +70,6 @@ pub(crate) enum MapOrNot2<'a, T, U> {
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
MapVec2(Vec<U>),
|
MapVec2(Vec<U>),
|
||||||
Not(Response<'a>),
|
Not(Response<'a>),
|
||||||
#[allow(dead_code)]
|
|
||||||
Ignore,
|
Ignore,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -149,6 +117,56 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_until_done_internal<'input, T, F>(
|
||||||
|
input: &'input [u8],
|
||||||
|
optional: bool,
|
||||||
|
unsolicited: &mut mpsc::Sender<UnsolicitedResponse>,
|
||||||
|
map: F,
|
||||||
|
) -> Result<Option<T>>
|
||||||
|
where
|
||||||
|
F: FnMut(Response<'input>) -> Result<MapOrNot<'input, T>>,
|
||||||
|
{
|
||||||
|
let mut temp_output = Vec::<T>::new();
|
||||||
|
|
||||||
|
parse_many_into(input, &mut temp_output, unsolicited, map)?;
|
||||||
|
|
||||||
|
match temp_output.len() {
|
||||||
|
1 => Ok(Some(temp_output.remove(0))),
|
||||||
|
0 if optional => Ok(None),
|
||||||
|
_ => Err(Error::Parse(ParseError::Invalid(input.to_vec()))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parse and return an optional single `T` Response with `F`.
|
||||||
|
/// Responses other than `T` go into the `unsolicited` channel.
|
||||||
|
///
|
||||||
|
/// If more than one `T` are found then [`Error::Parse`] is returned
|
||||||
|
pub(crate) fn parse_until_done_optional<'input, T, F>(
|
||||||
|
input: &'input [u8],
|
||||||
|
unsolicited: &mut mpsc::Sender<UnsolicitedResponse>,
|
||||||
|
map: F,
|
||||||
|
) -> Result<Option<T>>
|
||||||
|
where
|
||||||
|
F: FnMut(Response<'input>) -> Result<MapOrNot<'input, T>>,
|
||||||
|
{
|
||||||
|
parse_until_done_internal(input, true, unsolicited, map)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parse and return an expected single `T` Response with `F`.
|
||||||
|
/// Responses other than `T` go into the `unsolicited` channel.
|
||||||
|
///
|
||||||
|
/// If zero or more than one `T` are found then [`Error::Parse`] is returned.
|
||||||
|
pub(crate) fn parse_until_done<'input, T, F>(
|
||||||
|
input: &'input [u8],
|
||||||
|
unsolicited: &mut mpsc::Sender<UnsolicitedResponse>,
|
||||||
|
map: F,
|
||||||
|
) -> Result<T>
|
||||||
|
where
|
||||||
|
F: FnMut(Response<'input>) -> Result<MapOrNot<'input, T>>,
|
||||||
|
{
|
||||||
|
parse_until_done_internal(input, false, unsolicited, map).map(|e| e.unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn parse_expunge(
|
pub fn parse_expunge(
|
||||||
lines: Vec<u8>,
|
lines: Vec<u8>,
|
||||||
unsolicited: &mut mpsc::Sender<UnsolicitedResponse>,
|
unsolicited: &mut mpsc::Sender<UnsolicitedResponse>,
|
||||||
|
|
|
||||||
|
|
@ -123,7 +123,7 @@ impl AclResponse {
|
||||||
data: owned,
|
data: owned,
|
||||||
acl_builder: |input| {
|
acl_builder: |input| {
|
||||||
// There should only be ONE single ACL response
|
// There should only be ONE single ACL response
|
||||||
parse_until_done(input, false, unsolicited, |response| match response {
|
parse_until_done(input, unsolicited, |response| match response {
|
||||||
Response::Acl(a) => Ok(MapOrNot::Map(Acl {
|
Response::Acl(a) => Ok(MapOrNot::Map(Acl {
|
||||||
mailbox: a.mailbox,
|
mailbox: a.mailbox,
|
||||||
acls: a
|
acls: a
|
||||||
|
|
@ -137,7 +137,6 @@ impl AclResponse {
|
||||||
})),
|
})),
|
||||||
resp => Ok(MapOrNot::Not(resp)),
|
resp => Ok(MapOrNot::Not(resp)),
|
||||||
})
|
})
|
||||||
.map(|o| o.unwrap())
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
.try_build()
|
.try_build()
|
||||||
|
|
@ -207,7 +206,7 @@ impl ListRightsResponse {
|
||||||
data: owned,
|
data: owned,
|
||||||
rights_builder: |input| {
|
rights_builder: |input| {
|
||||||
// There should only be ONE single LISTRIGHTS response
|
// There should only be ONE single LISTRIGHTS response
|
||||||
parse_until_done(input, false, unsolicited, |response| match response {
|
parse_until_done(input, unsolicited, |response| match response {
|
||||||
Response::ListRights(a) => Ok(MapOrNot::Map(ListRights {
|
Response::ListRights(a) => Ok(MapOrNot::Map(ListRights {
|
||||||
mailbox: a.mailbox,
|
mailbox: a.mailbox,
|
||||||
identifier: a.identifier,
|
identifier: a.identifier,
|
||||||
|
|
@ -216,7 +215,6 @@ impl ListRightsResponse {
|
||||||
})),
|
})),
|
||||||
resp => Ok(MapOrNot::Not(resp)),
|
resp => Ok(MapOrNot::Not(resp)),
|
||||||
})
|
})
|
||||||
.map(|o| o.unwrap())
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
.try_build()
|
.try_build()
|
||||||
|
|
@ -288,14 +286,13 @@ impl MyRightsResponse {
|
||||||
data: owned,
|
data: owned,
|
||||||
rights_builder: |input| {
|
rights_builder: |input| {
|
||||||
// There should only be ONE single MYRIGHTS response
|
// There should only be ONE single MYRIGHTS response
|
||||||
parse_until_done(input, false, unsolicited, |response| match response {
|
parse_until_done(input, unsolicited, |response| match response {
|
||||||
Response::MyRights(a) => Ok(MapOrNot::Map(MyRights {
|
Response::MyRights(a) => Ok(MapOrNot::Map(MyRights {
|
||||||
mailbox: a.mailbox,
|
mailbox: a.mailbox,
|
||||||
rights: a.rights.into(),
|
rights: a.rights.into(),
|
||||||
})),
|
})),
|
||||||
resp => Ok(MapOrNot::Not(resp)),
|
resp => Ok(MapOrNot::Not(resp)),
|
||||||
})
|
})
|
||||||
.map(|o| o.unwrap())
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
.try_build()
|
.try_build()
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::error::{Error, ParseError};
|
use crate::error::{Error, ParseError};
|
||||||
use crate::parse::{parse_many_into2, parse_until_done, MapOrNot, MapOrNot2};
|
use crate::parse::{parse_many_into2, parse_until_done_optional, MapOrNot, MapOrNot2};
|
||||||
use crate::types::UnsolicitedResponse;
|
use crate::types::UnsolicitedResponse;
|
||||||
use imap_proto::Response;
|
use imap_proto::Response;
|
||||||
use ouroboros::self_referencing;
|
use ouroboros::self_referencing;
|
||||||
|
|
@ -90,7 +90,7 @@ impl QuotaResponse {
|
||||||
data: owned,
|
data: owned,
|
||||||
quota_builder: |input| {
|
quota_builder: |input| {
|
||||||
// There should zero or one QUOTA response
|
// There should zero or one QUOTA response
|
||||||
parse_until_done(input, true, unsolicited, |response| match response {
|
parse_until_done_optional(input, unsolicited, |response| match response {
|
||||||
Response::Quota(q) => Ok(MapOrNot::Map(Quota::from_imap_proto(q))),
|
Response::Quota(q) => Ok(MapOrNot::Map(Quota::from_imap_proto(q))),
|
||||||
resp => Ok(MapOrNot::Not(resp)),
|
resp => Ok(MapOrNot::Not(resp)),
|
||||||
})
|
})
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue