use std::collections::BTreeMap;
use std::sync::{Arc, Mutex};
use std::time::{Duration, Instant};
use std::collections::HashMap;
use std::collections::VecDeque;
#[derive(Debug, Clone)]
pub struct CacheEntry<T> {
pub data: T,
pub created_at: Instant,
pub last_accessed: Instant,
pub access_count: usize,
pub key: String,
}
#[derive(Debug, Clone)]
pub struct CacheStats {
pub hits: u64,
pub misses: u64,
pub size: usize,
pub max_size: usize,
pub total_accesses: u64,
pub created_at: Instant,
}
impl Default for CacheStats {
fn default() -> Self {
Self {
hits: 0,
misses: 0,
size: 0,
max_size: 0,
total_accesses: 0,
created_at: Instant::now(),
}
}
}
impl CacheStats {
pub fn hit_rate(&self) -> f64 {
let total: _ = self.hits + self.misses;
if total == 0 {
0.0
} else {
self.hits as f64 / total as f64
}
}
pub fn efficiency_score(&self) -> f64 {
self.hit_rate() * 100.0
}
}
#[derive(Debug, Clone)]
pub struct CacheConfig {
pub max_size: usize,
pub default_ttl: Duration,
pub cleanup_interval: Duration,
pub prewarm_threshold: usize,
pub enable_lru: bool,
pub enable_ttl: bool,
}
impl Default for CacheConfig {
fn default() -> Self {
Self {
max_size: 1000,
default_ttl: Duration::from_secs(3600), cleanup_interval: Duration::from_secs(300), prewarm_threshold: 4,
enable_lru: true,
enable_ttl: true,
}
}
}
pub struct SmartCache<T> {
cache: Arc<Mutex<HashMap<String, CacheEntry<T>>>>,
lru_queue: Arc<Mutex<VecDeque<String>>>,
access_frequency: Arc<Mutex<HashMap<String, usize>>>,
config: CacheConfig,
stats: Arc<Mutex<CacheStats>>,
last_cleanup: Arc<Mutex<Instant>>,
}
#[derive(Debug, Clone)]
pub enum AccessPattern {
Hot,
Warm,
Cold,
}
impl<T> SmartCache<T> {
pub fn new(config: CacheConfig) -> Self {
Self {
cache: Arc::new(Mutex::new(HashMap::new())),
lru_queue: Arc::new(Mutex::new(VecDeque::new())),
access_frequency: Arc::new(Mutex::new(HashMap::new())),
config,
stats: Arc::new(Mutex::new(CacheStats::default())),
last_cleanup: Arc::new(Mutex::new(Instant::now())),
}
}
pub fn with_default_config() -> Self {
Self::new(CacheConfig::default())
}
pub fn get(&self, key: &str) -> Option<T>
where
T: Clone,
{
let (cache_size, data) = {
let mut cache = self.cache.lock().unwrap();
let size: _ = cache.len();
let data: _ = cache.get_mut(key).map(|entry| {
entry.last_accessed = Instant::now();
entry.access_count += 1;
entry.data.clone()
});
(size, data)
};
if data.is_none() {
{
let mut stats = self.stats.lock().unwrap();
stats.misses += 1;
stats.total_accesses += 1;
}
return None;
}
{
let mut access_freq = self.access_frequency.lock().unwrap();
*access_freq.entry(key.to_string()).or_insert(0) += 1;
}
if self.config.enable_lru {
self.update_lru_queue(key);
}
{
let mut stats = self.stats.lock().unwrap();
stats.hits += 1;
stats.total_accesses += 1;
stats.size = cache_size;
}
data
}
pub fn set(&self, key: String, data: T) {
let mut cache = self.cache.lock().unwrap();
if cache.len() >= self.config.max_size && !cache.contains_key(&key) {
self.evict_lru_item(&mut cache);
}
let now: _ = Instant::now();
let entry: _ = CacheEntry {
data,
created_at: now,
last_accessed: now,
access_count: 1,
key: key.clone(),
};
cache.insert(key.clone(), entry);
if self.config.enable_lru {
let mut lru_queue = self.lru_queue.lock().unwrap();
lru_queue.retain(|k| k != &key);
lru_queue.push_back(key.clone());
}
{
let mut access_freq = self.access_frequency.lock().unwrap();
access_freq.entry(key).or_insert(0);
}
{
let mut stats = self.stats.lock().unwrap();
stats.size = cache.len();
}
}
pub fn set_many(&self, items: HashMap<String, T>) {
for (key, data) in items {
self.set(key, data);
}
}
pub fn contains(&self, key: &str) -> bool {
let cache: _ = self.cache.lock().unwrap();
cache.contains_key(key)
}
pub fn len(&self) -> usize {
let cache: _ = self.cache.lock().unwrap();
cache.len()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn get_stats(&self) -> CacheStats {
let stats: _ = self.stats.lock().unwrap();
stats.clone()
}
pub fn get_access_pattern(&self, key: &str) -> AccessPattern {
let access_freq: _ = self.access_frequency.lock().unwrap();
let count: _ = access_freq.get(key).unwrap_or(&0);
if *count >= self.config.prewarm_threshold {
AccessPattern::Hot
} else if *count >= 2 {
AccessPattern::Warm
} else {
AccessPattern::Cold
}
}
pub fn cleanup_expired(&self) {
let mut cache = self.cache.lock().unwrap();
let mut access_freq = self.access_frequency.lock().unwrap();
let mut lru_queue = self.lru_queue.lock().unwrap();
if !self.config.enable_ttl {
return;
}
let now: _ = Instant::now();
let keys_to_remove: Vec<String> = cache
.iter()
.filter(|(_, entry)| now.duration_since(entry.created_at) > self.config.default_ttl)
.map(|(key, _)| key.clone())
.collect();
for key in keys_to_remove {
cache.remove(&key);
access_freq.remove(&key);
lru_queue.retain(|k| k != &key);
}
{
let mut stats = self.stats.lock().unwrap();
stats.size = cache.len();
}
}
pub fn prewarm(&self, keys: Vec<String>) {
let access_freq: _ = self.access_frequency.lock().unwrap();
for key in keys {
let count: _ = access_freq.get(&key).unwrap_or(&0);
if *count >= self.config.prewarm_threshold {
}
}
}
pub fn clear(&self) {
let mut cache = self.cache.lock().unwrap();
let mut access_freq = self.access_frequency.lock().unwrap();
let mut lru_queue = self.lru_queue.lock().unwrap();
cache.clear();
access_freq.clear();
lru_queue.clear();
{
let mut stats = self.stats.lock().unwrap();
*stats = CacheStats::default();
stats.created_at = Instant::now();
}
}
pub fn keys(&self) -> Vec<String> {
let cache: _ = self.cache.lock().unwrap();
cache.keys().cloned().collect()
}
pub fn maintain(&self) {
let last_cleanup: _ = *self.last_cleanup.lock().unwrap();
if Instant::now().duration_since(last_cleanup) > self.config.cleanup_interval {
self.cleanup_expired();
{
let mut last_cleanup = self.last_cleanup.lock().unwrap();
*last_cleanup = Instant::now();
}
}
}
fn update_lru_queue(&self, key: &str) {
let mut lru_queue = self.lru_queue.lock().unwrap();
lru_queue.retain(|k| k != key);
lru_queue.push_back(key.to_string());
}
fn evict_lru_item(&self, cache: &mut HashMap<String, CacheEntry<T>>) {
if !self.config.enable_lru {
return;
}
let mut lru_queue = self.lru_queue.lock().unwrap();
let mut access_freq = self.access_frequency.lock().unwrap();
if let Some(lru_key) = lru_queue.pop_front() {
cache.remove(&lru_key);
access_freq.remove(&lru_key);
}
}
pub fn get_efficiency_report(&self) -> String {
let stats: _ = self.get_stats();
let hit_rate: _ = stats.hit_rate();
let efficiency: _ = stats.efficiency_score();
format!(
"Cache Efficiency Report:\n\
- Hit Rate: {:.2}%\n\
- Efficiency Score: {:.1}/100\n\
- Size: {}/{}\n\
- Total Accesses: {}\n\
- Cache Hits: {}\n\
- Cache Misses: {}",
hit_rate * 100.0,
efficiency,
stats.size,
stats.max_size,
stats.total_accesses,
stats.hits,
stats.misses
)
}
}
pub fn create_smart_cache<T>(max_size: usize, ttl_seconds: u64) -> SmartCache<T> {
let config: _ = CacheConfig {
max_size,
default_ttl: Duration::from_secs(ttl_seconds),
..Default::default()
};
SmartCache::new(config)
}
pub fn create_high_performance_cache<T>(max_size: usize) -> SmartCache<T> {
let config: _ = CacheConfig {
max_size,
default_ttl: Duration::from_secs(7200), prewarm_threshold: 5,
enable_lru: true,
enable_ttl: true,
..Default::default()
};
SmartCache::new(config)
}
pub fn create_persistent_cache<T>(max_size: usize) -> SmartCache<T> {
let config: _ = CacheConfig {
max_size,
default_ttl: Duration::from_secs(86400), cleanup_interval: Duration::from_secs(3600), prewarm_threshold: 2,
enable_lru: true,
enable_ttl: true,
..Default::default()
};
SmartCache::new(config)
}
#[cfg(test)]
mod tests {
#[test]
fn test_cache_creation() {
let cache: _ = SmartCache::<String>::with_default_config();
assert!(cache.is_empty());
assert_eq!(cache.len(), 0);
}
#[test]
fn test_cache_set_and_get() {
let cache: _ = SmartCache::<String>::with_default_config();
cache.set("key1".to_string(), "value1".to_string());
assert!(cache.contains("key1"));
assert_eq!(cache.len(), 1);
let value: _ = cache.get("key1");
assert!(value.is_some());
assert_eq!(value.unwrap(), "value1");
}
#[test]
fn test_cache_miss() {
let cache: _ = SmartCache::<String>::with_default_config();
let value: _ = cache.get("nonexistent");
assert!(value.is_none());
}
#[test]
fn test_cache_stats() {
let cache: _ = SmartCache::<String>::with_default_config();
let stats: _ = cache.get_stats();
assert_eq!(stats.hits, 0);
assert_eq!(stats.misses, 1); cache.set("key".to_string(), "value".to_string());
let _: _ = cache.get("key");
let stats: _ = cache.get_stats();
assert_eq!(stats.hits, 1);
}
#[test]
fn test_cache_clear() {
let cache: _ = SmartCache::<String>::with_default_config();
cache.set("key1".to_string(), "value1".to_string());
cache.set("key2".to_string(), "value2".to_string());
assert_eq!(cache.len(), 2);
cache.clear();
assert!(cache.is_empty());
}
#[test]
fn test_access_pattern() {
let cache: _ = SmartCache::<String>::with_default_config();
cache.set("hot".to_string(), "value".to_string());
cache.set("warm".to_string(), "value".to_string());
cache.set("cold".to_string(), "value".to_string());
for _ in 0..5 {
let _: _ = cache.get("hot");
}
for _ in 0..3 {
let _: _ = cache.get("warm");
}
let _: _ = cache.get("cold");
assert!(matches!(cache.get_access_pattern("hot"), AccessPattern::Hot));
assert!(matches!(cache.get_access_pattern("warm"), AccessPattern::Warm));
assert!(matches!(cache.get_access_pattern("cold"), AccessPattern::Cold));
}
}