use std::fmt;
use std::io::{self, SeekFrom};
#[derive(Clone, Copy)]
struct ReaderFnTable<R> {
skip_distance: fn(&mut Reader<R>, u64) -> io::Result<()>,
}
impl<R: io::Read> ReaderFnTable<R> {
#[inline]
#[must_use]
fn new_for_plain() -> Self {
Self {
skip_distance: Self::skip_distance_plain,
}
}
#[inline]
#[must_use]
fn new_for_seekable() -> Self
where
R: io::Seek,
{
Self {
skip_distance: Self::skip_distance_seekable,
}
}
#[inline]
fn skip_distance_plain(reader: &mut Reader<R>, distance: u64) -> io::Result<()> {
let mut limited = io::Read::take(reader.inner.by_ref(), distance);
io::copy(&mut limited, &mut io::sink())?;
Ok(())
}
fn skip_distance_seekable(reader: &mut Reader<R>, mut distance: u64) -> io::Result<()>
where
R: io::Seek,
{
while distance > 0 {
let part = std::cmp::min(distance, std::i64::MAX as u64);
reader.inner.seek(SeekFrom::Current(part as i64))?;
reader.advance(part as usize);
distance -= part;
}
Ok(())
}
}
#[derive(Clone)]
pub(crate) struct Reader<R> {
inner: R,
position: usize,
fn_table: ReaderFnTable<R>,
}
impl<R: fmt::Debug> fmt::Debug for Reader<R> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Reader")
.field("inner", &self.inner)
.field("position", &self.position)
.finish()
}
}
impl<R: io::Read> Reader<R> {
#[inline]
#[must_use]
pub(crate) fn new(inner: R, current_position: usize) -> Self {
Self {
inner,
position: current_position,
fn_table: ReaderFnTable::new_for_plain(),
}
}
#[inline]
#[must_use]
pub(crate) fn with_seekable(inner: R, current_position: usize) -> Self
where
R: io::Seek,
{
Self {
inner,
position: current_position,
fn_table: ReaderFnTable::new_for_seekable(),
}
}
#[inline]
#[must_use]
pub(crate) fn position(&self) -> u64 {
self.position as u64
}
#[inline]
pub(crate) fn skip_distance(&mut self, distance: u64) -> io::Result<()> {
(self.fn_table.skip_distance)(self, distance)
}
#[inline]
pub(crate) fn skip_to(&mut self, pos: u64) -> io::Result<()> {
let distance = pos
.checked_sub(self.position())
.expect("Attempt to skip backward");
self.skip_distance(distance)
}
#[inline]
fn advance(&mut self, n: usize) {
self.position = self.position.checked_add(n).expect("Position overflowed");
}
}
impl<R: io::Read> io::Read for Reader<R> {
#[inline]
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let size = self.inner.read(buf)?;
self.advance(size);
Ok(size)
}
}
impl<R: io::BufRead> io::BufRead for Reader<R> {
#[inline]
fn fill_buf(&mut self) -> io::Result<&[u8]> {
self.inner.fill_buf()
}
#[inline]
fn consume(&mut self, amt: usize) {
self.inner.consume(amt);
self.advance(amt);
}
}