use std::fs::File;
use std::io;
#[cfg(all(not(unix), not(windows)))]
use std::io::{Read, Seek, SeekFrom};
pub trait ByteSource: Send + Sync {
fn len(&self) -> u64;
fn is_empty(&self) -> bool {
self.len() == 0
}
fn read_at(&self, offset: u64, len: usize) -> io::Result<Vec<u8>>;
}
pub struct FileSource {
file: File, len: u64,
}
impl FileSource {
pub fn new(file: File) -> io::Result<Self> {
let len = file.metadata()?.len();
Ok(Self { file, len })
}
}
#[cfg(unix)]
impl ByteSource for FileSource {
fn len(&self) -> u64 {
self.len
}
fn read_at(&self, offset: u64, len: usize) -> io::Result<Vec<u8>> {
use std::os::unix::fs::FileExt; let mut buffer = vec![0u8; len];
self.file.read_exact_at(&mut buffer, offset)?;
Ok(buffer)
}
}
#[cfg(windows)]
impl ByteSource for FileSource {
fn len(&self) -> u64 {
self.len
}
fn read_at(&self, offset: u64, len: usize) -> io::Result<Vec<u8>> {
use std::os::windows::fs::FileExt;
let mut buffer = vec![0u8; len];
self.file.seek_read(&mut buffer, offset)?;
Ok(buffer)
}
}
#[cfg(all(not(unix), not(windows)))]
impl ByteSource for FileSource {
fn len(&self) -> u64 {
self.len
}
fn read_at(&self, offset: u64, len: usize) -> io::Result<Vec<u8>> {
let mut file_clone = self.file.try_clone()?;
file_clone.seek(SeekFrom::Start(offset))?;
let mut buffer = vec![0u8; len];
file_clone.read_exact(&mut buffer)?;
Ok(buffer)
}
}
pub struct MemorySource {
data: Vec<u8>,
}
impl MemorySource {
pub fn new(data: Vec<u8>) -> Self {
Self { data }
}
}
impl ByteSource for MemorySource {
fn len(&self) -> u64 {
self.data.len() as u64
}
fn read_at(&self, offset: u64, len: usize) -> io::Result<Vec<u8>> {
let offset = offset as usize;
if offset > self.data.len() {
return Err(io::Error::new(
io::ErrorKind::UnexpectedEof,
"offset beyond end of data",
));
}
let end = (offset + len).min(self.data.len());
if end - offset < len {
return Err(io::Error::new(
io::ErrorKind::UnexpectedEof,
"not enough data",
));
}
Ok(self.data[offset..end].to_vec())
}
}