use crate::entry::CacheEntry;
use crate::error::Result;
use async_trait::async_trait;
use serde::{de::DeserializeOwned, Serialize};
use std::collections::HashMap;
use std::hash::Hash;
#[async_trait]
pub trait StorageBackend: Send + Sync + 'static {
type Key: Serialize + DeserializeOwned + Hash + Eq + Clone + Send + Sync;
type Value: Serialize + DeserializeOwned + Clone + Send + Sync;
type Metadata: Serialize + DeserializeOwned + Clone + Send + Sync;
async fn save(
&self,
entries: &HashMap<Self::Key, Vec<CacheEntry<Self::Key, Self::Value, Self::Metadata>>>,
) -> Result<()>;
async fn load(
&self,
) -> Result<HashMap<Self::Key, Vec<CacheEntry<Self::Key, Self::Value, Self::Metadata>>>>;
async fn remove(&self, key: &Self::Key) -> Result<()>;
async fn clear(&self) -> Result<()>;
async fn contains(&self, key: &Self::Key) -> Result<bool> {
let entries = self.load().await?;
Ok(entries.contains_key(key))
}
async fn size_bytes(&self) -> Result<u64> {
Ok(0) }
async fn compact(&self) -> Result<()> {
Ok(()) }
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SerializationFormat {
#[cfg(feature = "json-serialization")]
Json,
#[cfg(feature = "bincode-serialization")]
Bincode,
}
impl SerializationFormat {
pub fn extension(&self) -> &'static str {
match self {
#[cfg(feature = "json-serialization")]
SerializationFormat::Json => "json",
#[cfg(feature = "bincode-serialization")]
SerializationFormat::Bincode => "bin",
#[cfg(not(any(feature = "json-serialization", feature = "bincode-serialization")))]
_ => "data",
}
}
#[allow(unused_variables)]
pub fn serialize<T: Serialize>(&self, value: &T) -> Result<Vec<u8>> {
match self {
#[cfg(feature = "json-serialization")]
SerializationFormat::Json => serde_json::to_vec_pretty(value).map_err(Into::into),
#[cfg(feature = "bincode-serialization")]
SerializationFormat::Bincode => bincode::serialize(value).map_err(Into::into),
#[cfg(not(any(feature = "json-serialization", feature = "bincode-serialization")))]
_ => Err(crate::error::CacheError::Serialization(
"No serialization features enabled".to_string(),
)),
}
}
#[allow(unused_variables)]
pub fn deserialize<T: DeserializeOwned>(&self, data: &[u8]) -> Result<T> {
match self {
#[cfg(feature = "json-serialization")]
SerializationFormat::Json => serde_json::from_slice(data).map_err(Into::into),
#[cfg(feature = "bincode-serialization")]
SerializationFormat::Bincode => bincode::deserialize(data).map_err(Into::into),
#[cfg(not(any(feature = "json-serialization", feature = "bincode-serialization")))]
_ => Err(crate::error::CacheError::Serialization(
"No serialization features enabled".to_string(),
)),
}
}
}
#[derive(Debug, Clone, Default)]
pub struct StorageStats {
pub total_keys: usize,
pub total_entries: usize,
pub total_bytes: u64,
pub avg_entries_per_key: f64,
}
#[cfg(test)]
mod tests {
#[cfg(any(feature = "json-serialization", feature = "bincode-serialization"))]
use super::*;
#[test]
fn test_serialization_format_extension() {
#[cfg(feature = "json-serialization")]
assert_eq!(SerializationFormat::Json.extension(), "json");
#[cfg(feature = "bincode-serialization")]
assert_eq!(SerializationFormat::Bincode.extension(), "bin");
}
#[cfg(feature = "json-serialization")]
#[test]
fn test_json_serialization() {
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct TestData {
value: String,
}
let data = TestData {
value: "test".to_string(),
};
let format = SerializationFormat::Json;
let serialized = format.serialize(&data).unwrap();
let deserialized: TestData = format.deserialize(&serialized).unwrap();
assert_eq!(data, deserialized);
}
}