asai/iter/
mod.rs

1use std::str::Lines;
2
3#[derive(Debug, PartialEq, Eq)]
4pub enum Element<'a> {
5    SectionDefinition(&'a str),
6    Line { name: &'a str, value: &'a str },
7    Comment(&'a str),
8}
9
10impl<'a> Element<'a> {
11    pub fn is_line(&self) -> bool {
12        match self {
13            Element::Line {..} => true,
14            _ => false
15        }
16    }
17
18    pub fn is_section(&self) -> bool {
19        match self {
20            Element::SectionDefinition(_) => true,
21            _ => false
22        }
23    }
24
25    pub fn is_comment(&self) -> bool {
26        match self {
27            Element::Comment(_) => true,
28            _ => false
29        }
30    }
31}
32
33#[derive(Debug, Copy, Clone, PartialEq, Eq)]
34pub struct InvalidElement<'a>(pub &'a str);
35
36pub struct Elements<'a, T: Iterator<Item = &'a str>> {
37    iter: T,
38}
39
40pub fn parse_str(s: &str) -> Elements<Lines> {
41    Elements::new(s.lines())
42}
43
44impl<'a, T: Iterator<Item = &'a str>> Elements<'a, T> {
45    pub fn new(iter: T) -> Self {
46        Self { iter }
47    }
48}
49
50impl<'a, T: Iterator<Item = &'a str>> Iterator for Elements<'a, T> {
51    type Item = Result<Element<'a>, InvalidElement<'a>>;
52    fn next(&mut self) -> Option<Self::Item> {
53        let mut v = self.iter.next();
54        while v == Some("") {
55            v = self.iter.next();
56        }
57        match v {
58            Some(line) if line.starts_with(';') => Some(Ok(Element::Comment(
59                line.strip_prefix(";").unwrap()
60            ))),
61            Some(line) if line.starts_with('[') && line.ends_with(']') => {
62                Some(Ok(Element::SectionDefinition(
63                    line.strip_prefix('[')
64                        .and_then(|x| x.strip_suffix(']'))
65                        .unwrap(),
66                )))
67            }
68            Some(line)
69                if line.contains(": ") =>
70            {
71                let mut parts = line.splitn(2, ": ");
72                Some(Ok(Element::Line {
73                    name: parts.next().unwrap(),
74                    value: parts.next().unwrap(),
75                }))
76            }
77            Some(line) => Some(Err(InvalidElement(line))),
78            None => None,
79        }
80    }
81}