Skip to main content

cachet_tier/
dynamic.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Dynamic cache tier wrapper for type erasure.
5
6use std::fmt::Debug;
7use std::sync::Arc;
8
9use crate::tier::DynCacheTier;
10use crate::{CacheEntry, CacheTier, Error, SizeError};
11
12/// A cloneable dynamic cache tier with type erasure.
13///
14/// `DynamicCache` wraps a trait object in an `Arc` to enable cloning while maintaining
15/// dynamic dispatch. Use this when you need to erase the concrete storage type
16/// in multi-tier cache hierarchies.
17///
18/// # Examples
19///
20/// ```ignore
21/// let dynamic = DynamicCache::new(some_tier);
22///
23/// // DynamicCache is Clone
24/// let clone = dynamic.clone();
25/// ```
26pub struct DynamicCache<K, V>(Arc<DynCacheTier<'static, K, V>>);
27
28impl<K, V> DynamicCache<K, V> {
29    /// Creates a new dynamic cache from any `CacheTier` implementation.
30    pub fn new<T>(strategy: T) -> Self
31    where
32        T: CacheTier<K, V> + Send + Sync + 'static,
33    {
34        Self(DynCacheTier::new_arc(strategy))
35    }
36}
37
38impl<K, V> Debug for DynamicCache<K, V> {
39    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
40        f.debug_struct("DynamicCache").finish()
41    }
42}
43
44impl<K, V> Clone for DynamicCache<K, V> {
45    fn clone(&self) -> Self {
46        Self(Arc::clone(&self.0))
47    }
48}
49
50impl<K: Send + Sync, V: Send> CacheTier<K, V> for DynamicCache<K, V> {
51    async fn get(&self, key: &K) -> Result<Option<CacheEntry<V>>, Error> {
52        self.0.get(key).await
53    }
54
55    async fn insert(&self, key: K, entry: CacheEntry<V>) -> Result<(), Error> {
56        self.0.insert(key, entry).await
57    }
58
59    async fn invalidate(&self, key: &K) -> Result<(), Error> {
60        self.0.invalidate(key).await
61    }
62
63    async fn clear(&self) -> Result<(), Error> {
64        self.0.clear().await
65    }
66
67    async fn len(&self) -> Result<u64, SizeError> {
68        self.0.len().await
69    }
70}
71
72#[cfg(test)]
73mod tests {
74    use super::*;
75    use crate::MockCache;
76
77    #[cfg_attr(miri, ignore)]
78    #[tokio::test]
79    async fn clone_shares_state() {
80        let cache = MockCache::<String, i32>::new();
81        let dynamic = DynamicCache::new(cache);
82        let clone = dynamic.clone();
83
84        dynamic.insert("key".to_string(), CacheEntry::new(42)).await.unwrap();
85
86        let entry = clone.get(&"key".to_string()).await.unwrap().unwrap();
87        assert_eq!(*entry.value(), 42);
88    }
89}