use std::iter::Peekable;
use std::str::CharIndices;
pub struct ParserIterator<'a> {
iter: Peekable<CharIndices<'a>>,
checkpoints: Vec<Peekable<CharIndices<'a>>>,
_index: usize,
len: usize,
}
impl<'a> ParserIterator<'a> {
pub fn new(text: &'a str) -> Self {
Self {
iter: text.char_indices().peekable(),
checkpoints: Vec::new(),
_index: 0,
len: text.len(),
}
}
pub fn peek(&mut self) -> Option<char> {
if let Some((_,c)) = self.iter.peek() {
return Some(*c);
}
return None;
}
pub fn next(&mut self) -> Option<char> {
if let Some((_,c)) = self.iter.next() {
if let Some((i,_)) = self.iter.peek() {
self._index = *i;
} else {
self._index = self.len;
}
return Some(c);
}
return None;
}
#[inline]
pub fn index(&self) -> usize {
return self._index;
}
pub fn consume_chars<F>(&mut self, matcher: F) -> usize
where F: Fn(char) -> bool {
let mut counter: usize = 0;
loop {
match self.peek() {
Some(c) => {
if matcher(c) {
self.next();
counter += 1;
} else {
break;
}
},
None => {
break;
}
}
}
return counter;
}
pub fn try_consume_char(&mut self, mc: char) -> bool {
if Some(mc) == self.peek() {
self.next();
return true;
}
return false;
}
pub fn checkpoint(&mut self) {
self.checkpoints.push(self.iter.clone());
}
pub fn drop_checkpoint(&mut self) -> bool {
return self.checkpoints.pop().is_some();
}
pub fn restore(&mut self) -> bool {
if let Some(checkpoint) = self.checkpoints.pop() {
self.iter = checkpoint;
if let Some((i,_)) = self.iter.peek() {
self._index = *i;
} else {
self._index = self.len;
}
}
return false;
}
}