use std::fs::File;
use std::io;
pub(crate) trait ReadAt: Sync {
fn read_exact_at(&self, buf: &mut [u8], offset: u64) -> io::Result<()>;
fn read_vec_at(&self, offset: u64, len: usize) -> io::Result<Vec<u8>> {
let mut buf = vec![0; len];
self.read_exact_at(&mut buf, offset)?;
Ok(buf)
}
}
impl ReadAt for [u8] {
fn read_exact_at(&self, buf: &mut [u8], offset: u64) -> io::Result<()> {
let start = usize::try_from(offset).map_err(|_| io::ErrorKind::UnexpectedEof)?;
let source =
start.checked_add(buf.len()).and_then(|end| self.get(start..end)).ok_or(io::ErrorKind::UnexpectedEof)?;
buf.copy_from_slice(source);
Ok(())
}
}
impl ReadAt for Vec<u8> {
fn read_exact_at(&self, buf: &mut [u8], offset: u64) -> io::Result<()> {
self.as_slice().read_exact_at(buf, offset)
}
}
impl ReadAt for File {
#[cfg(unix)]
fn read_exact_at(&self, buf: &mut [u8], offset: u64) -> io::Result<()> {
std::os::unix::fs::FileExt::read_exact_at(self, buf, offset)
}
#[cfg(windows)]
fn read_exact_at(&self, mut buf: &mut [u8], mut offset: u64) -> io::Result<()> {
use std::os::windows::fs::FileExt;
while !buf.is_empty() {
match self.seek_read(buf, offset) {
Ok(0) => return Err(io::ErrorKind::UnexpectedEof.into()),
Ok(n) => {
buf = &mut buf[n..];
offset += n as u64;
}
Err(error) if error.kind() == io::ErrorKind::Interrupted => {}
Err(error) => return Err(error),
}
}
Ok(())
}
}
impl<T: ReadAt + ?Sized> ReadAt for &T {
fn read_exact_at(&self, buf: &mut [u8], offset: u64) -> io::Result<()> {
(**self).read_exact_at(buf, offset)
}
}