use crate::error::{PersistenceError, PersistenceResult};
use crate::storage::Directory;
use std::path::PathBuf;
use std::sync::Arc;
#[allow(async_fn_in_trait)]
pub trait AsyncDirectory: Send + Sync {
async fn write_file(&self, path: &str, data: Vec<u8>) -> PersistenceResult<()>;
async fn read_file(&self, path: &str) -> PersistenceResult<Vec<u8>>;
async fn append(&self, path: &str, data: Vec<u8>) -> PersistenceResult<()>;
async fn exists(&self, path: &str) -> PersistenceResult<bool>;
async fn delete(&self, path: &str) -> PersistenceResult<()>;
async fn atomic_write(&self, path: &str, data: Vec<u8>) -> PersistenceResult<()>;
async fn create_dir_all(&self, path: &str) -> PersistenceResult<()>;
async fn list_dir(&self, path: &str) -> PersistenceResult<Vec<String>>;
fn file_path(&self, path: &str) -> Option<PathBuf>;
}
pub struct BlockingBridge<D> {
inner: Arc<D>,
}
impl<D: Directory + 'static> BlockingBridge<D> {
pub fn new(dir: D) -> Self {
Self {
inner: Arc::new(dir),
}
}
pub fn from_arc(dir: Arc<D>) -> Self {
Self { inner: dir }
}
pub fn inner(&self) -> &D {
&self.inner
}
pub fn inner_arc(&self) -> Arc<D> {
self.inner.clone()
}
}
impl<D: Directory + 'static> AsyncDirectory for BlockingBridge<D> {
async fn write_file(&self, path: &str, data: Vec<u8>) -> PersistenceResult<()> {
let dir = self.inner.clone();
let path = path.to_string();
tokio::task::spawn_blocking(move || {
let mut f = dir.create_file(&path)?;
std::io::Write::write_all(&mut f, &data)?;
std::io::Write::flush(&mut f)?;
Ok(())
})
.await
.map_err(|e| PersistenceError::InvalidState(format!("spawn_blocking panicked: {e}")))?
}
async fn read_file(&self, path: &str) -> PersistenceResult<Vec<u8>> {
let dir = self.inner.clone();
let path = path.to_string();
tokio::task::spawn_blocking(move || {
let mut f = dir.open_file(&path)?;
let mut buf = Vec::new();
std::io::Read::read_to_end(&mut f, &mut buf)?;
Ok(buf)
})
.await
.map_err(|e| PersistenceError::InvalidState(format!("spawn_blocking panicked: {e}")))?
}
async fn append(&self, path: &str, data: Vec<u8>) -> PersistenceResult<()> {
let dir = self.inner.clone();
let path = path.to_string();
tokio::task::spawn_blocking(move || {
let mut f = dir.append_file(&path)?;
std::io::Write::write_all(&mut f, &data)?;
std::io::Write::flush(&mut f)?;
Ok(())
})
.await
.map_err(|e| PersistenceError::InvalidState(format!("spawn_blocking panicked: {e}")))?
}
async fn exists(&self, path: &str) -> PersistenceResult<bool> {
let dir = self.inner.clone();
let path = path.to_string();
tokio::task::spawn_blocking(move || Ok(dir.exists(&path)))
.await
.map_err(|e| PersistenceError::InvalidState(format!("spawn_blocking panicked: {e}")))?
}
async fn delete(&self, path: &str) -> PersistenceResult<()> {
let dir = self.inner.clone();
let path = path.to_string();
tokio::task::spawn_blocking(move || dir.delete(&path))
.await
.map_err(|e| PersistenceError::InvalidState(format!("spawn_blocking panicked: {e}")))?
}
async fn atomic_write(&self, path: &str, data: Vec<u8>) -> PersistenceResult<()> {
let dir = self.inner.clone();
let path = path.to_string();
tokio::task::spawn_blocking(move || dir.atomic_write(&path, &data))
.await
.map_err(|e| PersistenceError::InvalidState(format!("spawn_blocking panicked: {e}")))?
}
async fn create_dir_all(&self, path: &str) -> PersistenceResult<()> {
let dir = self.inner.clone();
let path = path.to_string();
tokio::task::spawn_blocking(move || dir.create_dir_all(&path))
.await
.map_err(|e| PersistenceError::InvalidState(format!("spawn_blocking panicked: {e}")))?
}
async fn list_dir(&self, path: &str) -> PersistenceResult<Vec<String>> {
let dir = self.inner.clone();
let path = path.to_string();
tokio::task::spawn_blocking(move || dir.list_dir(&path))
.await
.map_err(|e| PersistenceError::InvalidState(format!("spawn_blocking panicked: {e}")))?
}
fn file_path(&self, path: &str) -> Option<PathBuf> {
self.inner.file_path(path)
}
}