use std::cmp;
use std::io;
use super::{FiniteStream, ReadBytes};
#[inline(always)]
fn underrun_error<T>() -> io::Result<T> {
Err(io::Error::new(io::ErrorKind::UnexpectedEof, "buffer underrun"))
}
pub struct BufReader<'a> {
buf: &'a [u8],
pos: usize,
}
impl<'a> BufReader<'a> {
pub fn new(buf: &'a [u8]) -> Self {
BufReader { buf, pos: 0 }
}
#[inline(always)]
pub fn scan_bytes_ref(&mut self, pattern: &[u8], scan_len: usize) -> io::Result<&'a [u8]> {
self.scan_bytes_aligned_ref(pattern, 1, scan_len)
}
pub fn scan_bytes_aligned_ref(
&mut self,
pattern: &[u8],
align: usize,
scan_len: usize,
) -> io::Result<&'a [u8]> {
debug_assert!(!pattern.is_empty());
let start = self.pos;
let remaining = self.buf.len() - start;
let end = start + cmp::min(remaining, scan_len);
if remaining < pattern.len() || scan_len < pattern.len() {
return Ok(&self.buf[start..end]);
}
let mut j = start;
let mut i = start + pattern.len();
while i < end {
if &self.buf[j..i] == pattern {
break;
}
i += align;
j += align;
}
self.pos = cmp::min(i, self.buf.len());
Ok(&self.buf[start..self.pos])
}
pub fn read_buf_bytes_ref(&mut self, len: usize) -> io::Result<&'a [u8]> {
if self.pos + len > self.buf.len() {
return underrun_error();
}
self.pos += len;
Ok(&self.buf[self.pos - len..self.pos])
}
pub fn read_buf_bytes_available_ref(&mut self) -> &'a [u8] {
let pos = self.pos;
self.pos = self.buf.len();
&self.buf[pos..]
}
}
impl<'a> ReadBytes for BufReader<'a> {
#[inline(always)]
fn read_byte(&mut self) -> io::Result<u8> {
if self.buf.len() - self.pos < 1 {
return underrun_error();
}
self.pos += 1;
Ok(self.buf[self.pos - 1])
}
#[inline(always)]
fn read_double_bytes(&mut self) -> io::Result<[u8; 2]> {
if self.buf.len() - self.pos < 2 {
return underrun_error();
}
let mut bytes: [u8; 2] = [0u8; 2];
bytes.copy_from_slice(&self.buf[self.pos..self.pos + 2]);
self.pos += 2;
Ok(bytes)
}
#[inline(always)]
fn read_triple_bytes(&mut self) -> io::Result<[u8; 3]> {
if self.buf.len() - self.pos < 3 {
return underrun_error();
}
let mut bytes: [u8; 3] = [0u8; 3];
bytes.copy_from_slice(&self.buf[self.pos..self.pos + 3]);
self.pos += 3;
Ok(bytes)
}
#[inline(always)]
fn read_quad_bytes(&mut self) -> io::Result<[u8; 4]> {
if self.buf.len() - self.pos < 4 {
return underrun_error();
}
let mut bytes: [u8; 4] = [0u8; 4];
bytes.copy_from_slice(&self.buf[self.pos..self.pos + 4]);
self.pos += 4;
Ok(bytes)
}
fn read_buf(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let len = cmp::min(self.buf.len() - self.pos, buf.len());
buf[..len].copy_from_slice(&self.buf[self.pos..self.pos + len]);
self.pos += len;
Ok(len)
}
fn read_buf_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
let len = buf.len();
if self.buf.len() - self.pos < len {
return underrun_error();
}
buf.copy_from_slice(&self.buf[self.pos..self.pos + len]);
self.pos += len;
Ok(())
}
fn scan_bytes_aligned<'b>(
&mut self,
pattern: &[u8],
align: usize,
buf: &'b mut [u8],
) -> io::Result<&'b mut [u8]> {
let scanned = self.scan_bytes_aligned_ref(pattern, align, buf.len())?;
buf[..scanned.len()].copy_from_slice(scanned);
Ok(&mut buf[..scanned.len()])
}
fn ignore_bytes(&mut self, count: u64) -> io::Result<()> {
if self.buf.len() - self.pos < count as usize {
return underrun_error();
}
self.pos += count as usize;
Ok(())
}
#[inline(always)]
fn pos(&self) -> u64 {
self.pos as u64
}
}
impl<'a> FiniteStream for BufReader<'a> {
#[inline(always)]
fn byte_len(&self) -> u64 {
self.buf.len() as u64
}
#[inline(always)]
fn bytes_read(&self) -> u64 {
self.pos as u64
}
#[inline(always)]
fn bytes_available(&self) -> u64 {
(self.buf.len() - self.pos) as u64
}
}