1use winnow::{ModalResult, Parser, combinator::separated, token::take_till};
2
3use crate::OmaContentsError;
4
5pub fn parse_contetns(input: &str) -> Result<Vec<(&str, Vec<&str>)>, OmaContentsError> {
7 input
8 .lines()
9 .enumerate()
10 .map(|x| match parse_contents_single_line(x.1) {
11 Ok(v) => Ok(v),
12 Err(e) => Err(OmaContentsError::InvalidContentsWithLine(
13 e.to_string(),
14 x.0,
15 )),
16 })
17 .collect::<Result<Vec<_>, OmaContentsError>>()
18}
19
20pub fn parse_contents_single_line(input: &str) -> Result<(&str, Vec<&str>), OmaContentsError> {
22 let (file, pkgs) = input
25 .rsplit_once(|c: char| c.is_whitespace() && c != '\n')
26 .ok_or(OmaContentsError::InvalidContents(
27 "Failed to get last space".to_string(),
28 ))?;
29
30 let file = file.trim();
31 let mut pkgs = pkgs.trim();
32 let pkgs = multi_packages(&mut pkgs)
33 .map_err(|e| OmaContentsError::InvalidContents(format!("Failed to get packages: {e}")))?;
34
35 Ok((file, pkgs))
36}
37
38#[inline]
39fn single_package<'a>(input: &mut &'a str) -> ModalResult<&'a str> {
40 take_till(0.., |c| c == ',' || c == '\n').parse_next(input)
41}
42
43#[inline]
44fn multi_packages<'a>(input: &mut &'a str) -> ModalResult<Vec<&'a str>> {
45 separated(0.., single_package, ',').parse_next(input)
46}
47
48#[test]
49fn test_single_line() {
50 let s = "etc/dpkg/dpkg.cfg.d/pk4\t\t\t\t\t universe/utils/pk4\n";
51 let res = parse_contents_single_line(s);
52
53 assert_eq!(
54 res.unwrap(),
55 ("etc/dpkg/dpkg.cfg.d/pk4", vec!["universe/utils/pk4"])
56 )
57}
58
59#[test]
60fn test_single_line_multi_packages() {
61 let s = "opt/32/libexec devel/gcc+32,devel/llvm+32,gnome/gconf+32,libs/gdk-pixbuf+32\n";
62 let res = parse_contents_single_line(s);
63
64 assert_eq!(
65 res.unwrap(),
66 (
67 "opt/32/libexec",
68 vec![
69 "devel/gcc+32",
70 "devel/llvm+32",
71 "gnome/gconf+32",
72 "libs/gdk-pixbuf+32"
73 ]
74 )
75 )
76}
77
78#[test]
79fn test_single_line_file_multi_space() {
80 let s = "/etc/i have multi space foo/bar/abc\n";
81 let res = parse_contents_single_line(s);
82
83 assert_eq!(
84 res.unwrap(),
85 ("/etc/i have multi space", vec!["foo/bar/abc"])
86 )
87}