use std::io::{Error, ErrorKind, Read, Result};
use std::str::{self, FromStr};
use std::fs::File;
use byteorder::{ByteOrder, LittleEndian};
use nom::{IResult, alphanumeric, digit, is_digit, not_line_ending, space};
pub fn read_to_end<'a>(file: &mut File, buf: &'a mut [u8]) -> Result<&'a mut [u8]> {
let mut from = 0;
loop {
if from == buf.len() {
return Err(Error::new(ErrorKind::Other, "read underflow"));
}
match file.read(&mut buf[from..]) {
Ok(0) => return Ok(&mut buf[..from]),
Ok(n) => from += n,
Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
Err(e) => return Err(e),
}
}
}
pub fn map_result<T>(result: IResult<&[u8], T>) -> Result<T> {
match result {
IResult::Done(remaining, val) => {
if remaining.is_empty() {
Ok(val)
} else {
Err(Error::new(ErrorKind::InvalidInput, "unable to parse whole input"))
}
}
IResult::Error(err) => Err(Error::new(ErrorKind::InvalidInput,
format!("unable to parse input: {:?}", err))),
_ => Err(Error::new(ErrorKind::InvalidInput, "unable to parse input")),
}
}
fn fdigit(input: &[u8]) -> IResult<&[u8], &[u8]> {
for idx in 0..input.len() {
if (!is_digit(input[idx])) && ('.' as u8 != input[idx]) {
return IResult::Done(&input[idx..], &input[0..idx])
}
}
IResult::Done(b"", input)
}
named!(pub parse_to_end<String>,
map_res!(map_res!(not_line_ending, str::from_utf8), FromStr::from_str));
named!(pub parse_u32<u32>,
map_res!(map_res!(digit, str::from_utf8), FromStr::from_str));
named!(pub parse_f32<f32>,
map_res!(map_res!(fdigit, str::from_utf8), FromStr::from_str));
named!(pub parse_u32s<Vec<u32> >, separated_list!(space, parse_u32));
named!(pub parse_i32<i32>, map!(parse_u32, { |n| { n as i32 } }));
named!(pub parse_i32s<Vec<i32> >, separated_list!(space, parse_i32));
named!(pub parse_u64<u64>,
map_res!(map_res!(digit, str::from_utf8), FromStr::from_str));
named!(pub parse_usize<usize>,
map_res!(map_res!(digit, str::from_utf8), FromStr::from_str));
named!(pub parse_kb<usize>,
chain!(space ~ bytes: parse_usize ~ space ~ tag!("kB"), || { bytes }));
named!(pub parse_u32_hex<u32>,
map_res!(map_res!(alphanumeric, str::from_utf8),
|s| u32::from_str_radix(s, 16)));
named!(pub parse_u64_hex<u64>,
map_res!(map_res!(alphanumeric, str::from_utf8),
|s| u64::from_str_radix(s, 16)));
fn reverse(n: u8) -> u8 {
const LOOKUP: [u8; 16] = [ 0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe,
0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf ];
(LOOKUP[(n & 0b1111) as usize] << 4) | LOOKUP[(n >> 4) as usize]
}
named!(pub parse_u32_mask_list<Box<[u8]> >,
map!(separated_nonempty_list!(tag!(","), parse_u32_hex), |mut ints: Vec<u32>| {
let mut bytes: Vec<u8> = Vec::with_capacity(ints.len() * 4);
let mut buf: [u8; 4] = [0; 4];
ints.reverse();
for int in ints {
LittleEndian::write_u32(&mut buf, int);
for b in buf.iter_mut() {
*b = reverse(*b);
}
bytes.extend(&buf);
}
bytes.into_boxed_slice()
}));
#[cfg(test)]
pub mod tests {
extern crate test;
use std::u32;
use nom::IResult;
use super::{map_result, parse_f32, parse_i32s, parse_u32_hex, parse_u32_mask_list, parse_u32s,
reverse};
pub fn unwrap<T>(result: IResult<&[u8], T>) -> T {
map_result(result).unwrap()
}
#[test]
fn test_reverse() {
assert_eq!(0b00000000, reverse(0b00000000));
assert_eq!(0b00000010, reverse(0b01000000));
assert_eq!(0b00011000, reverse(0b00011000));
assert_eq!(0b01011000, reverse(0b00011010));
assert_eq!(0b11111111, reverse(0b11111111));
}
#[test]
fn test_parse_u32_hex() {
assert_eq!(0, unwrap(parse_u32_hex(b"00000000")));
assert_eq!(1, unwrap(parse_u32_hex(b"00000001")));
assert_eq!(42, unwrap(parse_u32_hex(b"0000002a")));
assert_eq!(286331153, unwrap(parse_u32_hex(b"11111111")));
assert_eq!(u32::MAX, unwrap(parse_u32_hex(b"ffffffff")));
}
#[test]
fn test_u32_mask_list() {
assert_eq!([0, 0, 0, 0], &*unwrap(parse_u32_mask_list(b"00000000")));
assert_eq!([0x80, 0, 0, 0], &*unwrap(parse_u32_mask_list(b"00000001")));
assert_eq!([0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 2], &*unwrap(parse_u32_mask_list(b"40000000,00000000,00000000")));
assert_eq!([0, 0, 0, 0,
0, 0, 0, 0,
128, 0, 0, 0], &*unwrap(parse_u32_mask_list(b"00000001,00000000,00000000")));
assert_eq!([0, 0, 0, 0,
0xff, 0, 0, 0], &*unwrap(parse_u32_mask_list(b"000000ff,00000000")));
assert_eq!([0x46, 0x1c, 0x70, 0,
0, 0, 0, 0], &*unwrap(parse_u32_mask_list(b"00000000,000e3862")));
}
#[test]
fn test_parse_u32s() {
assert_eq!(Vec::<u32>::new(), &*unwrap(parse_u32s(b"")));
assert_eq!(vec![0u32], &*unwrap(parse_u32s(b"0")));
assert_eq!(vec![0u32, 1], &*unwrap(parse_u32s(b"0 1")));
assert_eq!(vec![99999u32, 32, 22, 888], &*unwrap(parse_u32s(b"99999 32 22 888")));
}
#[test]
fn test_parse_i32s() {
assert_eq!(Vec::<i32>::new(), &*unwrap(parse_i32s(b"")));
assert_eq!(vec![0i32], &*unwrap(parse_i32s(b"0")));
assert_eq!(vec![0i32, 1], &*unwrap(parse_i32s(b"0 1")));
assert_eq!(vec![99999i32, 32, 22, 888], &*unwrap(parse_i32s(b"99999 32 22 888")));
}
#[test]
fn test_parse_f32() {
assert_eq!(0.0, unwrap(parse_f32(b"0")));
assert_eq!(0.0, unwrap(parse_f32(b"0.0")));
assert_eq!(2.0, unwrap(parse_f32(b"2.0")));
assert_eq!(45.67, unwrap(parse_f32(b"45.67")));
}
}