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::, newline::), 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") }