Coverage Report

Created: 2025-02-25 06:39

/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
}