summaryrefslogtreecommitdiffstats
path: root/vendor/gix-object/src/parse.rs
blob: 0013d9b72a35e743e25b203b8474eb94b299de3c (plain)
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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
use bstr::{BStr, BString, ByteVec};
use winnow::{
    combinator::{preceded, repeat, terminated},
    error::{AddContext, ParserError, StrContext},
    prelude::*,
    token::{take_till1, take_until0, take_while},
    Parser,
};

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: ParserError<&'a [u8]> + AddContext<&'a [u8], StrContext>>(
    i: &mut &'a [u8],
) -> PResult<(&'a [u8], BString), E> {
    (
        terminated(take_till1(SPACE_OR_NL), SPACE),
        (
            take_till1(NL),
            NL,
            repeat(1.., terminated((SPACE, take_until0(NL)), NL)).map(|()| ()),
        )
            .recognize()
            .map(|o: &[u8]| {
                let bytes = o.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
                }
                out
            }),
    )
        .context(StrContext::Expected("name <multi-line-value>".into()))
        .parse_next(i)
}

pub(crate) fn header_field<'a, T, E: ParserError<&'a [u8]>>(
    i: &mut &'a [u8],
    name: &'static [u8],
    parse_value: impl Parser<&'a [u8], T, E>,
) -> PResult<T, E> {
    terminated(preceded(terminated(name, SPACE), parse_value), NL).parse_next(i)
}

pub(crate) fn any_header_field<'a, T, E: ParserError<&'a [u8]>>(
    i: &mut &'a [u8],
    parse_value: impl Parser<&'a [u8], T, E>,
) -> PResult<(&'a [u8], T), E> {
    terminated((terminated(take_till1(SPACE_OR_NL), SPACE), parse_value), NL).parse_next(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: ParserError<&'a [u8]>>(i: &mut &'a [u8]) -> PResult<&'a BStr, E> {
    take_while(
        gix_hash::Kind::shortest().len_in_hex()..=gix_hash::Kind::longest().len_in_hex(),
        is_hex_digit_lc,
    )
    .map(ByteSlice::as_bstr)
    .parse_next(i)
}

pub(crate) fn signature<'a, E: ParserError<&'a [u8]> + AddContext<&'a [u8], StrContext>>(
    i: &mut &'a [u8],
) -> PResult<gix_actor::SignatureRef<'a>, E> {
    gix_actor::signature::decode(i)
}