use nom::bytes::streaming::take; use nom::combinator::{complete, map_res, opt}; use nom::error::{Error, FromExternalError, ParseError}; use nom::multi::{many0, many_m_n}; use nom::number::streaming::*; use nom::sequence::pair; use nom::*; use std::convert::TryFrom; use std::ops::RangeFrom; pub use nom::{InputLength, Slice}; pub trait InputSlice: Slice> + InputIter + InputLength + InputTake { } impl<'a> InputSlice for &'a [u8] {} /// Common trait for all parsers in nom-derive /// /// This trait is used to provide parser implementations, usually as generic as possible for the /// error type. Implementations are provided for common and primitive types. /// The only required method is `parse`, but it is advised to implement the `parse_be` and `parse_le` /// methods. Derived code will call one of these methods, depending on the field endianness. /// /// # Example /// /// A possible implementation for the type `u32` is: /// ```rust,ignore /// impl Parse for u32 /// where /// E: ParseError, /// I: InputSlice, /// { /// fn parse(i: I) -> IResult { be_u32(i) } // default to big-endian /// fn parse_be(i: I) -> IResult { be_u32(i) } /// fn parse_le(i: I) -> IResult { le_u32(i) } /// } /// ``` /// /// # Generic type parameters and input /// /// Note: `I` is a generic type that is mostly equivalent to `&'a [u8]`. It is used to /// "hide" the lifetime of the input slice `&'a [u8]` and simplify traits implementation /// and generation of derived code. /// /// It is possible to implement the `Parse` trait only for `&[u8]` if the /// implementation contains non-generic functions. /// /// For example, the implementation for `String` is: /// ```rust,ignore /// impl<'a, E> Parse<&'a [u8], E> for String /// where /// E: ParseError<&'a [u8]> + FromExternalError<&'a [u8], std::str::Utf8Error>, /// { /// fn parse(i: &'a [u8]) -> IResult<&'a [u8], Self, E> { /// let (rem, sz) = ::parse(i)?; /// let (rem, s) = map_res(take(sz as usize), std::str::from_utf8)(rem)?; /// Ok((rem, s.to_owned())) /// } /// } /// ``` /// /// # Implementing primitives or specific types /// /// To implement an existing type differently, or a type where implementation was not provided, a /// common way is to use a newtype pattern: /// /// ```rust /// use nom_derive::{Parse, nom}; /// /// use nom::IResult; /// use nom::bytes::complete::take; /// use nom::combinator::map_res; /// use nom::error::{Error, FromExternalError, ParseError}; /// /// # #[derive(Debug, PartialEq)] /// pub struct MyString(pub String); /// impl<'a, E> Parse<&'a [u8], E> for MyString /// where /// E: ParseError<&'a [u8]> + FromExternalError<&'a [u8], std::str::Utf8Error>, /// { /// fn parse(i: &'a [u8]) -> IResult<&'a [u8], Self, E> { /// let (rem, sz) = ::parse(i)?; /// let (rem, s) = map_res(take(sz as usize), std::str::from_utf8)(rem)?; /// Ok((rem, MyString(s.to_owned()))) /// } /// } /// /// # let input = b"\x00\x00\x00\x04test"; /// // error type cannot be inferred by compiler and must be explicit /// let res: IResult<_, _, Error<_>> = MyString::parse(input); /// # assert_eq!(res, Ok((&input[8..], MyString(String::from("test"))))); /// ``` pub trait Parse> where I: InputSlice, E: ParseError, Self: Sized, { /// Parse input, not knowing the endianness /// /// Usually, this means choosing between big and little-endian. /// Default implementations for common types are big-endian. fn parse(i: I) -> IResult; /// Parse input as Big-Endian fn parse_be(i: I) -> IResult { Self::parse(i) } /// Parse input as Little-Endian fn parse_le(i: I) -> IResult { Self::parse(i) } } macro_rules! impl_primitive_type { ( $ty:ty, $be_fn: ident, $le_fn: ident ) => { impl Parse for $ty where E: ParseError, I: InputSlice, { fn parse(i: I) -> IResult { Self::parse_be(i) } fn parse_be(i: I) -> IResult { $be_fn(i) } fn parse_le(i: I) -> IResult { $le_fn(i) } } }; } impl_primitive_type!(i8, be_i8, le_i8); impl_primitive_type!(i16, be_i16, le_i16); impl_primitive_type!(i32, be_i32, le_i32); impl_primitive_type!(i64, be_i64, le_i64); impl_primitive_type!(i128, be_i128, le_i128); impl_primitive_type!(u8, be_u8, le_u8); impl_primitive_type!(u16, be_u16, le_u16); impl_primitive_type!(u32, be_u32, le_u32); impl_primitive_type!(u64, be_u64, le_u64); impl_primitive_type!(u128, be_u128, le_u128); impl_primitive_type!(f32, be_f32, le_f32); impl_primitive_type!(f64, be_f64, le_f64); impl<'a, E> Parse<&'a [u8], E> for String where E: ParseError<&'a [u8]> + FromExternalError<&'a [u8], std::str::Utf8Error>, { fn parse(i: &'a [u8]) -> IResult<&'a [u8], Self, E> { let (rem, sz) = ::parse(i)?; let (rem, s) = map_res(take(sz as usize), std::str::from_utf8)(rem)?; Ok((rem, s.to_owned())) } } impl Parse for Option where I: Clone + InputSlice, E: ParseError, T: Parse, { fn parse(i: I) -> IResult { opt(complete(::parse))(i) } fn parse_be(i: I) -> IResult { opt(complete(::parse_be))(i) } fn parse_le(i: I) -> IResult { opt(complete(::parse_le))(i) } } impl Parse for Vec where I: Clone + PartialEq + InputSlice, E: ParseError, T: Parse, { fn parse(i: I) -> IResult { many0(complete(::parse))(i) } fn parse_be(i: I) -> IResult { many0(complete(::parse_be))(i) } fn parse_le(i: I) -> IResult { many0(complete(::parse_le))(i) } } impl Parse for (T1, T2) where I: Clone + PartialEq + InputSlice, E: ParseError, T1: Parse, T2: Parse, { fn parse(i: I) -> IResult { pair(T1::parse, T2::parse)(i) } fn parse_be(i: I) -> IResult { pair(T1::parse_be, T2::parse_be)(i) } fn parse_le(i: I) -> IResult { pair(T1::parse_le, T2::parse_le)(i) } } /// *Note: this implementation uses const generics and requires rust >= 1.51* #[rustversion::since(1.51)] impl Parse for [T; N] where I: Clone + PartialEq + InputSlice, E: ParseError + FromExternalError>, T: Parse, { fn parse(i: I) -> IResult { map_res(many_m_n(N, N, complete(::parse)), Self::try_from)(i) } fn parse_be(i: I) -> IResult { map_res(many_m_n(N, N, complete(::parse_be)), |v| { Self::try_from(v) })(i) } fn parse_le(i: I) -> IResult { map_res(many_m_n(N, N, complete(::parse_le)), |v| { Self::try_from(v) })(i) } } #[cfg(test)] mod tests { use super::*; #[test] fn test_parse_trait_vec() { let input: &[u8] = b"\x00\x01\x02\x03"; type T = Vec; let res: IResult<_, _, Error<&[u8]>> = ::parse(input); assert_eq!(res.unwrap(), (b"" as &[u8], vec![0, 1, 2, 3])); } #[test] fn test_parse_trait_array() { let input: &[u8] = b"\x00\x01\x02\x03"; type T = [u8; 4]; let res: IResult<_, _, Error<&[u8]>> = ::parse(input); assert_eq!(res.unwrap(), (b"" as &[u8], [0, 1, 2, 3])); } #[test] fn test_parse_trait_string() { let input: &[u8] = b"\x00\x00\x00\x04abcd"; type T = String; let res: IResult<_, _, Error<&[u8]>> = ::parse_le(input); assert_eq!(res.unwrap(), (b"" as &[u8], String::from("abcd"))); } }