Skip to main content

warpack_formats/parser/
profile.rs

1use 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}