use std::cmp;
use std::io;
use std::ptr;
pub const DEFAULT_BUFFER_CAPACITY: usize = 8 * (1 << 10);
#[derive(Debug)]
pub struct Buffer {
buf: Vec<u8>,
min: usize,
end: usize,
}
impl Buffer {
pub fn new(min_buffer_len: usize) -> Buffer {
let min = cmp::max(1, min_buffer_len);
let capacity = cmp::max(min * 8, DEFAULT_BUFFER_CAPACITY);
Buffer { buf: vec![0; capacity], min, end: 0 }
}
#[inline]
pub fn min_buffer_len(&self) -> usize {
self.min
}
#[inline]
pub fn buffer(&self) -> &[u8] {
&self.buf[..self.end]
}
#[inline]
pub fn len(&self) -> usize {
self.end
}
fn free_buffer(&mut self) -> &mut [u8] {
&mut self.buf[self.end..]
}
pub fn fill<R: io::Read>(&mut self, mut rdr: R) -> io::Result<bool> {
let mut readany = false;
loop {
let bytes_read = rdr.read(self.free_buffer())?;
if bytes_read == 0 {
return Ok(readany);
}
readany = true;
self.end += bytes_read;
if self.len() >= self.min {
return Ok(true);
}
}
}
pub fn roll(&mut self) {
let roll_start = self
.end
.checked_sub(self.min)
.expect("buffer capacity should be bigger than minimum amount.");
let roll_len = self.min;
assert!(roll_start + roll_len <= self.end);
unsafe {
ptr::copy(
self.buf[roll_start..].as_ptr(),
self.buf.as_mut_ptr(),
roll_len,
);
}
self.end = roll_len;
}
}
#[derive(Debug)]
pub struct BufferRev {
buf: Vec<u8>,
min: usize,
end: usize,
}
impl BufferRev {
pub fn new(min_buffer_len: usize) -> Self {
let min = cmp::max(1, min_buffer_len);
let capacity = cmp::max(min * 8, DEFAULT_BUFFER_CAPACITY);
BufferRev { buf: vec![0; capacity], min, end: 0 }
}
#[inline]
pub fn min_buffer_len(&self) -> usize {
self.min
}
#[inline]
pub fn capacity(&self) -> usize {
self.buf.capacity()
}
#[inline]
pub fn buffer(&self) -> &[u8] {
&self.buf[self.capacity() - self.end..]
}
#[inline]
pub fn len(&self) -> usize {
self.end
}
pub fn free_buffer(&mut self) -> &mut [u8] {
let capacity = self.capacity();
&mut self.buf[..capacity - self.end]
}
pub fn fill_exact<R: io::Read>(
&mut self,
mut rdr: R,
amount: usize,
) -> io::Result<bool> {
let free_buffer_len = self.free_buffer().len();
match rdr
.read_exact(&mut self.free_buffer()[free_buffer_len - amount..])
{
Ok(_) => {
self.end += amount;
Ok(true)
}
Err(e) => match e.kind() {
io::ErrorKind::UnexpectedEof => Ok(false),
_ => Err(e),
},
}
}
pub fn roll_right(&mut self) {
let roll_start = self
.end
.checked_sub(self.min)
.expect("buffer capacity should be bigger than minimum amount.");
let roll_len = self.min;
assert!(roll_start + roll_len <= self.end);
unsafe {
ptr::copy(
self.buffer()[..roll_len].as_ptr(),
self.buf.as_mut_ptr().add(self.capacity() - roll_len),
roll_len,
);
}
self.end = roll_len;
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::io::prelude::*;
use std::io::{Cursor, SeekFrom};
#[test]
fn test_buffer() {
let mut haystack = Cursor::new("0123456789".as_bytes());
let mut buf = Buffer::new(2);
assert_eq!(buf.min_buffer_len(), 2);
while buf.fill(&mut haystack).unwrap() {}
assert_eq!(buf.buffer(), b"0123456789");
assert_eq!(buf.len(), 10);
buf.roll();
assert_eq!(buf.buffer(), "89".as_bytes());
assert_eq!(buf.len(), 2);
}
#[test]
fn test_buffer_rev() {
let mut haystack = Cursor::new("0123456789".as_bytes());
let mut buf = BufferRev::new(2);
assert_eq!(buf.min_buffer_len(), 2);
haystack.seek(SeekFrom::End(-4)).unwrap();
buf.fill_exact(&mut haystack, 4).unwrap();
assert_eq!(buf.buffer(), "6789".as_bytes());
assert_eq!(buf.len(), 4);
buf.roll_right();
assert_eq!(buf.buffer(), "67".as_bytes());
assert_eq!(buf.len(), 2);
haystack.seek(SeekFrom::End(-10)).unwrap();
buf.fill_exact(&mut haystack, 6).unwrap();
assert_eq!(buf.buffer(), "01234567".as_bytes());
assert_eq!(buf.len(), 8);
}
}