use super::char_source::CharSource;
use log::trace;
use std::borrow::Cow;
use std::collections::VecDeque;
#[derive(Debug)]
pub struct PeekAdapter<S> {
source: S,
peek_index: usize,
peek_buffer: VecDeque<(usize, char)>,
consumed_start_byte: Option<usize>,
consumed_end_byte: usize,
consumed: String,
}
impl<'s, S: CharSource<'s>> PeekAdapter<S> {
pub fn new(source: S) -> PeekAdapter<S> {
PeekAdapter {
source,
peek_index: 0,
peek_buffer: VecDeque::new(),
consumed_start_byte: None,
consumed_end_byte: 0,
consumed: String::new(),
}
}
pub fn get_len(&self) -> usize {
self.source.get_len()
}
pub fn peek(&mut self) -> Option<(usize, char)> {
match self.inner_peek() {
Some(x @ (_, '\\')) => match self.inner_peek() {
Some((_, '\n')) => self.peek(),
Some((_, _)) => {
self.return_peek();
Some(x)
}
None => Some(x),
},
out @ Some(_) | out @ None => out,
}
}
pub fn return_peek(&mut self) {
assert!(self.peek_index > 0);
self.peek_index -= 1;
}
pub fn reset_peek(&mut self) {
self.peek_index = 0;
}
pub fn consume(&mut self) -> Result<(), ()> {
match self.inner_consume()? {
(b, c @ '\\') => match self.inner_peek() {
Some((_, '\n')) => {
trace!("Consume: Skipping escaped newline ({})", b);
self.inner_consume()?;
self.consume()
}
Some((_, _)) => {
self.reset_peek();
self.consumed_start_byte.get_or_insert(b);
self.consumed_end_byte = b + c.len_utf8() - 1;
self.consumed.push(c);
trace!(
"Consumed: {:?} ({}, {})",
c,
self.consumed_start_byte.unwrap_or(0),
self.consumed_end_byte
);
Ok(())
}
None => {
self.reset_peek();
self.consumed_start_byte.get_or_insert(b);
self.consumed_end_byte = b + c.len_utf8() - 1;
self.consumed.push(c);
trace!(
"Consumed: {:?} ({}, {})",
c,
self.consumed_start_byte.unwrap_or(0),
self.consumed_end_byte
);
Ok(())
}
},
(b, c) => {
trace!("{:?} {}", self.consumed_start_byte, b);
self.consumed_start_byte.get_or_insert(b);
self.consumed_end_byte = b + c.len_utf8() - 1;
self.consumed.push(c);
trace!(
"Consumed: {:?} ({}, {})",
c,
self.consumed_start_byte.unwrap_or(0),
self.consumed_end_byte
);
Ok(())
}
}
}
fn inner_consume(&mut self) -> Result<(usize, char), ()> {
self.reset_peek();
self.peek_buffer
.pop_front()
.or_else(|| self.source.next())
.map_or_else(|| Err(()), Ok)
}
pub fn get_consumed_range(&self) -> (usize, usize) {
(
self.consumed_start_byte.unwrap_or(0),
self.consumed_end_byte,
)
}
pub fn get_consumed(&mut self) -> Cow<'s, str> {
let consume_len = self.consumed_end_byte - self.consumed_start_byte.unwrap_or(0) + 1;
let out = if dbg!(self.consumed.len()) == dbg!(consume_len) {
self.source
.get_slice(self.consumed_start_byte.unwrap_or(0)..=self.consumed_end_byte)
} else {
Cow::Owned(self.consumed.clone())
};
self.consumed_start_byte = None;
self.consumed_end_byte += 1;
self.consumed.truncate(0);
out
}
fn inner_peek(&mut self) -> Option<(usize, char)> {
let out = if self.peek_index < self.peek_buffer.len() {
Some(self.peek_buffer[self.peek_index])
} else {
match self.source.next() {
Some(x) => {
self.peek_buffer.push_back(x);
Some(self.peek_buffer[self.peek_index])
}
None => return None,
}
};
self.peek_index += 1;
out
}
}