use std::cell::RefCell;
use crate::{Metrics, Position, Span};
pub struct SourceBuffer<E, I: Iterator<Item = Result<char, E>>, M: Metrics> {
p: RefCell<Inner<E, I>>,
metrics: M,
}
struct Inner<E, I: Iterator<Item = Result<char, E>>> {
input: I,
error: Option<E>,
data: Vec<char>,
lines: Vec<usize>,
span: Span,
}
impl<E, I: Iterator<Item = Result<char, E>>> Inner<E, I> {
fn read_line<M: Metrics>(&mut self, metrics: &M) -> bool {
if self.error.is_none() {
let line = self.span.end().line;
while line == self.span.end().line {
match self.input.next() {
Some(Ok(c)) => {
self.data.push(c);
self.span.push(c, metrics);
}
Some(Err(e)) => {
self.error = Some(e);
return false;
}
None => return false,
}
}
self.lines.push(self.data.len());
true
} else {
false
}
}
fn index_at<M: Metrics>(&mut self, pos: Position, metrics: &M) -> Result<Option<usize>, E> {
if pos < self.span.start() {
Ok(None)
} else {
while pos >= self.span.end() && self.read_line(metrics) {}
if pos >= self.span.end() {
let mut error = None;
std::mem::swap(&mut error, &mut self.error);
match error {
Some(e) => Err(e),
None => Ok(None),
}
} else {
let relative_line = pos.line - self.span.start().line;
let mut i = self.lines[relative_line];
let mut cursor = Position::new(pos.line, 0);
while cursor < pos {
cursor = cursor.next(self.data[i], metrics);
i += 1;
}
if cursor == pos {
Ok(Some(i))
} else {
Ok(None)
}
}
}
}
fn get<M: Metrics>(&mut self, i: usize, metrics: &M) -> Result<Option<char>, E> {
while i >= self.data.len() && self.read_line(metrics) {}
if i >= self.data.len() {
let mut error = None;
std::mem::swap(&mut error, &mut self.error);
match error {
Some(e) => Err(e),
None => Ok(None),
}
} else {
Ok(Some(self.data[i]))
}
}
}
impl<E, I: Iterator<Item = Result<char, E>>, M: Metrics> SourceBuffer<E, I, M> {
pub fn new(input: I, position: Position, metrics: M) -> Self {
Self {
p: RefCell::new(Inner {
input,
error: None,
data: Vec::new(),
lines: vec![0],
span: position.into(),
}),
metrics,
}
}
pub fn metrics(&self) -> &M { &self.metrics }
pub fn span(&self) -> Span { self.p.borrow().span }
pub fn index_at(&self, pos: Position) -> Result<Option<usize>, E> {
self.p.borrow_mut().index_at(pos, &self.metrics)
}
pub fn at(&self, pos: Position) -> Result<Option<char>, E> {
match self.index_at(pos) {
Ok(Some(i)) => self.p.borrow_mut().get(i, &self.metrics),
Ok(None) => Ok(None),
Err(e) => Err(e)
}
}
pub fn get(&self, i: usize) -> Result<Option<char>, E> { self.p.borrow_mut().get(i, &self.metrics) }
pub fn iter(&self) -> Iter<E, I, M> {
Iter {
buffer: self,
i: Some(Ok(0)),
pos: self.p.borrow().span.start(),
end: Position::end(),
}
}
pub fn iter_from(&self, pos: Position) -> Iter<E, I, M> {
let start = self.p.borrow().span.start();
let pos = std::cmp::max(start, pos);
Iter {
buffer: self,
i: self.index_at(pos).transpose(),
pos,
end: Position::end(),
}
}
pub fn iter_span(&self, span: Span) -> Iter<E, I, M> {
let start = self.p.borrow().span.start();
let pos = std::cmp::max(start, span.start());
Iter {
buffer: self,
i: self.index_at(pos).transpose(),
pos,
end: span.end(),
}
}
}
pub struct Iter<'b, E, I: 'b + Iterator<Item = Result<char, E>>, M: Metrics> {
buffer: &'b SourceBuffer<E, I, M>,
i: Option<Result<usize, E>>,
pos: Position,
end: Position,
}
impl<'b, E, I: 'b + Iterator<Item = Result<char, E>>, M: Metrics> Iter<'b, E, I, M> {
pub fn into_string(self) -> Result<String, E> {
let mut string = String::new();
for c in self {
string.push(c?);
}
Ok(string)
}
}
impl<'b, E, I: 'b + Iterator<Item = Result<char, E>>, M: Metrics> Iterator for Iter<'b, E, I, M> {
type Item = Result<char, E>;
fn next(&mut self) -> Option<Result<char, E>> {
if self.pos >= self.end {
None
} else {
match &mut self.i {
Some(Ok(ref mut i)) => match self.buffer.get(*i) {
Ok(Some(c)) => {
self.pos = self.pos.next(c, self.buffer.metrics());
*i += 1;
Some(Ok(c))
}
Ok(None) => None,
Err(e) => Some(Err(e)),
},
None => None,
ref mut i => {
let mut new_i = None;
std::mem::swap(&mut new_i, i);
if let Some(Err(e)) = new_i {
Some(Err(e))
} else {
unreachable!()
}
}
}
}
}
}