use std::io;
use std::str::Chars;
use utf8reader;
struct UTF8Reader<R: io::Read>(utf8reader::UTF8Reader<R>);
impl<R: io::Read> Iterator for UTF8Reader<R> {
type Item = char;
fn next(&mut self) -> Option<Self::Item> {
loop {
match self.0.next() {
None => return None,
Some(Err(_)) => continue,
Some(Ok(c)) => return Some(c),
}
}
}
}
#[derive(Debug)]
pub struct ParseState<Iter: Iterator<Item = char>> {
buf: Vec<char>,
next: Option<Iter>,
global: usize,
current: usize,
oldest_hold_count: Option<(usize, usize)>,
}
pub struct Hold {
ix: usize,
released: bool,
}
impl Hold {
fn new(ix: usize) -> Hold {
Hold {
ix: ix,
released: false,
}
}
fn defuse(&mut self) {
self.released = true;
}
}
impl Drop for Hold {
fn drop(&mut self) {
if !std::thread::panicking() {
assert!(self.released, "Dropped unreleased hold! This is a bug");
}
}
}
impl<'a> ParseState<Chars<'a>> {
pub fn new(s: &'a str) -> ParseState<Chars<'a>> {
ParseState {
buf: vec![],
next: Some(s.chars()),
current: 0,
global: 0,
oldest_hold_count: None,
}
}
pub fn from_reader<R: io::Read>(r: R) -> ParseState<impl Iterator<Item = char>> {
ParseState {
buf: vec![],
next: Some(UTF8Reader(utf8reader::UTF8Reader::new(r))),
current: 0,
global: 0,
oldest_hold_count: None,
}
}
}
impl<Iter: Iterator<Item = char>> ParseState<Iter> {
const PREFILL_DEFAULT: usize = 1024;
const GARBAGE_COLLECT_THRESHOLD: usize = 1024 * 4;
pub fn index(&mut self) -> usize {
self.global
}
pub fn hold(&mut self) -> Hold {
if self.oldest_hold_count.is_none() {
self.oldest_hold_count = Some((self.global, 1))
} else if let Some((ix, count)) = self.oldest_hold_count {
if self.global == ix {
self.oldest_hold_count = Some((self.global, count + 1));
}
}
Hold::new(self.global)
}
pub fn release(&mut self, mut h: Hold) {
match self.oldest_hold_count {
Some((ix, count)) if ix == h.ix && count > 1 => {
self.oldest_hold_count = Some((ix, count - 1));
}
Some((ix, count)) if ix == h.ix && count == 1 => {
self.oldest_hold_count = None;
self.maybe_gc();
}
_ => {}
}
h.defuse();
}
pub fn reset(&mut self, mut h: Hold) {
match self.oldest_hold_count {
Some((ix, count)) if ix == h.ix && count > 1 => {
self.oldest_hold_count = Some((ix, count - 1));
}
Some((ix, count)) if ix == h.ix && count == 1 => {
self.oldest_hold_count = None;
}
_ => {}
}
self.current -= self.global - h.ix;
self.global = h.ix;
h.defuse();
}
fn maybe_gc(&mut self) -> bool {
if self.next.is_none() {
return false;
}
match self.oldest_hold_count {
None if self.current > 0 => {
if self.current < Self::GARBAGE_COLLECT_THRESHOLD {
return false;
}
self.buf.rotate_left(self.current - 1);
self.buf
.resize(self.buf.len() - self.current + 1, 0 as char);
self.current = 1;
true
}
Some((ix, _)) => {
let ix = ix - self.global;
if ix < Self::GARBAGE_COLLECT_THRESHOLD {
return false;
}
self.buf.rotate_left(ix - 1);
self.buf.resize(self.buf.len() - ix + 1, 0 as char);
self.current = 1;
true
}
_ => false,
}
}
pub fn finished(&self) -> bool {
self.next.is_none() && self.current == self.buf.len()
}
pub fn undo_next(&mut self) {
assert!(self.current > 0);
self.current -= 1;
self.global -= 1;
}
fn prefill(&mut self, n: usize) -> bool {
if let Some(next) = self.next.as_mut() {
let oldlen = self.buf.len();
self.buf.extend(next.take(n));
return (self.buf.len() - oldlen) > 0;
}
false
}
pub fn peek(&mut self) -> Option<Iter::Item> {
if self.current < self.buf.len() {
return Some(self.buf[self.current]);
} else if self.current == self.buf.len() && self.next.is_some() {
match self.next() {
Some(c) => {
self.current -= 1;
self.global -= 1;
return Some(c);
}
None => return None,
}
} else if self.next.is_none() {
return None;
}
unreachable!()
}
}
impl<Iter: Iterator<Item = char>> Iterator for ParseState<Iter> {
type Item = char;
fn next(&mut self) -> Option<Iter::Item> {
if self.current < self.buf.len() {
self.current += 1;
self.global += 1;
Some(self.buf[self.current - 1])
} else {
if self.prefill(Self::PREFILL_DEFAULT) {
self.next()
} else {
self.next = None;
None
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::parser::Parser;
#[test]
fn test_basic() {
let mut s = ParseState::new("Hello");
assert_eq!(Some('H'), s.next());
let rest: String = s.collect();
assert_eq!("ello", rest);
let mut s = ParseState::new("Hello");
let hold = s.hold();
s.next();
s.next();
s.next();
assert_eq!(Some('l'), s.peek());
assert_eq!(Some('l'), s.next());
s.reset(hold);
let rest: String = s.collect();
assert_eq!("Hello", rest);
}
#[test]
#[should_panic]
fn test_hold_unreleased() {
let mut s = ParseState::new("abcde");
let _hold = s.hold();
}
use crate::primitives;
#[test]
fn test_utf8_stream() {
let s = "Hüðslþ".to_owned();
let mut ps = ParseState::from_reader(s.as_bytes());
assert_eq!(Some('H'), ps.next());
assert_eq!(
Ok("üð".to_string()),
primitives::StringParser::new("üð".to_string()).parse(&mut ps)
);
}
}