use std::collections::HashSet;
use std::pin::Pin;
use crate::gc::Gc;
use crate::heap_entry::{EntryLike, HeapEntry};
use crate::trace::Trace;
#[derive(Debug, Default)]
pub struct Heap {
objects: Vec<Pin<Box<dyn EntryLike>>>,
roots: HashSet<*const dyn Trace>,
}
impl Heap {
pub fn manage<T: Trace + 'static>(&mut self, value: T) -> Gc<T> {
let entry = HeapEntry::pin(value);
let gc = entry.as_ref().get_gc();
self.objects.push(entry);
gc
}
pub fn add_root<T: Trace + 'static>(&mut self, object: Gc<T>) -> bool {
if object.entry().mark_root() {
return false;
}
let object = &*object as *const dyn Trace;
self.roots.insert(object)
}
pub fn remove_root<T: Trace + 'static>(&mut self, object: Gc<T>) -> bool {
if !object.entry().unmark_root() {
return false;
}
let object = &*object as *const dyn Trace;
self.roots.remove(&object)
}
pub unsafe fn add_unmanaged_root<T: Trace + 'static>(&mut self, object: Pin<&T>) -> bool {
let object = object.as_ref().get_ref() as *const dyn Trace;
self.roots.insert(object)
}
pub fn remove_unmanaged_root<T: Trace + 'static>(&mut self, object: Pin<&T>) -> bool {
let object = object.as_ref().get_ref() as *const dyn Trace;
self.roots.remove(&object)
}
pub fn collect(&mut self) -> usize {
for object in &self.objects {
object.unmark_reachable();
}
for root in &self.roots {
unsafe {
let root = *root;
(*root).mark_children();
}
}
let before = self.objects.len();
self.objects.retain(|object| object.is_root() || object.unmark_reachable());
let after = self.objects.len();
before - after
}
pub fn object_count(&self) -> usize {
self.objects.len()
}
}