use std::io::Read;
pub trait ThBufRead {
fn get_buf(&self) -> &[u8];
fn fill_buf(&mut self) -> std::io::Result<usize>;
fn consume(&mut self, amount: usize);
}
pub struct ThBufReader<R> {
inner: R,
buf: Vec<u8>,
pos: usize,
cap: usize,
}
impl<R: Read> ThBufReader<R> {
pub fn new(inner: R) -> ThBufReader<R> {
ThBufReader {
inner,
buf: vec![0; 4096],
pos: 0,
cap: 0,
}
}
pub fn reuse(mut self, inner: R) -> Self {
self.inner = inner;
self.pos = 0;
self.cap = 0;
self
}
}
impl<R: Read> ThBufRead for ThBufReader<R> {
fn get_buf(&self) -> &[u8] {
&self.buf[self.pos..self.cap]
}
fn fill_buf(&mut self) -> std::io::Result<usize> {
let resize = if self.buf.len() / 2 < self.pos && self.buf.len() < self.cap + 8196 {
if self.pos < self.cap {
self.buf.copy_within(self.pos..self.cap, 0);
self.cap -= self.pos;
self.pos = 0;
}
true
} else {
false
};
if self.pos >= self.cap {
debug_assert!(self.pos == self.cap);
self.cap = 0;
self.pos = 0;
}
if (resize && self.buf.capacity() < 67108864) || self.buf.len() < self.cap + 8196 {
self.buf.resize(self.buf.capacity() * 2, 0);
}
let num_read = self.inner.read(&mut self.buf[self.cap..])?;
self.cap += num_read;
Ok(num_read)
}
fn consume(&mut self, amount: usize) {
self.pos = std::cmp::min(self.pos + amount, self.cap);
}
}
impl ThBufRead for &[u8] {
fn get_buf(&self) -> &[u8] {
self
}
fn fill_buf(&mut self) -> std::io::Result<usize> {
Ok(0)
}
fn consume(&mut self, amount: usize) {
*self = &self[amount..];
}
}