use std::{
cmp,
io::{self, Read, Write},
};
#[derive(Debug, PartialEq, Clone)]
pub struct Buffer {
memory: Vec<u8>,
capacity: usize,
position: usize,
end: usize,
}
impl Buffer {
pub fn with_capacity(capacity: usize) -> Buffer {
Buffer {
memory: vec![0u8; capacity],
capacity,
position: 0,
end: 0,
}
}
pub fn from_slice(data: &[u8]) -> Buffer {
Buffer {
memory: Vec::from(data),
capacity: data.len(),
position: 0,
end: data.len(),
}
}
pub fn grow(&mut self, new_size: usize) -> bool {
if self.capacity >= new_size {
return false;
}
self.memory.resize(new_size, 0);
self.capacity = new_size;
true
}
#[inline]
pub fn available_data(&self) -> usize {
self.end - self.position
}
#[inline]
pub fn available_space(&self) -> usize {
self.capacity - self.end
}
#[inline]
pub fn capacity(&self) -> usize {
self.capacity
}
#[inline]
pub fn empty(&self) -> bool {
self.position == self.end
}
#[inline]
pub fn consume(&mut self, count: usize) -> usize {
let cnt = cmp::min(count, self.available_data());
self.position += cnt;
if self.position > self.capacity / 2 {
self.shift();
}
cnt
}
#[inline]
pub fn consume_noshift(&mut self, count: usize) -> usize {
let cnt = cmp::min(count, self.available_data());
self.position += cnt;
cnt
}
#[inline]
pub fn fill(&mut self, count: usize) -> usize {
let cnt = cmp::min(count, self.available_space());
self.end += cnt;
if self.available_space() < self.available_data() + cnt {
self.shift();
}
cnt
}
#[inline]
pub fn position(&self) -> usize {
self.position
}
#[inline]
pub fn reset(&mut self) {
self.position = 0;
self.end = 0;
}
#[inline]
pub fn data(&self) -> &[u8] {
&self.memory[self.position..self.end]
}
#[inline]
pub fn space(&mut self) -> &mut [u8] {
&mut self.memory[self.end..self.capacity]
}
#[inline]
pub fn shift(&mut self) {
if self.position > 0 {
let length = self.end - self.position;
self.memory.copy_within(self.position..self.end, 0);
self.position = 0;
self.end = length;
}
}
}
impl Write for Buffer {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
match self.space().write(buf) {
Ok(size) => {
self.fill(size);
Ok(size)
}
err => err,
}
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
impl Read for Buffer {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let len = cmp::min(self.available_data(), buf.len());
buf[0..len].copy_from_slice(&self.memory[self.position..self.position + len]);
self.position += len;
Ok(len)
}
}
#[cfg(feature = "bytes")]
impl bytes::Buf for Buffer {
#[inline]
fn remaining(&self) -> usize {
self.available_data()
}
#[inline]
fn chunk(&self) -> &[u8] {
self.data()
}
#[inline]
fn advance(&mut self, cnt: usize) {
self.consume(cnt);
}
}
#[cfg(feature = "bytes")]
unsafe impl bytes::BufMut for Buffer {
#[inline]
fn remaining_mut(&self) -> usize {
self.available_space()
}
#[inline]
unsafe fn advance_mut(&mut self, cnt: usize) {
self.fill(cnt);
}
#[inline]
fn chunk_mut(&mut self) -> &mut bytes::buf::UninitSlice {
unsafe { &mut *(self.space() as *mut [u8] as *mut _) }
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::io::Write;
#[test]
fn fill_and_consume() {
let mut b = Buffer::with_capacity(10);
assert_eq!(b.available_data(), 0);
assert_eq!(b.available_space(), 10);
let res = b.write(&b"abcd"[..]);
assert_eq!(res.ok(), Some(4));
assert_eq!(b.available_data(), 4);
assert_eq!(b.available_space(), 6);
assert_eq!(b.data(), &b"abcd"[..]);
b.consume(2);
assert_eq!(b.available_data(), 2);
assert_eq!(b.available_space(), 6);
assert_eq!(b.data(), &b"cd"[..]);
b.shift();
assert_eq!(b.available_data(), 2);
assert_eq!(b.available_space(), 8);
assert_eq!(b.data(), &b"cd"[..]);
assert_eq!(b.write(&b"efghijklmnop"[..]).ok(), Some(8));
assert_eq!(b.available_data(), 10);
assert_eq!(b.available_space(), 0);
assert_eq!(b.data(), &b"cdefghijkl"[..]);
b.shift();
assert_eq!(b.available_data(), 10);
assert_eq!(b.available_space(), 0);
assert_eq!(b.data(), &b"cdefghijkl"[..]);
}
#[test]
fn set_position() {
let mut output = [0; 5];
let mut b = Buffer::with_capacity(10);
let _ = b.write(&b"abcdefgh"[..]);
let _ = b.read(&mut output);
assert_eq!(b.available_data(), 3);
println!("{:?}", b.position());
}
#[test]
fn consume_without_shift() {
let mut b = Buffer::with_capacity(10);
let _ = b.write(&b"abcdefgh"[..]);
b.consume_noshift(6);
assert_eq!(b.position(), 6);
}
}