Skip to main content

deb_control_codec/
parser.rs

1use memchr::memchr;
2
3pub struct Control<'a> {
4    source: &'a str,
5}
6
7impl<'a> Control<'a> {
8    pub fn new(source: &'a str) -> Self {
9        Self { source }
10    }
11}
12
13#[derive(Debug)]
14pub enum Kind {
15    Single,
16    Folded,
17    Multiline,
18}
19
20impl std::fmt::Display for Kind {
21    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
22        f.write_str(match self {
23            Kind::Single => "Single",
24            Kind::Folded => "Folded",
25            Self::Multiline => "Multiline",
26        })
27    }
28}
29
30#[derive(Debug)]
31pub struct Entry<'a> {
32    pub key: &'a str,
33    pub value: &'a str,
34    pub kind: Kind,
35}
36
37impl<'a> Iterator for Control<'a> {
38    type Item = Entry<'a>;
39
40    fn next(&mut self) -> Option<Self::Item> {
41        let (kend, vstart);
42        let source = self.source.as_bytes();
43
44        let mut vend = match memchr(b'\n', source) {
45            Some(vend) => vend,
46            None => {
47                kend = memchr(b':', source)?;
48                vstart = kend + 2;
49                let key = &self.source[..kend];
50                let value = &self.source[vstart..];
51                self.source = "";
52                return Some(Entry {
53                    key,
54                    value,
55                    kind: Kind::Single,
56                });
57            }
58        };
59
60        kend = memchr(b':', &source[..vend])?;
61        vstart = kend + 2;
62        let mut eof = false;
63
64        let (value, kind) = if kend == vend - 1 {
65            vend += 1;
66
67            let values = fetch_lines(source, vend);
68            vend = values.0;
69            eof = values.1;
70
71            (&self.source[vstart..vend], Kind::Multiline)
72        } else if is_space(source, vend + 1) {
73            vend += 1;
74
75            let values = fetch_lines(source, vend);
76            vend = values.0;
77            eof = values.1;
78
79            (&self.source[vstart..vend], Kind::Folded)
80        } else {
81            (&self.source[vstart..vend], Kind::Single)
82        };
83
84        let key = &self.source[..kend];
85        self.source = if eof { "" } else { &self.source[vend + 1..] };
86
87        Some(Entry { key, value, kind })
88    }
89}
90
91fn is_space(bytes: &[u8], pos: usize) -> bool {
92    bytes
93        .get(pos)
94        .map_or(false, |&byte| byte == b' ' || byte == b'\t')
95}
96
97fn next_line(bytes: &[u8], start: usize) -> (usize, bool) {
98    match memchr(b'\n', &bytes[start..]) {
99        Some(pos) => (start + pos + 1, false),
100        None => (bytes.len(), true),
101    }
102}
103
104fn fetch_lines(source: &[u8], mut vend: usize) -> (usize, bool) {
105    let mut eof = false;
106    let (newv, was_eof) = next_line(source, vend);
107
108    vend = newv;
109    if was_eof {
110        eof = true;
111    }
112
113    while is_space(&source, vend) {
114        let (newv, was_eof) = next_line(source, vend);
115
116        vend = newv;
117        if was_eof {
118            eof = true;
119        }
120    }
121
122    if !eof {
123        vend -= 1;
124    }
125
126    (vend, eof)
127}