mod in_memory;
mod local_fs;
use std::fmt;
use async_trait::async_trait;
use bytes::Bytes;
use crate::error::Result;
pub use in_memory::InMemoryBackend;
pub use local_fs::LocalFsBackend;
#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct StorageKey(String);
impl StorageKey {
pub fn new(s: impl Into<String>) -> Self {
let mut s = s.into();
if s.starts_with('/') {
s.remove(0);
}
StorageKey(s)
}
#[must_use]
pub fn as_str(&self) -> &str {
&self.0
}
#[must_use]
pub fn join(&self, child: &str) -> StorageKey {
let child = child.trim_start_matches('/');
if self.0.is_empty() {
StorageKey(child.to_string())
} else {
StorageKey(format!("{}/{}", self.0, child))
}
}
}
impl fmt::Display for StorageKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.0)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StorageEntry {
pub key: StorageKey,
pub size: u64,
}
#[async_trait]
pub trait Storage: Send + Sync + fmt::Debug + 'static {
fn id(&self) -> String;
async fn put(&self, key: &StorageKey, body: Bytes) -> Result<()>;
async fn get(&self, key: &StorageKey) -> Result<Bytes>;
async fn exists(&self, key: &StorageKey) -> Result<bool>;
async fn delete(&self, key: &StorageKey) -> Result<()>;
async fn list_prefix(&self, prefix: &StorageKey) -> Result<Vec<StorageEntry>>;
fn capabilities(&self) -> crate::capabilities::StorageCapabilities {
crate::capabilities::StorageCapabilities::default()
}
fn root_hint(&self) -> Option<std::path::PathBuf> {
None
}
async fn rename_within(&self, src: &StorageKey, dst: &StorageKey) -> Result<()> {
if src == dst {
return Ok(());
}
if !self.exists(src).await? {
return Ok(());
}
let body = self.get(src).await?;
self.put(dst, body).await?;
self.delete(src).await?;
Ok(())
}
}