use crate::platform::Platform;
use crate::support::int;
use crate::support::Opaque;
use crate::support::SharedRef;
use crate::support::UniqueRef;
extern "C" {
fn cppgc__initialize_process(platform: *mut Platform);
fn cppgc__shutdown_process();
fn cppgc__heap__create(
platform: *mut Platform,
wrappable_type_index: int,
wrappable_instance_index: int,
embedder_id_for_garbage_collected: u16,
) -> *mut Heap;
fn cppgc__heap__DELETE(heap: *mut Heap);
fn cppgc__make_garbage_collectable(
heap: *mut Heap,
obj: *mut (),
trace: TraceFn,
destroy: DestroyFn,
) -> *mut InnerMember;
fn cppgc__heap__enable_detached_garbage_collections_for_testing(
heap: *mut Heap,
);
fn cppgc__heap__collect_garbage_for_testing(
heap: *mut Heap,
stack_state: EmbedderStackState,
);
fn cppgc__visitor__trace(visitor: *const Visitor, member: *const InnerMember);
}
pub fn initalize_process(platform: SharedRef<Platform>) {
unsafe {
cppgc__initialize_process(&*platform as *const Platform as *mut _);
}
}
pub unsafe fn shutdown_process() {
cppgc__shutdown_process();
}
#[repr(C)]
#[derive(Debug)]
pub struct Visitor(Opaque);
impl Visitor {
pub fn trace<T: GarbageCollected>(&self, member: &Member<T>) {
unsafe { cppgc__visitor__trace(self, member.handle) }
}
}
#[repr(C)]
pub enum EmbedderStackState {
MayContainHeapPointers,
NoHeapPointers,
}
#[repr(u8)]
pub enum MarkingType {
Atomic,
Incremental,
IncrementalAndConcurrent,
}
#[repr(u8)]
pub enum SweepingType {
Atomic,
Incremental,
IncrementalAndConcurrent,
}
pub type InternalFieldIndex = int;
pub struct WrapperDescriptor {
pub wrappable_type_index: InternalFieldIndex,
pub wrappable_instance_index: InternalFieldIndex,
pub embedder_id_for_garbage_collected: u16,
}
impl WrapperDescriptor {
pub fn new(
wrappable_type_index: InternalFieldIndex,
wrappable_instance_index: InternalFieldIndex,
embedder_id_for_garbage_collected: u16,
) -> Self {
Self {
wrappable_type_index,
wrappable_instance_index,
embedder_id_for_garbage_collected,
}
}
}
pub struct HeapCreateParams {
wrapper_descriptor: WrapperDescriptor,
pub marking_support: MarkingType,
pub sweeping_support: SweepingType,
}
impl HeapCreateParams {
pub fn new(wrapper_descriptor: WrapperDescriptor) -> Self {
Self {
wrapper_descriptor,
marking_support: MarkingType::IncrementalAndConcurrent,
sweeping_support: SweepingType::IncrementalAndConcurrent,
}
}
}
type TraceFn = unsafe extern "C" fn(*mut (), *mut Visitor);
type DestroyFn = unsafe extern "C" fn(*mut ());
#[repr(C)]
#[derive(Debug)]
pub struct Heap(Opaque);
impl Drop for Heap {
fn drop(&mut self) {
unsafe { cppgc__heap__DELETE(self as *mut Heap) }
}
}
impl Heap {
pub fn create(
platform: SharedRef<Platform>,
params: HeapCreateParams,
) -> UniqueRef<Heap> {
let WrapperDescriptor {
wrappable_type_index,
wrappable_instance_index,
embedder_id_for_garbage_collected,
} = params.wrapper_descriptor;
unsafe {
UniqueRef::from_raw(cppgc__heap__create(
&*platform as *const Platform as *mut _,
wrappable_type_index,
wrappable_instance_index,
embedder_id_for_garbage_collected,
))
}
}
pub fn collect_garbage_for_testing(&self, stack_state: EmbedderStackState) {
unsafe {
cppgc__heap__collect_garbage_for_testing(
self as *const Heap as *mut _,
stack_state,
);
}
}
pub fn enable_detached_garbage_collections_for_testing(&self) {
unsafe {
cppgc__heap__enable_detached_garbage_collections_for_testing(
self as *const Heap as *mut _,
);
}
}
}
pub trait GarbageCollected {
fn trace(&self, _visitor: &Visitor) {}
}
#[repr(C)]
pub struct InnerMember {
inner: [usize; 2],
ptr: *mut (),
}
impl InnerMember {
pub unsafe fn get<T: GarbageCollected>(&self) -> &T {
unsafe { self.ptr.cast::<T>().as_ref().unwrap() }
}
}
#[repr(transparent)]
pub struct Member<T: GarbageCollected> {
pub handle: *mut InnerMember,
_phantom: std::marker::PhantomData<T>,
}
impl<T: GarbageCollected> Member<T> {
pub unsafe fn get(&self) -> &T {
unsafe { (*self.handle).get() }
}
}
impl<T: GarbageCollected> std::ops::Deref for Member<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { self.get() }
}
}
pub fn make_garbage_collected<T: GarbageCollected>(
heap: &Heap,
obj: Box<T>,
) -> Member<T> {
unsafe extern "C" fn destroy<T>(obj: *mut ()) {
let _ = Box::from_raw(obj as *mut T);
}
unsafe { make_garbage_collected_raw(heap, Box::into_raw(obj), destroy::<T>) }
}
pub unsafe fn make_garbage_collected_raw<T: GarbageCollected>(
heap: &Heap,
obj: *mut T,
destroy: DestroyFn,
) -> Member<T> {
unsafe extern "C" fn trace<T: GarbageCollected>(
obj: *mut (),
visitor: *mut Visitor,
) {
let obj = unsafe { &*(obj as *const T) };
obj.trace(unsafe { &*visitor });
}
let handle = cppgc__make_garbage_collectable(
heap as *const Heap as *mut _,
obj as _,
trace::<T>,
destroy,
);
Member {
handle,
_phantom: std::marker::PhantomData,
}
}