agentic-forge-core 0.1.0

Blueprint engine for complete project architecture before code generation
Documentation
//! Cache metrics — hit rate, size, evictions.

use std::sync::atomic::{AtomicU64, AtomicUsize, Ordering};

pub struct CacheMetrics {
    hit_count: AtomicU64,
    miss_count: AtomicU64,
    eviction_count: AtomicU64,
    current_size: AtomicUsize,
}

impl CacheMetrics {
    pub fn new() -> Self {
        Self {
            hit_count: AtomicU64::new(0),
            miss_count: AtomicU64::new(0),
            eviction_count: AtomicU64::new(0),
            current_size: AtomicUsize::new(0),
        }
    }

    pub fn record_hit(&self) {
        self.hit_count.fetch_add(1, Ordering::Relaxed);
    }

    pub fn record_miss(&self) {
        self.miss_count.fetch_add(1, Ordering::Relaxed);
    }

    pub fn record_eviction(&self) {
        self.eviction_count.fetch_add(1, Ordering::Relaxed);
    }

    pub fn set_size(&self, size: usize) {
        self.current_size.store(size, Ordering::Relaxed);
    }

    pub fn hits(&self) -> u64 {
        self.hit_count.load(Ordering::Relaxed)
    }

    pub fn misses(&self) -> u64 {
        self.miss_count.load(Ordering::Relaxed)
    }

    pub fn evictions(&self) -> u64 {
        self.eviction_count.load(Ordering::Relaxed)
    }

    pub fn size(&self) -> usize {
        self.current_size.load(Ordering::Relaxed)
    }

    pub fn total_requests(&self) -> u64 {
        self.hits() + self.misses()
    }

    pub fn hit_rate(&self) -> f64 {
        let total = self.total_requests();
        if total == 0 {
            return 0.0;
        }
        self.hits() as f64 / total as f64
    }

    pub fn reset(&self) {
        self.hit_count.store(0, Ordering::Relaxed);
        self.miss_count.store(0, Ordering::Relaxed);
        self.eviction_count.store(0, Ordering::Relaxed);
    }
}

impl Default for CacheMetrics {
    fn default() -> Self {
        Self::new()
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_metrics_initial() {
        let m = CacheMetrics::new();
        assert_eq!(m.hits(), 0);
        assert_eq!(m.misses(), 0);
        assert_eq!(m.hit_rate(), 0.0);
    }

    #[test]
    fn test_metrics_hit_rate() {
        let m = CacheMetrics::new();
        m.record_hit();
        m.record_hit();
        m.record_miss();
        assert!((m.hit_rate() - 0.6667).abs() < 0.01);
    }

    #[test]
    fn test_metrics_reset() {
        let m = CacheMetrics::new();
        m.record_hit();
        m.record_miss();
        m.reset();
        assert_eq!(m.total_requests(), 0);
    }

    #[test]
    fn test_metrics_evictions() {
        let m = CacheMetrics::new();
        m.record_eviction();
        m.record_eviction();
        assert_eq!(m.evictions(), 2);
    }
}