use std::cell::{RefCell};
use std::io::{Result, Error};
use crate::{Position, Span};
pub struct Buffer<I: Iterator<Item=Result<char>>> {
p: RefCell<Inner<I>>
}
struct Inner<I: Iterator<Item=Result<char>>> {
input: I,
error: Option<Error>,
data: Vec<char>,
lines: Vec<usize>,
span: Span
}
impl<I: Iterator<Item=Result<char>>> Inner<I> {
fn read_line(&mut self) -> 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);
},
Some(Err(e)) => {
self.error = Some(e);
return false
},
None => {
return false
}
}
}
self.lines.push(self.data.len());
true
} else {
false
}
}
fn index_at(&mut self, pos: Position) -> Option<Result<usize>> {
if pos < self.span.start() {
None
} else {
while pos >= self.span.end() && self.read_line() { }
if pos >= self.span.end() {
let mut error = None;
std::mem::swap(&mut error, &mut self.error);
match error {
Some(e) => Some(Err(e)),
None => 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]);
i += 1;
}
if cursor == pos {
Some(Ok(i))
} else {
None
}
}
}
}
fn get(&mut self, i: usize) -> Option<Result<char>> {
while i >= self.data.len() && self.read_line() { }
if i >= self.data.len() {
let mut error = None;
std::mem::swap(&mut error, &mut self.error);
match error {
Some(e) => Some(Err(e)),
None => None
}
} else {
Some(Ok(self.data[i]))
}
}
}
impl<I: Iterator<Item=Result<char>>> Buffer<I> {
pub fn new(input: I, position: Position) -> Buffer<I> {
Buffer {
p: RefCell::new(Inner {
input: input,
error: None,
data: Vec::new(),
lines: vec![0],
span: position.into()
})
}
}
pub fn span(&self) -> Span {
self.p.borrow().span
}
pub fn index_at(&self, pos: Position) -> Option<Result<usize>> {
self.p.borrow_mut().index_at(pos)
}
pub fn at(&self, pos: Position) -> Option<Result<char>> {
match self.index_at(pos) {
Some(Ok(i)) => self.p.borrow_mut().get(i),
Some(Err(e)) => Some(Err(e)),
None => None
}
}
fn get(&self, i: usize) -> Option<Result<char>> {
self.p.borrow_mut().get(i)
}
pub fn iter(&self) -> Iter<I> {
Iter {
buffer: &self,
i: Some(Ok(0))
}
}
pub fn iter_from(&self, pos: Position) -> Iter<I> {
Iter {
buffer: &self,
i: self.index_at(std::cmp::max(self.p.borrow().span.start(), pos))
}
}
}
pub struct Iter<'b, I: 'b + Iterator<Item=Result<char>>> {
buffer: &'b Buffer<I>,
i: Option<Result<usize>>
}
impl<'b, I: 'b + Iterator<Item=Result<char>>> Iterator for Iter<'b, I> {
type Item = Result<char>;
fn next(&mut self) -> Option<Result<char>> {
match &mut self.i {
Some(Ok(ref mut i)) => {
match self.buffer.get(*i) {
Some(Ok(c)) => {
*i = *i+1;
Some(Ok(c))
},
Some(Err(e)) => Some(Err(e)),
None => None
}
},
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!()
}
},
}
}
}