use std::time::Duration;
#[derive(Debug, Clone)]
pub struct OxcacheConfig {
pub capacity: u64,
pub ttl: Option<Duration>,
pub tti: Option<Duration>,
}
impl Default for OxcacheConfig {
fn default() -> Self {
Self {
capacity: 10_000,
ttl: None,
tti: None,
}
}
}
use std::any::TypeId;
use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;
use trait_kit::prelude::*;
use crate::backend::{CacheBackend, MokaMemoryBackend};
use crate::error::CacheError;
pub struct OxcacheModule;
impl ModuleMeta for OxcacheModule {
const NAME: &'static str = "oxcache";
fn dependencies() -> &'static [(&'static str, TypeId)] {
&[]
}
}
impl AsyncAutoBuilder for OxcacheModule {
type Capability = Arc<dyn CacheBackend + Send + Sync>;
type Error = CacheError;
fn build<'a>(
kit: &'a AsyncKit,
) -> Pin<Box<dyn Future<Output = Result<Self::Capability, Self::Error>> + Send + 'a>> {
Box::pin(async move {
let config: OxcacheConfig = kit
.config()
.map_err(|e| CacheError::Internal(format!("OxcacheModule: read config: {e}")))?;
let mut builder = MokaMemoryBackend::builder().capacity(config.capacity);
if let Some(ttl) = config.ttl {
builder = builder.ttl(ttl);
}
if let Some(tti) = config.tti {
builder = builder.time_to_idle(tti);
}
let backend = builder.build();
Ok(Arc::new(backend) as Arc<dyn CacheBackend + Send + Sync>)
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::backend::CacheBackend;
use std::any::TypeId;
use std::sync::Arc;
#[test]
fn oxcache_module_meta_name() {
assert_eq!(OxcacheModule::NAME, "oxcache");
}
#[test]
fn oxcache_module_meta_dependencies_empty() {
assert_eq!(OxcacheModule::dependencies(), &[] as &[(&'static str, TypeId)]);
}
#[tokio::test]
async fn oxcache_module_build_returns_cache_capability() {
let mut kit = AsyncKit::new();
kit.set_config(OxcacheConfig::default());
kit.register::<OxcacheModule>().expect("register OxcacheModule");
let kit = kit.build().await.expect("AsyncKit::build");
let cache: Arc<dyn CacheBackend + Send + Sync> = kit.require::<OxcacheModule>().expect("require OxcacheModule");
cache.set("k", b"v".to_vec(), None).await.expect("set");
let got = cache.get("k").await.expect("get");
assert_eq!(got, Some(b"v".to_vec()));
}
#[tokio::test]
async fn oxcache_module_build_reads_config_from_kit() {
let mut kit = AsyncKit::new();
kit.set_config(OxcacheConfig {
capacity: 5,
ttl: None,
tti: None,
});
kit.register::<OxcacheModule>().expect("register OxcacheModule");
let kit = kit.build().await.expect("AsyncKit::build");
let cache: Arc<dyn CacheBackend + Send + Sync> = kit.require::<OxcacheModule>().expect("require OxcacheModule");
for i in 0..6u8 {
cache.set(&format!("k{i}"), vec![i], None).await.expect("set");
}
cache.health_check().await.expect("health_check");
}
#[tokio::test]
async fn oxcache_module_build_is_async() {
let kit = AsyncKit::new();
kit.set_config(OxcacheConfig::default());
let fut = <OxcacheModule as AsyncAutoBuilder>::build(&kit);
let cache: Arc<dyn CacheBackend + Send + Sync> = fut.await.expect("build future resolves");
cache.clear().await.expect("clear");
fn assert_send_sync<T: Send + Sync>() {}
assert_send_sync::<Arc<dyn CacheBackend + Send + Sync>>();
}
}