|  | //! Helper macros | 
|  |  | 
|  | use nom::bytes::complete::take; | 
|  | use nom::combinator::map_res; | 
|  | use nom::IResult; | 
|  |  | 
|  | #[doc(hidden)] | 
|  | pub mod export { | 
|  | pub use core::{fmt, mem, ptr}; | 
|  | } | 
|  |  | 
|  | /// Helper macro for newtypes: declare associated constants and implement Display trait | 
|  | #[macro_export] | 
|  | macro_rules! newtype_enum ( | 
|  | (@collect_impl, $name:ident, $($key:ident = $val:expr),* $(,)*) => { | 
|  | $( pub const $key : $name = $name($val); )* | 
|  | }; | 
|  |  | 
|  | (@collect_disp, $name:ident, $f:ident, $m:expr, $($key:ident = $val:expr),* $(,)*) => { | 
|  | match $m { | 
|  | $( $val => write!($f, stringify!{$key}), )* | 
|  | n => write!($f, "{}({} / 0x{:x})", stringify!{$name}, n, n) | 
|  | } | 
|  | }; | 
|  |  | 
|  | // entry | 
|  | (impl $name:ident {$($body:tt)*}) => ( | 
|  | #[allow(non_upper_case_globals)] | 
|  | impl $name { | 
|  | newtype_enum!{@collect_impl, $name, $($body)*} | 
|  | } | 
|  | ); | 
|  |  | 
|  | // entry with display | 
|  | (impl display $name:ident {$($body:tt)*}) => ( | 
|  | newtype_enum!(impl $name { $($body)* }); | 
|  |  | 
|  | impl $crate::export::fmt::Display for $name { | 
|  | fn fmt(&self, f: &mut $crate::export::fmt::Formatter) -> $crate::export::fmt::Result { | 
|  | newtype_enum!(@collect_disp, $name, f, self.0, $($body)*) | 
|  | } | 
|  | } | 
|  | ); | 
|  |  | 
|  | // entry with display and debug | 
|  | (impl debug $name:ident {$($body:tt)*}) => ( | 
|  | newtype_enum!(impl display $name { $($body)* }); | 
|  |  | 
|  | impl $crate::export::fmt::Debug for $name { | 
|  | fn fmt(&self, f: &mut $crate::export::fmt::Formatter) -> $crate::export::fmt::Result { | 
|  | write!(f, "{}", self) | 
|  | } | 
|  | } | 
|  | ); | 
|  | ); | 
|  |  | 
|  | /// Helper macro for nom parsers: raise error if the condition is true | 
|  | /// | 
|  | /// This macro is used when using custom errors | 
|  | #[macro_export] | 
|  | macro_rules! custom_check ( | 
|  | ($i:expr, $cond:expr, $err:expr) => ( | 
|  | { | 
|  | if $cond { | 
|  | Err(::nom::Err::Error($err)) | 
|  | } else { | 
|  | Ok(($i, ())) | 
|  | } | 
|  | } | 
|  | ); | 
|  | ); | 
|  |  | 
|  | /// Helper macro for nom parsers: raise error if the condition is true | 
|  | /// | 
|  | /// This macro is used when using `ErrorKind` | 
|  | #[macro_export] | 
|  | macro_rules! error_if ( | 
|  | ($i:expr, $cond:expr, $err:expr) => ( | 
|  | { | 
|  | use nom::error_position; | 
|  | if $cond { | 
|  | Err(::nom::Err::Error(error_position!($i, $err))) | 
|  | } else { | 
|  | Ok(($i, ())) | 
|  | } | 
|  | } | 
|  | ); | 
|  | ); | 
|  |  | 
|  | /// Helper macro for nom parsers: raise error if input is not empty | 
|  | /// | 
|  | /// Deprecated - use `nom::eof` | 
|  | #[macro_export] | 
|  | #[deprecated(since = "2.0.0")] | 
|  | macro_rules! empty ( | 
|  | ($i:expr,) => ( | 
|  | { | 
|  | use nom::eof; | 
|  | eof!($i,) | 
|  | } | 
|  | ); | 
|  | ); | 
|  |  | 
|  | #[deprecated(since = "3.0.1", note = "please use `be_var_u64` instead")] | 
|  | /// Read an entire slice as a big-endian value. | 
|  | /// | 
|  | /// Returns the value as `u64`. This function checks for integer overflows, and returns a | 
|  | /// `Result::Err` value if the value is too big. | 
|  | pub fn bytes_to_u64(s: &[u8]) -> Result<u64, &'static str> { | 
|  | let mut u: u64 = 0; | 
|  |  | 
|  | if s.is_empty() { | 
|  | return Err("empty"); | 
|  | }; | 
|  | if s.len() > 8 { | 
|  | return Err("overflow"); | 
|  | } | 
|  | for &c in s { | 
|  | let u1 = u << 8; | 
|  | u = u1 | (c as u64); | 
|  | } | 
|  |  | 
|  | Ok(u) | 
|  | } | 
|  |  | 
|  | /// Read a slice as a big-endian value. | 
|  | #[macro_export] | 
|  | macro_rules! parse_hex_to_u64 ( | 
|  | ( $i:expr, $size:expr ) => { | 
|  | map_res(take($size as usize), $crate::combinator::be_var_u64)($i) | 
|  | }; | 
|  | ); | 
|  |  | 
|  | /// Read 3 bytes as an unsigned integer | 
|  | #[deprecated(since = "0.5.0", note = "please use `be_u24` instead")] | 
|  | #[allow(deprecated)] | 
|  | #[inline] | 
|  | pub fn parse_uint24(i: &[u8]) -> IResult<&[u8], u64> { | 
|  | map_res(take(3usize), bytes_to_u64)(i) | 
|  | } | 
|  |  | 
|  | //named!(parse_hex4<&[u8], u64>, parse_hex_to_u64!(4)); | 
|  |  | 
|  | /// Combination and flat_map! and take! as first combinator | 
|  | #[macro_export] | 
|  | macro_rules! flat_take ( | 
|  | ($i:expr, $len:expr, $f:ident) => ({ | 
|  | if $i.len() < $len { Err(::nom::Err::Incomplete(::nom::Needed::new($len))) } | 
|  | else { | 
|  | let taken = &$i[0..$len]; | 
|  | let rem = &$i[$len..]; | 
|  | match $f(taken) { | 
|  | Ok((_,res)) => Ok((rem,res)), | 
|  | Err(e)      => Err(e) | 
|  | } | 
|  | } | 
|  | }); | 
|  | ($i:expr, $len:expr, $submac:ident!( $($args:tt)*)) => ({ | 
|  | if $i.len() < $len { Err(::nom::Err::Incomplete(::nom::Needed::new($len))) } | 
|  | else { | 
|  | let taken = &$i[0..$len]; | 
|  | let rem = &$i[$len..]; | 
|  | match $submac!(taken, $($args)*) { | 
|  | Ok((_,res)) => Ok((rem,res)), | 
|  | Err(e)      => Err(e) | 
|  | } | 
|  | } | 
|  | }); | 
|  | ); | 
|  |  | 
|  | /// Apply combinator, trying to "upgrade" error to next error type (using the `Into` or `From` | 
|  | /// traits). | 
|  | #[macro_export] | 
|  | macro_rules! upgrade_error ( | 
|  | ($i:expr, $submac:ident!( $($args:tt)*) ) => ({ | 
|  | upgrade_error!( $submac!( $i, $($args)* ) ) | 
|  | }); | 
|  | ($i:expr, $f:expr) => ({ | 
|  | upgrade_error!( call!($i, $f) ) | 
|  | }); | 
|  | ($e:expr) => ({ | 
|  | match $e { | 
|  | Ok(o) => Ok(o), | 
|  | Err(::nom::Err::Error(e)) => Err(::nom::Err::Error(e.into())), | 
|  | Err(::nom::Err::Failure(e)) => Err(::nom::Err::Failure(e.into())), | 
|  | Err(::nom::Err::Incomplete(i)) => Err(::nom::Err::Incomplete(i)), | 
|  | } | 
|  | }); | 
|  | ); | 
|  |  | 
|  | /// Apply combinator, trying to "upgrade" error to next error type (using the `Into` or `From` | 
|  | /// traits). | 
|  | #[macro_export] | 
|  | macro_rules! upgrade_error_to ( | 
|  | ($i:expr, $ty:ty, $submac:ident!( $($args:tt)*) ) => ({ | 
|  | upgrade_error_to!( $ty, $submac!( $i, $($args)* ) ) | 
|  | }); | 
|  | ($i:expr, $ty:ty, $f:expr) => ({ | 
|  | upgrade_error_to!( $ty, call!($i, $f) ) | 
|  | }); | 
|  | ($ty:ty, $e:expr) => ({ | 
|  | match $e { | 
|  | Ok(o) => Ok(o), | 
|  | Err(::nom::Err::Error(e)) => Err(::nom::Err::Error(e.into::<$ty>())), | 
|  | Err(::nom::Err::Failure(e)) => Err(::nom::Err::Failure(e.into::<$ty>())), | 
|  | Err(::nom::Err::Incomplete(i)) => Err(::nom::Err::Incomplete(i)), | 
|  | } | 
|  | }); | 
|  | ); | 
|  |  | 
|  | /// Nom combinator that returns the given expression unchanged | 
|  | #[macro_export] | 
|  | macro_rules! q { | 
|  | ($i:expr, $x:expr) => {{ | 
|  | Ok(($i, $x)) | 
|  | }}; | 
|  | } | 
|  |  | 
|  | /// Align input value to the next multiple of n bytes | 
|  | /// Valid only if n is a power of 2 | 
|  | #[macro_export] | 
|  | macro_rules! align_n2 { | 
|  | ($x:expr, $n:expr) => { | 
|  | ($x + ($n - 1)) & !($n - 1) | 
|  | }; | 
|  | } | 
|  |  | 
|  | /// Align input value to the next multiple of 4 bytes | 
|  | #[macro_export] | 
|  | macro_rules! align32 { | 
|  | ($x:expr) => { | 
|  | $crate::align_n2!($x, 4) | 
|  | }; | 
|  | } | 
|  |  | 
|  | #[cfg(test)] | 
|  | mod tests { | 
|  | use nom::error::ErrorKind; | 
|  | use nom::number::streaming::{be_u16, be_u32}; | 
|  | use nom::{error_position, Err, IResult, Needed}; | 
|  |  | 
|  | #[test] | 
|  | fn test_error_if() { | 
|  | let empty = &b""[..]; | 
|  | let res: IResult<&[u8], ()> = error_if!(empty, true, ErrorKind::Tag); | 
|  | assert_eq!(res, Err(Err::Error(error_position!(empty, ErrorKind::Tag)))); | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn test_newtype_enum() { | 
|  | #[derive(Debug, PartialEq, Eq)] | 
|  | struct MyType(pub u8); | 
|  |  | 
|  | newtype_enum! { | 
|  | impl display MyType { | 
|  | Val1 = 0, | 
|  | Val2 = 1 | 
|  | } | 
|  | } | 
|  |  | 
|  | assert_eq!(MyType(0), MyType::Val1); | 
|  | assert_eq!(MyType(1), MyType::Val2); | 
|  |  | 
|  | assert_eq!(format!("{}", MyType(0)), "Val1"); | 
|  | assert_eq!(format!("{}", MyType(4)), "MyType(4 / 0x4)"); | 
|  | } | 
|  | #[test] | 
|  | fn test_flat_take() { | 
|  | let input = &[0x00, 0x01, 0xff]; | 
|  | // read first 2 bytes and use correct combinator: OK | 
|  | let res: IResult<&[u8], u16> = flat_take!(input, 2, be_u16); | 
|  | assert_eq!(res, Ok((&input[2..], 0x0001))); | 
|  | // read 3 bytes and use 2: OK (some input is just lost) | 
|  | let res: IResult<&[u8], u16> = flat_take!(input, 3, be_u16); | 
|  | assert_eq!(res, Ok((&b""[..], 0x0001))); | 
|  | // read 2 bytes and a combinator requiring more bytes | 
|  | let res: IResult<&[u8], u32> = flat_take!(input, 2, be_u32); | 
|  | assert_eq!(res, Err(Err::Incomplete(Needed::new(2)))); | 
|  | // test with macro as sub-combinator | 
|  | let res: IResult<&[u8], u16> = flat_take!(input, 2, be_u16); | 
|  | assert_eq!(res, Ok((&input[2..], 0x0001))); | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn test_q() { | 
|  | let empty = &b""[..]; | 
|  | let res: IResult<&[u8], &str, ErrorKind> = q!(empty, "test"); | 
|  | assert_eq!(res, Ok((empty, "test"))); | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn test_align32() { | 
|  | assert_eq!(align32!(3), 4); | 
|  | assert_eq!(align32!(4), 4); | 
|  | assert_eq!(align32!(5), 8); | 
|  | assert_eq!(align32!(5u32), 8); | 
|  | assert_eq!(align32!(5i32), 8); | 
|  | assert_eq!(align32!(5usize), 8); | 
|  | } | 
|  | } |