use crate::util::seek_add_offset;
use crate::{
detail::{PeekCursorState, PeekReadImpl},
PeekCursor, PeekRead,
};
use std::io::{Error, ErrorKind, Read, Result, Seek, SeekFrom};
#[derive(Debug)]
pub struct SeekPeekReader<R> {
inner: R,
start_pos: Option<u64>,
}
impl<R: Read + Seek> SeekPeekReader<R> {
pub fn new(reader: R) -> Self {
Self {
inner: reader,
start_pos: None,
}
}
pub fn get_ref(&self) -> &R {
&self.inner
}
pub fn get_mut(&mut self) -> &mut R {
&mut self.inner
}
pub fn into_inner(self) -> R {
self.inner
}
fn init_start_pos(&mut self) -> Result<u64> {
let start_pos = self
.start_pos
.map(Ok)
.unwrap_or_else(|| self.inner.stream_position())?;
self.start_pos = Some(start_pos);
Ok(start_pos)
}
}
impl<R: Seek + Read> Seek for SeekPeekReader<R> {
fn seek(&mut self, pos: SeekFrom) -> Result<u64> {
self.inner.seek(pos)
}
fn stream_position(&mut self) -> Result<u64> {
self.inner.stream_position()
}
}
impl<R: Seek + Read> Read for SeekPeekReader<R> {
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
self.inner.read(buf)
}
fn read_exact(&mut self, buf: &mut [u8]) -> Result<()> {
self.inner.read_exact(buf)
}
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize> {
self.inner.read_to_end(buf)
}
fn read_to_string(&mut self, buf: &mut String) -> Result<usize> {
self.inner.read_to_string(buf)
}
}
impl<R: Read + Seek> PeekRead for SeekPeekReader<R> {
fn peek(&mut self) -> PeekCursor<'_> {
self.start_pos = None;
PeekCursor::new(self)
}
}
impl<R: Read + Seek> PeekReadImpl for SeekPeekReader<R> {
fn peek_seek(&mut self, _state: &mut PeekCursorState, pos: SeekFrom) -> Result<u64> {
let start_pos = self.init_start_pos()?;
let cur_pos = self.stream_position()?;
let new_pos = match pos {
SeekFrom::Start(offset) => self.inner.seek(SeekFrom::Start(start_pos + offset))?,
SeekFrom::Current(offset) => self.inner.seek(SeekFrom::Current(offset))?,
SeekFrom::End(offset) => {
let end_pos = self.inner.seek(SeekFrom::End(0))?.max(start_pos);
match seek_add_offset(end_pos, offset) {
Ok(o) => self.inner.seek(SeekFrom::Start(o))?,
Err(e) => {
self.inner.seek(SeekFrom::Start(cur_pos))?;
return Err(e);
}
}
}
};
if new_pos < start_pos {
self.inner.seek(SeekFrom::Start(cur_pos))?;
Err(Error::new(
ErrorKind::InvalidInput,
"invalid seek to a negative or overflowing position",
))
} else {
Ok(new_pos - start_pos)
}
}
fn peek_read(&mut self, _state: &mut PeekCursorState, buf: &mut [u8]) -> Result<usize> {
self.init_start_pos()?;
let written = self.inner.read(buf)?;
Ok(written)
}
fn peek_read_exact(&mut self, _state: &mut PeekCursorState, buf: &mut [u8]) -> Result<()> {
self.init_start_pos()?;
self.inner.read_exact(buf)?;
Ok(())
}
fn peek_fill_buf<'a>(&'a mut self, state: &'a mut PeekCursorState) -> Result<&'a [u8]> {
self.init_start_pos()?;
let read = self.inner.read(&mut state.buf)?;
self.inner.seek(SeekFrom::Current(-(read as i64)))?;
Ok(&state.buf[..read])
}
fn peek_consume(&mut self, _state: &mut PeekCursorState, amt: usize) {
self.init_start_pos().ok();
self.inner.seek(SeekFrom::Current(amt as i64)).ok();
}
fn peek_drop(&mut self, _state: &mut PeekCursorState) {
if let Some(start_pos) = self.start_pos {
while let Err(e) = self.inner.seek(SeekFrom::Start(start_pos)) {
if e.kind() != std::io::ErrorKind::Interrupted {
break;
}
}
}
}
}