47 lines
1.0 KiB
Rust
47 lines
1.0 KiB
Rust
use std::{collections::HashSet, ops::Deref};
|
|
|
|
use crate::gc_ref::GcRef;
|
|
|
|
pub struct GCTracer {
|
|
accessible: HashSet<*const ()>,
|
|
explored: HashSet<*const ()>,
|
|
}
|
|
|
|
impl GCTracer {
|
|
pub(super) fn with_capacity(cap: usize) -> Self {
|
|
Self {
|
|
accessible: HashSet::with_capacity(cap),
|
|
explored: HashSet::with_capacity(cap),
|
|
}
|
|
}
|
|
|
|
pub fn is_accessible(&self, ptr: *const ()) -> bool {
|
|
self.accessible.contains(&ptr)
|
|
}
|
|
|
|
pub fn mark_reachable_rec<T: GCTrace>(&mut self, obj: &T) {
|
|
let ptr = obj as *const T as *const ();
|
|
if !self.explored.contains(&ptr) {
|
|
self.explored.insert(ptr);
|
|
obj.trace(self);
|
|
}
|
|
}
|
|
}
|
|
|
|
pub use gctrace_derive::GCTrace;
|
|
|
|
///
|
|
/// # Safety
|
|
/// Implementors of the trait *need* to ensure that every reachable reference gets marked as
|
|
/// reachable by callign trace on it
|
|
pub unsafe trait GCTrace {
|
|
fn trace(&self, _tracer: &mut GCTracer) {}
|
|
}
|
|
|
|
unsafe impl<T: GCTrace> GCTrace for GcRef<T> {
|
|
fn trace(&self, tracer: &mut GCTracer) {
|
|
tracer.accessible.insert(self.0.as_ptr() as *const ());
|
|
tracer.mark_reachable_rec(self.deref());
|
|
}
|
|
}
|