use crate::pristine::InodeMetadata;
use crate::working_copy::{memory, WorkingCopy, WorkingCopyRead};
use crate::{working_copy, Inode};
use std::fs::File;
use std::io;
use std::io::BufWriter;
use std::time::SystemTime;
use thiserror::Error;
#[inline]
fn dispatch_callfn<F, T, R>(f: F, v: T) -> R
where
T: WorkingCopyRead,
F: FnOnce(T) -> R,
{
f(v)
}
macro_rules! dispatch_fallible {
($s:expr, $f:expr) => {
match $s {
#[cfg(feature = "ondisk-repos")]
Any::FileSystem(v) => Ok(dispatch_callfn($f, v)?),
Any::Memory(v) => Ok(dispatch_callfn($f, v)?),
Any::Sink(v) => Ok(dispatch_callfn($f, v)?),
}
};
}
#[derive(Clone)]
pub enum Any {
#[cfg(feature = "ondisk-repos")]
FileSystem(working_copy::FileSystem),
Memory(working_copy::Memory),
Sink(working_copy::Sink),
}
#[derive(Debug, Error)]
pub enum Error {
#[error("{0}")]
Io(#[from] io::Error),
#[error("{0}")]
Memory(#[from] memory::Error),
}
pub enum Writer {
File(BufWriter<File>),
Memory(memory::Writer),
Sink(io::Sink),
}
impl From<BufWriter<File>> for Writer {
fn from(value: BufWriter<File>) -> Self {
Writer::File(value)
}
}
impl From<memory::Writer> for Writer {
fn from(value: memory::Writer) -> Self {
Writer::Memory(value)
}
}
impl From<io::Sink> for Writer {
fn from(value: io::Sink) -> Self {
Writer::Sink(value)
}
}
impl io::Write for Writer {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
match self {
Writer::File(v) => v.write(buf),
Writer::Memory(v) => v.write(buf),
Writer::Sink(v) => v.write(buf),
}
}
fn flush(&mut self) -> io::Result<()> {
match self {
Writer::File(v) => v.flush(),
Writer::Memory(v) => v.flush(),
Writer::Sink(v) => v.flush(),
}
}
}
impl WorkingCopyRead for Any {
type Error = Error;
fn file_metadata(&self, file: &str) -> Result<InodeMetadata, Self::Error> {
dispatch_fallible!(self, |v| v.file_metadata(file))
}
fn read_file(&self, file: &str, buffer: &mut Vec<u8>) -> Result<(), Self::Error> {
dispatch_fallible!(self, |v| v.read_file(file, buffer))
}
fn modified_time(&self, file: &str) -> Result<SystemTime, Self::Error> {
dispatch_fallible!(self, |v| v.modified_time(file))
}
}
impl WorkingCopy for Any {
fn create_dir_all(&self, path: &str) -> Result<(), Self::Error> {
dispatch_fallible!(self, |v| v.create_dir_all(path))
}
fn remove_path(&self, name: &str, rec: bool) -> Result<(), Self::Error> {
dispatch_fallible!(self, |v| v.remove_path(name, rec))
}
fn rename(&self, former: &str, new: &str) -> Result<(), Self::Error> {
dispatch_fallible!(self, |v| v.rename(former, new))
}
fn set_permissions(&self, name: &str, permissions: u16) -> Result<(), Self::Error> {
dispatch_fallible!(self, |v| v.set_permissions(name, permissions))
}
type Writer = Writer;
fn write_file(&self, file: &str, inode: Inode) -> Result<Self::Writer, Self::Error> {
dispatch_fallible!(self, |v| v.write_file(file, inode).map(|wr| wr.into()))
}
}