- Introduced corex-storage crate with support for local disk, S3-compatible, and Google Cloud Storage backends. - Implemented StorageDriver trait for various storage backends. - Added LocalFileStorage for local disk operations. - Added S3Storage for S3-compatible object storage with multipart upload support. - Added GcsStorage for Google Cloud Storage operations. - Included error handling for storage operations. - Added tests for each storage backend to ensure functionality. - Created README.md for documentation and usage examples. - Added Apache and MIT licenses for open-source compliance.
78 lines
2.5 KiB
Rust
78 lines
2.5 KiB
Rust
//! The core [`Cache`] and [`KeyEncoder`] traits.
|
|
|
|
use std::borrow::Cow;
|
|
use std::time::Duration;
|
|
|
|
use async_trait::async_trait;
|
|
|
|
/// Errors returned by cache operations.
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
pub enum CacheError {
|
|
/// The backend could not be reached (e.g. Redis connection lost).
|
|
Io(String),
|
|
/// A value could not be serialized / deserialized.
|
|
Serialization(String),
|
|
/// A key could not be encoded for the backend.
|
|
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 {}
|
|
|
|
/// A generic byte-oriented cache.
|
|
///
|
|
/// Real caches operate on bytes or strings; typed convenience is layered on
|
|
/// top (see [`crate::memory::typed::TypedCache`], behind `cache-aside`).
|
|
/// Implementors control the value format.
|
|
#[async_trait]
|
|
pub trait Cache: Send + Sync {
|
|
/// Fetches a value by key. `None` indicates a miss.
|
|
async fn get(&self, key: &str) -> Result<Option<Vec<u8>>, CacheError>;
|
|
/// Stores a value under `key`, optionally expiring after `ttl`.
|
|
async fn set(&self, key: &str, value: Vec<u8>, ttl: Option<Duration>)
|
|
-> Result<(), CacheError>;
|
|
/// Removes a key.
|
|
async fn invalidate(&self, key: &str) -> Result<(), CacheError>;
|
|
/// Removes all entries.
|
|
async fn clear(&self) -> Result<(), CacheError>;
|
|
}
|
|
|
|
/// Keys given to the byte-oriented [`Cache`] are `&str`, but concrete backends
|
|
/// may need richer keys. [`KeyEncoder`] turns typed keys into canonical strings.
|
|
pub trait KeyEncoder {
|
|
/// The "shape" of a key, e.g. `"user:{id}:profile"`.
|
|
fn encode<C: Into<Cow<'static, str>>, R: std::fmt::Display>(parts: (C, R)) -> String;
|
|
}
|
|
|
|
/// A blanket implementation that formats `{collection}:{id}`.
|
|
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"
|
|
);
|
|
}
|
|
}
|