use std::borrow::Cow;
use std::time::Duration;
use async_trait::async_trait;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum CacheError {
Io(String),
Serialization(String),
Key(String),
}
impl std::fmt::Display for CacheError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Io(s) => write!(f, "cache io: {s}"),
Self::Serialization(s) => write!(f, "cache serialization: {s}"),
Self::Key(s) => write!(f, "cache key: {s}"),
}
}
}
impl std::error::Error for CacheError {}
#[async_trait]
pub trait Cache: Send + Sync {
async fn get(&self, key: &str) -> Result<Option<Vec<u8>>, CacheError>;
async fn set(&self, key: &str, value: Vec<u8>, ttl: Option<Duration>)
-> Result<(), CacheError>;
async fn invalidate(&self, key: &str) -> Result<(), CacheError>;
async fn clear(&self) -> Result<(), CacheError>;
}
pub trait KeyEncoder {
fn encode<C: Into<Cow<'static, str>>, R: std::fmt::Display>(parts: (C, R)) -> String;
}
pub struct DefaultKeyEncoder;
impl KeyEncoder for DefaultKeyEncoder {
fn encode<C: Into<Cow<'static, str>>, R: std::fmt::Display>(parts: (C, R)) -> String {
format!("{}:{}", parts.0.into(), parts.1)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn default_key_encoder_formats() {
assert_eq!(DefaultKeyEncoder::encode(("user", 42)), "user:42");
assert_eq!(
DefaultKeyEncoder::encode(("session", "abc-123")),
"session:abc-123"
);
}
}