use super::util::{EventAggregator, HasTypeInfo, Trace, TypeInfo};
use crate::{assert_variant, impl_struct_ty};
use mun_memory::gc::{Event, GcPtr, GcRootPtr, GcRuntime, HasIndirectionPtr, MarkSweep, TypeTrace};
use std::sync::Arc;
struct Foo {
bar: GcPtr,
}
impl Trace for Foo {
fn trace(&self, handles: &mut Vec<GcPtr>) {
handles.push(self.bar)
}
}
impl_struct_ty!(Foo);
#[test]
fn test_trace() {
let runtime = MarkSweep::<&'static TypeInfo, EventAggregator<Event>>::default();
let mut foo_handle = runtime.alloc(Foo::type_info());
let bar_handle = runtime.alloc(i64::type_info());
unsafe {
(*foo_handle.deref_mut::<Foo>()).bar = bar_handle;
}
let mut trace = Foo::type_info().trace(foo_handle);
assert_eq!(trace.next(), Some(bar_handle));
assert_eq!(trace.next(), None)
}
#[test]
fn trace_collect() {
let runtime = Arc::new(MarkSweep::<&'static TypeInfo, EventAggregator<Event>>::default());
let mut foo = GcRootPtr::new(&runtime, runtime.alloc(Foo::type_info()));
let bar = runtime.alloc(i64::type_info());
unsafe {
(*foo.deref_mut::<Foo>()).bar = bar;
}
runtime.collect();
let foo = foo.unroot();
runtime.collect();
let mut events = runtime.observer().take_all().into_iter();
assert_eq!(events.next(), Some(Event::Allocation(foo)));
assert_eq!(events.next(), Some(Event::Allocation(bar)));
assert_eq!(events.next(), Some(Event::Start));
assert_eq!(events.next(), Some(Event::End));
assert_eq!(events.next(), Some(Event::Start));
assert_variant!(events.next(), Some(Event::Deallocation(..))); assert_variant!(events.next(), Some(Event::Deallocation(..)));
assert_eq!(events.next(), Some(Event::End));
assert_eq!(events.next(), None);
}
#[test]
fn trace_cycle() {
let runtime = Arc::new(MarkSweep::<&'static TypeInfo, EventAggregator<Event>>::default());
let mut foo = GcRootPtr::new(&runtime, runtime.alloc(Foo::type_info()));
unsafe {
(*foo.deref_mut::<Foo>()).bar = foo.handle();
}
runtime.collect();
let foo = foo.unroot();
runtime.collect();
let mut events = runtime.observer().take_all().into_iter();
assert_eq!(events.next(), Some(Event::Allocation(foo)));
assert_eq!(events.next(), Some(Event::Start));
assert_eq!(events.next(), Some(Event::End));
assert_eq!(events.next(), Some(Event::Start));
assert_eq!(events.next(), Some(Event::Deallocation(foo)));
assert_eq!(events.next(), Some(Event::End));
assert_eq!(events.next(), None);
}