use async_trait::async_trait;
#[async_trait]
pub trait Backend {
type Error: std::error::Error + Send + Sync + 'static;
async fn read(&mut self) -> Result<Vec<u8>, Self::Error>;
async fn write(&mut self, data: Vec<u8>) -> Result<(), Self::Error>;
}
#[derive(std::default::Default, Debug, Clone, PartialEq, Eq)]
pub struct Memory(Vec<u8>);
impl Memory {
pub fn new() -> Self {
Self(Vec::new())
}
pub fn take(&mut self) -> Vec<u8> {
std::mem::take(&mut self.0)
}
}
impl From<Vec<u8>> for Memory {
fn from(buf: Vec<u8>) -> Self {
Self(buf)
}
}
#[async_trait]
impl Backend for Memory {
type Error = std::convert::Infallible;
async fn read(&mut self) -> Result<Vec<u8>, Self::Error> {
Ok(self.0.clone())
}
async fn write(&mut self, data: Vec<u8>) -> Result<(), Self::Error> {
self.0 = data;
Ok(())
}
}
#[cfg(feature = "file-backend")]
pub use self::file::File;
#[cfg(feature = "file-backend")]
mod file {
use async_std::io::prelude::{ReadExt, SeekExt, WriteExt};
use async_trait::async_trait;
use super::Backend;
#[cfg_attr(docsrs, doc(cfg(feature = "file-backend")))]
#[derive(Debug)]
pub struct File(async_std::fs::File);
impl File {
pub async fn from_path<P>(path: P) -> Result<Self, std::io::Error>
where
P: AsRef<std::path::Path>,
{
Ok(Self(
async_std::fs::OpenOptions::new()
.read(true)
.write(true)
.open(path.as_ref())
.await?,
))
}
pub async fn from_path_or_create<P>(path: P) -> Result<(Self, bool), std::io::Error>
where
P: AsRef<std::path::Path>,
{
let backend = Self::from_path(&path).await;
match backend {
Ok(self_) => Ok((self_, true)),
Err(err) => match err.kind() {
std::io::ErrorKind::NotFound => Ok((
Self(
async_std::fs::OpenOptions::new()
.read(true)
.write(true)
.create(true)
.open(path.as_ref())
.await?,
),
false,
)),
_ => Err(err),
},
}
}
}
#[async_trait]
impl Backend for File {
type Error = std::io::Error;
async fn read(&mut self) -> Result<Vec<u8>, Self::Error> {
let mut buffer = Vec::new();
self.0.seek(std::io::SeekFrom::Start(0)).await?;
self.0.read_to_end(&mut buffer).await?;
Ok(buffer)
}
async fn write(&mut self, data: Vec<u8>) -> Result<(), Self::Error> {
self.0.seek(std::io::SeekFrom::Start(0)).await?;
self.0.set_len(0).await?;
self.0.write_all(&data).await?;
self.0.sync_all().await?;
Ok(())
}
}
}