use std::io::{self, BufRead, BufReader, Read, Seek, SeekFrom};
const DEFAULT_BUF_SIZE: usize = 64 * 1024;
pub struct SeekBufReader<R> {
inner: BufReader<R>,
pos: u64,
bytes_read: u64,
}
impl<R: Read + Seek> SeekBufReader<R> {
pub fn new(inner: R) -> Self {
Self {
inner: BufReader::with_capacity(DEFAULT_BUF_SIZE, inner),
pos: 0,
bytes_read: 0,
}
}
pub fn with_capacity(capacity: usize, inner: R) -> Self {
Self {
inner: BufReader::with_capacity(capacity, inner),
pos: 0,
bytes_read: 0,
}
}
#[inline]
pub fn position(&self) -> u64 {
self.pos
}
#[inline]
pub fn bytes_read(&self) -> u64 {
self.bytes_read
}
pub fn skip(&mut self, n: u64) -> io::Result<()> {
if n == 0 {
return Ok(());
}
let buffered = self.inner.buffer().len() as u64;
if n <= buffered {
self.inner.consume(n as usize);
self.pos += n;
Ok(())
} else {
let remaining = n - buffered;
self.inner.consume(buffered as usize);
self.pos += buffered;
self.inner.seek_relative(remaining as i64)?;
self.pos += remaining;
Ok(())
}
}
pub fn seek_to(&mut self, pos: u64) -> io::Result<()> {
if pos == self.pos {
return Ok(());
}
if pos > self.pos {
let delta = pos - self.pos;
let buffered = self.inner.buffer().len() as u64;
if delta <= buffered {
self.inner.consume(delta as usize);
self.pos = pos;
return Ok(());
}
}
self.inner.seek(SeekFrom::Start(pos))?;
self.pos = pos;
Ok(())
}
#[inline]
pub fn read_u16_be(&mut self) -> io::Result<u16> {
let mut buf = [0u8; 2];
self.read_exact(&mut buf)?;
Ok(u16::from_be_bytes(buf))
}
#[inline]
pub fn read_u32_be(&mut self) -> io::Result<u32> {
let mut buf = [0u8; 4];
self.read_exact(&mut buf)?;
Ok(u32::from_be_bytes(buf))
}
#[inline]
pub fn read_u64_be(&mut self) -> io::Result<u64> {
let mut buf = [0u8; 8];
self.read_exact(&mut buf)?;
Ok(u64::from_be_bytes(buf))
}
#[inline]
pub fn read_uint_be(&mut self, n: usize) -> io::Result<u64> {
debug_assert!((1..=8).contains(&n));
let mut buf = [0u8; 8];
self.read_exact(&mut buf[8 - n..])?;
Ok(u64::from_be_bytes(buf))
}
pub fn read_string(&mut self, len: usize) -> io::Result<String> {
let mut buf = vec![0u8; len];
self.read_exact(&mut buf)?;
String::from_utf8(buf).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
}
pub fn read_bytes(&mut self, len: usize) -> io::Result<Vec<u8>> {
let mut buf = vec![0u8; len];
self.read_exact(&mut buf)?;
Ok(buf)
}
pub fn drain(&mut self, n: u64) -> io::Result<()> {
let mut remaining = n;
let buffered = self.inner.buffer().len() as u64;
if buffered > 0 {
let consume = remaining.min(buffered);
self.inner.consume(consume as usize);
self.pos += consume;
self.bytes_read += consume;
remaining -= consume;
}
while remaining > 0 {
let buf = self.inner.fill_buf()?;
if buf.is_empty() {
return Err(io::Error::new(
io::ErrorKind::UnexpectedEof,
"unexpected EOF during drain",
));
}
let consume = (remaining as usize).min(buf.len());
self.inner.consume(consume);
self.pos += consume as u64;
self.bytes_read += consume as u64;
remaining -= consume as u64;
}
Ok(())
}
pub fn file_size(&mut self) -> io::Result<u64> {
let current = self.pos;
let size = self.inner.seek(SeekFrom::End(0))?;
self.inner.seek(SeekFrom::Start(current))?;
self.pos = current;
Ok(size)
}
}
impl<R: Read + Seek> Read for SeekBufReader<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let n = self.inner.read(buf)?;
self.pos += n as u64;
self.bytes_read += n as u64;
Ok(n)
}
}
impl<R: Read + Seek> SeekBufReader<R> {
pub fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
self.inner.read_exact(buf)?;
let n = buf.len() as u64;
self.pos += n;
self.bytes_read += n;
Ok(())
}
pub fn try_read_exact(&mut self, buf: &mut [u8]) -> io::Result<bool> {
if buf.is_empty() {
return Ok(true);
}
let mut filled = 0;
while filled < buf.len() {
match self.inner.read(&mut buf[filled..])? {
0 => {
if filled == 0 {
return Ok(false);
}
return Err(io::Error::new(
io::ErrorKind::UnexpectedEof,
"unexpected EOF in middle of read",
));
}
n => {
filled += n;
self.pos += n as u64;
self.bytes_read += n as u64;
}
}
}
Ok(true)
}
}