#![cfg_attr(feature = "nightly", feature(io))]
use std::io::prelude::*;
use std::io::SeekFrom;
use std::{cmp, fmt, io, ptr};
#[cfg(test)]
mod tests;
pub mod strategy;
use self::strategy::{MoveStrategy, ReadStrategy, IfEmpty, AtEndLessThan1k};
const DEFAULT_BUF_SIZE: usize = 8 * 1024;
pub type DefaultReadStrategy = IfEmpty;
pub type DefaultMoveStrategy = AtEndLessThan1k;
pub struct BufReader<R, Rs, Ms>{
inner: R,
buf: Vec<u8>,
pos: usize,
cap: usize,
read_strat: Rs,
move_strat: Ms,
}
impl<R> BufReader<R, DefaultReadStrategy, DefaultMoveStrategy> {
pub fn new(inner: R) -> Self {
Self::with_strategies(inner, Default::default(), Default::default())
}
pub fn with_capacity(cap: usize, inner: R) -> Self {
Self::with_cap_and_strategies(inner, cap, Default::default(), Default::default())
}
}
impl<R, Rs: ReadStrategy, Ms: MoveStrategy> BufReader<R, Rs, Ms> {
pub fn with_strategies(inner: R, rs: Rs, ms: Ms) -> Self {
Self::with_cap_and_strategies(inner, DEFAULT_BUF_SIZE, rs, ms)
}
pub fn with_cap_and_strategies(inner: R, cap: usize, rs: Rs, ms: Ms) -> Self {
let mut self_ = BufReader {
inner: inner,
buf: Vec::new(),
pos: 0,
cap: 0,
read_strat: rs,
move_strat: ms,
};
self_.grow(cap);
self_
}
pub fn move_strategy<Ms_: MoveStrategy>(self, ms: Ms_) -> BufReader<R, Rs, Ms_> {
BufReader {
inner: self.inner,
buf: self.buf,
pos: self.pos,
cap: self.cap,
read_strat: self.read_strat,
move_strat: ms,
}
}
pub fn read_strategy<Rs_: ReadStrategy>(self, rs: Rs_) -> BufReader<R, Rs_, Ms> {
BufReader {
inner: self.inner,
buf: self.buf,
pos: self.pos,
cap: self.cap,
read_strat: rs,
move_strat: self.move_strat,
}
}
pub fn move_strategy_mut(&mut self) -> &mut Ms { &mut self.move_strat }
pub fn read_strategy_mut(&mut self) -> &mut Rs { &mut self.read_strat }
pub fn make_room(&mut self) {
if self.pos == 0 {
return;
}
if self.pos == self.cap {
self.pos = 0;
self.cap = 0;
return;
}
let src = self.buf[self.pos..].as_ptr();
let dest = self.buf.as_mut_ptr();
unsafe {
ptr::copy(src, dest, self.cap - self.pos);
}
self.cap -= self.pos;
self.pos = 0;
}
pub fn grow(&mut self, additional: usize) {
self.buf.reserve_exact(additional);
let new_len = self.buf.capacity();
self.buf.resize(new_len, 0u8);
}
pub fn get_buf(&self) -> &[u8] {
&self.buf[self.pos .. self.cap]
}
pub fn available(&self) -> usize {
self.cap - self.pos
}
pub fn capacity(&self) -> usize {
self.buf.len()
}
pub fn get_ref(&self) -> &R { &self.inner }
pub fn get_mut(&mut self) -> &mut R { &mut self.inner }
pub fn into_inner(self) -> R {
self.inner
}
pub fn into_inner_with_buf(mut self) -> (R, Vec<u8>) {
self.make_room();
self.buf.truncate(self.cap);
(self.inner, self.buf)
}
pub fn unbuffer(mut self) -> Unbuffer<R> {
self.buf.truncate(self.cap);
Unbuffer {
inner: self.inner,
buf: self.buf,
pos: self.pos,
}
}
#[inline]
fn should_read(&self) -> bool {
self.read_strat.should_read(self.pos, self.cap, self.buf.len())
}
fn should_move(&self) -> bool {
self.move_strat.should_move(self.pos, self.cap, self.buf.len())
}
}
impl<R: Read, Rs: ReadStrategy, Ms: MoveStrategy> BufReader<R, Rs, Ms> {
pub fn read_into_buf(&mut self) -> io::Result<usize> {
if self.pos == self.cap {
self.cap = try!(self.inner.read(&mut self.buf));
self.pos = 0;
} else {
if self.should_move() {
self.make_room();
}
self.cap += try!(self.inner.read(&mut self.buf[self.cap..]));
}
Ok(self.cap - self.pos)
}
}
impl<R: Read, Rs: ReadStrategy, Ms: MoveStrategy> Read for BufReader<R, Rs, Ms> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
if self.pos == self.cap && buf.len() >= self.buf.len() {
return self.inner.read(buf);
}
let nread = {
let mut rem = try!(self.fill_buf());
try!(rem.read(buf))
};
self.consume(nread);
Ok(nread)
}
}
impl<R: Read, Rs: ReadStrategy, Ms: MoveStrategy> BufRead for BufReader<R, Rs, Ms> {
fn fill_buf(&mut self) -> io::Result<&[u8]> {
if self.should_read() {
let _ = try!(self.read_into_buf());
}
Ok(&self.buf[self.pos..self.cap])
}
fn consume(&mut self, amt: usize) {
self.pos = cmp::min(self.pos + amt, self.cap);
}
}
impl<R: fmt::Debug, Rs: ReadStrategy, Ms: MoveStrategy> fmt::Debug for BufReader<R, Rs, Ms> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("buf_redux::BufReader")
.field("reader", &self.inner)
.field("available", &self.available())
.field("capacity", &self.capacity())
.field("read_strategy", &self.read_strat)
.field("move_strategy", &self.move_strat)
.finish()
}
}
impl<R: Seek, Rs: ReadStrategy, Ms: MoveStrategy> Seek for BufReader<R, Rs, Ms> {
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
let result: u64;
if let SeekFrom::Current(n) = pos {
let remainder = (self.cap - self.pos) as i64;
if let Some(offset) = n.checked_sub(remainder) {
result = try!(self.inner.seek(SeekFrom::Current(offset)));
} else {
try!(self.inner.seek(SeekFrom::Current(-remainder)));
self.pos = self.cap; result = try!(self.inner.seek(SeekFrom::Current(n)));
}
} else {
result = try!(self.inner.seek(pos));
}
self.pos = self.cap; Ok(result)
}
}
pub struct Unbuffer<R> {
inner: R,
buf: Vec<u8>,
pos: usize,
}
impl<R> Unbuffer<R> {
pub fn is_buf_empty(&self) -> bool {
self.pos >= self.buf.len()
}
pub fn buf_len(&self) -> usize {
self.buf.len().saturating_sub(self.pos)
}
pub fn into_inner(self) -> R {
self.inner
}
}
impl<R: Read> Read for Unbuffer<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
if self.pos < self.buf.len() {
let read = try!((&self.buf[self.pos..]).read(buf));
self.pos += read;
if self.pos == self.buf.len() {
self.buf == Vec::new();
}
Ok(read)
} else {
self.inner.read(buf)
}
}
}
impl<R: fmt::Debug> fmt::Debug for Unbuffer<R> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("buf_redux::Unbuffer")
.field("reader", &self.inner)
.field("buffer", &format_args!("{}/{}", self.pos, self.buf.len()))
.finish()
}
}