git_ref/store/packed/
decode.rs1use std::convert::TryInto;
2
3use git_object::bstr::{BStr, ByteSlice};
4use nom::{
5 bytes::complete::{tag, take_while},
6 combinator::{map, map_res, opt},
7 error::{FromExternalError, ParseError},
8 sequence::{delimited, preceded, terminated, tuple},
9 IResult,
10};
11
12use crate::{
13 parse::{hex_hash, newline},
14 store_impl::packed,
15};
16
17#[derive(Debug, PartialEq, Eq)]
18enum Peeled {
19 Unspecified,
20 Partial,
21 Fully,
22}
23
24#[derive(Debug, PartialEq, Eq)]
26pub struct Header {
27 peeled: Peeled,
28 pub sorted: bool,
29}
30
31impl Default for Header {
32 fn default() -> Self {
33 Header {
34 peeled: Peeled::Unspecified,
35 sorted: false,
36 }
37 }
38}
39
40fn until_newline<'a, E>(input: &'a [u8]) -> IResult<&'a [u8], &'a BStr, E>
41where
42 E: ParseError<&'a [u8]>,
43{
44 map(
45 terminated(take_while(|b: u8| b != b'\r' && b != b'\n'), newline),
46 |not_newline| not_newline.as_bstr(),
47 )(input)
48}
49
50pub fn header<'a, E>(input: &'a [u8]) -> IResult<&'a [u8], Header, E>
51where
52 E: ParseError<&'a [u8]>,
53{
54 let (rest, traits) = preceded(tag(b"# pack-refs with: "), until_newline)(input)?;
55
56 let mut peeled = Peeled::Unspecified;
57 let mut sorted = false;
58 for token in traits.as_bstr().split_str(b" ") {
59 if token == b"fully-peeled" {
60 peeled = Peeled::Fully;
61 } else if token == b"peeled" {
62 peeled = Peeled::Partial;
63 } else if token == b"sorted" {
64 sorted = true;
65 }
66 }
67
68 Ok((rest, Header { peeled, sorted }))
69}
70
71pub fn reference<'a, E: ParseError<&'a [u8]> + FromExternalError<&'a [u8], crate::name::Error>>(
72 input: &'a [u8],
73) -> IResult<&'a [u8], packed::Reference<'a>, E> {
74 let (input, (target, name)) = tuple((
75 terminated(hex_hash, tag(b" ")),
76 map_res(until_newline, TryInto::try_into),
77 ))(input)?;
78 let (rest, object) = opt(delimited(tag(b"^"), hex_hash, newline))(input)?;
79 Ok((rest, packed::Reference { name, target, object }))
80}
81
82#[cfg(test)]
83mod tests;