use core::fmt::Debug;
use std::io::{Read, Result, Seek, Write};
use std::path::{Path, PathBuf};
pub trait ReadonlyRandomAccessFile: Read + Seek + Send + Sync {
fn read_from(&self, buf: &mut [u8], offset: usize) -> Result<usize>;
fn len(&self) -> Result<u64>;
fn is_empty(&self) -> Result<bool> {
Ok(self.len()? == 0)
}
}
pub trait RandomAccessFile: ReadonlyRandomAccessFile + Write {
fn append(&mut self, buf: &[u8]) -> Result<usize>;
}
pub trait FileSystem: Send + Sync {
fn get_name(&self) -> String;
fn create_dir(&self, path: &Path) -> Result<()>;
fn create_dir_all(&self, path: &Path) -> Result<()>;
fn list_dir(&self, path: &Path) -> Result<Vec<PathBuf>>;
fn open_file(&self, path: &Path) -> Result<Box<dyn ReadonlyRandomAccessFile>>;
fn rename(&self, from: &Path, to: &Path) -> Result<()>;
fn create_file(&self, path: &Path, append: bool) -> Result<Box<dyn RandomAccessFile>>;
fn remove_file(&self, path: &Path) -> Result<()>;
fn remove_dir(&self, path: &Path) -> Result<()>;
fn remove_dir_all(&self, path: &Path) -> Result<()>;
fn get_file_size(&self, path: &Path) -> Result<u64>;
fn is_dir(&self, path: &Path) -> Result<bool>;
fn lock_file(&self, path: &Path) -> Result<FileLock>;
}
impl Debug for dyn FileSystem {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.get_name())
}
}
pub struct FileLock {
inner: Box<dyn UnlockableFile>,
}
impl FileLock {
pub fn new(file: Box<dyn UnlockableFile>) -> Self {
Self { inner: file }
}
}
impl Drop for FileLock {
fn drop(&mut self) {
if let Err(unlock_error) = self.inner.unlock() {
log::error!(
"There was an error trying to release the database lock during shutdown. Error: \
{error}",
error = unlock_error
);
}
}
}
pub trait UnlockableFile: Send + Sync {
fn unlock(&self) -> Result<()>;
}