#![deny(missing_debug_implementations)]
extern crate bytes;
use std::error;
use std::fmt;
use std::io::{Cursor, Read, Result as IoResult};
use bytes::{Buf, BufMut};
#[derive(Debug)]
pub struct InputBuffer(Cursor<Vec<u8>>);
pub const MIN_READ: usize = 4096;
impl InputBuffer {
pub fn new() -> Self {
Self::with_capacity(MIN_READ)
}
pub fn with_capacity(capacity: usize) -> Self {
Self::from_partially_read(Vec::with_capacity(capacity))
}
pub fn from_partially_read(part: Vec<u8>) -> Self {
InputBuffer(Cursor::new(part))
}
pub fn as_cursor(&self) -> &Cursor<Vec<u8>> {
&self.0
}
pub fn as_cursor_mut(&mut self) -> &mut Cursor<Vec<u8>> {
&mut self.0
}
pub fn remove_garbage(&mut self) {
let pos = self.0.position() as usize;
self.0.get_mut().drain(0..pos).count();
self.0.set_position(0);
}
pub fn into_vec(mut self) -> Vec<u8> {
self.remove_garbage();
self.0.into_inner()
}
pub fn read_from<S: Read>(&mut self, stream: &mut S) -> IoResult<usize> {
self.prepare().read_from(stream)
}
pub fn prepare<'t>(&'t mut self) -> DoRead<'t> {
self.prepare_reserve(MIN_READ)
}
pub fn prepare_reserve<'t>(&'t mut self, reserve: usize) -> DoRead<'t> {
let free_space = self.total_len() - self.filled_len();
let total_space = free_space + self.consumed_len();
let remove_garbage = free_space < reserve && total_space >= reserve;
DoRead {
buf: self,
remove_garbage,
reserve,
}
}
}
impl InputBuffer {
fn total_len(&self) -> usize {
self.0.get_ref().capacity()
}
fn filled_len(&self) -> usize {
self.0.get_ref().len()
}
fn consumed_len(&self) -> usize {
self.0.position() as usize
}
}
impl Buf for InputBuffer {
fn remaining(&self) -> usize {
Buf::remaining(self.as_cursor())
}
fn chunk(&self) -> &[u8] {
Buf::chunk(self.as_cursor())
}
fn advance(&mut self, size: usize) {
Buf::advance(self.as_cursor_mut(), size)
}
}
#[derive(Debug)]
pub struct DoRead<'t> {
buf: &'t mut InputBuffer,
remove_garbage: bool,
reserve: usize,
}
impl<'t> DoRead<'t> {
pub fn with_limit(mut self, limit: usize) -> Result<Self, SizeLimit> {
let total_len = self.buf.filled_len() + self.reserve;
let consumed_len = self.buf.consumed_len();
if total_len - consumed_len <= limit {
if total_len > limit {
self.remove_garbage = true;
}
Ok(self)
} else {
Err(SizeLimit)
}
}
pub fn read_from<S: Read>(self, stream: &mut S) -> IoResult<usize> {
if self.remove_garbage {
self.buf.remove_garbage();
}
let v: &mut Vec<u8> = self.buf.0.get_mut();
v.reserve(self.reserve);
assert!(v.capacity() > v.len());
let size = unsafe {
let data = &mut v.chunk_mut()[..self.reserve];
{
let memory_to_zero = data.as_mut_ptr();
for i in 0..data.len() {
memory_to_zero.add(i).write(0);
}
}
let data = std::slice::from_raw_parts_mut(data.as_mut_ptr() as *mut u8, data.len());
let size = stream.read(data)?;
v.advance_mut(size);
size
};
Ok(size)
}
}
#[derive(Debug, Clone, Copy)]
pub struct SizeLimit;
impl fmt::Display for SizeLimit {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "SizeLimit")
}
}
impl error::Error for SizeLimit {
fn description(&self) -> &'static str {
"Size limit exceeded"
}
}
#[cfg(test)]
mod tests {
use super::InputBuffer;
use bytes::Buf;
use std::io::Cursor;
#[test]
fn simple_reading() {
let mut inp = Cursor::new(b"Hello World!".to_vec());
let mut buf = InputBuffer::new();
let size = buf.read_from(&mut inp).unwrap();
assert_eq!(size, 12);
assert_eq!(buf.chunk(), b"Hello World!");
}
#[test]
fn partial_reading() {
let mut inp = Cursor::new(b"Hello World!".to_vec());
let mut buf = InputBuffer::with_capacity(4);
let size = buf.prepare_reserve(4).read_from(&mut inp).unwrap();
assert_eq!(size, 4);
assert_eq!(buf.chunk(), b"Hell");
buf.advance(2);
assert_eq!(buf.chunk(), b"ll");
let size = buf.prepare_reserve(1).read_from(&mut inp).unwrap();
assert_eq!(size, 1);
assert_eq!(buf.chunk(), b"llo");
let size = buf.prepare_reserve(4).read_from(&mut inp).unwrap();
assert_eq!(size, 4);
assert_eq!(buf.chunk(), b"llo Wor");
let size = buf.prepare_reserve(16).read_from(&mut inp).unwrap();
assert_eq!(size, 3);
assert_eq!(buf.chunk(), b"llo World!");
}
#[test]
fn limiting() {
let mut inp = Cursor::new(b"Hello World!".to_vec());
let mut buf = InputBuffer::with_capacity(4);
let size = buf
.prepare_reserve(4)
.with_limit(5)
.unwrap()
.read_from(&mut inp)
.unwrap();
assert_eq!(size, 4);
assert_eq!(buf.chunk(), b"Hell");
buf.advance(2);
assert_eq!(buf.chunk(), b"ll");
{
let e = buf.prepare_reserve(4).with_limit(5);
assert!(e.is_err());
}
buf.advance(1);
let size = buf
.prepare_reserve(4)
.with_limit(5)
.unwrap()
.read_from(&mut inp)
.unwrap();
assert_eq!(size, 4);
assert_eq!(buf.chunk(), b"lo Wo");
}
}