49 lines · 1.6 KB · Rust
RawDownload
use winnow::{    combinator::{alt, eof, preceded, terminated},    error::ParserError,    prelude::*,    stream::{Offset, Stream},    token::{rest, take_till},}; use crate::bstr::{BStr, ByteSlice}; pub(crate) fn newline<'a, E: ParserError<&'a [u8]>>(i: &mut &'a [u8]) -> ModalResult<&'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]) -> ModalResult<(&'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 separatorpub fn message(mut input: &[u8]) -> (&BStr, Option<&BStr>) {    terminated(subject_and_body::<()>, eof)        .parse_next(&mut input)        .expect("cannot fail")}