1 //! Helper macros
2
3 use nom::bytes::complete::take;
4 use nom::combinator::map_res;
5 use nom::IResult;
6
7 #[doc(hidden)]
8 pub mod export {
9 pub use core::{fmt, mem, ptr};
10 }
11
12 /// Helper macro for newtypes: declare associated constants and implement Display trait
13 #[macro_export]
14 macro_rules! newtype_enum (
15 (@collect_impl, $name:ident, $($key:ident = $val:expr),* $(,)*) => {
16 $( pub const $key : $name = $name($val); )*
17 };
18
19 (@collect_disp, $name:ident, $f:ident, $m:expr, $($key:ident = $val:expr),* $(,)*) => {
20 match $m {
21 $( $val => write!($f, stringify!{$key}), )*
22 n => write!($f, "{}({} / 0x{:x})", stringify!{$name}, n, n)
23 }
24 };
25
26 // entry
27 (impl $name:ident {$($body:tt)*}) => (
28 #[allow(non_upper_case_globals)]
29 impl $name {
30 newtype_enum!{@collect_impl, $name, $($body)*}
31 }
32 );
33
34 // entry with display
35 (impl display $name:ident {$($body:tt)*}) => (
36 newtype_enum!(impl $name { $($body)* });
37
38 impl $crate::export::fmt::Display for $name {
39 fn fmt(&self, f: &mut $crate::export::fmt::Formatter) -> $crate::export::fmt::Result {
40 newtype_enum!(@collect_disp, $name, f, self.0, $($body)*)
41 }
42 }
43 );
44
45 // entry with display and debug
46 (impl debug $name:ident {$($body:tt)*}) => (
47 newtype_enum!(impl display $name { $($body)* });
48
49 impl $crate::export::fmt::Debug for $name {
50 fn fmt(&self, f: &mut $crate::export::fmt::Formatter) -> $crate::export::fmt::Result {
51 write!(f, "{}", self)
52 }
53 }
54 );
55 );
56
57 /// Helper macro for nom parsers: raise error if the condition is true
58 ///
59 /// This macro is used when using custom errors
60 #[macro_export]
61 macro_rules! custom_check (
62 ($i:expr, $cond:expr, $err:expr) => (
63 {
64 if $cond {
65 Err(::nom::Err::Error($err))
66 } else {
67 Ok(($i, ()))
68 }
69 }
70 );
71 );
72
73 /// Helper macro for nom parsers: raise error if the condition is true
74 ///
75 /// This macro is used when using `ErrorKind`
76 #[macro_export]
77 macro_rules! error_if (
78 ($i:expr, $cond:expr, $err:expr) => (
79 {
80 use nom::error_position;
81 if $cond {
82 Err(::nom::Err::Error(error_position!($i, $err)))
83 } else {
84 Ok(($i, ()))
85 }
86 }
87 );
88 );
89
90 /// Helper macro for nom parsers: raise error if input is not empty
91 ///
92 /// Deprecated - use `nom::eof`
93 #[macro_export]
94 #[deprecated(since = "2.0.0")]
95 macro_rules! empty (
96 ($i:expr,) => (
97 {
98 use nom::eof;
99 eof!($i,)
100 }
101 );
102 );
103
104 #[deprecated(since = "3.0.1", note = "please use `be_var_u64` instead")]
105 /// Read an entire slice as a big-endian value.
106 ///
107 /// Returns the value as `u64`. This function checks for integer overflows, and returns a
108 /// `Result::Err` value if the value is too big.
bytes_to_u64(s: &[u8]) -> Result<u64, &'static str>109 pub fn bytes_to_u64(s: &[u8]) -> Result<u64, &'static str> {
110 let mut u: u64 = 0;
111
112 if s.is_empty() {
113 return Err("empty");
114 };
115 if s.len() > 8 {
116 return Err("overflow");
117 }
118 for &c in s {
119 let u1 = u << 8;
120 u = u1 | (c as u64);
121 }
122
123 Ok(u)
124 }
125
126 /// Read a slice as a big-endian value.
127 #[macro_export]
128 macro_rules! parse_hex_to_u64 (
129 ( $i:expr, $size:expr ) => {
130 map_res(take($size as usize), $crate::combinator::be_var_u64)($i)
131 };
132 );
133
134 /// Read 3 bytes as an unsigned integer
135 #[deprecated(since = "0.5.0", note = "please use `be_u24` instead")]
136 #[allow(deprecated)]
137 #[inline]
parse_uint24(i: &[u8]) -> IResult<&[u8], u64>138 pub fn parse_uint24(i: &[u8]) -> IResult<&[u8], u64> {
139 map_res(take(3usize), bytes_to_u64)(i)
140 }
141
142 //named!(parse_hex4<&[u8], u64>, parse_hex_to_u64!(4));
143
144 /// Combination and flat_map! and take! as first combinator
145 #[macro_export]
146 macro_rules! flat_take (
147 ($i:expr, $len:expr, $f:ident) => ({
148 if $i.len() < $len { Err(::nom::Err::Incomplete(::nom::Needed::new($len))) }
149 else {
150 let taken = &$i[0..$len];
151 let rem = &$i[$len..];
152 match $f(taken) {
153 Ok((_,res)) => Ok((rem,res)),
154 Err(e) => Err(e)
155 }
156 }
157 });
158 ($i:expr, $len:expr, $submac:ident!( $($args:tt)*)) => ({
159 if $i.len() < $len { Err(::nom::Err::Incomplete(::nom::Needed::new($len))) }
160 else {
161 let taken = &$i[0..$len];
162 let rem = &$i[$len..];
163 match $submac!(taken, $($args)*) {
164 Ok((_,res)) => Ok((rem,res)),
165 Err(e) => Err(e)
166 }
167 }
168 });
169 );
170
171 /// Apply combinator, trying to "upgrade" error to next error type (using the `Into` or `From`
172 /// traits).
173 #[macro_export]
174 macro_rules! upgrade_error (
175 ($i:expr, $submac:ident!( $($args:tt)*) ) => ({
176 upgrade_error!( $submac!( $i, $($args)* ) )
177 });
178 ($i:expr, $f:expr) => ({
179 upgrade_error!( call!($i, $f) )
180 });
181 ($e:expr) => ({
182 match $e {
183 Ok(o) => Ok(o),
184 Err(::nom::Err::Error(e)) => Err(::nom::Err::Error(e.into())),
185 Err(::nom::Err::Failure(e)) => Err(::nom::Err::Failure(e.into())),
186 Err(::nom::Err::Incomplete(i)) => Err(::nom::Err::Incomplete(i)),
187 }
188 });
189 );
190
191 /// Apply combinator, trying to "upgrade" error to next error type (using the `Into` or `From`
192 /// traits).
193 #[macro_export]
194 macro_rules! upgrade_error_to (
195 ($i:expr, $ty:ty, $submac:ident!( $($args:tt)*) ) => ({
196 upgrade_error_to!( $ty, $submac!( $i, $($args)* ) )
197 });
198 ($i:expr, $ty:ty, $f:expr) => ({
199 upgrade_error_to!( $ty, call!($i, $f) )
200 });
201 ($ty:ty, $e:expr) => ({
202 match $e {
203 Ok(o) => Ok(o),
204 Err(::nom::Err::Error(e)) => Err(::nom::Err::Error(e.into::<$ty>())),
205 Err(::nom::Err::Failure(e)) => Err(::nom::Err::Failure(e.into::<$ty>())),
206 Err(::nom::Err::Incomplete(i)) => Err(::nom::Err::Incomplete(i)),
207 }
208 });
209 );
210
211 /// Nom combinator that returns the given expression unchanged
212 #[macro_export]
213 macro_rules! q {
214 ($i:expr, $x:expr) => {{
215 Ok(($i, $x))
216 }};
217 }
218
219 /// Align input value to the next multiple of n bytes
220 /// Valid only if n is a power of 2
221 #[macro_export]
222 macro_rules! align_n2 {
223 ($x:expr, $n:expr) => {
224 ($x + ($n - 1)) & !($n - 1)
225 };
226 }
227
228 /// Align input value to the next multiple of 4 bytes
229 #[macro_export]
230 macro_rules! align32 {
231 ($x:expr) => {
232 $crate::align_n2!($x, 4)
233 };
234 }
235
236 #[cfg(test)]
237 mod tests {
238 use nom::error::ErrorKind;
239 use nom::number::streaming::{be_u16, be_u32};
240 use nom::{error_position, Err, IResult, Needed};
241
242 #[test]
test_error_if()243 fn test_error_if() {
244 let empty = &b""[..];
245 let res: IResult<&[u8], ()> = error_if!(empty, true, ErrorKind::Tag);
246 assert_eq!(res, Err(Err::Error(error_position!(empty, ErrorKind::Tag))));
247 }
248
249 #[test]
test_newtype_enum()250 fn test_newtype_enum() {
251 #[derive(Debug, PartialEq, Eq)]
252 struct MyType(pub u8);
253
254 newtype_enum! {
255 impl display MyType {
256 Val1 = 0,
257 Val2 = 1
258 }
259 }
260
261 assert_eq!(MyType(0), MyType::Val1);
262 assert_eq!(MyType(1), MyType::Val2);
263
264 assert_eq!(format!("{}", MyType(0)), "Val1");
265 assert_eq!(format!("{}", MyType(4)), "MyType(4 / 0x4)");
266 }
267 #[test]
test_flat_take()268 fn test_flat_take() {
269 let input = &[0x00, 0x01, 0xff];
270 // read first 2 bytes and use correct combinator: OK
271 let res: IResult<&[u8], u16> = flat_take!(input, 2, be_u16);
272 assert_eq!(res, Ok((&input[2..], 0x0001)));
273 // read 3 bytes and use 2: OK (some input is just lost)
274 let res: IResult<&[u8], u16> = flat_take!(input, 3, be_u16);
275 assert_eq!(res, Ok((&b""[..], 0x0001)));
276 // read 2 bytes and a combinator requiring more bytes
277 let res: IResult<&[u8], u32> = flat_take!(input, 2, be_u32);
278 assert_eq!(res, Err(Err::Incomplete(Needed::new(2))));
279 // test with macro as sub-combinator
280 let res: IResult<&[u8], u16> = flat_take!(input, 2, be_u16);
281 assert_eq!(res, Ok((&input[2..], 0x0001)));
282 }
283
284 #[test]
test_q()285 fn test_q() {
286 let empty = &b""[..];
287 let res: IResult<&[u8], &str, ErrorKind> = q!(empty, "test");
288 assert_eq!(res, Ok((empty, "test")));
289 }
290
291 #[test]
test_align32()292 fn test_align32() {
293 assert_eq!(align32!(3), 4);
294 assert_eq!(align32!(4), 4);
295 assert_eq!(align32!(5), 8);
296 assert_eq!(align32!(5u32), 8);
297 assert_eq!(align32!(5i32), 8);
298 assert_eq!(align32!(5usize), 8);
299 }
300 }
301