1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
use std::borrow::Cow;
use std::str;

use encoding::{Encoding, DecoderTrap};
use encoding::all::ASCII;

use nom::IResult;
use nom::bytes::complete::take;
use nom::combinator::{map, recognize, verify};
use nom::multi::{fold_many0, fold_many1};
// Change this to something else that implements ParseError to get a
// different error type out of nom.
pub(crate) type NomError<'a> = ();

/// Shortcut type for taking in bytes and spitting out a success or NomError.
pub type NomResult<'a, O, E=NomError<'a>> = IResult<&'a [u8], O, E>;

pub fn ascii_to_string<'a, T: Into<Cow<'a, [u8]>>>(i: T) -> Cow<'a, str> {
    let i = i.into();

    if i.is_ascii() {
        match i {
            Cow::Borrowed(i) => Cow::Borrowed(str::from_utf8(i).unwrap()),
            Cow::Owned(i) => Cow::Owned(String::from_utf8(i).unwrap()),
        }
    } else {
        Cow::Owned(ASCII.decode(&i, DecoderTrap::Replace).unwrap())
    }
}

macro_rules! nom_fromstr {
    ( $type:ty, $func:path ) => {
        impl std::str::FromStr for $type {
            type Err = ();

            fn from_str(s: &str) -> Result<Self, Self::Err> {
                exact!(s.as_bytes(), $func).map(|(_, r)| r).map_err(|_| ())
            }
        }
        impl <'a> std::convert::TryFrom<&'a [u8]> for $type {
            type Error = nom::Err<NomError<'a>>;

            fn try_from(value: &'a [u8]) -> Result<Self, Self::Error> {
                exact!(value, $func).map(|(_, v)| v)
            }
        }
        impl <'a> std::convert::TryFrom<&'a str> for $type {
            type Error = nom::Err<NomError<'a>>;

            fn try_from(value: &'a str) -> Result<Self, Self::Error> {
                exact!(value.as_bytes(), $func).map(|(_, v)| v)
            }
        }
    }
}

macro_rules! nom_from_smtp {
    ( $smtp_func:path ) => {
        /// Parse using SMTP syntax.
        pub fn from_smtp(value: &[u8]) -> Result<Self, nom::Err<NomError>> {
            exact!(value, $smtp_func).map(|(_, v)| v)
        }
    }
}
macro_rules! nom_from_imf {
    ( $imf_func:path ) => {
        /// Parse using Internet Message Format syntax.
        pub fn from_imf(value: &[u8]) -> Result<Self, nom::Err<NomError>> {
            exact!(value, $imf_func).map(|(_, v)| v)
        }
    }
}

macro_rules! string_newtype {
    ( $type:ident ) => {
        impl std::fmt::Display for $type {
            fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
                write!(f, "{}", self.0)
            }
        }
        impl std::convert::AsRef<[u8]> for $type {
            fn as_ref(&self) -> &[u8] {
                self.0.as_bytes()
            }
        }
        impl std::ops::Deref for $type {
            type Target = str;
            fn deref(&self) -> &Self::Target {
                &self.0
            }
        }
        impl From<$type> for String {
            fn from(value: $type) -> String {
                value.0
            }
        }

        impl std::fmt::Debug for $type {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                write!(f, "{:?}", self.0)
            }
        }
    }
}

pub(crate) fn fold_prefix0<I, O, E, F, G>(prefix: F, cont: G) -> impl Fn(I) -> IResult<I, Vec<O>, E>
    where I: Clone + PartialEq,
          F: Fn(I) -> IResult<I, O, E>,
          G: Fn(I) -> IResult<I, O, E>,
          E: nom::error::ParseError::<I>,
          Vec<O>: Clone,
{
    move |input: I| {
        let (rem, v1) = prefix(input)?;
        let out = vec![v1];

        fold_many0(&cont, out, |mut acc, value| {
            acc.push(value);
            acc
        })(rem)
    }
}

pub(crate) fn recognize_many0<I, O, E, F>(f: F) -> impl Fn(I) -> IResult<I, I, E>
    where I: Clone + PartialEq + nom::Slice<std::ops::RangeTo<usize>> + nom::Offset,
          F: Fn(I) -> IResult<I, O, E>,
          E: nom::error::ParseError::<I>,
{
    recognize(fold_many0(f, (), |_, _| ()))
}

pub(crate) fn recognize_many1<I, O, E, F>(f: F) -> impl Fn(I) -> IResult<I, I, E>
    where I: Clone + PartialEq + nom::Slice<std::ops::RangeTo<usize>> + nom::Offset,
          F: Fn(I) -> IResult<I, O, E>,
          E: nom::error::ParseError::<I>,
{
    recognize(fold_many1(f, (), |_, _| ()))
}

pub(crate) fn take1_filter<F>(pred: F) -> impl Fn(&[u8]) -> NomResult<u8>
    where F: Fn(u8) -> bool,
{
    move |input| {
        verify(map(take(1usize), |c: &[u8]| c[0]), |c| pred(*c))(input)
    }
}