pub use nom::IResult;
pub use cookie_factory::GenError;
use nom::{le_u8, le_u16};
use std::net::{
IpAddr,
Ipv4Addr,
Ipv6Addr,
};
pub trait FromBytes : Sized {
fn from_bytes(i: &[u8]) -> IResult<&[u8], Self>;
}
pub trait ToBytes : Sized {
fn to_bytes<'a>(&self, buf: (&'a mut [u8], usize)) -> Result<(&'a mut [u8], usize), GenError>;
}
impl ToBytes for IpAddr {
fn to_bytes<'a>(&self, buf: (&'a mut [u8], usize)) -> Result<(&'a mut [u8], usize), GenError> {
match *self {
IpAddr::V4(ref p) => p.to_bytes(buf),
IpAddr::V6(ref p) => p.to_bytes(buf),
}
}
}
impl FromBytes for Ipv4Addr {
named!(from_bytes<Ipv4Addr>, map!(count!(le_u8, 4),
|v| Ipv4Addr::new(v[0], v[1], v[2], v[3])
));
}
impl ToBytes for Ipv4Addr {
fn to_bytes<'a>(&self, buf: (&'a mut [u8], usize)) -> Result<(&'a mut [u8], usize), GenError> {
let o = self.octets();
do_gen!(buf,
gen_be_u8!(o[0]) >>
gen_be_u8!(o[1]) >>
gen_be_u8!(o[2]) >>
gen_be_u8!(o[3])
)
}
}
impl FromBytes for Ipv6Addr {
named!(from_bytes<Ipv6Addr>, map!(count!(le_u16, 8),
|v| Ipv6Addr::new(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7])
));
}
impl ToBytes for Ipv6Addr {
fn to_bytes<'a>(&self, buf: (&'a mut [u8], usize)) -> Result<(&'a mut [u8], usize), GenError> {
let s = self.segments();
do_gen!(buf,
gen_le_u16!(s[0]) >>
gen_le_u16!(s[1]) >>
gen_le_u16!(s[2]) >>
gen_le_u16!(s[3]) >>
gen_le_u16!(s[4]) >>
gen_le_u16!(s[5]) >>
gen_le_u16!(s[6]) >>
gen_le_u16!(s[7])
)
}
}
pub fn rest_len(input: &[u8]) -> IResult<&[u8], usize> {
IResult::Done(input, input.len())
}
pub fn gen_len_limit(buf: (&mut [u8], usize), limit: usize) -> Result<(&mut [u8], usize), GenError> {
if buf.1 <= limit {
Ok(buf)
} else {
Err(GenError::BufferTooSmall(buf.1))
}
}
pub fn gen_error(_buf: (&mut [u8], usize), error: u32) -> Result<(&mut [u8], usize), GenError> {
Err(GenError::CustomError(error))
}
#[cfg(test)]
macro_rules! encode_decode_test (
($test:ident, $value:expr) => (
#[test]
fn $test() {
let value = $value;
let mut buf = [0; 1024 * 1024];
let (_, size) = value.to_bytes((&mut buf, 0)).unwrap();
assert!(size <= 1024 * 1024);
let (rest, decoded_value) = FromBytes::from_bytes(&buf[..size]).unwrap();
fn infer<T>(_: &T, _: &T) { }
infer(&decoded_value, &value);
assert!(rest.is_empty());
assert_eq!(decoded_value, value);
}
)
);
#[cfg(test)]
macro_rules! unpack {
($variable:expr, $variant:path, $name:ident) => (
match $variable {
$variant { $name, .. } => $name,
other => panic!("Expected {} but got {:?}", stringify!($variant), other),
}
);
($variable:expr, $variant:path) => (
match $variable {
$variant(inner) => inner,
other => panic!("Expected {} but got {:?}", stringify!($variant), other),
}
)
}