use super::Rules;
pub struct StrWalker<'input> {
to_walk: &'input str,
index: usize,
}
impl<'input> StrWalker<'input> {
pub fn new(str: &'input str) -> Self {
Self {
to_walk: str,
index: 0,
}
}
pub fn next_char(&mut self) -> Option<char> {
if self.reached_end() {
return None;
}
let og_index = self.index;
self.index += 1;
loop {
if self.reached_end() || self.to_walk.is_char_boundary(self.index) {
return Some(
self.to_walk[og_index..self.index]
.chars()
.next()
.expect("Should be a valid char!"),
);
}
self.index += 1;
}
}
pub fn reached_end(&self) -> bool {
self.to_walk.len() <= self.index
}
pub fn jump_to_next(&mut self, target: &str) {
loop {
self.next_char();
if self.currently_starts_with(target) || self.reached_end() {
return;
}
}
}
pub fn currently_starts_with(&self, cmp: &str) -> bool {
let end_index = self.index.wrapping_add(cmp.len());
if end_index > self.to_walk.len() || end_index < self.index {
return false;
}
self.to_walk.as_bytes()[self.index..end_index] == *cmp.as_bytes()
}
pub fn jump_by(&mut self, amount: usize) {
self.index += amount;
if !self.to_walk.is_char_boundary(self.index) {
panic!("{} is not a valid char boundary", self.index)
}
}
pub fn try_each<T: Clone>(&mut self, rules: Rules<T>) -> Option<T> {
for (key, val) in rules {
if self.currently_starts_with(key) {
self.jump_by(key.len());
return Some(val.clone());
}
}
None
}
}