#![cfg_attr(coverage_nightly, coverage(off))]
use crate::services::cache::{
base::{CacheStats, CacheStrategy},
content_cache::ContentCache,
persistent::PersistentCache,
unified::UnifiedCache,
};
use anyhow::Result;
use async_trait::async_trait;
use parking_lot::RwLock;
use serde::{Deserialize, Serialize};
use std::sync::Arc;
#[derive(Clone)]
pub struct ContentCacheAdapter<T: CacheStrategy> {
inner: Arc<RwLock<ContentCache<T>>>,
}
impl<T: CacheStrategy> ContentCacheAdapter<T> {
#[must_use]
pub fn new(cache: ContentCache<T>) -> Self {
Self {
inner: Arc::new(RwLock::new(cache)),
}
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.inner.read().len() == 0
}
}
#[async_trait]
impl<T> UnifiedCache for ContentCacheAdapter<T>
where
T: CacheStrategy + Send + Sync + Clone + 'static,
T::Key: Send + Sync + 'static,
T::Value: Send + Sync + 'static,
{
type Key = T::Key;
type Value = T::Value;
async fn get(&self, key: &Self::Key) -> Option<Arc<Self::Value>> {
self.inner.read().get(key)
}
async fn put(&self, key: Self::Key, value: Self::Value) -> Result<()> {
self.inner.write().put(key, value);
Ok(())
}
async fn remove(&self, key: &Self::Key) -> Option<Arc<Self::Value>> {
self.inner.write().remove(key)
}
async fn clear(&self) -> Result<()> {
self.inner.write().clear();
Ok(())
}
fn stats(&self) -> Arc<CacheStats> {
Arc::new(self.inner.read().stats.clone())
}
fn size_bytes(&self) -> usize {
self.inner.read().stats.memory_usage()
}
fn len(&self) -> usize {
self.inner.read().len()
}
}
#[derive(Clone)]
pub struct PersistentCacheAdapter<T: CacheStrategy> {
inner: Arc<RwLock<PersistentCache<T>>>,
}
impl<T: CacheStrategy> PersistentCacheAdapter<T> {
#[must_use]
pub fn new(cache: PersistentCache<T>) -> Self {
Self {
inner: Arc::new(RwLock::new(cache)),
}
}
}
#[async_trait]
impl<T> UnifiedCache for PersistentCacheAdapter<T>
where
T: CacheStrategy + Send + Sync + Clone + 'static,
T::Key: Send + Sync + 'static,
T::Value: Serialize + for<'de> Deserialize<'de> + Send + Sync + 'static,
{
type Key = T::Key;
type Value = T::Value;
async fn get(&self, key: &Self::Key) -> Option<Arc<Self::Value>> {
self.inner.read().get(key)
}
async fn put(&self, key: Self::Key, value: Self::Value) -> Result<()> {
self.inner.write().put(key, value)?;
Ok(())
}
async fn remove(&self, key: &Self::Key) -> Option<Arc<Self::Value>> {
self.inner.write().remove(key)
}
async fn clear(&self) -> Result<()> {
self.inner.write().clear()?;
Ok(())
}
fn stats(&self) -> Arc<CacheStats> {
Arc::new(self.inner.read().stats.clone())
}
fn size_bytes(&self) -> usize {
self.inner.read().stats.memory_usage()
}
fn len(&self) -> usize {
self.inner.read().len()
}
}
#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod tests {
use super::*;
use crate::services::cache::strategies::AstCacheStrategy;
#[tokio::test]
async fn test_content_cache_adapter() {
let cache = ContentCache::new(AstCacheStrategy);
let adapter = ContentCacheAdapter::new(cache);
assert_eq!(adapter.len(), 0);
assert!(adapter.is_empty());
}
}
#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod property_tests {
use proptest::prelude::*;
proptest! {
#[test]
fn basic_property_stability(_input in ".*") {
prop_assert!(true);
}
#[test]
fn module_consistency_check(_x in 0u32..1000) {
prop_assert!(_x < 1001);
}
}
}