use super::byte_source::ByteSource;
use std::io::{self, Read, Seek, SeekFrom};
use std::sync::Arc;
pub struct ByteSourceCursor {
inner: Arc<dyn ByteSource>,
position: u64,
}
impl ByteSourceCursor {
pub fn new(inner: Arc<dyn ByteSource>) -> Self {
Self { inner, position: 0 }
}
}
impl Read for ByteSourceCursor {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let total_len = self.inner.len();
if self.position >= total_len {
return Ok(0);
}
let max_read = (total_len - self.position).min(buf.len() as u64) as usize;
let read = self
.inner
.read_at_into(self.position, &mut buf[..max_read])?;
self.position += read as u64;
Ok(read)
}
}
impl Seek for ByteSourceCursor {
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
let invalid = || io::Error::new(io::ErrorKind::InvalidInput, "Seek out of range");
let new_pos = match pos {
SeekFrom::Start(p) => p,
SeekFrom::End(p) => {
let total_len = i64::try_from(self.inner.len()).map_err(|_| invalid())?;
u64::try_from(total_len.checked_add(p).ok_or_else(invalid)?)
.map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "Seek before 0"))?
}
SeekFrom::Current(p) => {
let current = i64::try_from(self.position).map_err(|_| invalid())?;
u64::try_from(current.checked_add(p).ok_or_else(invalid)?)
.map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "Seek before 0"))?
}
};
self.position = new_pos;
Ok(self.position)
}
}