use cachet_tier::CacheEntry;
#[derive(Debug, Clone)]
pub enum CacheOperation<K, V> {
Get(GetRequest<K>),
Insert(InsertRequest<K, V>),
Invalidate(InvalidateRequest<K>),
Clear,
}
#[derive(Debug, Clone)]
pub struct GetRequest<K> {
pub key: K,
}
impl<K> GetRequest<K> {
#[must_use]
pub fn new(key: K) -> Self {
Self { key }
}
}
#[derive(Debug, Clone)]
pub struct InsertRequest<K, V> {
pub key: K,
pub entry: CacheEntry<V>,
}
impl<K, V> InsertRequest<K, V> {
#[must_use]
pub fn new(key: K, entry: CacheEntry<V>) -> Self {
Self { key, entry }
}
}
#[derive(Debug, Clone)]
pub struct InvalidateRequest<K> {
pub key: K,
}
impl<K> InvalidateRequest<K> {
#[must_use]
pub fn new(key: K) -> Self {
Self { key }
}
}
#[derive(Debug, Clone)]
pub enum CacheResponse<V> {
Get(Option<CacheEntry<V>>),
Insert,
Invalidate,
Clear,
}
impl<V> CacheResponse<V> {
#[must_use]
pub fn is_hit(&self) -> bool {
matches!(self, Self::Get(Some(_)))
}
#[must_use]
pub fn is_miss(&self) -> bool {
matches!(self, Self::Get(None))
}
#[must_use]
pub fn into_entry(self) -> Option<CacheEntry<V>> {
match self {
Self::Get(entry) => entry,
_ => None,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn get_request_new() {
let req = GetRequest::new("key".to_string());
assert_eq!(req.key, "key");
}
#[test]
fn insert_request_new() {
let entry = CacheEntry::new(42);
let req = InsertRequest::new("key".to_string(), entry);
assert_eq!(req.key, "key");
assert_eq!(*req.entry, 42);
}
#[test]
fn invalidate_request_new() {
let req = InvalidateRequest::new("key".to_string());
assert_eq!(req.key, "key");
}
#[test]
fn cache_operation_get() {
let op: CacheOperation<String, i32> = CacheOperation::Get(GetRequest::new("key".to_string()));
assert!(matches!(op, CacheOperation::Get(_)));
}
#[test]
fn cache_operation_insert() {
let entry = CacheEntry::new(42);
let op = CacheOperation::Insert(InsertRequest::new("key".to_string(), entry));
assert!(matches!(op, CacheOperation::Insert(_)));
}
#[test]
fn cache_operation_invalidate() {
let op: CacheOperation<String, i32> = CacheOperation::Invalidate(InvalidateRequest::new("key".to_string()));
assert!(matches!(op, CacheOperation::Invalidate(_)));
}
#[test]
fn cache_operation_clear() {
let op: CacheOperation<String, i32> = CacheOperation::Clear;
assert!(matches!(op, CacheOperation::Clear));
}
#[test]
fn cache_response_is_hit() {
let entry = CacheEntry::new(42);
let response: CacheResponse<i32> = CacheResponse::Get(Some(entry));
assert!(response.is_hit());
assert!(!response.is_miss());
}
#[test]
fn cache_response_is_miss() {
let response: CacheResponse<i32> = CacheResponse::Get(None);
assert!(response.is_miss());
assert!(!response.is_hit());
}
#[test]
fn cache_response_into_entry_with_value() {
let entry = CacheEntry::new(42);
let response = CacheResponse::Get(Some(entry));
let extracted = response.into_entry();
assert!(extracted.is_some());
assert_eq!(*extracted.unwrap(), 42);
}
#[test]
fn cache_response_into_entry_without_value() {
let response: CacheResponse<i32> = CacheResponse::Get(None);
let extracted = response.into_entry();
assert!(extracted.is_none());
}
#[test]
fn cache_response_into_entry_non_get() {
let response: CacheResponse<i32> = CacheResponse::Insert;
let extracted = response.into_entry();
assert!(extracted.is_none());
}
#[test]
fn cache_response_is_hit_false_for_non_get() {
assert!(!CacheResponse::<i32>::Insert.is_hit());
assert!(!CacheResponse::<i32>::Invalidate.is_hit());
assert!(!CacheResponse::<i32>::Clear.is_hit());
}
#[test]
fn cache_response_is_miss_false_for_non_get() {
assert!(!CacheResponse::<i32>::Insert.is_miss());
assert!(!CacheResponse::<i32>::Invalidate.is_miss());
assert!(!CacheResponse::<i32>::Clear.is_miss());
}
}