Skip to main content

lrwf_core/cache/
cache_ext.rs

1//! Typed cache extensions — matches ASP.NET Core's `DistributedCacheExtensions`.
2//!
3//| ASP.NET Core                          | LRWF                                    |
4//|---------------------------------------|-----------------------------------------|
5//| `GetStringAsync(cache, key, token)`   | `get_string(&self, key)`                |
6//| `SetStringAsync(cache, key, val, opts)`| `set_string(&self, key, &val, opts)`    |
7
8use super::options::DistributedCacheEntryOptions;
9use super::trait_def::{CacheError, IDistributedCache, Result};
10use std::future::Future;
11
12#[async_trait::async_trait]
13pub trait DistributedCacheExtensions: IDistributedCache {
14    async fn get_string<T: serde::de::DeserializeOwned + Send>(
15        &self,
16        key: &str,
17    ) -> Result<Option<T>>;
18    async fn set_string<T: serde::Serialize + Send + Sync>(
19        &self,
20        key: &str,
21        val: &T,
22        opts: &DistributedCacheEntryOptions,
23    ) -> Result<()>;
24    async fn get_or_create<T, F, Fut>(
25        &self,
26        key: &str,
27        factory: F,
28        opts: &DistributedCacheEntryOptions,
29    ) -> Result<T>
30    where
31        T: serde::Serialize + serde::de::DeserializeOwned + Send + Sync + Clone + 'static,
32        F: FnOnce() -> Fut + Send,
33        Fut: Future<Output = T> + Send;
34    async fn get_or_try_create<T, F, Fut, E>(
35        &self,
36        key: &str,
37        factory: F,
38        opts: &DistributedCacheEntryOptions,
39    ) -> Result<T>
40    where
41        T: serde::Serialize + serde::de::DeserializeOwned + Send + Sync + Clone + 'static,
42        F: FnOnce() -> Fut + Send,
43        Fut: Future<Output = std::result::Result<T, E>> + Send,
44        E: std::fmt::Display;
45}
46
47#[async_trait::async_trait]
48impl<T: IDistributedCache + ?Sized + Sync> DistributedCacheExtensions for T {
49    async fn get_string<U: serde::de::DeserializeOwned + Send>(
50        &self,
51        key: &str,
52    ) -> Result<Option<U>> {
53        let bytes = self.get(key).await?;
54        match bytes {
55            Some(data) => Ok(Some(
56                serde_json::from_slice(&data)
57                    .map_err(|e| CacheError::Serialization(e.to_string()))?,
58            )),
59            None => Ok(None),
60        }
61    }
62
63    async fn set_string<U: serde::Serialize + Send + Sync>(
64        &self,
65        key: &str,
66        val: &U,
67        opts: &DistributedCacheEntryOptions,
68    ) -> Result<()> {
69        let data = serde_json::to_vec(val).map_err(|e| CacheError::Serialization(e.to_string()))?;
70        if opts.size_limit > 0 && data.len() > opts.size_limit {
71            return Err(CacheError::Message(format!(
72                "value size {} exceeds limit {}",
73                data.len(),
74                opts.size_limit
75            )));
76        }
77        self.set(key, data, Some(opts)).await
78    }
79
80    async fn get_or_create<U, F, Fut>(
81        &self,
82        key: &str,
83        factory: F,
84        opts: &DistributedCacheEntryOptions,
85    ) -> Result<U>
86    where
87        U: serde::Serialize + serde::de::DeserializeOwned + Send + Sync + Clone + 'static,
88        F: FnOnce() -> Fut + Send,
89        Fut: Future<Output = U> + Send,
90    {
91        if let Some(val) = self.get_string::<U>(key).await? {
92            return Ok(val);
93        }
94        let val = factory().await;
95        self.set_string(key, &val, opts).await?;
96        Ok(val)
97    }
98
99    async fn get_or_try_create<U, F, Fut, E>(
100        &self,
101        key: &str,
102        factory: F,
103        opts: &DistributedCacheEntryOptions,
104    ) -> Result<U>
105    where
106        U: serde::Serialize + serde::de::DeserializeOwned + Send + Sync + Clone + 'static,
107        F: FnOnce() -> Fut + Send,
108        Fut: Future<Output = std::result::Result<U, E>> + Send,
109        E: std::fmt::Display,
110    {
111        if let Some(val) = self.get_string::<U>(key).await? {
112            return Ok(val);
113        }
114        let val = factory()
115            .await
116            .map_err(|e| CacheError::Message(e.to_string()))?;
117        self.set_string(key, &val, opts).await?;
118        Ok(val)
119    }
120}