81 lines · 2.6 KB · Rust
RawDownload
use bstr::{BStr, BString, ByteVec};use nom::{    bytes::complete::{is_not, tag, take_until, take_while_m_n},    combinator::{peek, recognize},    error::{context, ContextError, ParseError},    multi::many1_count,    sequence::{preceded, terminated, tuple},    IResult,}; use crate::ByteSlice; pub(crate) const NL: &[u8] = b"\n";pub(crate) const SPACE: &[u8] = b" ";const SPACE_OR_NL: &[u8] = b" \n"; pub(crate) fn any_header_field_multi_line<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>(    i: &'a [u8],) -> IResult<&'a [u8], (&'a [u8], BString), E> {    let (i, (k, o)) = context(        "name <multi-line-value>",        peek(tuple((            terminated(is_not(SPACE_OR_NL), tag(SPACE)),            recognize(tuple((                is_not(NL),                tag(NL),                many1_count(terminated(tuple((tag(SPACE), take_until(NL))), tag(NL))),            ))),        ))),    )(i)?;    assert!(!o.is_empty(), "we have parsed more than one value here");    let end = &o[o.len() - 1] as *const u8 as usize;    let start_input = &i[0] as *const u8 as usize;     let bytes = o[..o.len() - 1].as_bstr();    let mut out = BString::from(Vec::with_capacity(bytes.len()));    let mut lines = bytes.lines();    out.push_str(lines.next().expect("first line"));    for line in lines {        out.push(b'\n');        out.push_str(&line[1..]); // cut leading space    }    Ok((&i[end - start_input + 1..], (k, out)))} pub(crate) fn header_field<'a, T, E: ParseError<&'a [u8]>>(    i: &'a [u8],    name: &'static [u8],    parse_value: impl Fn(&'a [u8]) -> IResult<&'a [u8], T, E>,) -> IResult<&'a [u8], T, E> {    terminated(preceded(terminated(tag(name), tag(SPACE)), parse_value), tag(NL))(i)} pub(crate) fn any_header_field<'a, T, E: ParseError<&'a [u8]>>(    i: &'a [u8],    parse_value: impl Fn(&'a [u8]) -> IResult<&'a [u8], T, E>,) -> IResult<&'a [u8], (&'a [u8], T), E> {    terminated(        tuple((terminated(is_not(SPACE_OR_NL), tag(SPACE)), parse_value)),        tag(NL),    )(i)} fn is_hex_digit_lc(b: u8) -> bool {    matches!(b, b'0'..=b'9' | b'a'..=b'f')} pub fn hex_hash<'a, E: ParseError<&'a [u8]>>(i: &'a [u8]) -> IResult<&'a [u8], &'a BStr, E> {    take_while_m_n(        gix_hash::Kind::shortest().len_in_hex(),        gix_hash::Kind::longest().len_in_hex(),        is_hex_digit_lc,    )(i)    .map(|(i, hex)| (i, hex.as_bstr()))} pub(crate) fn signature<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>(    i: &'a [u8],) -> IResult<&'a [u8], gix_actor::SignatureRef<'a>, E> {    gix_actor::signature::decode(i)}