cache_fn/
cache.rs

1use serde::{de::DeserializeOwned, Serialize};
2use std::collections::hash_map::DefaultHasher;
3use std::future::Future;
4use std::hash::{Hash, Hasher};
5
6use crate::client::WorkerClient;
7use crate::error::CacheError;
8use crate::options::CacheOptions;
9
10pub struct Cache {
11    client: WorkerClient,
12}
13
14type CacheFuture<R> = Box<dyn Future<Output = Result<R, CacheError>> + Send + 'static>;
15impl Cache {
16    pub fn new(options: CacheOptions) -> Self {
17        Self {
18            client: WorkerClient::new(options),
19        }
20    }
21
22    pub async fn invalidate_by_tag(&self, tags: Vec<String>) -> Result<(), CacheError> {
23        self.client.invalidate_tags(&tags).await
24    }
25
26    pub fn cache<F, Fut, Args, R>(
27        &self,
28        func: F,
29        tags: Vec<String>,
30        options: Option<CacheOptions>,
31    ) -> impl Fn(Args) -> CacheFuture<R>
32    where
33        F: Fn(Args) -> Fut + Clone + Send + 'static,
34        Fut: Future<Output = R> + Send + 'static,
35        Args: Clone + Serialize + Send + 'static,
36        R: Serialize + DeserializeOwned + Send + Sync + 'static,
37    {
38        let client = self.client.clone();
39        let mut cache_options = options.unwrap_or_else(|| CacheOptions::default());
40        cache_options.tags = tags;
41
42        move |args: Args| {
43            let func = func.clone();
44            let args_clone = args.clone();
45            let client = client.clone();
46            let options = cache_options.clone();
47
48            Box::new(async move {
49                let mut hasher = DefaultHasher::new();
50                let args_serialized =
51                    serde_json::to_string(&args_clone).map_err(CacheError::Serialization)?;
52                args_serialized.hash(&mut hasher);
53
54                let key = format!("{:x}", hasher.finish());
55                if let Some(cached_result) = client.get::<R>(&key).await? {
56                    return Ok(cached_result);
57                }
58
59                let result = func(args).await;
60                let should_cache = options.should_cache.unwrap_or(true);
61                if should_cache {
62                    client.set(&key, &result).await?;
63                }
64
65                Ok(result)
66            })
67        }
68    }
69}