use std::fmt::Debug;
use std::ops::{Add, AddAssign, Sub};
use crate::reader::{IntoReader, Reader};
pub trait Offset:
Default
+ Copy
+ Eq
+ Ord
+ Add<usize, Output = Self>
+ Sub<usize, Output = Self>
+ AddAssign<usize>
+ Debug
{
}
impl Offset for usize {}
impl Offset for NoopOffset {}
#[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
pub struct NoopOffset;
pub trait Position<T> {
fn position(&self) -> T;
}
impl<R: Reader> Position<NoopOffset> for R {
fn position(&self) -> NoopOffset {
NoopOffset
}
}
pub struct PosTrackingReader<R> {
reader: R,
position: usize,
}
impl<R> PosTrackingReader<R> {
pub fn new<'a>(into_reader: impl IntoReader<'a, Reader = R>) -> Self {
Self {
reader: into_reader.into_reader(),
position: 0,
}
}
}
impl<R> Position<usize> for PosTrackingReader<R> {
fn position(&self) -> usize {
self.position
}
}
impl Add<usize> for NoopOffset {
type Output = Self;
fn add(self, _rhs: usize) -> NoopOffset {
self
}
}
impl Sub<usize> for NoopOffset {
type Output = Self;
fn sub(self, _rhs: usize) -> NoopOffset {
self
}
}
impl AddAssign<usize> for NoopOffset {
fn add_assign(&mut self, _rhs: usize) {}
}
impl<R: Reader> Reader for PosTrackingReader<R> {
type Error = R::Error;
fn read_char(&mut self) -> Result<Option<char>, Self::Error> {
match self.reader.read_char()? {
Some(char) => {
self.position += self.reader.len_of_char_in_current_encoding(char);
Ok(Some(char))
}
None => Ok(None),
}
}
fn try_read_string(&mut self, s: &str, case_sensitive: bool) -> Result<bool, Self::Error> {
match self.reader.try_read_string(s, case_sensitive)? {
true => {
for c in s.chars() {
self.position += self.reader.len_of_char_in_current_encoding(c);
}
Ok(true)
}
false => Ok(false),
}
}
fn len_of_char_in_current_encoding(&self, c: char) -> usize {
self.reader.len_of_char_in_current_encoding(c)
}
}