use std::time::Instant;
#[derive(Clone)]
pub struct CacheEntry<R> {
pub value: R,
pub inserted_at: Instant,
pub frequency: u64,
}
impl<R> CacheEntry<R> {
pub fn new(value: R) -> Self {
Self {
value,
inserted_at: Instant::now(),
frequency: 0,
}
}
pub fn is_expired(&self, ttl: Option<u64>) -> bool {
if let Some(ttl_secs) = ttl {
self.inserted_at.elapsed().as_secs() >= ttl_secs
} else {
false
}
}
pub fn increment_frequency(&mut self) {
self.frequency = self.frequency.saturating_add(1);
}
}
use crate::MemoryEstimator;
impl<R: MemoryEstimator> MemoryEstimator for CacheEntry<R> {
fn estimate_memory(&self) -> usize {
let base = std::mem::size_of::<Self>();
let value_size = self.value.estimate_memory();
base + value_size.saturating_sub(std::mem::size_of_val(&self.value))
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::thread;
use std::time::Duration;
#[test]
fn test_new_entry_not_expired() {
let entry = CacheEntry::new(42);
assert_eq!(entry.value, 42);
assert!(!entry.is_expired(Some(10)));
}
#[test]
fn test_entry_expiration() {
let entry = CacheEntry::new("data");
thread::sleep(Duration::from_secs(2));
assert!(entry.is_expired(Some(1)));
assert!(!entry.is_expired(Some(3)));
}
#[test]
fn test_no_ttl_never_expires() {
let entry = CacheEntry::new(100);
thread::sleep(Duration::from_millis(100));
assert!(!entry.is_expired(None));
}
#[test]
fn test_memory_estimation_primitive() {
let entry = CacheEntry::new(42i32);
let estimated = entry.estimate_memory();
assert!(estimated >= std::mem::size_of::<CacheEntry<i32>>());
}
#[test]
fn test_memory_estimation_string() {
let s = String::from("Hello, World!");
let entry = CacheEntry::new(s.clone());
let estimated = entry.estimate_memory();
let expected_min = std::mem::size_of::<CacheEntry<String>>() + s.capacity();
assert!(estimated >= expected_min);
}
#[test]
fn test_memory_estimation_vec() {
let v = vec![1, 2, 3, 4, 5];
let entry = CacheEntry::new(v.clone());
let estimated = entry.estimate_memory();
let expected_min =
std::mem::size_of::<CacheEntry<Vec<i32>>>() + v.capacity() * std::mem::size_of::<i32>();
assert!(estimated >= expected_min);
}
}