oxcache 0.3.7

A high-performance multi-level cache library for Rust with L1 (memory) and L2 (Redis) caching.
// Copyright (c) 2025-2026 Kirky.X
// SPDX-License-Identifier: MIT
//! Cache API - 核心缓存结构和方法

mod api_impl;
mod basic_ops;
mod batch_ops;
mod bytes_ops;
mod macros;

use crate::backend::{CacheBackend, SyncCacheBackend};
use crate::infra::UnifiedSerializer;
use std::sync::Arc;

/// 核心 Cache 类型
pub struct Cache<K, V> {
    pub(crate) backend: Arc<dyn CacheBackend>,
    /// 同步后端(可选)。当 builder 启用 `sync_mode` 且后端支持 SyncCacheBackend 时填充。
    /// sync API(get_sync/set_sync 等)通过此字段派发;为 None 时返回 Err(NotSupported)。
    pub(crate) backend_sync: Option<Arc<dyn SyncCacheBackend>>,
    #[cfg(any(feature = "serialization", feature = "full"))]
    pub(crate) serializer: Arc<crate::infra::JsonSerializer>,
    pub(crate) unified_serializer: UnifiedSerializer,
    _phantom: std::marker::PhantomData<(K, V)>,
}

#[cfg(test)]
mod tests {
    use super::*;

    #[tokio::test]
    async fn test_cache_memory() {
        let cache: Cache<String, String> = Cache::memory().await.unwrap();
        assert!(cache.health_check().await.is_ok());
    }

    #[tokio::test]
    async fn test_cache_new_with_backend() {
        use crate::backend::MokaMemoryBackend;
        let backend = Arc::new(MokaMemoryBackend::new());
        let cache: Cache<String, String> = Cache::new_with_backend(backend);
        assert!(cache.health_check().await.is_ok());
    }

    #[tokio::test]
    async fn test_cache_builder_default() {
        let cache: Cache<String, i32> = Cache::builder().build().await.unwrap();
        cache.set(&"key".to_string(), &42).await.unwrap();
        let val = cache.get(&"key".to_string()).await.unwrap().unwrap();
        assert_eq!(val, 42);
    }

    #[tokio::test]
    async fn test_cache_serializer_pool() {
        let cache: Cache<String, String> = Cache::builder().build().await.unwrap();
        cache.set(&"test".to_string(), &"value".to_string()).await.unwrap();
        assert!(cache.get(&"test".to_string()).await.unwrap().is_some());
    }

    #[tokio::test]
    async fn test_cache_unified_serializer() {
        let cache: Cache<String, Vec<u8>> = Cache::builder().build().await.unwrap();
        let data = b"binary data".to_vec();
        cache.set(&"bin".to_string(), &data.clone()).await.unwrap();
        let retrieved = cache.get(&"bin".to_string()).await.unwrap().unwrap();
        assert_eq!(retrieved, data);
    }

    #[tokio::test]
    async fn test_cache_new() {
        // Cache::new() uses MokaMemoryBackend under the memory feature
        let cache: Cache<String, String> = Cache::new();
        assert!(cache.health_check().await.is_ok());

        cache.set(&"key".to_string(), &"value".to_string()).await.unwrap();
        let val = cache.get(&"key".to_string()).await.unwrap().unwrap();
        assert_eq!(val, "value");
    }

    #[tokio::test]
    async fn test_cache_with_dependencies() {
        use crate::backend::MokaMemoryBackend;
        let backend = Arc::new(MokaMemoryBackend::new());
        let cache: Cache<String, i32> = Cache::with_dependencies(backend);

        assert!(cache.health_check().await.is_ok());
        cache.set(&"k".to_string(), &42).await.unwrap();
        assert_eq!(cache.get(&"k".to_string()).await.unwrap().unwrap(), 42);
    }

    #[tokio::test]
    async fn test_cache_default() {
        // Default impl delegates to Cache::new()
        let cache: Cache<String, String> = Cache::default();
        assert!(cache.health_check().await.is_ok());

        cache.set(&"k".to_string(), &"v".to_string()).await.unwrap();
        assert_eq!(cache.get(&"k".to_string()).await.unwrap().unwrap(), "v".to_string());
    }

    #[test]
    fn test_cache_debug() {
        let cache: Cache<String, String> = Cache::new();
        let debug_str = format!("{:?}", cache);
        assert!(debug_str.contains("Cache"));
    }

    #[tokio::test]
    async fn test_cache_new_with_backend_custom() {
        // Verify new_with_backend works with a builder-configured Moka backend
        use crate::backend::MokaMemoryBackend;
        let backend = Arc::new(MokaMemoryBackend::builder().capacity(50).build());
        let cache: Cache<String, Vec<u8>> = Cache::new_with_backend(backend);

        let data = b"hello".to_vec();
        cache.set(&"k".to_string(), &data.clone()).await.unwrap();
        assert_eq!(cache.get(&"k".to_string()).await.unwrap().unwrap(), data);
    }

    #[tokio::test]
    async fn test_cache_builder_with_backend_arc() {
        // Verify builder() works with a pre-built backend
        use crate::backend::MokaMemoryBackend;
        let backend = Arc::new(MokaMemoryBackend::new());
        let cache: Cache<String, i32> = Cache::builder().backend_arc(backend).build().await.unwrap();

        cache.set(&"n".to_string(), &7).await.unwrap();
        assert_eq!(cache.get(&"n".to_string()).await.unwrap().unwrap(), 7);
    }
}