mod memory;
mod os;
#[cfg(test)]
pub(crate) mod counted;
#[cfg(test)]
mod tests;
use std::path::Path;
use std::sync::Arc;
pub use memory::MemoryStorage;
pub use os::OsStorage;
use crate::{Error, Result};
pub trait Storage: Send + Sync + std::fmt::Debug {
fn create(&self, path: &Path) -> Result<Box<dyn WritableFile>>;
fn open(&self, path: &Path) -> Result<Arc<dyn ReadableFile>>;
fn exists(&self, path: &Path) -> Result<bool>;
fn remove(&self, path: &Path) -> Result<()>;
fn rename(&self, from: &Path, to: &Path) -> Result<()>;
fn list(&self, dir: &Path) -> Result<Vec<String>>;
fn create_dir_all(&self, dir: &Path) -> Result<()>;
fn sync_dir(&self, dir: &Path) -> Result<()>;
fn lock(&self, path: &Path) -> Result<Box<dyn StorageLock>>;
}
pub trait WritableFile: Send {
fn append(&mut self, data: &[u8]) -> Result<()>;
fn sync(&mut self) -> Result<()>;
fn len(&self) -> u64;
fn is_empty(&self) -> bool {
self.len() == 0
}
}
pub trait ReadableFile: Send + Sync {
fn read_at(&self, offset: u64, buf: &mut [u8]) -> Result<()>;
fn try_read_at(&self, offset: u64, buf: &mut [u8]) -> Result<bool> {
let _ = (offset, buf);
Ok(false)
}
fn len(&self) -> Result<u64>;
fn is_empty(&self) -> Result<bool> {
Ok(self.len()? == 0)
}
}
pub trait StorageLock: Send + Sync + std::fmt::Debug {}
pub(crate) fn read_all(storage: &dyn Storage, path: &Path, what: &'static str) -> Result<Vec<u8>> {
let file = storage.open(path)?;
let len = usize::try_from(file.len()?).map_err(|_| Error::Corruption {
what,
path: Some(path.to_path_buf()),
offset: Some(0),
detail: "the file is larger than memory can address".to_owned(),
})?;
let mut bytes = vec![0; len];
file.read_at(0, &mut bytes)?;
Ok(bytes)
}