1#![cfg_attr(not(test), no_std)]
2
3use core::{cell::Cell, str};
4
5#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
6pub enum Token<'a> {
7 Begin,
8 End,
9 Str(&'a str),
10}
11
12impl<'a> Token<'a> {
13 pub fn into_str(self) -> Option<&'a str> {
14 match self {
15 Self::Str(s) => Some(s),
16 _ => None,
17 }
18 }
19}
20
21pub struct Iter<'a> {
22 data: &'a [u8],
23 index: usize,
24}
25
26impl<'a> Iterator for Iter<'a> {
27 type Item = Result<Token<'a>, Error>;
28
29 fn next(&mut self) -> Option<Self::Item> {
30 let ret_str = |s| {
31 str::from_utf8(s)
32 .map_err(|_| Error::InvalidUtf8)
33 .map(|s| Token::Str(s))
34 };
35 loop {
36 let c = self.data.get(self.index)?;
37 self.index += 1;
38 match c {
39 c if c.is_ascii_whitespace() => {}
40 b'(' => return Some(Ok(Token::Begin)),
41 b')' => return Some(Ok(Token::End)),
42 lim @ b'"' | lim @ b'\'' => loop {
43 let start = self.index;
44 while let Some(&c) = self.data.get(self.index) {
45 self.index += 1;
46 match c {
47 b'\\' => self.index += 1,
48 c if c == *lim => {
49 return Some(ret_str(&self.data[start..self.index - 1]));
50 }
51 _ => {}
52 }
53 }
54 return Some(Err(Error::UnterminatedQuote));
55 },
56 b';' => {
57 while self.data.get(self.index).map_or(false, |c| *c != b'\n') {
58 self.index += 1;
59 }
60 }
61 _ => loop {
62 let start = self.index - 1;
63 while let Some(&c) = self.data.get(self.index) {
64 self.index += 1;
65 match c {
66 c if c == b'(' || c == b')' || c.is_ascii_whitespace() => {
67 self.index -= 1;
68 break;
69 }
70 _ => {}
71 }
72 }
73 return Some(ret_str(&self.data[start..self.index]));
74 },
75 }
76 }
77 }
78}
79
80#[derive(Debug)]
81#[must_use = "an error may have occured"]
82pub struct Groups<'a> {
83 data: &'a [u8],
84 index: Cell<usize>,
85}
86
87impl<'a> Groups<'a> {
88 pub fn iter(&mut self) -> GroupsIter<'a, '_> {
89 GroupsIter { inner: Some(self) }
90 }
91
92 pub fn into_error(self) -> Option<Error> {
93 Error::from_num(self.index.get())
94 }
95}
96
97#[derive(Debug)]
98pub struct GroupsIter<'a, 'b> {
99 inner: Option<&'b Groups<'a>>,
100}
101
102impl<'a, 'b> GroupsIter<'a, 'b> {
103 pub fn next_str(&mut self) -> Option<&'a str> {
104 self.next().and_then(|e| e.into_str())
105 }
106
107 pub fn next_group(&mut self) -> Option<GroupsIter<'a, 'b>> {
108 self.next().and_then(|e| e.into_group())
109 }
110}
111
112impl<'a, 'b> Iterator for GroupsIter<'a, 'b> {
113 type Item = Item<'a, 'b>;
114
115 fn next(&mut self) -> Option<Self::Item> {
116 let r = self.inner?;
117 let mut it = Iter {
118 data: r.data,
119 index: r.index.get(),
120 };
121 if (it.index as isize) < 0 {
122 return None;
123 }
124 let tk = it.next();
125 r.index.set(it.index);
126 match tk {
127 None => None,
128 Some(Err(e)) => {
129 r.index.set(e.into_num());
130 None
131 }
132 Some(Ok(tk)) => Some(match tk {
133 Token::Str(s) => Item::Str(s),
134 Token::Begin => Item::Group(Self { inner: self.inner }),
135 Token::End => {
136 self.inner = None;
137 return None
138 }
139 }),
140 }
141 }
142}
143
144impl Drop for GroupsIter<'_, '_> {
145 fn drop(&mut self) {
146 for _ in self {}
147 }
148}
149
150impl core::iter::FusedIterator for GroupsIter<'_, '_> {}
151
152#[derive(Debug)]
153pub enum Item<'a, 'b> {
154 Str(&'a str),
155 Group(GroupsIter<'a, 'b>),
156}
157
158impl<'a, 'b> Item<'a, 'b> {
159 pub fn into_str(self) -> Option<&'a str> {
160 match self {
161 Self::Str(s) => Some(s),
162 _ => None,
163 }
164 }
165
166 pub fn into_group(self) -> Option<GroupsIter<'a, 'b>> {
167 match self {
168 Self::Group(g) => Some(g),
169 _ => None,
170 }
171 }
172}
173
174#[derive(Debug, PartialEq, Eq)]
175pub enum Error {
176 UnterminatedQuote,
177 InvalidSymbolChar,
178 InvalidUtf8,
179}
180
181impl Error {
182 fn into_num(self) -> usize {
183 (match self {
184 Self::UnterminatedQuote => -1,
185 Self::InvalidSymbolChar => -2,
186 Self::InvalidUtf8 => -3,
187 }) as usize
188 }
189
190 fn from_num(n: usize) -> Option<Self> {
191 Some(match n as isize {
192 -1 => Self::UnterminatedQuote,
193 -2 => Self::InvalidSymbolChar,
194 -3 => Self::InvalidUtf8,
195 _ => return None,
196 })
197 }
198}
199
200#[deprecated(note = "use `parse2`, which is less error-prone")]
201pub fn parse<'a>(data: &'a [u8]) -> Iter<'a> {
202 Iter { data, index: 0 }
203}
204
205pub fn parse2<'a>(data: &'a [u8]) -> Groups<'a> {
206 Groups { data, index: 0.into() }
207}
208
209#[cfg(test)]
210mod test {
211 use super::*;
212
213 #[test]
214 fn example_pci() {
215 let t = br#"(pci-drivers
216 (1af4 ; Red Hat
217 (1000 "drivers/pci/virtio/net")
218 (1001 "drivers/pci/virtio/blk")
219 (1050 "drivers/pci/virtio/gpu"))
220 (8086 ; Intel
221 (1616 "drivers/pci/intel/hd graphics"))) ; intentional space"#;
222 #[allow(deprecated)]
223 let mut it = parse(t);
224 assert_eq!(it.next(), Some(Ok(Token::Begin)));
225 assert_eq!(it.next(), Some(Ok(Token::Str("pci-drivers"))));
226 assert_eq!(it.next(), Some(Ok(Token::Begin)));
227 assert_eq!(it.next(), Some(Ok(Token::Str("1af4"))));
228 assert_eq!(it.next(), Some(Ok(Token::Begin)));
229 assert_eq!(it.next(), Some(Ok(Token::Str("1000"))));
230 assert_eq!(it.next(), Some(Ok(Token::Str("drivers/pci/virtio/net"))));
231 assert_eq!(it.next(), Some(Ok(Token::End)));
232 assert_eq!(it.next(), Some(Ok(Token::Begin)));
233 assert_eq!(it.next(), Some(Ok(Token::Str("1001"))));
234 assert_eq!(it.next(), Some(Ok(Token::Str("drivers/pci/virtio/blk"))));
235 assert_eq!(it.next(), Some(Ok(Token::End)));
236 assert_eq!(it.next(), Some(Ok(Token::Begin)));
237 assert_eq!(it.next(), Some(Ok(Token::Str("1050"))));
238 assert_eq!(it.next(), Some(Ok(Token::Str("drivers/pci/virtio/gpu"))));
239 assert_eq!(it.next(), Some(Ok(Token::End)));
240 assert_eq!(it.next(), Some(Ok(Token::End)));
241 assert_eq!(it.next(), Some(Ok(Token::Begin)));
242 assert_eq!(it.next(), Some(Ok(Token::Str("8086"))));
243 assert_eq!(it.next(), Some(Ok(Token::Begin)));
244 assert_eq!(it.next(), Some(Ok(Token::Str("1616"))));
245 assert_eq!(
246 it.next(),
247 Some(Ok(Token::Str("drivers/pci/intel/hd graphics")))
248 );
249 assert_eq!(it.next(), Some(Ok(Token::End)));
250 assert_eq!(it.next(), Some(Ok(Token::End)));
251 assert_eq!(it.next(), Some(Ok(Token::End)));
252 assert_eq!(it.next(), None);
253 }
254
255 #[test]
256 fn example_pci_groups() {
257 let t = br#"(pci-drivers
258 (1af4 ; Red Hat
259 (1000 "drivers/pci/virtio/net")
260 (1001 "drivers/pci/virtio/blk")
261 (1050 "drivers/pci/virtio/gpu"))
262 (8086 ; Intel
263 (1616 "drivers/pci/intel/hd graphics"))) ; intentional space"#;
264 #[track_caller]
265 fn string<'a, 'b>(it: &mut GroupsIter<'a, 'b>) -> &'a str {
266 it.next().unwrap().into_str().unwrap()
267 }
268 #[track_caller]
269 fn group<'a, 'b>(it: &mut GroupsIter<'a, 'b>) -> GroupsIter<'a, 'b> {
270 it.next().unwrap().into_group().unwrap()
271 }
272 #[track_caller]
273 fn none<'a, 'b>(it: &mut GroupsIter<'a, 'b>) {
274 assert!(it.next().is_none());
275 assert!(it.next().is_none());
277 assert!(it.next().is_none());
278 }
279
280 let mut cf = parse2(t);
281 {
282 let mut it = cf.iter();
283 let mut it2 = group(&mut it);
284 assert_eq!(string(&mut it2), "pci-drivers");
285 let mut it3 = group(&mut it2);
286 assert_eq!(string(&mut it3), "1af4");
287 let mut it4 = group(&mut it3);
288 assert_eq!(string(&mut it4), "1000");
289 assert_eq!(string(&mut it4), "drivers/pci/virtio/net");
290 none(&mut it4);
291 let mut it4 = group(&mut it3);
292 assert_eq!(string(&mut it4), "1001");
293 assert_eq!(string(&mut it4), "drivers/pci/virtio/blk");
294 none(&mut it4);
295 let mut it4 = group(&mut it3);
296 assert_eq!(string(&mut it4), "1050");
297 assert_eq!(string(&mut it4), "drivers/pci/virtio/gpu");
298 none(&mut it4);
299 none(&mut it3);
300 let mut it3 = group(&mut it2);
301 assert_eq!(string(&mut it3), "8086");
302 let mut it4 = group(&mut it3);
303 assert_eq!(string(&mut it4), "1616");
304 assert_eq!(string(&mut it4), "drivers/pci/intel/hd graphics");
305 none(&mut it4);
306 none(&mut it3);
307 none(&mut it2);
308 none(&mut it);
309 }
310 assert!(cf.into_error().is_none());
311 }
312
313 #[test]
314 fn partial_iter_group() {
315 let t = br#"(pci-drivers
316 (1af4 ; Red Hat
317 (1000 "drivers/pci/virtio/net")
318 (1001 "drivers/pci/virtio/blk")
319 (1050 "drivers/pci/virtio/gpu"))
320 (8086 ; Intel
321 (1616 "drivers/pci/intel/hd graphics"))) ; intentional space"#;
322 #[track_caller]
323 fn string<'a, 'b>(it: &mut GroupsIter<'a, 'b>) -> &'a str {
324 it.next().unwrap().into_str().unwrap()
325 }
326 #[track_caller]
327 fn group<'a, 'b>(it: &mut GroupsIter<'a, 'b>) -> GroupsIter<'a, 'b> {
328 it.next().unwrap().into_group().unwrap()
329 }
330 #[track_caller]
331 fn none<'a, 'b>(it: &mut GroupsIter<'a, 'b>) {
332 assert!(it.next().is_none());
333 assert!(it.next().is_none());
335 assert!(it.next().is_none());
336 }
337
338 let mut cf = parse2(t);
339 {
340 let mut it = cf.iter();
341 let mut it2 = group(&mut it);
342 assert_eq!(string(&mut it2), "pci-drivers");
343 let mut it3 = group(&mut it2);
344 assert_eq!(string(&mut it3), "1af4");
345 let mut it4 = group(&mut it3);
346 assert_eq!(string(&mut it4), "1000");
347 assert_eq!(string(&mut it4), "drivers/pci/virtio/net");
348 none(&mut it4);
349 let mut it4 = group(&mut it3);
350 assert_eq!(string(&mut it4), "1001");
351 drop(it4);
352 drop(it3);
353 let mut it3 = group(&mut it2);
354 assert_eq!(string(&mut it3), "8086");
355 let mut it4 = group(&mut it3);
356 assert_eq!(string(&mut it4), "1616");
357 assert_eq!(string(&mut it4), "drivers/pci/intel/hd graphics");
358 none(&mut it4);
359 none(&mut it3);
360 none(&mut it2);
361 none(&mut it);
362 }
363 assert!(cf.into_error().is_none());
364 }
365}