#![cfg_attr(feature = "read_initializer", feature(read_initializer))]
use io_helpers::{append_to_string, read_until};
use std::io::prelude::*;
use std::fmt;
use std::io::{self, IoSliceMut, SeekFrom};
#[cfg(feature = "read_initializer")]
use std::io::Initializer;
mod io_helpers;
#[cfg(test)]
mod tests;
const DEFAULT_BUF_SIZE: usize = if cfg!(target_os = "espidf") {
512
} else {
8 * 1024
};
pub struct RevBufReader<R> {
inner: R,
buf: Box<[u8]>,
pos: usize,
cap: usize,
}
impl<R: Read + Seek> RevBufReader<R> {
pub fn new(inner: R) -> RevBufReader<R> {
RevBufReader::with_capacity(DEFAULT_BUF_SIZE, inner)
}
pub fn with_capacity(capacity: usize, mut inner: R) -> RevBufReader<R> {
unsafe {
let mut buffer = Vec::with_capacity(capacity);
buffer.set_len(capacity);
#[cfg(feature = "read_initializer")]
inner.initializer().initialize(&mut buffer);
inner
.seek(SeekFrom::End(0))
.expect("Cannot find the end of the stream.");
RevBufReader {
inner,
buf: buffer.into_boxed_slice(),
pos: 0,
cap: 0,
}
}
}
#[inline]
fn checked_seek_back(&mut self, length: usize) -> io::Result<usize> {
let offset = (self.cap + length) as i64;
let checked_length = match self.inner.seek(SeekFrom::Current(-offset)) {
Ok(_) => length,
Err(error) => {
let position = self.inner.seek(SeekFrom::Current(0))? as usize;
if position > offset as usize {
return Err(error);
}
self.inner.seek(SeekFrom::Start(0))?;
position.saturating_sub(self.cap)
}
};
self.cap = 0;
Ok(checked_length)
}
}
impl<R> RevBufReader<R> {
pub fn get_ref(&self) -> &R {
&self.inner
}
pub fn get_mut(&mut self) -> &mut R {
&mut self.inner
}
pub fn buffer(&self) -> &[u8] {
&self.buf[0..self.pos]
}
pub fn capacity(&self) -> usize {
self.buf.len()
}
pub fn into_inner(self) -> R {
self.inner
}
#[inline]
fn discard_buffer(&mut self) {
self.pos = 0;
self.cap = 0;
}
}
impl<R: Seek> RevBufReader<R> {
pub fn seek_relative(&mut self, offset: i64) -> io::Result<()> {
let pos = self.pos as u64;
if offset < 0 {
if let Some(new_pos) = pos.checked_sub((-offset) as u64) {
self.pos = new_pos as usize;
return Ok(());
}
} else if let Some(new_pos) = pos.checked_add(offset as u64) {
if new_pos <= self.cap as u64 {
self.pos = new_pos as usize;
return Ok(());
}
}
self.seek(SeekFrom::Current(offset)).map(drop)
}
}
impl<R: Read + Seek> Read for RevBufReader<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
if self.pos == 0 && buf.len() >= self.buf.len() {
let length = self.checked_seek_back(buf.len())?;
self.inner.read_exact(&mut buf[..length])?;
self.inner.seek(SeekFrom::Current(-(length as i64)))?;
return Ok(length);
}
let nread = {
let rem = self.fill_buf()?;
let offset = rem.len().saturating_sub(buf.len());
let mut rem = &rem[offset..];
rem.read(buf)?
};
self.consume(nread);
Ok(nread)
}
#[allow(clippy::unused_io_amount)]
fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
let total_len = bufs.iter().map(|b| b.len()).sum::<usize>();
if self.pos == self.cap && total_len >= self.buf.len() {
let length = self.checked_seek_back(total_len)?;
self.inner.read_vectored(bufs)?;
self.inner.seek(SeekFrom::Current(-(length as i64)))?;
return Ok(length);
}
let nread = {
let rem = self.fill_buf()?;
let offset = rem.len().saturating_sub(total_len);
let mut rem = &rem[offset..];
rem.read_vectored(bufs)?
};
self.consume(nread);
Ok(nread)
}
#[cfg(feature = "read_initializer")]
unsafe fn initializer(&self) -> Initializer {
self.inner.initializer()
}
}
impl<R: Read + Seek> BufRead for RevBufReader<R> {
fn fill_buf(&mut self) -> io::Result<&[u8]> {
if self.pos == 0 {
let length = self.checked_seek_back(self.buf.len())?;
self.inner.read_exact(&mut self.buf[..length])?;
self.cap = length;
self.pos = self.cap;
}
Ok(&self.buf[0..self.pos])
}
fn consume(&mut self, amt: usize) {
self.pos = self.pos.saturating_sub(amt);
}
fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> io::Result<usize> {
read_until(self, byte, buf)
}
fn read_line(&mut self, buf: &mut String) -> io::Result<usize> {
unsafe { append_to_string(buf, |b| read_until(self, b'\n', b)) }
}
}
impl<R> fmt::Debug for RevBufReader<R>
where
R: fmt::Debug,
{
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_struct("RevBufReader")
.field("reader", &self.inner)
.field("buffer", &format_args!("{}/{}", self.pos, self.buf.len()))
.finish()
}
}
impl<R: Seek> Seek for RevBufReader<R> {
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
let result: u64;
if let SeekFrom::Current(n) = pos {
let remainder = (self.cap - self.pos) as i64;
if let Some(offset) = n.checked_sub(remainder) {
result = self.inner.seek(SeekFrom::Current(offset))?;
} else {
self.inner.seek(SeekFrom::Current(-remainder))?;
self.discard_buffer();
result = self.inner.seek(SeekFrom::Current(n))?;
}
} else {
result = self.inner.seek(pos)?;
}
self.discard_buffer();
Ok(result)
}
}