use crate::encoding::EncodingType;
use crate::{ParseError, ParserResult};
#[derive(Debug)]
pub(crate) struct Cursor<'a, T: EncodingType> {
pos: usize,
source: &'a [T::CodeUnit],
}
impl<'a, T: EncodingType> Cursor<'a, T> {
#[must_use]
pub fn new(source: &'a [T::CodeUnit]) -> Self {
Self { pos: 0, source }
}
pub(crate) fn slice(&self, start: usize, end: usize) -> Option<&'a [T::CodeUnit]> {
T::slice(self.source, start, end)
}
pub(crate) const fn pos(&self) -> usize {
self.pos
}
pub(crate) fn set_position(&mut self, pos: usize) {
self.pos = pos;
}
pub(crate) fn peek(&self) -> ParserResult<Option<u8>> {
self.peek_n(1)
}
pub(crate) fn current(&self) -> ParserResult<Option<u8>> {
self.peek_n(0)
}
pub(crate) fn peek_n(&self, n: usize) -> ParserResult<Option<u8>> {
T::get_ascii(self.source, self.pos + n)
}
pub(crate) fn check<F>(&self, f: F) -> ParserResult<Option<bool>>
where
F: FnOnce(u8) -> bool,
{
Ok(self.current()?.map(f))
}
pub(crate) fn check_or<F>(&self, default: bool, f: F) -> ParserResult<bool>
where
F: FnOnce(u8) -> bool,
{
Ok(self.current()?.map_or(default, f))
}
pub(crate) fn next(&mut self) -> ParserResult<Option<u8>> {
let result = self.current();
self.advance_n(1);
result
}
pub(crate) fn next_digit(&mut self) -> ParserResult<Option<u8>> {
let ascii_char = self.next_or(ParseError::AbruptEnd { location: "digit" })?;
if ascii_char.is_ascii_digit() {
Ok(Some(ascii_char - 48))
} else {
Ok(None)
}
}
pub(crate) fn next_or(&mut self, err: ParseError) -> ParserResult<u8> {
self.next()?.ok_or(err)
}
pub(crate) fn advance_n(&mut self, n: usize) {
self.pos += n;
}
pub(crate) fn advance(&mut self) {
self.advance_n(1)
}
pub(crate) fn advance_if(&mut self, condition: bool) {
if condition {
self.advance();
}
}
pub(crate) fn close(&mut self) -> ParserResult<()> {
if self.pos < self.source.len() {
return Err(ParseError::InvalidEnd);
}
Ok(())
}
}