use std::io;
use std::str;
use std::string::String;
use bytes::Bytes;
use regex::{Captures, Regex};
use nom;
use nom::*;
pub type DataOut = Bytes;
#[derive(Debug, PartialEq, Eq)]
pub enum DataIn {
ARQ(Bytes),
FEC(Bytes),
IDF(String, Option<String>),
}
impl DataIn {
pub fn parse(buf: &[u8]) -> io::Result<(usize, Option<DataIn>)> {
match parse_data(buf) {
Ok((rem, (dtype, data))) => {
let taken = buf.len() - rem.len();
let out = match dtype {
"ARQ" => Some(DataIn::ARQ(Bytes::copy_from_slice(data))),
"FEC" => Some(DataIn::FEC(Bytes::copy_from_slice(data))),
"IDF" => parse_id_frame(data),
_ => None,
};
Ok((taken, out))
}
Err(e) => {
if e.is_incomplete() {
Ok((0, None))
} else {
Err(io::Error::new(
io::ErrorKind::InvalidData,
format!("Unexpected data channel parse error: {:?}", e),
))
}
}
}
}
}
fn parse_id_frame(inp: &[u8]) -> Option<DataIn> {
lazy_static! {
static ref RE: Regex =
Regex::new("^ID:\\s*([0-9A-Za-z-]+)(?:\\s+\\[(\\w{2,8})\\])?").unwrap();
}
let id_string = match str::from_utf8(inp) {
Ok(st) => st,
Err(_e) => return None,
};
let mtch: Captures = match RE.captures(id_string) {
Some(c) => c,
None => return None,
};
let peer_call = mtch.get(1).unwrap().as_str().to_owned();
let peer_grid = match mtch.get(2) {
Some(gr) => Some(gr.as_str().to_owned()),
None => None,
};
Some(DataIn::IDF(peer_call, peer_grid))
}
named!(
parse_data<&[u8], (&str, &[u8])>,
do_parse!(
dlen: be_u16 >>
dtype: map_res!(
take!(3),
std::str::from_utf8
) >>
data: take!(dlen - 3) >>
((dtype, data))
)
);
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_parse() {
let data = b"\x00\x08ARQHELLO";
let res = DataIn::parse(data).unwrap();
assert_eq!(data.len(), res.0);
assert_eq!(DataIn::ARQ(Bytes::from("HELLO")), res.1.unwrap());
let data = b"\x00\x08ERRHELLO";
let res = DataIn::parse(data).unwrap();
assert_eq!(data.len(), res.0);
assert!(res.1.is_none());
let data = b"\x00\x08ARQHELL";
let res = DataIn::parse(data).unwrap();
assert_eq!(0, res.0);
assert!(res.1.is_none());
let data = b"\x00\x08ARQHELLO\x00\x08";
let res = DataIn::parse(data).unwrap();
assert_eq!(data.len() - 2, res.0);
assert_eq!(DataIn::ARQ(Bytes::from("HELLO")), res.1.unwrap());
let data = b"\x00\x08ZZZHELLO";
let res = DataIn::parse(data).unwrap();
assert_eq!(data.len(), res.0);
assert!(res.1.is_none());
}
#[test]
fn test_parse_id_frame() {
let outgoing_id = b"W1AW:[EM00aa]";
let call_only = b"ID: W1AW";
let call_and_bad_grid = b"ID: W1AW [bad grid]:";
let call_and_grid = b"ID: W1AW-8 [EM00]:";
assert_eq!(None, parse_id_frame(outgoing_id));
assert_eq!(
DataIn::IDF("W1AW".to_owned(), None),
parse_id_frame(call_only).unwrap()
);
assert_eq!(
DataIn::IDF("W1AW".to_owned(), None),
parse_id_frame(call_and_bad_grid).unwrap()
);
assert_eq!(
DataIn::IDF("W1AW-8".to_owned(), Some("EM00".to_owned())),
parse_id_frame(call_and_grid).unwrap()
);
}
}