eight-deep-parser 0.3.2

Dpkg info parser
Documentation
use nom::{
    bytes::complete::{tag, take_until},
    character::complete::{char, multispace0, space0},
    combinator::{map, verify},
    multi::{many0, many1},
    sequence::{delimited, preceded, separated_pair, terminated, tuple},
    IResult,
};

type KeyValueResult<'a> = IResult<&'a [u8], (&'a [u8], (&'a [u8], Vec<u8>))>;
type SinglePackageResult<'a> = IResult<&'a [u8], Vec<(&'a [u8], (&'a [u8], Vec<u8>))>>;
type MultiPackageResult<'a> = IResult<&'a [u8], Vec<Vec<(&'a [u8], (&'a [u8], Vec<u8>))>>>;

#[inline]
fn key_name(input: &[u8]) -> IResult<&[u8], &[u8]> {
    verify(handle_key, |input: &[u8]| {
        if !input.is_empty() {
            input[0] != b'\n'
        } else {
            false
        }
    })(input)
}

#[inline]
fn handle_key(input: &[u8]) -> IResult<&[u8], &[u8]> {
    preceded(handle_key_name, take_until(":"))(input)
}

#[inline]
fn handle_key_name(input: &[u8]) -> IResult<&[u8], ()> {
    map(
        many0(delimited(tag(" "), take_until("\n"), tag("\n"))),
        |_| (),
    )(input)
}

#[inline]
fn separator(input: &[u8]) -> IResult<&[u8], ()> {
    map(tuple((char(':'), space0)), |_| ())(input)
}

#[inline]
fn key_value(input: &[u8]) -> KeyValueResult {
    separated_pair(key_name, separator, value_field)(input)
}

#[inline]
fn value_field(input: &[u8]) -> IResult<&[u8], (&[u8], Vec<u8>)> {
    tuple((single_line, multi_to_one))(input)
}

#[inline]
fn single_line(input: &[u8]) -> IResult<&[u8], &[u8]> {
    terminated(take_until("\n"), tag("\n"))(input)
}

#[inline]
fn multi_line_single(input: &[u8]) -> IResult<&[u8], &[u8]> {
    delimited(tag(" "), take_until("\n"), tag("\n"))(input)
}

#[inline]
fn multi_line(input: &[u8]) -> IResult<&[u8], Vec<&[u8]>> {
    many0(multi_line_single)(input)
}

fn multi_to_one(input: &[u8]) -> IResult<&[u8], Vec<u8>> {
    let ctx = multi_line(input)?;

    let mut s = String::new();
    for (i, c) in ctx.1.iter().enumerate() {
        s += std::str::from_utf8(c).unwrap();
        if i != ctx.1.len() - 1 {
            s += "\n";
        }
    }

    let s = s.as_bytes().to_vec();

    Ok((input, s))
}

#[inline]
pub fn single_package(input: &[u8]) -> SinglePackageResult {
    terminated(many1(key_value), multispace0)(input)
}

#[inline]
pub fn multi_package(input: &[u8]) -> MultiPackageResult {
    many1(single_package)(input)
}

#[test]
fn test_single_line() {
    let test = b"zsync\n";

    let r = single_line(test);

    assert_eq!(r, Ok((&b""[..], &b"zsync"[..])));
}

#[test]
fn test_value_field() {
    let test = b"zsync\n";
    let r = value_field(test);

    assert_eq!(r, Ok((&b""[..], (&b"zsync"[..], b"".to_vec()))));

    let test = b"\n a\n b\n c\n";
    let r = value_field(test);

    assert_eq!(
        r,
        Ok((&b" a\n b\n c\n"[..], (&b""[..], b"a\nb\nc".to_vec())))
    );
}

#[test]
fn test_multi_line() {
    let test = b" a\n b\n c\nD: E";
    let r = multi_line(test);

    assert_eq!(r, Ok((&b"D: E"[..], vec![&b"a"[..], &b"b"[..], &b"c"[..]])))
}

#[test]
fn test_multi_line_to_one() {
    let test = b" c\n d\n e\n";

    let r = multi_to_one(test);

    assert_eq!(r, Ok((&b" c\n d\n e\n"[..], b"c\nd\ne".to_vec())))
}

#[test]
fn test_handle_key() {
    let test = b" b\n c\nD: E";

    let r = handle_key(test);

    assert_eq!(r, Ok((&b": E"[..], &b"D"[..])))
}

#[test]
fn test_key_name() {
    let test = b"Package: zsync\n";

    let r = key_name(test);

    assert_eq!(r, Ok((&b": zsync\n"[..], &b"Package"[..])))
}

#[test]
fn test_key_value() {
    let test = b"Package: zsync\n";
    let r = key_value(test);

    assert_eq!(
        r,
        Ok((&b""[..], (&b"Package"[..], (&b"zsync"[..], b"".to_vec()))))
    );

    let test = b"c:\n d\n e\n";

    let r = key_value(test);

    assert_eq!(
        r,
        Ok((&b" d\n e\n"[..], (&b"c"[..], (&b""[..], b"d\ne".to_vec()))))
    );
}

#[test]
fn test_single_package() {
    let test = b"Package: a\nMulti:\n a\n b\n c\nD: E\n";

    let r = single_package(test);

    assert_eq!(
        r,
        Ok((
            &b""[..],
            vec![
                (&b"Package"[..], (&b"a"[..], b"".to_vec())),
                (&b"Multi"[..], (&b""[..], b"a\nb\nc".to_vec())),
                (&b"D"[..], (&b"E"[..], b"".to_vec())),
            ]
        ))
    )
}