use std::mem;
use gapbuffer::GapBuffer;
pub struct Lines<'a> {
pub buffer: &'a GapBuffer<u8>,
pub tail: usize,
pub head: usize,
}
impl<'a> Iterator for Lines<'a> {
type Item = Vec<u8>;
fn next(&mut self) -> Option<Vec<u8>> {
if self.tail != self.head {
let old_tail = self.tail;
self.tail = (old_tail..self.head).filter(|i| { *i + 1 == self.head
|| self.buffer[*i] == b'\n' })
.take(1)
.next()
.unwrap() + 1;
Some((old_tail..if self.tail == self.head { self.tail - 1 } else { self.tail })
.map( |i| self.buffer[i] ).collect())
} else { None }
}
fn size_hint(&self) -> (usize, Option<usize>) {
(1, Some(self.head))
}
}
pub struct Chars<'a> {
pub buffer: &'a GapBuffer<u8>,
pub idx: usize,
pub forward: bool,
}
pub struct CharIndices<'a> {
iter: Chars<'a>
}
const CONT_MASK: u8 = 0b0011_1111u8;
const TAG_CONT_U8: u8 = 0b1000_0000u8;
macro_rules! utf8_first_byte {
($byte:expr, $width:expr) => (($byte & (0x7F >> $width)) as u32)
}
macro_rules! utf8_acc_cont_byte {
($ch:expr, $byte:expr) => (($ch << 6) | ($byte & CONT_MASK) as u32)
}
macro_rules! utf8_is_cont_byte {
($byte:expr) => (($byte & !CONT_MASK) == TAG_CONT_U8)
}
impl<'a> Chars<'a> {
pub fn reverse(mut self) -> Chars<'a> {
self.forward = !self.forward;
self
}
pub fn forward(mut self) -> Chars<'a> {
self.forward = true;
self
}
pub fn backward(mut self) -> Chars<'a> {
self.forward = false;
self
}
pub fn indices(self) -> CharIndices<'a> {
CharIndices {
iter: self
}
}
fn next_u8(&mut self) -> Option<u8> {
let n = if self.idx < self.buffer.len() {
Some(self.buffer[self.idx])
} else { None };
if self.forward {
self.idx += 1;
} else {
self.idx -= 1;
}
n
}
}
impl<'a> Iterator for Chars<'a> {
type Item = char;
#[inline]
fn next(&mut self) -> Option<char> {
if self.forward {
let x = match self.next_u8() {
None => return None,
Some(next_byte) if next_byte < 128 => return Some(next_byte as char),
Some(next_byte) => next_byte
};
let init = utf8_first_byte!(x, 2);
let y = self.next_u8().unwrap_or(0);
let mut ch = utf8_acc_cont_byte!(init, y);
if x >= 0xE0 {
let z = self.next_u8().unwrap_or(0);
let y_z = utf8_acc_cont_byte!((y & CONT_MASK) as u32, z);
ch = init << 12 | y_z;
if x >= 0xF0 {
let w = self.next_u8().unwrap_or(0);
ch = (init & 7) << 18 | utf8_acc_cont_byte!(y_z, w);
}
}
return unsafe { Some(mem::transmute(ch)) };
} else {
let w = match self.next_u8() {
None => return None,
Some(back_byte) if back_byte < 128 => return Some(back_byte as char),
Some(back_byte) => back_byte,
};
let mut ch;
let z = self.next_u8().unwrap_or(0);
ch = utf8_first_byte!(z, 2);
if utf8_is_cont_byte!(z) {
let y = self.next_u8().unwrap_or(0);
ch = utf8_first_byte!(y, 3);
if utf8_is_cont_byte!(y) {
let x = self.next_u8().unwrap_or(0);
ch = utf8_first_byte!(x, 4);
ch = utf8_acc_cont_byte!(ch, y);
}
ch = utf8_acc_cont_byte!(ch, z);
}
ch = utf8_acc_cont_byte!(ch, w);
return unsafe { Some(mem::transmute(ch)) };
}
}
}
impl<'a> CharIndices<'a> {
pub fn rev(mut self) -> CharIndices<'a> {
self.iter.forward = !self.iter.forward;
self
}
pub fn forward(mut self) -> CharIndices<'a> {
self.iter.forward = true;
self
}
pub fn backward(mut self) -> CharIndices<'a> {
self.iter.forward = false;
self
}
}
impl<'a> Iterator for CharIndices<'a> {
type Item = (usize, char);
#[inline]
fn next(&mut self) -> Option<(usize, char)> {
if let Some(c) = self.iter.next() {
Some((self.iter.idx, c))
} else {
None
}
}
}