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
|
use winnow::{
combinator::{alt, eof, preceded, rest, terminated},
error::ParserError,
prelude::*,
stream::{Offset, Stream},
token::take_till,
};
use crate::bstr::{BStr, ByteSlice};
pub(crate) fn newline<'a, E: ParserError<&'a [u8]>>(i: &mut &'a [u8]) -> PResult<&'a [u8], E> {
alt((b"\n", b"\r\n")).parse_next(i)
}
fn subject_and_body<'a, E: ParserError<&'a [u8]>>(i: &mut &'a [u8]) -> PResult<(&'a BStr, Option<&'a BStr>), E> {
let start_i = *i;
let start = i.checkpoint();
while !i.is_empty() {
match take_till::<_, _, E>(1.., |c| c == b'\n' || c == b'\r').parse_next(i) {
Ok(_) => {
let consumed_bytes = i.offset_from(&start);
match preceded((newline::<E>, newline::<E>), rest).parse_next(i) {
Ok(body) => {
let body = (!body.is_empty()).then(|| body.as_bstr());
return Ok((start_i[0usize..consumed_bytes].as_bstr(), body));
}
Err(_) => match i.next_token() {
Some(_) => {}
None => break,
},
}
}
Err(_) => match i.next_token() {
Some(_) => {}
None => break,
},
}
}
i.reset(start);
rest.map(|r: &[u8]| (r.as_bstr(), None)).parse_next(i)
}
/// Returns title and body, without separator
pub fn message(mut input: &[u8]) -> (&BStr, Option<&BStr>) {
terminated(subject_and_body::<()>, eof)
.parse_next(&mut input)
.expect("cannot fail")
}
|