+ 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()))
+ }
+ }