/rust/registry/src/index.crates.io-6f17d22bba15001f/rusticata-macros-4.1.0/src/macros.rs
Line | Count | Source (jump to first uncovered line) |
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 | 0 | fn fmt(&self, f: &mut $crate::export::fmt::Formatter) -> $crate::export::fmt::Result { |
40 | 0 | newtype_enum!(@collect_disp, $name, f, self.0, $($body)*) |
41 | 0 | } Unexecuted instantiation: <x509_parser::x509::X509Version as core::fmt::Display>::fmt Unexecuted instantiation: <x509_parser::x509::ReasonCode as core::fmt::Display>::fmt Unexecuted instantiation: <asn1_rs::tag::Tag as core::fmt::Display>::fmt |
42 | 0 | } |
43 | 0 | ); |
44 | 0 |
|
45 | 0 | // entry with display and debug |
46 | 0 | (impl debug $name:ident {$($body:tt)*}) => ( |
47 | 0 | newtype_enum!(impl display $name { $($body)* }); |
48 | 0 |
|
49 | 0 | impl $crate::export::fmt::Debug for $name { |
50 | 0 | fn fmt(&self, f: &mut $crate::export::fmt::Formatter) -> $crate::export::fmt::Result { |
51 | 0 | write!(f, "{}", self) |
52 | 0 | } |
53 | 0 | } |
54 | 0 | ); |
55 | 0 | ); |
56 | 0 |
|
57 | 0 | /// Helper macro for nom parsers: raise error if the condition is true |
58 | 0 | /// |
59 | 0 | /// This macro is used when using custom errors |
60 | 0 | #[macro_export] |
61 | 0 | macro_rules! custom_check ( |
62 | 0 | ($i:expr, $cond:expr, $err:expr) => ( |
63 | 0 | { |
64 | 0 | if $cond { |
65 | 0 | Err(::nom::Err::Error($err)) |
66 | 0 | } else { |
67 | 0 | Ok(($i, ())) |
68 | 0 | } |
69 | 0 | } |
70 | 0 | ); |
71 | 0 | ); |
72 | 0 |
|
73 | 0 | /// Helper macro for nom parsers: raise error if the condition is true |
74 | 0 | /// |
75 | 0 | /// This macro is used when using `ErrorKind` |
76 | 0 | #[macro_export] |
77 | 0 | macro_rules! error_if ( |
78 | 0 | ($i:expr, $cond:expr, $err:expr) => ( |
79 | 0 | { |
80 | 0 | use nom::error_position; |
81 | 0 | if $cond { |
82 | 0 | Err(::nom::Err::Error(error_position!($i, $err))) |
83 | 0 | } else { |
84 | 0 | Ok(($i, ())) |
85 | 0 | } |
86 | 0 | } |
87 | 0 | ); |
88 | 0 | ); |
89 | 0 |
|
90 | 0 | /// Helper macro for nom parsers: raise error if input is not empty |
91 | 0 | /// |
92 | 0 | /// Deprecated - use `nom::eof` |
93 | 0 | #[macro_export] |
94 | 0 | #[deprecated(since = "2.0.0")] |
95 | 0 | macro_rules! empty ( |
96 | 0 | ($i:expr,) => ( |
97 | 0 | { |
98 | 0 | use nom::eof; |
99 | 0 | eof!($i,) |
100 | 0 | } |
101 | 0 | ); |
102 | 0 | ); |
103 | 0 |
|
104 | 0 | #[deprecated(since = "3.0.1", note = "please use `be_var_u64` instead")] |
105 | 0 | /// Read an entire slice as a big-endian value. |
106 | 0 | /// |
107 | 0 | /// Returns the value as `u64`. This function checks for integer overflows, and returns a |
108 | 0 | /// `Result::Err` value if the value is too big. |
109 | 0 | pub fn bytes_to_u64(s: &[u8]) -> Result<u64, &'static str> { |
110 | 0 | let mut u: u64 = 0; |
111 | 0 |
|
112 | 0 | if s.is_empty() { |
113 | 0 | return Err("empty"); |
114 | 0 | }; |
115 | 0 | if s.len() > 8 { |
116 | 0 | return Err("overflow"); |
117 | 0 | } |
118 | 0 | for &c in s { |
119 | 0 | let u1 = u << 8; |
120 | 0 | u = u1 | (c as u64); |
121 | 0 | } |
122 | | |
123 | 0 | Ok(u) |
124 | 0 | } |
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] |
138 | 0 | pub fn parse_uint24(i: &[u8]) -> IResult<&[u8], u64> { |
139 | 0 | map_res(take(3usize), bytes_to_u64)(i) |
140 | 0 | } |
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] |
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] |
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] |
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] |
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] |
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 | | } |