pub mod memory;
#[cfg(feature = "mmap")]
pub mod mmap;
pub mod reader;
use crate::error::Result;
use std::ops::Deref;
use std::path::Path;
pub trait ByteSource: Send + Sync {
fn len(&self) -> u64;
fn is_empty(&self) -> bool {
self.len() == 0
}
fn read_bytes(&self, offset: u64, len: usize) -> Result<ByteSlice<'_>>;
fn read_bytes_to_end(&self, offset: u64) -> Result<ByteSlice<'_>> {
let remaining = self.len().saturating_sub(offset) as usize;
self.read_bytes(offset, remaining)
}
}
#[derive(Debug)]
pub enum ByteSlice<'a> {
Borrowed(&'a [u8]),
Owned(Vec<u8>),
}
impl<'a> Deref for ByteSlice<'a> {
type Target = [u8];
fn deref(&self) -> &Self::Target {
match self {
ByteSlice::Borrowed(slice) => slice,
ByteSlice::Owned(vec) => vec,
}
}
}
impl<'a> AsRef<[u8]> for ByteSlice<'a> {
fn as_ref(&self) -> &[u8] {
self
}
}
impl<'a> ByteSlice<'a> {
pub fn borrowed(slice: &'a [u8]) -> Self {
ByteSlice::Borrowed(slice)
}
pub fn owned(data: Vec<u8>) -> Self {
ByteSlice::Owned(data)
}
pub fn into_owned(self) -> Vec<u8> {
match self {
ByteSlice::Borrowed(slice) => slice.to_vec(),
ByteSlice::Owned(vec) => vec,
}
}
}
#[non_exhaustive]
pub enum IoBackend {
#[cfg(feature = "mmap")]
Mmap(mmap::MmapSource),
Buffered(reader::BufferedSource),
Memory(memory::MemorySource),
}
impl IoBackend {
#[cfg(feature = "mmap")]
pub fn open_mmap<P: AsRef<Path>>(path: P) -> Result<Self> {
Ok(IoBackend::Mmap(mmap::MmapSource::open(path)?))
}
pub fn open_buffered<P: AsRef<Path>>(path: P) -> Result<Self> {
Ok(IoBackend::Buffered(reader::BufferedSource::open(path)?))
}
pub fn from_bytes(bytes: Vec<u8>) -> Self {
IoBackend::Memory(memory::MemorySource::new(bytes))
}
pub fn open<P: AsRef<Path>>(path: P) -> Result<Self> {
#[cfg(feature = "mmap")]
{
Self::open_mmap(path)
}
#[cfg(not(feature = "mmap"))]
{
Self::open_buffered(path)
}
}
}
impl ByteSource for IoBackend {
fn len(&self) -> u64 {
match self {
#[cfg(feature = "mmap")]
IoBackend::Mmap(source) => source.len(),
IoBackend::Buffered(source) => source.len(),
IoBackend::Memory(source) => source.len(),
}
}
fn read_bytes(&self, offset: u64, len: usize) -> Result<ByteSlice<'_>> {
if len == 0 && offset <= self.len() {
return Ok(ByteSlice::borrowed(&[]));
}
match self {
#[cfg(feature = "mmap")]
IoBackend::Mmap(source) => source.read_bytes(offset, len),
IoBackend::Buffered(source) => source.read_bytes(offset, len),
IoBackend::Memory(source) => source.read_bytes(offset, len),
}
}
}
impl<T: ByteSource + ?Sized> ByteSource for std::sync::Arc<T> {
fn len(&self) -> u64 {
(**self).len()
}
fn read_bytes(&self, offset: u64, len: usize) -> Result<ByteSlice<'_>> {
(**self).read_bytes(offset, len)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_byte_slice_deref() {
let data = vec![1, 2, 3, 4, 5];
let slice = ByteSlice::owned(data.clone());
assert_eq!(&*slice, &[1, 2, 3, 4, 5]);
let borrowed = ByteSlice::borrowed(&data);
assert_eq!(&*borrowed, &[1, 2, 3, 4, 5]);
}
#[test]
fn test_byte_slice_into_owned() {
let data = vec![1, 2, 3];
let slice = ByteSlice::borrowed(&data);
let owned = slice.into_owned();
assert_eq!(owned, vec![1, 2, 3]);
}
}