deb_control_codec/
parser.rs1use 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}