//! [TSM.ID].[11031972] — Platform X Ecosystem
//! xcu-garbage-collector — Deterministic Memory Cleaner
#![deny(warnings)]
#![allow(dead_code)]

pub mod collector;
pub mod tracker;

#[derive(Debug)]
pub enum GcError {
    AllocationFailed,
    InvalidReference,
    CollectionFailed(String),
    HeapCorrupted,
}
impl std::fmt::Display for GcError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::AllocationFailed => write!(f, "Allocation failed"),
            Self::InvalidReference => write!(f, "Invalid reference"),
            Self::CollectionFailed(e) => write!(f, "Collection failed: {e}"),
            Self::HeapCorrupted => write!(f, "Heap corrupted"),
        }
    }
}
impl std::error::Error for GcError {}
pub type Result<T> = std::result::Result<T, GcError>;

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum GcColor { White, Gray, Black }

pub struct GcConfig {
    pub heap_size: usize,
    pub threshold: usize,
    pub generation_count: u8,
}

impl Default for GcConfig {
    fn default() -> Self { Self { heap_size: 1_048_576, threshold: 768_000, generation_count: 3 } }
}

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

    #[test]
    fn test_allocate_and_collect() {
        let config = GcConfig { heap_size: 1024, threshold: 512, generation_count: 3 };
        let mut gc = MarkSweepCollector::new(config);
        let a = gc.allocate(100).expect("alloc a");
        let b = gc.allocate(100).expect("alloc b");
        gc.add_root(a);
        let freed = gc.collect().expect("collect");
        assert_eq!(freed, 100);
        let (collections, bytes_freed, alive) = gc.stats();
        assert_eq!(collections, 1);
        assert_eq!(bytes_freed, 100);
        assert_eq!(alive, 1);
        let _ = b;
    }

    #[test]
    fn test_reference_keeps_alive() {
        let config = GcConfig::default();
        let mut gc = MarkSweepCollector::new(config);
        let root = gc.allocate(64).expect("root");
        let child = gc.allocate(64).expect("child");
        gc.add_root(root);
        gc.add_reference(root, child).expect("ref");
        let freed = gc.collect().expect("collect");
        assert_eq!(freed, 0);
    }

    #[test]
    fn test_generation_promotion() {
        let config = GcConfig::default();
        let mut gc = MarkSweepCollector::new(config);
        let obj = gc.allocate(32).expect("alloc");
        gc.add_root(obj);
        gc.collect().expect("collect");
        gc.promote_survivors();
        let gen = gc.object_generation(obj).expect("gen");
        assert_eq!(gen, 1);
    }
}
