rok-cache 0.1.0

Cache façade for the rok ecosystem — Memory/Redis drivers, Cache::get/set/remember
Documentation
use std::time::Duration;

use crate::{drivers::MemoryDriver, CacheError};

#[cfg(feature = "redis")]
use crate::drivers::RedisDriver;

/// Enum-dispatched driver. Cheap to clone (Arc-backed internals).
#[derive(Clone)]
pub enum Driver {
    Memory(MemoryDriver),
    #[cfg(feature = "redis")]
    Redis(RedisDriver),
}

impl Driver {
    pub async fn get(&self, key: &str) -> Result<Option<String>, CacheError> {
        match self {
            Driver::Memory(d) => d.get(key).await,
            #[cfg(feature = "redis")]
            Driver::Redis(d) => d.get(key).await,
        }
    }

    pub async fn set(
        &self,
        key: &str,
        value: String,
        ttl: Option<Duration>,
    ) -> Result<(), CacheError> {
        match self {
            Driver::Memory(d) => d.set(key, value, ttl).await,
            #[cfg(feature = "redis")]
            Driver::Redis(d) => d.set(key, value, ttl).await,
        }
    }

    pub async fn forget(&self, key: &str) -> Result<(), CacheError> {
        match self {
            Driver::Memory(d) => d.forget(key).await,
            #[cfg(feature = "redis")]
            Driver::Redis(d) => d.forget(key).await,
        }
    }

    pub async fn flush(&self) -> Result<(), CacheError> {
        match self {
            Driver::Memory(d) => d.flush().await,
            #[cfg(feature = "redis")]
            Driver::Redis(d) => d.flush().await,
        }
    }
}

/// Build a driver from config strings.  Falls back to `Memory` for unknown names.
pub fn build_driver(name: &str, redis_url: Option<&str>) -> Result<Driver, CacheError> {
    match name {
        #[cfg(feature = "redis")]
        "redis" => {
            let url = redis_url.ok_or(CacheError::MissingRedisUrl)?;
            Ok(Driver::Redis(RedisDriver::new(url)?))
        }
        _ => Ok(Driver::Memory(MemoryDriver::new())),
    }
}

/// Bundles a driver with a key prefix.  Stored task-locally by `CacheLayer`.
#[derive(Clone)]
pub struct CacheHandle {
    pub(crate) driver: Driver,
    pub(crate) prefix: String,
}

impl CacheHandle {
    pub fn new(driver: Driver, prefix: impl Into<String>) -> Self {
        Self {
            driver,
            prefix: prefix.into(),
        }
    }

    pub(crate) fn key(&self, k: &str) -> String {
        if self.prefix.is_empty() {
            k.to_string()
        } else {
            format!("{}{}", self.prefix, k)
        }
    }
}