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])
}
}