1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
use std::str::Chars;

pub struct LineKConfigTokenizerIterator<'s> {
    line: &'s str,

    at_pos: usize,
    at_char: Option<char>,
    last_char: Option<char>,

    chars_iter: Chars<'s>,
}

impl<'s> LineKConfigTokenizerIterator<'s> {
    pub fn from_line(line: &'s str) -> Self {
        let mut inner_iter = line.chars();
        let at_char = inner_iter.next();
        Self {
            line,
            at_pos: 0,
            at_char,
            last_char: None,
            chars_iter: inner_iter,
        }
    }

    fn advance_one(&mut self) {
        self.at_pos += 1;
        self.last_char = self.at_char.clone();
        self.at_char = self.chars_iter.next();
    }

    fn advance_while(&mut self, while_fn: impl Fn(&Self) -> bool) {
        while self.at_char.is_some() && while_fn(self) {
            self.advance_one();

            if self.at_char.is_none() {
                break;
            }
        }
    }

    fn advance_while_is_whitespace_is(&mut self, whitespace: bool) {
        self.advance_while(|iter| {
            if let Some(at_char) = iter.at_char {
                at_char.is_whitespace() == whitespace
            } else {
                false
            }
        });
    }

    pub fn get_remaining_slice(&self) -> &'s str {
        &self.line[self.at_pos..]
    }
}

impl<'s> Iterator for LineKConfigTokenizerIterator<'s> {
    type Item = &'s str;

    fn next(&mut self) -> Option<Self::Item> {
        self.advance_while_is_whitespace_is(true);
        let start_at = self.at_pos;

        if self.at_char.contains(&'"') {
            self.advance_one();

            self.advance_while(|iter| {
                if let Some(at_char) = iter.at_char {
                    at_char != '"' && !iter.last_char.contains(&'\\')
                } else {
                    false
                }
            });
        } else if self.at_char.contains(&'#') {
            return None;
        }

        self.advance_while_is_whitespace_is(false);

        if start_at == self.at_pos {
            return None;
        }
        Some(&self.line[start_at..self.at_pos])
    }
}