use crate::bookmark::Mark;
#[derive(Debug)]
pub struct TokenStream<'a, T> {
data: &'a [T],
cursor: usize,
}
impl<'a, T> TokenStream<'a, T> {
pub fn new(data: &'a [T]) -> Self {
TokenStream { data, cursor: 0 }
}
pub fn consume(&mut self) -> Option<&T> {
self.data.get(self.cursor).inspect(|_| self.cursor += 1)
}
pub fn peek(&self) -> Option<&T> {
self.peek_offset(0)
}
pub fn peek_offset(&self, offset: usize) -> Option<&T> {
self.data.get(self.cursor.saturating_add(offset))
}
pub fn rewind(&mut self) {
self.rewind_offset(1);
}
pub fn rewind_offset(&mut self, offset: usize) {
self.cursor = self.cursor.saturating_sub(offset);
}
pub fn mark(&self) -> Mark {
Mark::new(self.cursor)
}
pub fn reset(&mut self, bookmark: &Mark) -> usize {
let old = self.cursor;
self.cursor = bookmark.position();
old
}
pub fn tokens_remaining(&self) -> usize {
self.data.len().saturating_sub(self.cursor)
}
pub fn is_eof(&self) -> bool {
self.peek().is_none()
}
pub fn slice_from_marks(&self, mark_1: &Mark, mark_2: &Mark) -> &[T] {
let mut idx_1 = mark_1.position();
let mut idx_2 = mark_2.position();
if idx_1 >= idx_2 {
core::mem::swap(&mut idx_1, &mut idx_2);
}
&self.data[idx_1..idx_2]
}
pub fn advance(&mut self, offset: usize) {
self.cursor = self.data.len().min(self.cursor.saturating_add(offset));
}
pub fn peek_if<F: Fn(&T) -> bool>(&self, f: F) -> Option<&T> {
match self.peek() {
Some(v) if f(v) => Some(v),
_ => None,
}
}
pub fn expect<F: Fn(&T) -> bool>(&mut self, f: F) -> Option<&T> {
let ok = match self.peek() {
Some(v) if f(v) => true,
_ => false,
};
if ok { self.consume() } else { None }
}
pub fn consume_while<F: Fn(&T) -> bool>(&mut self, f: F) -> &[T] {
let m1 = self.mark();
while self.expect(&f).is_some() {}
let m2 = self.mark();
let slice = self.slice_from_marks(&m1, &m2);
slice
}
pub fn peek_while<F: Fn(&T) -> bool>(&self, f: F) -> &[T] {
let len = self.data[self.cursor..]
.iter().take_while(|item| f(item))
.count();
&self.data[self.cursor..self.cursor + len]
}
pub fn skip(&mut self) {
self.advance(1);
}
pub fn skip_if<F: Fn(&T) -> bool>(&mut self, f: F) {
match self.peek_if(f) {
Some(_) => self.skip(),
None => {}
}
}
pub fn skip_while<F: Fn(&T) -> bool>(&mut self, f: F) {
while self.peek_if(&f).is_some() {
self.advance(1);
}
}
pub fn position(&self) -> usize {
self.cursor
}
}