Skip to main content

mytheclipse_cache/
traits.rs

1//! The core [`Cache`] and [`KeyEncoder`] traits.
2
3use std::borrow::Cow;
4use std::time::Duration;
5
6use async_trait::async_trait;
7
8/// Errors returned by cache operations.
9#[derive(Debug, Clone, PartialEq, Eq)]
10pub enum CacheError {
11    /// The backend could not be reached (e.g. Redis connection lost).
12    Io(String),
13    /// A value could not be serialized / deserialized.
14    Serialization(String),
15    /// A key could not be encoded for the backend.
16    Key(String),
17}
18
19impl std::fmt::Display for CacheError {
20    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
21        match self {
22            Self::Io(s) => write!(f, "cache io: {s}"),
23            Self::Serialization(s) => write!(f, "cache serialization: {s}"),
24            Self::Key(s) => write!(f, "cache key: {s}"),
25        }
26    }
27}
28
29impl std::error::Error for CacheError {}
30
31/// A generic byte-oriented cache.
32///
33/// Real caches operate on bytes or strings; typed convenience is layered on
34/// top (see [`crate::memory::typed::TypedCache`], behind `cache-aside`).
35/// Implementors control the value format.
36#[async_trait]
37pub trait Cache: Send + Sync {
38    /// Fetches a value by key. `None` indicates a miss.
39    async fn get(&self, key: &str) -> Result<Option<Vec<u8>>, CacheError>;
40    /// Stores a value under `key`, optionally expiring after `ttl`.
41    async fn set(&self, key: &str, value: Vec<u8>, ttl: Option<Duration>)
42        -> Result<(), CacheError>;
43    /// Removes a key.
44    async fn invalidate(&self, key: &str) -> Result<(), CacheError>;
45    /// Removes all entries.
46    async fn clear(&self) -> Result<(), CacheError>;
47}
48
49/// Keys given to the byte-oriented [`Cache`] are `&str`, but concrete backends
50/// may need richer keys. [`KeyEncoder`] turns typed keys into canonical strings.
51pub trait KeyEncoder {
52    /// The "shape" of a key, e.g. `"user:{id}:profile"`.
53    fn encode<C: Into<Cow<'static, str>>, R: std::fmt::Display>(parts: (C, R)) -> String;
54}
55
56/// A blanket implementation that formats `{collection}:{id}`.
57pub struct DefaultKeyEncoder;
58
59impl KeyEncoder for DefaultKeyEncoder {
60    fn encode<C: Into<Cow<'static, str>>, R: std::fmt::Display>(parts: (C, R)) -> String {
61        format!("{}:{}", parts.0.into(), parts.1)
62    }
63}
64
65#[cfg(test)]
66mod tests {
67    use super::*;
68
69    #[test]
70    fn default_key_encoder_formats() {
71        assert_eq!(DefaultKeyEncoder::encode(("user", 42)), "user:42");
72        assert_eq!(
73            DefaultKeyEncoder::encode(("session", "abc-123")),
74            "session:abc-123"
75        );
76    }
77}