mxmlextrema_as3parser/util/
character_reader.rs1use std::str::CharIndices;
2
3#[derive(Clone)]
6pub struct CharacterReader<'a> {
7 length: usize,
8 start_offset: usize,
9 char_indices: CharIndices<'a>,
10}
11
12impl<'a> CharacterReader<'a> {
13 pub fn from_offset(value: &'a str, offset: usize) -> Self {
15 CharacterReader { length: value.len(), start_offset: offset, char_indices: value[offset..].char_indices() }
16 }
17
18 pub fn has_remaining(&self) -> bool {
20 self.clone().char_indices.next().is_some()
21 }
22
23 pub fn reached_end(&self) -> bool {
25 self.clone().char_indices.next().is_none()
26 }
27
28 pub fn skip_in_place(&mut self) {
31 self.next();
32 }
33
34 pub fn skip_count_in_place(&mut self, count: usize) {
36 for _ in 0..count {
37 if self.next().is_none() {
38 break;
39 }
40 }
41 }
42
43 pub fn index(&self) -> usize {
45 self.clone().char_indices.next().map_or(self.length, |(i, _)| self.start_offset + i)
46 }
47
48 pub fn next_or_zero(&mut self) -> char {
51 self.char_indices.next().map_or('\x00', |(_, cp)| cp)
52 }
53
54 pub fn peek(&self) -> Option<char> {
56 self.clone().char_indices.next().map(|(_, cp)| cp)
57 }
58
59 pub fn peek_or_zero(&self) -> char {
62 self.clone().next_or_zero()
63 }
64
65 pub fn peek_at(&self, index: usize) -> Option<char> {
67 let mut indices = self.clone().char_indices;
68 for _ in 0..index {
69 if indices.next().is_none() {
70 break;
71 }
72 }
73 indices.next().map(|(_, cp)| cp)
74 }
75
76 pub fn peek_at_or_zero(&self, index: usize) -> char {
79 self.peek_at(index).unwrap_or('\x00')
80 }
81
82 pub fn peek_seq(&self, num_code_points: u64) -> String {
84 let mut r = String::new();
85 let mut next_indices = self.char_indices.clone();
86 for _ in 0..num_code_points {
87 match next_indices.next() {
88 None => {
89 break;
90 },
91 Some(cp) => {
92 r.push(cp.1);
93 }
94 }
95 }
96 r
97 }
98}
99
100impl<'a> From<&'a str> for CharacterReader<'a> {
101 fn from(value: &'a str) -> Self {
103 CharacterReader { length: value.len(), start_offset: 0, char_indices: value.char_indices() }
104 }
105}
106
107impl<'a> From<&'a String> for CharacterReader<'a> {
108 fn from(value: &'a String) -> Self {
110 CharacterReader { length: value.len(), start_offset: 0, char_indices: value.char_indices() }
111 }
112}
113
114impl<'a> Iterator for CharacterReader<'a> {
115 type Item = char;
116
117 fn next(&mut self) -> Option<Self::Item> {
118 self.char_indices.next().map(|(_, cp)| cp)
119 }
120}
121
122#[cfg(test)]
123mod test {
124 use super::CharacterReader;
125 #[test]
126 fn test() {
127 let mut reader = CharacterReader::from("foo");
128 assert!(reader.has_remaining());
129 assert_eq!(reader.peek_seq(5), "foo");
130 assert_eq!(reader.peek_seq(1), "f");
131 assert_eq!(reader.peek_or_zero(), 'f');
132 for _ in 0..3 {
133 reader.next();
134 }
135 assert_eq!(reader.peek_or_zero(), '\x00');
136 assert!(reader.reached_end());
137 }
138}