diff --git a/Justfile b/Justfile new file mode 100644 index 0000000..5de3e0b --- /dev/null +++ b/Justfile @@ -0,0 +1,2 @@ +fmt: + cargo +nightly fmt --all diff --git a/imap/src/proto/macros.rs b/imap/src/proto/macros.rs index 308beaf..2d76e85 100644 --- a/imap/src/proto/macros.rs +++ b/imap/src/proto/macros.rs @@ -1,3 +1,4 @@ +#[macro_export] macro_rules! rule { ($vis:vis $name:ident : $ret:ty => $expr:expr) => { $vis fn $name(i: &[u8]) -> nom::IResult<&[u8], $ret> { @@ -5,3 +6,20 @@ macro_rules! rule { } }; } + +#[macro_export] +macro_rules! pred { + ($($expr:tt)*) => { |c: u8| _pred!(expr { $($expr)* })(c) }; +} + +macro_rules! _pred { + (expr {}) => {}; + (expr { $name:ident }) => { |b| $name(b) }; + (expr { ! $($expr:tt)* }) => { |b| !_pred!(expr { $($expr)* })(b) }; + (expr { ($($L:tt)*) && ($($R:tt)*) }) => { + |b| { _pred!(expr { $($L)* })(b) && _pred!(expr { $($R)* })(b) } + }; + (expr { ($($L:tt)*) || ($($R:tt)*) }) => { + |b| { _pred!(expr { $($L)* })(b) || _pred!(expr { $($R)* })(b) } + }; +} diff --git a/imap/src/proto/rfc2234.rs b/imap/src/proto/rfc2234.rs index 4ab3de1..ce30f56 100644 --- a/imap/src/proto/rfc2234.rs +++ b/imap/src/proto/rfc2234.rs @@ -8,17 +8,20 @@ rule!(pub ALPHA : u8 => satisfy(|c| (c >= b'a' && c <= b'z') || (c >= b'A' && c rule!(pub BIT : u8 => satisfy(|c| c == b'0' || c == b'1')); -rule!(pub CHAR : u8 => satisfy(|c| c != b'\0')); +pub fn is_char(c: u8) -> bool { c != b'\0' } +rule!(pub CHAR : u8 => satisfy(is_char)); rule!(pub CR : u8 => byte(b'\x0d')); rule!(pub CRLF : (u8, u8) => pair(CR, LF)); -rule!(pub CTL : u8 => satisfy(|c| c <= b'\x1f' || c == b'\x7f')); +pub fn is_ctl(c: u8) -> bool { c <= b'\x1f' || c == b'\x7f' } +rule!(pub CTL : u8 => satisfy(is_ctl)); rule!(pub DIGIT : u8 => satisfy(|c| c >= b'\x30' && c <= b'\x39')); -rule!(pub DQUOTE : u8 => byte(b'\x22')); +pub fn is_dquote(c: u8) -> bool { c == b'\x22' } +rule!(pub DQUOTE : u8 => satisfy(is_dquote)); rule!(pub HEXDIG : u8 => alt((DIGIT, satisfy(|c| c >= b'A' && c <= b'F')))); @@ -30,7 +33,8 @@ rule!(pub LWSP : () => skip(many0(alt((skip(WSP), skip(pair(CRLF, WSP))))))); rule!(pub OCTET : char => anychar); -rule!(pub SP : u8 => byte(b'\x20')); +pub fn is_sp(c: u8) -> bool { c == b'\x20' } +rule!(pub SP : u8 => satisfy(is_sp)); rule!(pub VCHAR : u8 => satisfy(|c| c >= b'\x21' && c <= b'\x7e')); diff --git a/imap/src/proto/rfc3501.rs b/imap/src/proto/rfc3501.rs index 8191e4e..5c7767c 100644 --- a/imap/src/proto/rfc3501.rs +++ b/imap/src/proto/rfc3501.rs @@ -10,8 +10,8 @@ use nom::{ IResult, }; -use super::rfc2234::{CRLF, DIGIT, DQUOTE}; -use super::parsers::byte; +use super::parsers::satisfy; +use super::rfc2234::{is_char, is_ctl, is_dquote, is_sp, CRLF, DIGIT, DQUOTE}; rule!(pub astring : Vec => alt((many1(ASTRING_CHAR), string))); @@ -19,9 +19,26 @@ rule!(pub ASTRING_CHAR : u8 => alt((ATOM_CHAR, resp_specials))); rule!(pub atom : Vec => many1(ATOM_CHAR)); -pub fn ATOM_CHAR(i: &[u8]) -> IResult<&[u8], u8> { - todo!() +// TODO: somehow incorporate CHAR in here? +// technically ATOM_CHAR is defined as +// but "except"-style rules don't really make sense except for character sets +// and some other niche cases so probably doesn't warrant a separate combinator +rule!(pub ATOM_CHAR : u8 => satisfy(pred!((is_char) && (!is_atom_specials)))); + +pub fn is_atom_specials(c: u8) -> bool { + c == b'(' + || c == b')' + || c == b'{' + || is_sp(c) + || is_ctl(c) + || is_list_wildcards(c) + || is_quoted_specials(c) + || is_resp_specials(c) } +rule!(pub atom_specials : u8 => satisfy(is_atom_specials)); + +pub fn is_list_wildcards(c: u8) -> bool { c == b'%' || c == b'*' } +rule!(pub list_wildcards : u8 => satisfy(is_list_wildcards)); /// literal = "{" number "}" CRLF *CHAR8 /// ; Number represents the number of CHAR8s @@ -52,14 +69,14 @@ pub fn number(i: &[u8]) -> IResult<&[u8], u32> { rule!(pub quoted : Vec => delimited(DQUOTE, many0(QUOTED_CHAR), DQUOTE)); -pub fn QUOTED_CHAR(i: &[u8]) -> IResult<&[u8], u8> { - todo!() -} +pub fn QUOTED_CHAR(i: &[u8]) -> IResult<&[u8], u8> { todo!() } -rule!(pub resp_specials : u8 => byte(b']')); +pub fn is_quoted_specials(c: u8) -> bool { is_dquote(c) || c == b'\\' } +rule!(pub quoted_specials : u8 => satisfy(is_quoted_specials)); + +pub fn is_resp_specials(c: u8) -> bool { c == b']' } +rule!(pub resp_specials : u8 => satisfy(is_resp_specials)); rule!(pub string : Vec => alt((quoted, literal))); -pub fn TEXT_CHAR(i: &[u8]) -> IResult<&[u8], u8> { - todo!() -} +pub fn TEXT_CHAR(i: &[u8]) -> IResult<&[u8], u8> { todo!() } diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..397187f --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,3 @@ +fn_single_line = true +max_width = 100 +wrap_comments = true \ No newline at end of file