2023-07-24 12:41:21 +00:00
|
|
|
|
2023-07-23 14:37:47 +00:00
|
|
|
use crate::text::misc_token::{unstructured, Unstructured};
|
|
|
|
use crate::text::whitespace::{foldable_line, obs_crlf};
|
2023-07-20 14:26:59 +00:00
|
|
|
use nom::{
|
2023-07-22 11:51:19 +00:00
|
|
|
branch::alt,
|
2023-07-23 14:37:47 +00:00
|
|
|
bytes::complete::{tag, tag_no_case, take_while1},
|
2023-07-20 14:26:59 +00:00
|
|
|
character::complete::space0,
|
2023-07-23 14:37:47 +00:00
|
|
|
combinator::map,
|
2023-07-24 17:19:49 +00:00
|
|
|
multi::{fold_many0},
|
2023-07-23 07:46:57 +00:00
|
|
|
sequence::{pair, terminated, tuple},
|
2023-07-23 14:37:47 +00:00
|
|
|
IResult,
|
2023-07-20 14:26:59 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
#[derive(Debug, PartialEq)]
|
|
|
|
pub enum CompField<'a, T> {
|
|
|
|
Known(T),
|
2023-07-24 17:19:49 +00:00
|
|
|
Unknown(Kv<'a>),
|
2023-07-20 14:26:59 +00:00
|
|
|
Bad(&'a [u8]),
|
|
|
|
}
|
|
|
|
|
2023-07-24 20:08:13 +00:00
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
|
|
|
pub struct Kv<'a>(pub &'a [u8], pub Unstructured<'a>);
|
2023-07-24 17:19:49 +00:00
|
|
|
|
2023-07-20 14:26:59 +00:00
|
|
|
|
2023-07-23 14:37:47 +00:00
|
|
|
pub fn header<'a, T>(
|
|
|
|
fx: impl Fn(&'a [u8]) -> IResult<&'a [u8], T> + Copy,
|
2023-07-24 17:19:49 +00:00
|
|
|
) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], (Vec::<T>, Vec::<Kv>, Vec<&'a [u8]>)> {
|
2023-07-23 14:37:47 +00:00
|
|
|
move |input| {
|
|
|
|
terminated(
|
2023-07-24 17:19:49 +00:00
|
|
|
fold_many0(
|
|
|
|
alt((
|
|
|
|
map(fx, CompField::Known),
|
|
|
|
map(opt_field, |(k, v)| CompField::Unknown(Kv(k, v))),
|
|
|
|
map(foldable_line, CompField::Bad),
|
|
|
|
)),
|
|
|
|
|| (Vec::<T>::new(), Vec::<Kv>::new(), Vec::<&'a [u8]>::new()),
|
|
|
|
|(mut known, mut unknown, mut bad), item| {
|
|
|
|
match item {
|
|
|
|
CompField::Known(v) => known.push(v),
|
|
|
|
CompField::Unknown(v) => unknown.push(v),
|
|
|
|
CompField::Bad(v) => bad.push(v),
|
|
|
|
};
|
|
|
|
(known, unknown, bad)
|
|
|
|
}
|
|
|
|
),
|
2023-07-23 14:37:47 +00:00
|
|
|
obs_crlf,
|
2023-07-24 17:19:49 +00:00
|
|
|
)(input)
|
2023-07-23 14:37:47 +00:00
|
|
|
}
|
2023-07-22 11:51:19 +00:00
|
|
|
}
|
|
|
|
|
2023-07-20 14:26:59 +00:00
|
|
|
pub fn field_name<'a>(name: &'static [u8]) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], &'a [u8]> {
|
2023-07-23 14:37:47 +00:00
|
|
|
move |input| terminated(tag_no_case(name), tuple((space0, tag(b":"), space0)))(input)
|
2023-07-20 14:26:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Optional field
|
|
|
|
///
|
|
|
|
/// ```abnf
|
|
|
|
/// field = field-name ":" unstructured CRLF
|
|
|
|
/// field-name = 1*ftext
|
|
|
|
/// ftext = %d33-57 / ; Printable US-ASCII
|
|
|
|
/// %d59-126 ; characters not including
|
|
|
|
/// ; ":".
|
|
|
|
/// ```
|
|
|
|
pub fn opt_field(input: &[u8]) -> IResult<&[u8], (&[u8], Unstructured)> {
|
2023-07-22 11:51:19 +00:00
|
|
|
terminated(
|
|
|
|
pair(
|
|
|
|
terminated(
|
2023-07-24 07:24:38 +00:00
|
|
|
take_while1(|c| (0x21..=0x7E).contains(&c) && c != 0x3A),
|
2023-07-22 11:51:19 +00:00
|
|
|
tuple((space0, tag(b":"), space0)),
|
|
|
|
),
|
|
|
|
unstructured,
|
2023-07-23 14:37:47 +00:00
|
|
|
),
|
|
|
|
obs_crlf,
|
|
|
|
)(input)
|
2023-07-20 14:26:59 +00:00
|
|
|
}
|