1 //! Helper macros 2 3 use nom::combinator::rest; 4 use nom::HexDisplay; 5 use nom::IResult; 6 7 /// Helper macro for newtypes: declare associated constants and implement Display trait 8 #[macro_export] 9 macro_rules! newtype_enum ( 10 (@collect_impl, $name:ident, $($key:ident = $val:expr),* $(,)*) => { 11 $( pub const $key : $name = $name($val); )* 12 }; 13 14 (@collect_disp, $name:ident, $f:ident, $m:expr, $($key:ident = $val:expr),* $(,)*) => { 15 match $m { 16 $( $val => write!($f, stringify!{$key}), )* 17 n => write!($f, "{}({} / 0x{:x})", stringify!{$name}, n, n) 18 } 19 }; 20 21 // entry 22 (impl $name:ident {$($body:tt)*}) => ( 23 #[allow(non_upper_case_globals)] 24 impl $name { 25 newtype_enum!{@collect_impl, $name, $($body)*} 26 } 27 ); 28 29 // entry with display 30 (impl display $name:ident {$($body:tt)*}) => ( 31 newtype_enum!(impl $name { $($body)* }); 32 33 impl ::std::fmt::Display for $name { 34 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 35 newtype_enum!(@collect_disp, $name, f, self.0, $($body)*) 36 } 37 } 38 ); 39 40 // entry with display and debug 41 (impl debug $name:ident {$($body:tt)*}) => ( 42 newtype_enum!(impl display $name { $($body)* }); 43 44 impl ::std::fmt::Debug for $name { 45 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 46 write!(f, "{}", self) 47 } 48 } 49 ); 50 ); 51 52 /// Helper macro for nom parsers: raise error if the condition is false 53 /// 54 /// This macro is used when using custom errors 55 #[macro_export] 56 macro_rules! custom_check ( 57 ($i:expr, $cond:expr, $err:expr) => ( 58 { 59 if $cond { 60 Err(::nom::Err::Error($err)) 61 } else { 62 Ok(($i, ())) 63 } 64 } 65 ); 66 ); 67 68 /// Helper macro for nom parsers: raise error if the condition is false 69 /// 70 /// This macro is used when using `ErrorKind` 71 #[macro_export] 72 macro_rules! error_if ( 73 ($i:expr, $cond:expr, $err:expr) => ( 74 { 75 use nom::error_position; 76 if $cond { 77 Err(::nom::Err::Error(error_position!($i, $err))) 78 } else { 79 Ok(($i, ())) 80 } 81 } 82 ); 83 ); 84 85 /// Helper macro for nom parsers: raise error if input is not empty 86 /// 87 /// Deprecated - use `nom::eof` 88 #[macro_export] 89 #[deprecated(since = "2.0.0")] 90 macro_rules! empty ( 91 ($i:expr,) => ( 92 { 93 use nom::eof; 94 eof!($i,) 95 } 96 ); 97 ); 98 99 /// Helper macro for nom parsers: run first parser if condition is true, else second parser 100 #[macro_export] 101 macro_rules! cond_else ( 102 ($i:expr, $cond:expr, $expr_then:ident!($($args_then:tt)*), $expr_else:ident!($($args_else:tt)*)) => ( 103 { 104 if $cond { $expr_then!($i, $($args_then)*) } 105 else { $expr_else!($i, $($args_else)*) } 106 } 107 ); 108 ($i:expr, $cond:expr, $expr_then:expr, $expr_else:ident!($($args_else:tt)*)) => ( 109 cond_else!($i, $cond, call!($expr_then), $expr_else!($($args_else)*)) 110 ); 111 ($i:expr, $cond:expr, $expr_then:ident!($($args_then:tt)*), $expr_else:expr) => ( 112 cond_else!($i, $cond, $expr_then!($($args_then)*), call!($expr_else)) 113 ); 114 ($i:expr, $cond:expr, $expr_then:expr, $expr_else:expr) => ( 115 cond_else!($i, $cond, call!($expr_then), call!($expr_else)) 116 ); 117 ); 118 119 /// Dump the remaining bytes to stderr, formatted as hex 120 pub fn dbg_dmp_rest(i: &[u8]) -> IResult<&[u8], ()> { 121 map!(i, peek!(call!(rest)), |r| eprintln!("\n{}\n", r.to_hex(16))) 122 } 123 124 /// Read an entire slice as a big-endian value. 125 /// 126 /// Returns the value as `u64`. This function checks for integer overflows, and returns a 127 /// `Result::Err` value if the value is too big. 128 pub fn bytes_to_u64(s: &[u8]) -> Result<u64, &'static str> { 129 let mut u: u64 = 0; 130 131 if s.is_empty() { 132 return Err("empty"); 133 }; 134 if s.len() > 8 { 135 return Err("overflow"); 136 } 137 for &c in s { 138 let u1 = u << 8; 139 u = u1 | (c as u64); 140 } 141 142 Ok(u) 143 } 144 145 /// Read a slice as a big-endian value. 146 #[macro_export] 147 macro_rules! parse_hex_to_u64 ( 148 ( $i:expr, $size:expr ) => ( 149 map_res!($i, take!(($size as usize)), $crate::bytes_to_u64) 150 ); 151 ); 152 153 named_attr!(#[doc = "Read 3 bytes as an unsigned integer"] 154 #[deprecated(since="0.5.0", note="please use `be_u24` instead")], 155 pub parse_uint24<&[u8], u64>, parse_hex_to_u64!(3)); 156 157 //named!(parse_hex4<&[u8], u64>, parse_hex_to_u64!(4)); 158 159 /// Parse a slice and return a fixed-sized array of bytes 160 /// 161 /// This creates a copy of input data 162 /// Uses unsafe code 163 #[macro_export] 164 macro_rules! slice_fixed( 165 ( $i:expr, $count:expr ) => ( 166 { 167 let cnt = $count; 168 let ires: IResult<_,_> = if $i.len() < cnt { 169 Err(::nom::Err::Incomplete(Needed::Size(cnt))) 170 } else { 171 let mut res: [u8; $count] = unsafe { 172 ::std::mem::MaybeUninit::uninit().assume_init() 173 }; 174 unsafe{::std::ptr::copy($i.as_ptr(), res.as_mut_ptr(), cnt)}; 175 Ok((&$i[cnt..],res)) 176 }; 177 ires 178 } 179 ); 180 ); 181 182 /// Combination and flat_map! and take! as first combinator 183 #[macro_export] 184 macro_rules! flat_take ( 185 ($i:expr, $len:expr, $f:ident) => ({ 186 if $i.len() < $len { Err(::nom::Err::Incomplete(::nom::Needed::Size($len))) } 187 else { 188 let taken = &$i[0..$len]; 189 let rem = &$i[$len..]; 190 match $f(taken) { 191 Ok((_,res)) => Ok((rem,res)), 192 Err(e) => Err(e) 193 } 194 } 195 }); 196 ($i:expr, $len:expr, $submac:ident!( $($args:tt)*)) => ({ 197 if $i.len() < $len { Err(::nom::Err::Incomplete(::nom::Needed::Size($len))) } 198 else { 199 let taken = &$i[0..$len]; 200 let rem = &$i[$len..]; 201 match $submac!(taken, $($args)*) { 202 Ok((_,res)) => Ok((rem,res)), 203 Err(e) => Err(e) 204 } 205 } 206 }); 207 ); 208 209 /// Apply combinator, trying to "upgrade" error to next error type (using the `Into` or `From` 210 /// traits). 211 #[macro_export] 212 macro_rules! upgrade_error ( 213 ($i:expr, $submac:ident!( $($args:tt)*) ) => ({ 214 upgrade_error!( $submac!( $i, $($args)* ) ) 215 }); 216 ($i:expr, $f:expr) => ({ 217 upgrade_error!( call!($i, $f) ) 218 }); 219 ($e:expr) => ({ 220 match $e { 221 Ok(o) => Ok(o), 222 Err(::nom::Err::Error(e)) => Err(::nom::Err::Error(e.into())), 223 Err(::nom::Err::Failure(e)) => Err(::nom::Err::Failure(e.into())), 224 Err(::nom::Err::Incomplete(i)) => Err(::nom::Err::Incomplete(i)), 225 } 226 }); 227 ); 228 229 /// Apply combinator, trying to "upgrade" error to next error type (using the `Into` or `From` 230 /// traits). 231 #[macro_export] 232 macro_rules! upgrade_error_to ( 233 ($i:expr, $ty:ty, $submac:ident!( $($args:tt)*) ) => ({ 234 upgrade_error_to!( $ty, $submac!( $i, $($args)* ) ) 235 }); 236 ($i:expr, $ty:ty, $f:expr) => ({ 237 upgrade_error_to!( $ty, call!($i, $f) ) 238 }); 239 ($ty:ty, $e:expr) => ({ 240 match $e { 241 Ok(o) => Ok(o), 242 Err(::nom::Err::Error(e)) => Err(::nom::Err::Error(e.into::<$ty>())), 243 Err(::nom::Err::Failure(e)) => Err(::nom::Err::Failure(e.into::<$ty>())), 244 Err(::nom::Err::Incomplete(i)) => Err(::nom::Err::Incomplete(i)), 245 } 246 }); 247 ); 248 249 /// Nom combinator that returns the given expression unchanged 250 #[macro_export] 251 macro_rules! q { 252 ($i:expr, $x:expr) => {{ 253 Ok(($i, $x)) 254 }}; 255 } 256 257 /// Align input value to the next multiple of n bytes 258 /// Valid only if n is a power of 2 259 #[macro_export] 260 macro_rules! align_n2 { 261 ($x:expr, $n:expr) => { 262 ($x + ($n - 1)) & !($n - 1) 263 }; 264 } 265 266 /// Align input value to the next multiple of 4 bytes 267 #[macro_export] 268 macro_rules! align32 { 269 ($x:expr) => { 270 $crate::align_n2!($x, 4) 271 }; 272 } 273 274 #[cfg(test)] 275 mod tests { 276 use nom::error::ErrorKind; 277 use nom::number::streaming::{be_u16, be_u32, be_u8}; 278 use nom::{Err, IResult, Needed}; 279 280 #[test] 281 #[allow(unsafe_code)] 282 fn test_slice_fixed() { 283 let empty = &b""[..]; 284 let b = &[0x01, 0x02, 0x03, 0x04, 0x05]; 285 286 let res = slice_fixed!(b, 4); 287 assert_eq!(res, Ok((&b[4..], [1, 2, 3, 4]))); 288 289 // can we still use the result ? 290 match res { 291 Ok((rem, _)) => { 292 let res2: IResult<&[u8], u8> = be_u8(rem); 293 assert_eq!(res2, Ok((empty, 5))); 294 } 295 _ => (), 296 } 297 } 298 299 #[test] 300 #[allow(unsafe_code)] 301 fn test_slice_fixed_incomplete() { 302 let b = &[0x01, 0x02, 0x03, 0x04, 0x05]; 303 let res = slice_fixed!(b, 8); 304 assert_eq!(res, Err(Err::Incomplete(Needed::Size(8)))); 305 } 306 307 #[test] 308 fn test_error_if() { 309 let empty = &b""[..]; 310 let res: IResult<&[u8], ()> = error_if!(empty, true, ErrorKind::Tag); 311 assert_eq!(res, Err(Err::Error(error_position!(empty, ErrorKind::Tag)))); 312 } 313 314 #[test] 315 fn test_cond_else() { 316 let input = &[0x01][..]; 317 let empty = &b""[..]; 318 let a = 1; 319 fn parse_u8(i: &[u8]) -> IResult<&[u8], u8> { 320 be_u8(i) 321 } 322 assert_eq!( 323 cond_else!(input, a == 1, call!(parse_u8), value!(0x02)), 324 Ok((empty, 0x01)) 325 ); 326 assert_eq!( 327 cond_else!(input, a == 1, parse_u8, value!(0x02)), 328 Ok((empty, 0x01)) 329 ); 330 assert_eq!( 331 cond_else!(input, a == 2, parse_u8, value!(0x02)), 332 Ok((input, 0x02)) 333 ); 334 assert_eq!( 335 cond_else!(input, a == 1, value!(0x02), parse_u8), 336 Ok((input, 0x02)) 337 ); 338 let res: IResult<&[u8], u8> = cond_else!(input, a == 1, parse_u8, parse_u8); 339 assert_eq!(res, Ok((empty, 0x01))); 340 } 341 342 #[test] 343 fn test_newtype_enum() { 344 #[derive(Debug, PartialEq, Eq)] 345 struct MyType(pub u8); 346 347 newtype_enum! { 348 impl display MyType { 349 Val1 = 0, 350 Val2 = 1 351 } 352 } 353 354 assert_eq!(MyType(0), MyType::Val1); 355 assert_eq!(MyType(1), MyType::Val2); 356 357 assert_eq!(format!("{}", MyType(0)), "Val1"); 358 assert_eq!(format!("{}", MyType(4)), "MyType(4 / 0x4)"); 359 } 360 #[test] 361 fn test_flat_take() { 362 let input = &[0x00, 0x01, 0xff]; 363 // read first 2 bytes and use correct combinator: OK 364 let res: IResult<&[u8], u16> = flat_take!(input, 2, be_u16); 365 assert_eq!(res, Ok((&input[2..], 0x0001))); 366 // read 3 bytes and use 2: OK (some input is just lost) 367 let res: IResult<&[u8], u16> = flat_take!(input, 3, be_u16); 368 assert_eq!(res, Ok((&b""[..], 0x0001))); 369 // read 2 bytes and a combinator requiring more bytes 370 let res: IResult<&[u8], u32> = flat_take!(input, 2, be_u32); 371 assert_eq!(res, Err(Err::Incomplete(Needed::Size(4)))); 372 // test with macro as sub-combinator 373 let res: IResult<&[u8], u16> = flat_take!(input, 2, be_u16); 374 assert_eq!(res, Ok((&input[2..], 0x0001))); 375 } 376 377 #[test] 378 fn test_q() { 379 let empty = &b""[..]; 380 let res: IResult<&[u8], &str, ErrorKind> = q!(empty, "test"); 381 assert_eq!(res, Ok((empty, "test"))); 382 } 383 384 #[test] 385 fn test_align32() { 386 assert_eq!(align32!(3), 4); 387 assert_eq!(align32!(4), 4); 388 assert_eq!(align32!(5), 8); 389 assert_eq!(align32!(5u32), 8); 390 assert_eq!(align32!(5i32), 8); 391 assert_eq!(align32!(5usize), 8); 392 } 393 } 394