time/parsing/combinator/rfc/
rfc2822.rs1use crate::parsing::combinator::rfc::rfc2234::wsp;
6use crate::parsing::combinator::{ascii_char, one_or_more, zero_or_more};
7use crate::parsing::ParsedItem;
8
9#[inline]
12pub(crate) fn fws(mut input: &[u8]) -> Option<ParsedItem<'_, ()>> {
13 if let [b'\r', b'\n', rest @ ..] = input {
14 one_or_more(wsp)(rest)
15 } else {
16 input = one_or_more(wsp)(input)?.into_inner();
17 while let [b'\r', b'\n', rest @ ..] = input {
18 input = one_or_more(wsp)(rest)?.into_inner();
19 }
20 Some(ParsedItem(input, ()))
21 }
22}
23
24#[inline]
27pub(crate) fn cfws(input: &[u8]) -> Option<ParsedItem<'_, ()>> {
28 one_or_more(|input| fws(input).or_else(|| comment(input)))(input)
29}
30
31#[inline]
33fn comment(mut input: &[u8]) -> Option<ParsedItem<'_, ()>> {
34 input = ascii_char::<b'('>(input)?.into_inner();
35 input = zero_or_more(fws)(input).into_inner();
36 while let Some(rest) = ccontent(input) {
37 input = rest.into_inner();
38 input = zero_or_more(fws)(input).into_inner();
39 }
40 input = ascii_char::<b')'>(input)?.into_inner();
41
42 Some(ParsedItem(input, ()))
43}
44
45#[inline]
47fn ccontent(input: &[u8]) -> Option<ParsedItem<'_, ()>> {
48 ctext(input)
49 .or_else(|| quoted_pair(input))
50 .or_else(|| comment(input))
51}
52
53#[expect(
55 clippy::unnecessary_lazy_evaluations,
56 reason = "rust-lang/rust-clippy#8522"
57)]
58#[inline]
59fn ctext(input: &[u8]) -> Option<ParsedItem<'_, ()>> {
60 no_ws_ctl(input).or_else(|| match input {
61 [33..=39 | 42..=91 | 93..=126, rest @ ..] => Some(ParsedItem(rest, ())),
62 _ => None,
63 })
64}
65
66#[inline]
68fn quoted_pair(mut input: &[u8]) -> Option<ParsedItem<'_, ()>> {
69 input = ascii_char::<b'\\'>(input)?.into_inner();
70 input = text(input).into_inner();
71
72 Some(ParsedItem(input, ()))
79}
80
81#[inline]
83const fn no_ws_ctl(input: &[u8]) -> Option<ParsedItem<'_, ()>> {
84 match input {
85 [1..=8 | 11..=12 | 14..=31 | 127, rest @ ..] => Some(ParsedItem(rest, ())),
86 _ => None,
87 }
88}
89
90#[inline]
92fn text<'a>(input: &'a [u8]) -> ParsedItem<'a, ()> {
93 let new_text = |input: &'a [u8]| match input {
94 [1..=9 | 11..=12 | 14..=127, rest @ ..] => Some(ParsedItem(rest, ())),
95 _ => None,
96 };
97
98 let obs_char = |input: &'a [u8]| match input {
99 [b')', ..] => None,
102 [0..=9 | 11..=12 | 14..=127, rest @ ..] => Some(rest),
103 _ => None,
104 };
105
106 let obs_text = |mut input| {
107 input = zero_or_more(ascii_char::<b'\n'>)(input).into_inner();
108 input = zero_or_more(ascii_char::<b'\r'>)(input).into_inner();
109 while let Some(rest) = obs_char(input) {
110 input = rest;
111 input = zero_or_more(ascii_char::<b'\n'>)(input).into_inner();
112 input = zero_or_more(ascii_char::<b'\r'>)(input).into_inner();
113 }
114
115 ParsedItem(input, ())
116 };
117
118 new_text(input).unwrap_or_else(|| obs_text(input))
119}