use std::io::{Read, self, ErrorKind};
pub struct DynReadBuffer<R: Read> {
buffer: Vec<u8>,
reader: R,
filled_buffer_start: usize,
filled_buffer_length: usize,
}
impl<R: Read> DynReadBuffer<R> {
pub fn new(reader: R) -> Self {
Self {
buffer: Vec::new(),
reader,
filled_buffer_start: 0,
filled_buffer_length: 0,
}
}
pub fn with_capacity(reader: R, capacity: usize) -> Self {
Self {
buffer: vec![0; capacity],
reader,
filled_buffer_start: 0,
filled_buffer_length: 0,
}
}
pub fn read_bytes(&mut self, amount: usize) -> Result<&[u8], io::Error> {
if amount > self.filled_buffer_length {
let amount_to_fill = amount - self.filled_buffer_length;
self.reserve(amount_to_fill);
let start = self.filled_buffer_end();
let end = start + amount_to_fill;
let buffer_to_fill = &mut self.buffer[start..end];
self.reader.read_exact(buffer_to_fill)?;
self.filled_buffer_length += amount_to_fill;
}
let start = self.filled_buffer_start;
let end = start + amount;
let result = &self.buffer[start..end];
self.filled_buffer_start += amount;
self.filled_buffer_length -= amount;
Ok(result)
}
pub fn read_until(&mut self, delimiter: u8) -> Result<&[u8], io::Error> {
if self.filled_buffer_length > 0 {
let filled_buffer = &self.buffer[
self.filled_buffer_start..self.filled_buffer_end()
];
let delimiter_position = filled_buffer.iter()
.position(|byte| *byte == delimiter);
if let Some(relative_position) = delimiter_position {
let absolute_position = self.filled_buffer_start
+ relative_position;
let result = &self.buffer[self.filled_buffer_start..=absolute_position];
self.filled_buffer_start = absolute_position + 1;
self.filled_buffer_length -= result.len();
return Ok(result);
}
}
loop {
self.reserve(32);
let filled_buffer_end = self.filled_buffer_end();
let available_buffer = &mut self.buffer[filled_buffer_end..];
let amount_read = match self.reader.read(available_buffer) {
Ok(n) => n,
Err(err) if err.kind() == ErrorKind::Interrupted => continue,
Err(err) => return Err(err),
};
if amount_read == 0 {
return Err(ErrorKind::UnexpectedEof.into());
}
self.filled_buffer_length += amount_read;
let read_data = &available_buffer[..amount_read];
let delimiter_position = read_data.iter()
.position(|byte| *byte == delimiter);
if let Some(relative_position) = delimiter_position {
let absolute_position = self.filled_buffer_end()
- amount_read
+ relative_position;
let result = &self.buffer[self.filled_buffer_start..=absolute_position];
self.filled_buffer_start = absolute_position + 1;
self.filled_buffer_length -= result.len();
return Ok(result);
}
}
}
fn reserve(&mut self, amount: usize) {
let filled_buffer_end = self.filled_buffer_start + self.filled_buffer_length;
if self.buffer.len() >= filled_buffer_end + amount {
return;
}
if self.filled_buffer_start >= amount {
self.buffer.rotate_left(self.filled_buffer_start);
self.filled_buffer_start = 0;
return;
}
self.buffer.resize(self.filled_buffer_end() + amount, 0);
}
fn filled_buffer_end(&self) -> usize {
self.filled_buffer_start + self.filled_buffer_length
}
}