use std::{cmp::min, io, ptr};
pub trait AsBuffer {
fn as_buffer(&self) -> &[u8];
fn as_mut_buffer(&mut self) -> &mut [u8];
}
pub struct Buffer<T: AsBuffer> {
pub start: usize,
pub head: usize,
pub end: usize,
pub buffer: T,
}
impl<T: AsBuffer + Clone> Clone for Buffer<T> {
fn clone(&self) -> Self {
Self {
start: self.start,
head: self.head,
end: self.end,
buffer: self.buffer.clone(),
}
}
}
impl<T: AsBuffer> Buffer<T> {
pub fn new(buffer: T) -> Self {
Self {
start: 0,
head: 0,
end: 0,
buffer,
}
}
pub fn meter(&self, half: usize) -> String {
let size = half * 2 + 1;
let len = self.capacity();
(0..size + 2)
.map(|i| {
if i == 0 {
'['
} else if i - 1 == half {
':'
} else if i - 1 < (self.start * size / len) {
' '
} else if i - 1 < (self.head * size / len) {
'█'
} else if i - 1 < (self.end * size / len) {
'░'
} else if i - 1 < size {
' '
} else {
']'
}
})
.collect()
}
pub fn available_data(&self) -> usize {
self.end - self.start
}
pub fn available_space(&self) -> usize {
self.capacity() - self.end
}
pub fn capacity(&self) -> usize {
self.buffer().len()
}
pub fn is_empty(&self) -> bool {
self.start == self.end
}
pub fn is_full(&self) -> bool {
self.end == self.capacity()
}
pub fn fill(&mut self, count: usize) -> usize {
let count = min(count, self.available_space());
self.end += count;
count
}
pub fn consume(&mut self, count: usize) -> usize {
let count = min(count, self.available_data());
self.start += count;
count
}
pub fn clear(&mut self) {
self.start = 0;
self.head = 0;
self.end = 0;
}
pub fn buffer(&self) -> &[u8] {
self.buffer.as_buffer()
}
pub fn mut_buffer(&mut self) -> &mut [u8] {
self.buffer.as_mut_buffer()
}
pub fn data(&self) -> &[u8] {
let range = self.start..self.end;
&self.buffer()[range]
}
pub fn unparsed_data(&self) -> &[u8] {
let range = self.head..self.end;
&self.buffer()[range]
}
pub fn space(&mut self) -> &mut [u8] {
let range = self.end..self.capacity();
&mut self.mut_buffer()[range]
}
pub fn used(&self) -> &[u8] {
let range = ..self.end;
&self.buffer()[range]
}
pub fn should_shift(&self) -> bool {
self.start > self.capacity() / 2 || (self.start > 0 && self.is_empty())
}
pub fn shift(&mut self) -> usize {
let start = self.start;
let end = self.end;
if start > 0 {
unsafe {
let len = end - start;
ptr::copy(
self.buffer()[start..end].as_ptr(),
self.mut_buffer()[..len].as_mut_ptr(),
len,
);
self.start = 0;
self.head -= start;
self.end = len;
}
}
start
}
}
impl<T: AsBuffer> io::Write for Buffer<T> {
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<T: AsBuffer> io::Read for Buffer<T> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let len = min(self.available_data(), buf.len());
unsafe {
ptr::copy(
self.buffer()[self.start..self.start + len].as_ptr(),
buf.as_mut_ptr(),
len,
);
self.start += len;
}
Ok(len)
}
}