use unicode_segmentation::UnicodeSegmentation;
pub mod nibblers;
pub struct Gaze<I> {
offset: usize,
input: Vec<I>,
}
impl<I> Gaze<I> {
pub fn from_str(text: &str) -> Gaze<&str> {
let input = text.graphemes(true).collect::<Vec<&str>>();
Gaze { input, offset: 0 }
}
pub fn from_vec(input: Vec<I>) -> Gaze<I> {
Gaze { input, offset: 0 }
}
pub fn is_complete(&self) -> bool {
self.offset >= self.input.len()
}
pub fn peek(&self) -> Option<I>
where
I: Clone,
{
if self.is_complete() {
None
} else {
Some(self.input[self.offset].clone())
}
}
pub fn next(&mut self) -> Option<I>
where
I: Clone,
{
if self.is_complete() {
None
} else {
let next = Some(self.input[self.offset].clone());
self.offset += 1;
next
}
}
pub fn attemptf<O>(&mut self, nibbler: &mut impl Fn(&mut Gaze<I>) -> Option<O>) -> Option<O>
where
I: Clone,
O: Clone,
{
let start_of_this_loop = self.offset;
let res = nibbler(self);
match res {
Some(_) => res,
None => {
self.offset = start_of_this_loop;
None
}
}
}
pub fn attempt<O>(&mut self, nibbler: &mut (impl Nibbler<I, O> + ?Sized)) -> Option<O>
where
I: Clone,
O: Clone,
{
let start_of_this_loop = self.offset;
let res = nibbler.run(self);
match res {
Some(_) => res,
None => {
self.offset = start_of_this_loop;
None
}
}
}
}
pub trait Nibbler<I, O> {
fn run(&mut self, gaze: &mut Gaze<I>) -> Option<O>;
}