use std::io::{Error, ErrorKind, Read, Result, Seek, SeekFrom, Write}; pub struct IoCursor { io: Io, cursor: u64, bounds: (u64, u64), } impl IoCursor { pub fn new(io: Io, cursor: u64, end: u64) -> Self { Self { io, cursor, bounds: (cursor, end), } } } impl Read for IoCursor { fn read(&mut self, buf: &mut [u8]) -> Result { let upper = buf.len().min((self.bounds.1 - self.cursor) as usize); let bytes = self.io.read(&mut buf[..upper])?; self.cursor += bytes as u64; Ok(bytes) } } impl Write for IoCursor { fn write(&mut self, buf: &[u8]) -> Result { let upper = buf.len().min((self.bounds.1 - self.cursor) as usize); let bytes = self.io.write(&buf[..upper])?; self.cursor += bytes as u64; Ok(bytes) } fn flush(&mut self) -> Result<()> { self.io.flush() } } impl Seek for IoCursor { fn seek(&mut self, pos: SeekFrom) -> Result { self.cursor = match pos { SeekFrom::Current(0) => return Ok(self.cursor - self.bounds.0), SeekFrom::Start(offset) => self.bounds.0.checked_add(offset), SeekFrom::End(offset) => self.bounds.1.checked_add_signed(offset), SeekFrom::Current(offset) => self.cursor.checked_add_signed(offset), } .filter(|v| *v >= self.bounds.0) .ok_or(Error::new( ErrorKind::InvalidInput, "Invalid seek to a negative or overflowing position", ))? .min(self.bounds.1); Ok(self.io.seek(SeekFrom::Start(self.cursor))? - self.bounds.0) } }