use crate::{Error, MAX_IO_CHUNK, RangedSource, Result};
use std::io::{Read, Seek, SeekFrom};
pub struct SeekableSource<R> {
inner: R,
size: u64,
}
impl<R: Read + Seek> SeekableSource<R> {
pub fn new(mut inner: R) -> Result<Self> {
let original = inner.stream_position()?;
let size = inner.seek(SeekFrom::End(0))?;
inner.seek(SeekFrom::Start(original))?;
Ok(Self { inner, size })
}
pub fn into_inner(self) -> R {
self.inner
}
}
impl<R: Read + Seek> RangedSource for SeekableSource<R> {
fn size(&self) -> u64 {
self.size
}
fn read_at(&mut self, offset: u64, destination: &mut [u8]) -> Result<usize> {
if destination.len() > MAX_IO_CHUNK {
return Err(Error::limit(
"I/O request bytes",
MAX_IO_CHUNK as u64,
destination.len() as u64,
));
}
if offset > self.size {
return Err(Error::invalid("read starts beyond source size"));
}
offset
.checked_add(destination.len() as u64)
.ok_or(Error::invalid("read end overflows 64-bit offset"))?;
self.inner.seek(SeekFrom::Start(offset))?;
Ok(self.inner.read(destination)?)
}
}