mod cell;
mod color;
mod gc;
mod gc_box;
mod heap;
mod ptr;
mod trace;
pub use cell::GcCell;
pub use gc::GcContext;
pub use heap::{GcOptions, Heap};
pub use ptr::{GcPtr, GcRoot};
pub use trace::{Trace, Tracer};
#[cfg(test)]
mod tests {
use crate::heap::GcOptions;
use super::*;
use std::time::Duration;
#[test]
fn basic_allocation() {
let ctx = GcContext::new();
let ptr = ctx.allocate(42);
assert_eq!(*ptr, 42);
}
#[test]
fn allocation_and_collection() {
let ctx = GcContext::new();
let ptr1 = ctx.allocate(100);
let _ptr2 = ctx.allocate(200);
drop(_ptr2);
ctx.collect();
assert_eq!(*ptr1, 100);
}
#[test]
fn concurrent_collection() {
use std::sync::Arc;
use std::thread;
let opts = heap::GcOptions {
min_threshold_bytes: 1024,
..GcOptions::DEFAULT
};
let ctx = GcContext::with_options(opts);
let heap = Arc::clone(ctx.heap());
let roots: Vec<_> = (0..10).map(|i| ctx.allocate(i)).collect();
let initial_bytes = heap.bytes_allocated();
let handles: Vec<_> = (0..4)
.map(|_| {
let heap = Arc::clone(&heap);
thread::spawn(move || {
let ctx = GcContext::with_heap(heap);
for _ in 0..100 {
let _temp = ctx.allocate(vec![1, 2, 3, 4, 5]);
}
})
})
.collect();
for handle in handles {
handle.join().unwrap();
}
let peak_bytes = heap.bytes_allocated();
thread::sleep(Duration::from_millis(300));
heap.force_collect();
for (i, root) in roots.iter().enumerate() {
assert_eq!(**root, i);
}
let final_bytes = heap.bytes_allocated();
println!(
"Initial: {}, Peak: {}, Final: {}",
initial_bytes, peak_bytes, final_bytes
);
assert!(
final_bytes < peak_bytes / 2,
"GC should have reclaimed significant memory"
);
}
#[test]
fn incremental_marking() {
let ctx = GcContext::new();
let root = ctx.allocate(vec![1, 2, 3]);
let _temp = ctx.allocate(vec![4, 5, 6]);
ctx.heap().force_collect();
assert_eq!(root.len(), 3);
}
}