use nom::{self, IResult};
use std::str;
pub fn list_wildcards(c: u8) -> bool {
c == b'%' || c == b'*'
}
pub fn quoted_specials(c: u8) -> bool {
c == b'"' || c == b'\\'
}
pub fn resp_specials(c: u8) -> bool {
c == b']'
}
pub fn atom_specials(c: u8) -> bool {
c == b'('
|| c == b')'
|| c == b'{'
|| c == b' '
|| c < 32
|| list_wildcards(c)
|| quoted_specials(c)
|| resp_specials(c)
}
pub fn atom_char(c: u8) -> bool {
!atom_specials(c)
}
named!(pub nil, tag_no_case!("NIL"));
pub fn astring_char(c: u8) -> bool {
atom_char(c) || resp_specials(c)
}
pub fn quoted_data(i: &[u8]) -> IResult<&[u8], &[u8]> {
let mut escape = false;
let mut len = 0;
for c in i {
if *c == b'"' && !escape {
break;
}
len += 1;
if *c == b'\\' && !escape {
escape = true
} else if escape {
escape = false;
}
}
Ok((&i[len..], &i[..len]))
}
named!(pub quoted<&[u8]>, delimited!(
char!('"'),
quoted_data,
char!('"')
));
named!(pub quoted_utf8<&str>, map_res!(quoted, str::from_utf8));
named!(pub literal<&[u8]>, do_parse!(
tag!("{") >>
len: number >>
tag!("}") >>
tag!("\r\n") >>
data: take!(len) >>
(data)
));
named!(pub string<&[u8]>, alt!(quoted | literal));
named!(pub string_utf8<&str>, map_res!(string, str::from_utf8));
named!(pub nstring<Option<&[u8]>>, alt!(
map!(nil, |_| None) |
map!(string, |s| Some(s))
));
named!(pub nstring_utf8<Option<&str>>, alt!(
map!(nil, |_| None) |
map!(string_utf8, |s| Some(s))
));
named!(pub number<u32>, flat_map!(nom::character::streaming::digit1, parse_to!(u32)));
named!(pub number_64<u64>, flat_map!(nom::character::streaming::digit1, parse_to!(u64)));
named!(pub atom<&str>, map_res!(take_while1!(atom_char),
str::from_utf8
));
named!(pub astring<&[u8]>, alt!(
take_while1!(astring_char) |
string
));
named!(pub astring_utf8<&str>, map_res!(astring, str::from_utf8));
named!(pub text<&str>, map_res!(take_while!(text_char),
str::from_utf8
));
pub fn text_char(c: u8) -> bool {
c != b'\r' && c != b'\n'
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_string_literal() {
match string(b"{3}\r\nXYZ") {
Ok((_, value)) => {
assert_eq!(value, b"XYZ");
}
rsp => panic!("unexpected response {:?}", rsp),
}
}
#[test]
fn test_astring() {
match astring(b"text ") {
Ok((_, value)) => {
assert_eq!(value, b"text");
}
rsp => panic!("unexpected response {:?}", rsp),
}
}
}