trelent-hyok 0.1.12

A Rust library implementing Hold Your Own Key (HYOK) encryption patterns with support for multiple cloud providers
Documentation
mod moka;
mod custom_cache;

/// This module provides various cache implementations and a shared `DEKCacheTrait`
/// for storing and retrieving data by an identifier.
pub use custom_cache::*;
pub use moka::*;

#[cfg(feature = "debug")]
use std::collections::HashMap;
#[cfg(feature = "debug")]
use std::sync::Mutex;

use crate::error::cache::CacheError;

/// A trait that defines the basic operations for a Data Encryption Key (DEK) cache.
///
/// The `Identifier` associated type is used to look up and store values in the cache.
/// Implementors of this trait must provide strategies for both retrieving items
/// (`get`) and inserting items (`set`) by `Identifier`.
pub trait DEKCacheTrait {
    type Identifier: AsRef<[u8]>;
    fn get(&self, k: &Self::Identifier) -> Option<Vec<u8>>;
    fn set(&self, k: Self::Identifier, v: Vec<u8>) -> Result<Vec<u8>, CacheError>;
}

#[cfg(feature = "debug")]
/// A debug cache that implements the [`DEKCacheTrait`] using an in-memory
/// [`HashMap`], protected by a [`Mutex`]. This cache is only available when
/// the "debug" feature is enabled.
pub struct DebugCache {
    cache: Mutex<HashMap<String, Vec<u8>>>,
}

#[cfg(feature = "debug")]
impl DEKCacheTrait for DebugCache {
    type Identifier = String;
    fn get(&self, k: &String) -> Option<Vec<u8>> {
        let cache = self.cache.lock();
        let mut hasher = md5::Context::new();
        hasher.consume(k);
        let hash_name = hex::encode(hasher.compute().0);
        match cache {
            Ok(cache) => cache.get(&hash_name).map(|thing| thing.clone()),
            Err(_) => None,
        }
    }

    fn set(&self, k: String, v: Vec<u8>) -> Result<Vec<u8>, CacheError> {
        let data = self.cache.lock();
        match data {
            Ok(mut data) => {
                let mut hasher = md5::Context::new();
                hasher.consume(k);
                let hash_name = hex::encode(hasher.compute().0);
                data.insert(hash_name.clone(), v);
                data.get(&hash_name).cloned().ok_or(CacheError("Could not insert!".to_string()))
            }
            Err(_) => Err(CacheError("Mutex error!".to_string())),
        }
    }
}

/// An enum representing the different cache implementations that can be used.
///
/// * `Custom` uses a user-defined closure-based cache.
/// * `Moka` uses a [mini-moka](https://crates.io/crates/mini-moka)-based cache.
/// * `NoCache` performs no caching at all.
pub enum DEKCache {
    Custom(CustomCache),
    Moka(MokaCache),
    NoCache,
}

impl DEKCache {
    /// Retrieves an item from the underlying cache implementation.
    ///
    /// # Arguments
    ///
    /// * `k` - A reference to the key used to look up the data in the cache.
    ///
    /// # Returns
    ///
    /// `Some(Vec<u8>)` if the item is found, or `None` if not present.
    pub fn get(&self, k: &String) -> Option<Vec<u8>> {
        match self {
            DEKCache::Custom(cache) => cache.get(k),
            DEKCache::Moka(cache) => cache.get(k),
            DEKCache::NoCache => None,
        }
    }

    /// Inserts an item into the underlying cache. Returns the stored data on success.
    ///
    /// # Arguments
    ///
    /// * `k` - The key under which the data should be stored.
    /// * `v` - The data to be stored in the cache.
    ///
    /// # Returns
    ///
    /// `Ok(Vec<u8>)` containing the new value if successful, or a [`CacheError`] on failure.
    pub fn set(&self, k: String, v: Vec<u8>) -> Result<Vec<u8>, CacheError> {
        match self {
            DEKCache::Custom(cache) => cache.set(k, v),
            DEKCache::Moka(cache) => cache.set(k, v),
            DEKCache::NoCache => Ok(v),
        }
    }
}