lambdust 0.1.1

A Scheme dialect with gradual typing and effect systems
//! Memory management and usage tracking for metaprogramming operations.
//!
//! This module provides memory usage tracking, allocation monitoring,
//! and basic memory management facilities for dynamic evaluation contexts.

use std::collections::{HashMap, VecDeque};
use std::sync::{Arc, RwLock};
use std::time::Instant;

/// Memory manager for garbage collection and monitoring.
#[derive(Debug)]
pub struct MemoryManager {
    /// Memory usage tracking
    usage_tracker: MemoryUsageTracker,
    /// GC policies
    gc_policies: HashMap<String, super::gc_policy::GcPolicy>,
    /// Memory pressure monitoring
    pressure_monitor: super::memory_pressure::MemoryPressureMonitor,
}

/// Memory usage tracker.
#[derive(Debug)]
pub struct MemoryUsageTracker {
    /// Current memory usage
    current_usage: Arc<RwLock<usize>>,
    /// Peak memory usage
    pub peak_usage: usize,
    /// Usage history
    usage_history: VecDeque<MemoryUsagePoint>,
    /// Maximum history length
    max_history: usize,
}

/// Point in memory usage history.
#[derive(Debug, Clone)]
pub struct MemoryUsagePoint {
    /// Timestamp
    pub timestamp: Instant,
    /// Memory usage in bytes
    pub usage: usize,
    /// Number of allocations
    pub allocations: usize,
}

/// Memory statistics.
#[derive(Debug, Clone)]
pub struct MemoryStats {
    /// Current memory usage
    pub current_usage: usize,
    /// Peak memory usage
    pub peak_usage: usize,
    /// Current memory pressure level
    pub pressure_level: super::memory_pressure::MemoryPressureLevel,
    /// Number of GC runs
    pub gc_runs: usize,
}

impl MemoryManager {
    /// Creates a new memory manager.
    pub fn new() -> Self {
        Self {
            usage_tracker: MemoryUsageTracker::new(),
            gc_policies: HashMap::new(),
            pressure_monitor: super::memory_pressure::MemoryPressureMonitor::new(),
        }
    }

    /// Triggers garbage collection.
    pub fn collect_garbage(&self) -> crate::diagnostics::Result<usize> {
        // Placeholder implementation - would integrate with actual GC
        let collected = 1024; // Mock collected bytes
        
        // Update usage tracking would go here
        // self.usage_tracker.record_collection(collected);
        
        Ok(collected)
    }

    /// Gets current memory usage.
    pub fn current_usage(&self) -> usize {
        *self.usage_tracker.current_usage.read().unwrap()
    }

    /// Gets memory statistics.
    pub fn get_memory_stats(&self) -> MemoryStats {
        MemoryStats {
            current_usage: self.current_usage(),
            peak_usage: self.usage_tracker.peak_usage,
            pressure_level: self.pressure_monitor.pressure_level,
            gc_runs: self.usage_tracker.usage_history.len(),
        }
    }

    /// Sets a garbage collection policy.
    pub fn set_gc_policy(&mut self, name: String, policy: super::gc_policy::GcPolicy) {
        self.gc_policies.insert(name, policy);
    }

    /// Gets a garbage collection policy.
    pub fn get_gc_policy(&self, name: &str) -> Option<&super::gc_policy::GcPolicy> {
        self.gc_policies.get(name)
    }

    /// Forces immediate garbage collection.
    pub fn force_gc(&self) -> crate::diagnostics::Result<usize> {
        self.collect_garbage()
    }

    /// Gets memory pressure level.
    pub fn memory_pressure(&self) -> super::memory_pressure::MemoryPressureLevel {
        self.pressure_monitor.pressure_level
    }

    /// Updates memory usage.
    pub fn update_usage(&mut self, usage: usize) {
        *self.usage_tracker.current_usage.write().unwrap() = usage;
        
        if usage > self.usage_tracker.peak_usage {
            self.usage_tracker.peak_usage = usage;
        }

        // Record usage point
        let point = MemoryUsagePoint {
            timestamp: Instant::now(),
            usage,
            allocations: 0, // Would track actual allocations
        };

        if self.usage_tracker.usage_history.len() >= self.usage_tracker.max_history {
            self.usage_tracker.usage_history.pop_front();
        }
        self.usage_tracker.usage_history.push_back(point);
    }

    /// Gets usage history.
    pub fn get_usage_history(&self) -> &VecDeque<MemoryUsagePoint> {
        &self.usage_tracker.usage_history
    }

    /// Gets average memory usage over time.
    pub fn average_usage(&self) -> Option<f64> {
        if self.usage_tracker.usage_history.is_empty() {
            return None;
        }

        let total: usize = self.usage_tracker.usage_history.iter().map(|p| p.usage).sum();
        Some(total as f64 / self.usage_tracker.usage_history.len() as f64)
    }

    /// Clears usage history.
    pub fn clear_history(&mut self) {
        self.usage_tracker.usage_history.clear();
    }
}

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

impl MemoryUsageTracker {
    /// Creates a new memory usage tracker.
    pub fn new() -> Self {
        Self {
            current_usage: Arc::new(RwLock::new(0)),
            peak_usage: 0,
            usage_history: VecDeque::new(),
            max_history: 1000,
        }
    }

    /// Records a garbage collection event.
    pub fn record_collection(&mut self, _collected: usize) {
        let current = *self.current_usage.read().unwrap();
        if current > self.peak_usage {
            self.peak_usage = current;
        }

        let point = MemoryUsagePoint {
            timestamp: Instant::now(),
            usage: current,
            allocations: 0, // Would track actual allocations
        };

        if self.usage_history.len() >= self.max_history {
            self.usage_history.pop_front();
        }
        self.usage_history.push_back(point);
    }

    /// Gets current usage.
    pub fn current(&self) -> usize {
        *self.current_usage.read().unwrap()
    }

    /// Gets peak usage.
    pub fn peak(&self) -> usize {
        self.peak_usage
    }

    /// Resets peak usage tracking.
    pub fn reset_peak(&mut self) {
        self.peak_usage = *self.current_usage.read().unwrap();
    }
}

impl MemoryUsagePoint {
    /// Creates a new memory usage point.
    pub fn new(usage: usize, allocations: usize) -> Self {
        Self {
            timestamp: Instant::now(),
            usage,
            allocations,
        }
    }

    /// Gets the age of this usage point.
    pub fn age(&self) -> std::time::Duration {
        Instant::now() - self.timestamp
    }

    /// Gets usage in MB.
    pub fn usage_mb(&self) -> f64 {
        self.usage as f64 / (1024.0 * 1024.0)
    }

    /// Gets usage in KB.
    pub fn usage_kb(&self) -> f64 {
        self.usage as f64 / 1024.0
    }
}

impl MemoryStats {
    /// Gets current usage in MB.
    pub fn current_usage_mb(&self) -> f64 {
        self.current_usage as f64 / (1024.0 * 1024.0)
    }

    /// Gets peak usage in MB.
    pub fn peak_usage_mb(&self) -> f64 {
        self.peak_usage as f64 / (1024.0 * 1024.0)
    }

    /// Gets memory utilization ratio.
    pub fn utilization_ratio(&self) -> f64 {
        if self.peak_usage == 0 {
            0.0
        } else {
            self.current_usage as f64 / self.peak_usage as f64
        }
    }
}

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