pub use nom::IResult;
pub use cookie_factory::GenError;
use nom::number::streaming::{le_u8, le_u16};
use nom::{named, map, count};
use cookie_factory::{do_gen, gen_be_u8, gen_le_u16};
use std::net::{
IpAddr,
Ipv4Addr,
Ipv6Addr,
};
#[cfg(feature = "sodiumoxide")]
pub use sodium::*;
#[cfg(feature = "sodiumoxide")]
mod sodium;
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 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))
}
}
#[allow(clippy::needless_pass_by_value)]
pub fn gen_error(_buf: (&mut [u8], usize), error: u32) -> Result<(&mut [u8], usize), GenError> {
Err(GenError::CustomError(error))
}
#[macro_export]
macro_rules! encode_decode_test (
($init:expr, $test:ident, $value:expr) => (
#[test]
fn $test() {
$init;
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);
}
)
);
#[macro_export]
macro_rules! unpack {
($variable:expr, $variant:path, $name:ident) => (
unpack!($variable, $variant { $name })
);
($variable:expr, $variant:path) => {
unpack!($variable, $variant[inner])
};
($variable:expr, $variant:path [ $($inner:ident),* ]) => (
match $variable {
$variant( $($inner),* ) => ( $($inner),* ),
other => panic!("Expected {} but got {:?}", stringify!($variant), other),
}
);
($variable:expr, $variant:path { $($inner:ident),* }) => (
match $variable {
$variant { $($inner,)* .. } => ( $($inner),* ),
other => panic!("Expected {} but got {:?}", stringify!($variant), other),
}
);
}