warpack_formats/parser/
profile.rs1use std::collections::HashMap;
2use std::iter::Peekable;
3use std::str::from_utf8;
4
5use crate::parser::crlf::Lines;
6
7#[derive(Debug)]
8pub struct Entry<'src> {
9 pub id: &'src str,
10 pub values: HashMap<&'src str, &'src str>,
11}
12
13#[derive(Debug)]
14pub struct Entries<'src> {
15 lines: Peekable<Lines<'src>>,
16}
17
18impl<'src> Entries<'src> {
19 pub fn new(source: &'src [u8]) -> Entries<'src> {
20 Entries {
21 lines: Lines::new(source).peekable(),
22 }
23 }
24}
25
26fn parse_entry_start(mut input: &[u8]) -> Option<&str> {
27 if input[0] == b'[' {
28 input = &input[1..];
29 if input.is_empty() {
30 return None;
31 }
32
33 let (end, _) = input.iter().enumerate().find(|(_, c)| **c == b']')?;
34
35 return Some(from_utf8(&input[..end]).ok()?);
36 }
37
38 None
39}
40
41fn parse_entry_value(input: &[u8]) -> Option<(&str, &str)> {
42 if input.starts_with(b"//") {
43 return None;
44 }
45
46 let equals = input
47 .iter()
48 .enumerate()
49 .find(|(_, c)| **c == b'=')
50 .map(|(i, _)| i);
51
52 if let Some(equals) = equals {
53 let key = from_utf8(&input[..equals]).ok()?;
54 let value = from_utf8(&input[equals + 1..]).ok()?;
55
56 if key.is_empty() || value.is_empty() {
57 return None;
58 }
59
60 Some((key, value))
61 } else {
62 None
63 }
64}
65
66impl<'src> Iterator for Entries<'src> {
67 type Item = Entry<'src>;
68
69 fn next(&mut self) -> Option<Self::Item> {
70 self.lines.find_map(|l| parse_entry_start(l)).map(|id| {
71 let mut values = HashMap::default();
72
73 loop {
74 if self.lines.peek().is_none() {
75 break;
76 }
77
78 if self
79 .lines
80 .peek()
81 .and_then(|l| parse_entry_start(l))
82 .is_some()
83 {
84 break;
85 }
86
87 if let Some((key, value)) = self.lines.next().and_then(|l| parse_entry_value(l)) {
88 values.insert(key, value);
89 }
90 }
91
92 Entry { id, values }
93 })
94 }
95}