use std::{fs::File, io};
use bao_tree::io::sync::{ReadAt, Size};
use bytes::Bytes;
#[derive(Debug)]
pub enum MemOrFile<M, F> {
Mem(M),
File(F),
}
impl<M, F> MemOrFile<M, (F, u64)>
where
M: AsRef<[u8]>,
{
pub fn size(&self) -> u64 {
match self {
MemOrFile::Mem(mem) => mem.as_ref().len() as u64,
MemOrFile::File((_, size)) => *size,
}
}
}
impl ReadAt for MemOrFile<Bytes, File> {
fn read_at(&self, offset: u64, buf: &mut [u8]) -> io::Result<usize> {
match self {
MemOrFile::Mem(mem) => mem.as_ref().read_at(offset, buf),
MemOrFile::File(file) => file.read_at(offset, buf),
}
}
}
impl Size for MemOrFile<Bytes, File> {
fn size(&self) -> io::Result<Option<u64>> {
match self {
MemOrFile::Mem(mem) => Ok(Some(mem.len() as u64)),
MemOrFile::File(file) => file.size(),
}
}
}
impl<M: Default, F> Default for MemOrFile<M, F> {
fn default() -> Self {
MemOrFile::Mem(Default::default())
}
}
impl<M, F> MemOrFile<M, F> {
pub fn as_ref(&self) -> MemOrFile<&M, &F> {
match self {
MemOrFile::Mem(mem) => MemOrFile::Mem(mem),
MemOrFile::File(file) => MemOrFile::File(file),
}
}
pub fn is_mem(&self) -> bool {
matches!(self, MemOrFile::Mem(_))
}
pub fn mem(&self) -> Option<&M> {
match self {
MemOrFile::Mem(mem) => Some(mem),
MemOrFile::File(_) => None,
}
}
pub fn map_file<F2>(self, f: impl FnOnce(F) -> F2) -> MemOrFile<M, F2> {
match self {
MemOrFile::Mem(mem) => MemOrFile::Mem(mem),
MemOrFile::File(file) => MemOrFile::File(f(file)),
}
}
pub fn try_map_file<F2, E>(
self,
f: impl FnOnce(F) -> Result<F2, E>,
) -> Result<MemOrFile<M, F2>, E> {
match self {
MemOrFile::Mem(mem) => Ok(MemOrFile::Mem(mem)),
MemOrFile::File(file) => f(file).map(MemOrFile::File),
}
}
pub fn map_mem<M2>(self, f: impl FnOnce(M) -> M2) -> MemOrFile<M2, F> {
match self {
MemOrFile::Mem(mem) => MemOrFile::Mem(f(mem)),
MemOrFile::File(file) => MemOrFile::File(file),
}
}
}