use std::{fmt, future::Future, sync::Arc, time::Duration};
use serde::{de::DeserializeOwned, Serialize};
use crate::{driver::CacheHandle, CacheError};
tokio::task_local! {
pub(crate) static CURRENT_CACHE: Arc<CacheHandle>;
}
pub fn scope_cache<F: Future>(handle: Arc<CacheHandle>, f: F) -> impl Future<Output = F::Output> {
CURRENT_CACHE.scope(handle, f)
}
pub struct Cache;
impl Cache {
fn handle() -> Result<Arc<CacheHandle>, CacheError> {
CURRENT_CACHE
.try_with(|h| h.clone())
.map_err(|_| CacheError::NotConfigured)
}
pub async fn get<T: DeserializeOwned>(key: &str) -> Result<Option<T>, CacheError> {
let h = Self::handle()?;
let full_key = h.key(key);
match h.driver.get(&full_key).await? {
None => Ok(None),
Some(json) => serde_json::from_str(&json)
.map(Some)
.map_err(|e| CacheError::Deserialize(e.to_string())),
}
}
pub async fn set<T: Serialize>(
key: &str,
value: &T,
ttl: Option<Duration>,
) -> Result<(), CacheError> {
let h = Self::handle()?;
let full_key = h.key(key);
let json =
serde_json::to_string(value).map_err(|e| CacheError::Serialize(e.to_string()))?;
h.driver.set(&full_key, json, ttl).await
}
pub async fn forget(key: &str) -> Result<(), CacheError> {
let h = Self::handle()?;
h.driver.forget(&h.key(key)).await
}
pub async fn flush() -> Result<(), CacheError> {
Self::handle()?.driver.flush().await
}
pub async fn remember<T, F, Fut, E>(key: &str, ttl: Duration, f: F) -> Result<T, CacheError>
where
T: Serialize + DeserializeOwned + Send,
F: FnOnce() -> Fut,
Fut: Future<Output = Result<T, E>>,
E: fmt::Display,
{
if let Some(cached) = Self::get::<T>(key).await? {
return Ok(cached);
}
let value = f().await.map_err(|e| CacheError::Fetch(e.to_string()))?;
Self::set(key, &value, Some(ttl)).await?;
Ok(value)
}
}