#![warn(missing_docs)]
use quick_error::quick_error;
use std::io::{self, Read};
use memchr::memchr;
mod buffer;
pub use buffer::{
Buffer,
VecBuffer,
MmapBuffer,
};
use slice_deque::AllocError;
use std::convert::From;
pub struct BufRefReader<R, B> {
src: R,
buf: B,
}
pub struct BufRefReaderBuilder<R> {
src: R,
bufsize: usize,
}
impl<R: Read> BufRefReaderBuilder<R> {
pub fn new(src: R) -> Self {
BufRefReaderBuilder {
src,
bufsize: 8192,
}
}
pub fn capacity(mut self, bufsize: usize) -> Self {
self.bufsize = bufsize;
self
}
pub fn build<B: Buffer>(self) -> Result<BufRefReader<R, B>, B::Error> {
Ok(BufRefReader {
src: self.src,
buf: B::new(self.bufsize)?,
})
}
}
quick_error! {
#[derive(Debug)]
pub enum Error {
IO(err: io::Error) { from() }
Buf(err: AllocError) { from() }
}
}
impl From<()> for Error {
fn from(_: ()) -> Self {
unimplemented!()
}
}
impl<R: Read, B: Buffer> BufRefReader<R, B>
where Error: From<B::Error>
{
pub fn new(src: R) -> Result<BufRefReader<R, B>, B::Error> {
BufRefReaderBuilder::new(src)
.build()
}
#[inline]
fn fill(&mut self) -> Result<Option<usize>, Error> {
self.buf.enlarge()?;
let old_len = self.buf.len();
match self.src.read(self.buf.appendable())? {
0 => Ok(None), n => {
self.buf.grow(n);
Ok(Some(old_len))
}
}
}
#[inline]
pub fn read(&mut self, n: usize) -> Result<Option<&[u8]>, Error> {
while n > self.buf.len() {
if self.fill()?.is_none() { break };
}
if self.buf.len() == 0 {
Ok(None)
} else {
let output = self.buf.consume(n);
Ok(Some(output))
}
}
#[inline]
pub fn read_until(&mut self, delim: u8) -> Result<Option<&[u8]>, Error> {
let mut len = None;
let mut pos = 0;
loop {
if let Some(n) = memchr(delim, &self.buf.filled()[pos..]) {
len = Some(pos+n);
break;
}
pos = match self.fill()? {
None => break, Some(pos) => pos,
};
}
match len {
None => { if self.buf.len() == 0 {
Ok(None)
} else {
let output = self.buf.consume(self.buf.len());
Ok(Some(output))
}
},
Some(len) => {
let len = len + 1; let output = self.buf.consume(len);
Ok(Some(output))
},
}
}
}
#[cfg(test)]
static WORDS: &'static [u8] = include_bytes!("/usr/share/dict/words");
#[cfg(test)]
mod tests {
use super::*;
use std::fmt::Debug;
fn read_until_empty_lines<B: Buffer>()
where
B::Error: Debug,
Error: From<B::Error>,
{
let mut r = BufRefReaderBuilder::new(&b" lorem ipsum "[..])
.capacity(4)
.build::<B>()
.unwrap();
assert_eq!(r.read_until(b' ').unwrap(), Some(&b" "[..]));
assert_eq!(r.read_until(b' ').unwrap(), Some(&b" "[..]));
assert_eq!(r.read_until(b' ').unwrap(), Some(&b"lorem "[..]));
assert_eq!(r.read_until(b' ').unwrap(), Some(&b" "[..]));
assert_eq!(r.read_until(b' ').unwrap(), Some(&b" "[..]));
assert_eq!(r.read_until(b' ').unwrap(), Some(&b"ipsum "[..]));
assert_eq!(r.read_until(b' ').unwrap(), Some(&b" "[..]));
assert_eq!(r.read_until(b' ').unwrap(), None);
}
#[test] fn read_until_empty_lines_vec() { read_until_empty_lines::<VecBuffer>() }
#[test] fn read_until_empty_lines_mmap() { read_until_empty_lines::<MmapBuffer>() }
fn read_until_words<B: Buffer>()
where
B::Error: Debug,
Error: From<B::Error>,
{
let mut r = BufRefReaderBuilder::new(WORDS)
.capacity(4)
.build::<B>()
.unwrap();
let mut words = WORDS.split(|&c| c == b'\n');
while let Ok(Some(slice_buf)) = r.read_until(b'\n') {
let mut slice_words = words.next().unwrap()
.to_vec();
slice_words.push(b'\n');
assert_eq!(slice_buf, &slice_words[..]);
}
assert_eq!(words.next(), Some(&b""[..]));
assert_eq!(words.next(), None);
}
#[test] fn read_until_words_vec() { read_until_words::<VecBuffer>() }
#[test] fn read_until_words_mmap() { read_until_words::<MmapBuffer>() }
fn read_until_words_long<B: Buffer>()
where
B::Error: Debug,
Error: From<B::Error>,
{
let mut r = BufRefReaderBuilder::new(WORDS)
.capacity(32)
.build::<B>()
.unwrap();
let mut words = WORDS.split(|&c| c == b'Q').peekable();
while let Ok(Some(slice_buf)) = r.read_until(b'Q') {
let mut slice_words = words.next().unwrap()
.to_vec();
if words.peek() != None {
slice_words.push(b'Q');
}
assert_eq!(slice_buf, &slice_words[..]);
}
assert_eq!(words.next(), None);
}
#[test] fn read_until_words_long_vec() { read_until_words_long::<VecBuffer>() }
#[test] fn read_until_words_long_mmap() { read_until_words_long::<MmapBuffer>() }
fn read<B: Buffer>()
where
B::Error: Debug,
Error: From<B::Error>,
{
let mut r = BufRefReaderBuilder::new(&b"lorem ipsum dolor sit amet"[..])
.capacity(4)
.build::<B>()
.unwrap();
assert_eq!(r.read(5).unwrap(), Some(&b"lorem"[..]));
assert_eq!(r.read(6).unwrap(), Some(&b" ipsum"[..]));
assert_eq!(r.read(1024).unwrap(), Some(&b" dolor sit amet"[..]));
assert_eq!(r.read(1).unwrap(), None);
}
#[test] fn read_vec() { read::<VecBuffer>() }
#[test] fn read_mmap() { read::<MmapBuffer>() }
fn read_words<B: Buffer>(cap: usize, read: usize)
where
B::Error: Debug,
Error: From<B::Error>,
{
let mut r = BufRefReaderBuilder::new(WORDS)
.capacity(cap)
.build::<B>()
.unwrap();
let mut words = WORDS.chunks(read);
while let Ok(Some(slice_buf)) = r.read(read) {
let slice_words = words.next().unwrap();
assert_eq!(slice_buf, slice_words);
}
assert_eq!(words.next(), None);
}
#[test] fn read_words_vec_4x3() { read_words::<VecBuffer>(4, 3) }
#[test] fn read_words_vec_4x5() { read_words::<VecBuffer>(4, 5) }
#[test] fn read_words_mmap_4x3() { read_words::<MmapBuffer>(4, 3) }
#[test] fn read_words_mmap_4x5() { read_words::<MmapBuffer>(4, 5) }
}