use std::cmp;
use std::io::{self, Read};
use std::ptr;
pub const DEFAULT_CHUNK_SIZE: usize = 8192;
pub struct ExpandingBufReader<R>
where
R: Read,
{
inner: R,
buff: Vec<u8>, pos: usize, mark: usize, chunk_size: usize, }
impl<R> ExpandingBufReader<R>
where
R: Read,
{
pub fn new(reader: R) -> ExpandingBufReader<R> {
ExpandingBufReader::with_chunk_size(reader, DEFAULT_CHUNK_SIZE)
}
pub fn with_chunk_size(reader: R, chunk_size: usize) -> ExpandingBufReader<R> {
ExpandingBufReader {
inner: reader,
buff: Vec::new(),
mark: 0,
pos: 0,
chunk_size,
}
}
fn fill(&mut self) -> io::Result<()> {
debug_assert!(self.pos == self.buff.len());
if self.mark > 0 {
let protected = self.pos - self.mark;
if protected == 0 {
self.buff.clear();
self.mark = 0;
self.pos = 0;
} else {
unsafe {
ptr::copy(self.buff[self.mark..].as_ptr(), self.buff[0..].as_mut_ptr(), protected);
self.buff.set_len(protected);
}
self.pos = protected;
self.mark = 0;
}
}
if self.pos >= self.buff.capacity() {
self.buff.reserve(self.chunk_size);
}
unsafe {
let len = self.buff.len();
self.buff.set_len(self.buff.capacity());
let n = self.inner.read(&mut self.buff[self.pos..])?;
self.buff.set_len(len + n);
if n == 0 {
return Err(io::ErrorKind::UnexpectedEof.into());
}
}
Ok(())
}
fn advance(&mut self) {
self.mark = self.pos;
}
fn next(&mut self) -> io::Result<u8> {
if self.pos >= self.buff.len() {
self.fill()?;
}
let b = self.buff[self.pos];
self.pos += 1;
Ok(b)
}
#[inline]
fn slice_off(&mut self, skip: usize) -> &[u8] {
let start = self.mark;
self.advance();
&self.buff[start..self.pos - skip]
}
pub fn read_line(&mut self) -> io::Result<&[u8]> {
self.advance();
loop {
let next = self.next()?;
if next == b'\n' {
return Ok(self.slice_off(1));
}
if next == b'\r' && self.next()? == b'\n' {
return Ok(self.slice_off(2));
}
}
}
}
impl<R> Read for ExpandingBufReader<R>
where
R: Read,
{
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let remaining = self.buff.len() - self.mark;
if remaining > 0 {
let amount = cmp::min(remaining, buf.len());
unsafe {
ptr::copy_nonoverlapping(self.buff[self.mark..].as_ptr(), buf.as_mut_ptr(), amount);
}
self.mark = self.mark + amount;
self.pos = self.mark;
Ok(amount)
} else {
let n = self.inner.read(buf)?;
self.pos = self.buff.len();
self.mark = self.buff.len();
Ok(n)
}
}
}
pub fn trim_byte(byte: u8, buf: &[u8]) -> &[u8] {
trim_byte_left(byte, trim_byte_right(byte, buf))
}
pub fn trim_byte_left(byte: u8, mut buf: &[u8]) -> &[u8] {
while let Some(b) = buf.first().map(|&b| b) {
if b == byte {
unsafe {
buf = &buf.get_unchecked(1..);
}
} else {
break;
}
}
buf
}
pub fn trim_byte_right(byte: u8, mut buf: &[u8]) -> &[u8] {
while let Some(b) = buf.last().map(|&b| b) {
if b == byte {
unsafe {
buf = &buf.get_unchecked(..buf.len() - 1);
}
} else {
break;
}
}
buf
}
#[test]
fn test_fill_grow() {
let mut reader = ExpandingBufReader::new(&b"hello"[..]);
assert_eq!(reader.next().unwrap(), b'h');
assert_eq!(reader.buff.capacity(), DEFAULT_CHUNK_SIZE);
assert_eq!(reader.buff.len(), 5);
assert_eq!(reader.mark, 0);
assert_eq!(reader.pos, 1);
}
#[test]
fn test_fill_grow_copy() {
let mut reader = ExpandingBufReader::with_chunk_size(&b"hello"[..], 1);
assert_eq!(reader.next().unwrap(), b'h');
reader.advance();
assert_eq!(reader.mark, 1);
assert_eq!(reader.next().unwrap(), b'e');
assert_eq!(reader.mark, 0);
assert_eq!(reader.pos, 1);
assert_eq!(reader.buff.len(), 1);
assert_eq!(reader.next().unwrap(), b'l');
assert_eq!(reader.mark, 0);
assert_eq!(reader.pos, 2);
assert_eq!(reader.buff.len(), 2);
}
#[test]
fn test_advance() {
let mut reader = ExpandingBufReader::new(&b"hello"[..]);
assert_eq!(reader.next().unwrap(), b'h');
assert_eq!(reader.next().unwrap(), b'e');
assert_eq!(reader.mark, 0);
assert_eq!(reader.pos, 2);
reader.advance();
assert_eq!(reader.mark, 2);
assert_eq!(reader.pos, 2);
}
#[test]
fn test_read_line_lf() {
let mut reader = ExpandingBufReader::new(&b"hello\n"[..]);
assert_eq!(reader.read_line().unwrap(), b"hello");
assert_eq!(reader.pos, 6);
}
#[test]
fn test_read_line_crlf() {
let mut reader = ExpandingBufReader::new(&b"hello\r\n"[..]);
assert_eq!(reader.read_line().unwrap(), b"hello");
assert_eq!(reader.pos, 7);
}
#[test]
fn test_read_line_eof() {
let mut reader = ExpandingBufReader::new(&b"hello"[..]);
assert!(reader.read_line().is_err());
}
#[test]
fn test_read_line_small_chunks() {
let mut reader = ExpandingBufReader::with_chunk_size(&b"hello world!\r\n"[..], 2);
let line = reader.read_line().unwrap();
assert_eq!(line, b"hello world!");
assert_eq!(reader.buff.len(), 14);
assert_eq!(reader.pos, 14);
assert_eq!(reader.mark, 14);
}
#[test]
fn test_read_line_marks_start() {
let mut reader = ExpandingBufReader::with_chunk_size(&b"abcdline1\r\n"[..], 10);
reader.next().unwrap();
reader.next().unwrap();
reader.next().unwrap();
reader.next().unwrap();
assert_eq!(reader.read_line().unwrap(), b"line1");
assert_eq!(reader.buff.len(), 7);
assert_eq!(reader.buff.capacity(), 10); }
#[test]
fn test_read() {
let mut reader = ExpandingBufReader::with_chunk_size(&b"hello"[..], 2);
reader.next().unwrap();
reader.advance();
let mut buf = [0u8; 1024];
let n = reader.read(&mut buf).unwrap();
assert_eq!(n, 1);
assert_eq!(&buf[..n], b"e");
let n = reader.read(&mut buf[..2]).unwrap();
assert_eq!(n, 2);
assert_eq!(&buf[..n], b"ll");
assert_eq!(reader.next().unwrap(), b'o');
assert_eq!(reader.buff, b"o");
}
#[test]
fn test_slice_off() {
let mut reader = ExpandingBufReader::new(&b"hello"[..]);
reader.next().unwrap();
reader.next().unwrap();
reader.next().unwrap();
assert_eq!(reader.slice_off(1), b"he");
}
#[test]
fn test_trim_byte() {
assert_eq!(trim_byte(b' ', b" hello "), b"hello");
assert_eq!(trim_byte(b' ', b"hello"), b"hello");
assert_eq!(trim_byte(b' ', b""), b"");
}
#[test]
fn test_trim_byte_left() {
assert_eq!(trim_byte_left(b' ', b" hello"), b"hello");
assert_eq!(trim_byte_left(b' ', b"hello"), b"hello");
assert_eq!(trim_byte_left(b' ', b""), b"");
}
#[test]
fn test_trim_byte_right() {
assert_eq!(trim_byte_right(b' ', b"hello "), b"hello");
assert_eq!(trim_byte_right(b' ', b"hello"), b"hello");
assert_eq!(trim_byte_right(b' ', b""), b"");
}