use std::fmt;
use std::io::{self, BufRead, Read, Seek, SeekFrom};
const DEFAULT_BUF_SIZE: usize = 8 * 1024;
pub struct BufReader<R> {
inner: R,
buf: Box<[u8]>,
buf_pos: usize,
cap: usize,
absolute_pos: u64,
}
impl<R: Read + Seek> BufReader<R> {
pub fn new(inner: R) -> BufReader<R> {
BufReader::with_capacity(DEFAULT_BUF_SIZE, inner)
}
pub fn with_capacity(cap: usize, inner: R) -> BufReader<R> {
BufReader {
inner: inner,
buf: vec![0; cap].into_boxed_slice(),
buf_pos: 0,
cap: 0,
absolute_pos: 0,
}
}
pub fn position(&self) -> u64 { self.absolute_pos }
pub fn capacity(&self) -> usize { self.cap }
pub fn available(&self) -> usize {
self.cap.checked_sub(self.buf_pos).unwrap_or(0)
}
pub fn into_inner(mut self) -> io::Result<R> {
try!(self.inner.seek(SeekFrom::Start(self.absolute_pos)));
Ok(self.inner)
}
fn sync_and_flush(&mut self, pos: SeekFrom) -> io::Result<u64> {
self.buf_pos = self.cap;
self.absolute_pos = try!(self.inner.seek(pos));
Ok(self.absolute_pos)
}
fn seek_backward(&mut self, n: i64) -> io::Result<u64> {
let n_abs = n.abs() as usize;
if self.buf_pos.checked_sub(n_abs).is_some() {
self.absolute_pos -= n_abs as u64;
self.buf_pos -= n_abs;
Ok(self.absolute_pos)
} else {
let new_pos = self.absolute_pos - n_abs as u64;
self.sync_and_flush(SeekFrom::Start(new_pos))
}
}
fn seek_forward(&mut self, n: usize) -> io::Result<u64> {
if self.available().checked_sub(n).is_some() {
self.consume(n);
Ok(self.absolute_pos)
} else {
let new_pos = self.absolute_pos + n as u64;
self.sync_and_flush(SeekFrom::Start(new_pos))
}
}
}
impl<R: Read> Read for BufReader<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let n_exp = buf.len();
let mut n_total = 0;
while n_total < n_exp {
let n_read = try!(try!(self.fill_buf()).read(&mut buf[n_total..]));
if n_read == 0 {
break;
}
self.consume(n_read);
n_total += n_read;
}
Ok(n_total)
}
}
impl<R: Read> BufRead for BufReader<R> {
fn fill_buf(&mut self) -> io::Result<&[u8]> {
if self.cap == self.buf_pos {
self.cap = try!(self.inner.read(&mut self.buf));
self.buf_pos = 0;
}
Ok(&self.buf[self.buf_pos..self.cap])
}
fn consume(&mut self, amt: usize) {
self.buf_pos += amt;
self.absolute_pos += amt as u64;
}
}
impl<R: Read + Seek> Seek for BufReader<R> {
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
match pos {
SeekFrom::Current(n) => {
match n >= 0 {
true => self.seek_forward(n as usize),
false => self.seek_backward(n)
}
}
SeekFrom::Start(n) => {
match n.checked_sub(self.absolute_pos) {
Some(n_bytes) => self.seek_forward(n_bytes as usize),
None => self.sync_and_flush(pos)
}
}
_ => self.sync_and_flush(pos)
}
}
}
impl<R> fmt::Debug for BufReader<R> where R: fmt::Debug + Read + Seek {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("BufReader")
.field("reader", &self.inner)
.field("available", &self.available())
.field("capacity", &self.cap)
.field("position", &self.absolute_pos)
.finish()
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::io::{self, Cursor, Read, Seek, SeekFrom};
#[test]
fn default_behaviour() {
let mut reader = BufReader::new(Cursor::new([5, 6, 7, 0, 1, 2, 3, 4]));
let mut buf = [0; 8];
reader.read(&mut buf).unwrap();
assert_eq!(buf, [5, 6, 7, 0, 1, 2, 3, 4]);
let mut buf = [0; 8];
reader.read(&mut buf).unwrap();
assert_eq!(buf, [0, 0, 0, 0, 0, 0, 0, 0]);
}
#[test]
fn default_behaviour_std() {
let mut reader = io::BufReader::new(Cursor::new([5, 6, 7, 0, 1, 2, 3, 4]));
let mut buf = [0; 8];
reader.read(&mut buf).unwrap();
assert_eq!(buf, [5, 6, 7, 0, 1, 2, 3, 4]);
let mut buf = [0; 8];
reader.read(&mut buf).unwrap();
assert_eq!(buf, [0, 0, 0, 0, 0, 0, 0, 0]);
}
#[test]
fn small_capacity() {
let inner = Cursor::new([5, 6, 7, 0, 1, 2, 3, 4]);
let mut reader = BufReader::with_capacity(2, inner);
let mut buf = [0, 0, 0];
reader.read(&mut buf).unwrap();
assert_eq!(buf, [5, 6, 7]);
let mut buf = [0, 0];
reader.read(&mut buf).unwrap();
assert_eq!(buf, [0, 1]);
let mut buf = [0];
reader.read(&mut buf).unwrap();
assert_eq!(buf, [2]);
}
#[test]
fn small_capacity_std() {
let inner = Cursor::new([5, 6, 7, 0, 1, 2, 3, 4]);
let mut reader = io::BufReader::with_capacity(2, inner);
let mut buf = [0, 0, 0];
reader.read(&mut buf).unwrap();
assert_eq!(buf, [5, 6, 7]);
let mut buf = [0, 0];
reader.read(&mut buf).unwrap();
assert_eq!(buf, [0, 1]);
let mut buf = [0];
reader.read(&mut buf).unwrap();
assert_eq!(buf, [2]);
}
#[test]
fn seek_start() {
let inner = Cursor::new([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
let mut reader = BufReader::with_capacity(10, inner);
reader.seek(SeekFrom::Start(3)).unwrap();
let mut buf = [0; 8];
reader.read(&mut buf).unwrap();
assert_eq!(buf, [3, 4, 5, 6, 7, 8, 9, 10]);
reader.seek(SeekFrom::Start(0)).unwrap();
let mut buf = [0; 8];
reader.read(&mut buf).unwrap();
assert_eq!(buf, [0, 1, 2, 3, 4, 5, 6, 7]);
reader.seek(SeekFrom::Start(13)).unwrap();
let mut buf = [0; 8];
reader.read(&mut buf).unwrap();
assert_eq!(buf, [13, 14, 15, 16, 0, 0, 0, 0]);
reader.seek(SeekFrom::Start(0)).unwrap();
let mut buf = [0; 8];
reader.read(&mut buf).unwrap();
assert_eq!(buf, [0, 1, 2, 3, 4, 5, 6, 7]);
}
#[test]
fn seek_start_std() {
let inner = Cursor::new([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
let mut reader = io::BufReader::with_capacity(10, inner);
reader.seek(SeekFrom::Start(3)).unwrap();
let mut buf = [0; 8];
reader.read(&mut buf).unwrap();
assert_eq!(buf, [3, 4, 5, 6, 7, 8, 9, 10]);
reader.seek(SeekFrom::Start(0)).unwrap();
let mut buf = [0; 8];
reader.read(&mut buf).unwrap();
assert_eq!(buf, [0, 1, 2, 3, 4, 5, 6, 7]);
reader.seek(SeekFrom::Start(13)).unwrap();
let mut buf = [0; 8];
reader.read(&mut buf).unwrap();
assert_eq!(buf, [13, 14, 15, 16, 0, 0, 0, 0]);
reader.seek(SeekFrom::Start(0)).unwrap();
let mut buf = [0; 8];
reader.read(&mut buf).unwrap();
assert_eq!(buf, [0, 1, 2, 3, 4, 5, 6, 7]);
}
#[test]
fn seek_current_positive() {
let inner = Cursor::new([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
let mut reader = BufReader::with_capacity(20, inner);
reader.seek(SeekFrom::Current(2)).unwrap();
let mut buf = [0; 8];
reader.read(&mut buf).unwrap();
assert_eq!(buf, [2, 3, 4, 5, 6, 7, 8, 9]);
reader.seek(SeekFrom::Current(6)).unwrap();
let mut buf = [0; 8];
reader.read(&mut buf).unwrap();
assert_eq!(buf, [16, 0, 0, 0, 0, 0, 0, 0]);
}
#[test]
fn seek_current_positive_std() {
let inner = Cursor::new([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
let mut reader = io::BufReader::with_capacity(20, inner);
reader.seek(SeekFrom::Current(2)).unwrap();
let mut buf = [0; 8];
reader.read(&mut buf).unwrap();
assert_eq!(buf, [2, 3, 4, 5, 6, 7, 8, 9]);
reader.seek(SeekFrom::Current(6)).unwrap();
let mut buf = [0; 8];
reader.read(&mut buf).unwrap();
assert_eq!(buf, [16, 0, 0, 0, 0, 0, 0, 0]);
}
#[test]
fn seek_current_negative() {
let inner = Cursor::new([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
let mut reader = BufReader::with_capacity(3, inner);
reader.seek(SeekFrom::Current(4)).unwrap();
let mut buf = [0; 4];
reader.read(&mut buf).unwrap();
assert_eq!(buf, [4, 5, 6, 7]);
reader.seek(SeekFrom::Current(-2)).unwrap();
let mut buf = [0; 4];
reader.read(&mut buf).unwrap();
assert_eq!(buf, [6, 7, 8, 9]);
reader.seek(SeekFrom::Current(-4)).unwrap();
let mut buf = [0; 4];
reader.read(&mut buf).unwrap();
assert_eq!(buf, [6, 7, 8, 9]);
}
#[test]
fn seek_current_negative_std() {
let inner = Cursor::new([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
let mut reader = io::BufReader::with_capacity(3, inner);
reader.seek(SeekFrom::Current(4)).unwrap();
let mut buf = [0; 4];
reader.read(&mut buf).unwrap();
assert_eq!(buf, [4, 5, 6, 7]);
reader.seek(SeekFrom::Current(-2)).unwrap();
let mut buf = [0; 4];
reader.read(&mut buf).unwrap();
assert_eq!(buf, [6, 7, 8, 9]);
reader.seek(SeekFrom::Current(-4)).unwrap();
let mut buf = [0; 4];
reader.read(&mut buf).unwrap();
assert_eq!(buf, [6, 7, 8, 9]);
}
#[test]
fn seek_end() {
let inner = Cursor::new([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
let mut reader = BufReader::with_capacity(2, inner);
reader.seek(SeekFrom::End(-6)).unwrap();
let mut buf = [0; 8];
reader.read(&mut buf).unwrap();
assert_eq!(buf, [11, 12, 13, 14, 15, 16, 0, 0]);
reader.seek(SeekFrom::End(0)).unwrap();
let mut buf = [0; 8];
reader.read(&mut buf).unwrap();
assert_eq!(buf, [0, 0, 0, 0, 0, 0, 0, 0]);
}
#[test]
fn seek_end_std() {
let inner = Cursor::new([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
let mut reader = io::BufReader::with_capacity(2, inner);
reader.seek(SeekFrom::End(-6)).unwrap();
let mut buf = [0; 8];
reader.read(&mut buf).unwrap();
assert_eq!(buf, [11, 12, 13, 14, 15, 16, 0, 0]);
reader.seek(SeekFrom::End(0)).unwrap();
let mut buf = [0; 8];
reader.read(&mut buf).unwrap();
assert_eq!(buf, [0, 0, 0, 0, 0, 0, 0, 0]);
}
#[test]
fn into_inner() {
let inner = Cursor::new([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
let mut reader = BufReader::with_capacity(4, inner);
reader.seek(SeekFrom::Current(5)).unwrap();
let mut buf = [0; 8];
reader.read(&mut buf).unwrap();
assert_eq!(buf, [5, 6, 7, 8, 9, 10, 11, 12]);
reader.seek(SeekFrom::Current(-2)).unwrap();
let mut buf = [0; 2];
reader.read(&mut buf).unwrap();
assert_eq!(buf, [11, 12]);
let mut inner = reader.into_inner().unwrap();
let mut buf = [0; 8];
inner.read(&mut buf).unwrap();
assert_eq!(buf, [13, 14, 15, 16, 0, 0, 0, 0]);
}
}