use crate::binding::RustObj;
use crate::platform::Platform;
use crate::support::int;
use crate::support::Opaque;
use crate::support::SharedRef;
use crate::support::UniqueRef;
use crate::Data;
use crate::TracedReference;
use std::ffi::c_char;
use std::ffi::CStr;
use std::marker::PhantomData;
use std::ptr::NonNull;
extern "C" {
fn cppgc__initialize_process(platform: *mut Platform);
fn cppgc__shutdown_process();
fn v8__CppHeap__Create(
platform: *mut Platform,
marking_support: MarkingType,
sweeping_support: SweepingType,
) -> *mut Heap;
fn v8__CppHeap__Terminate(heap: *mut Heap);
fn v8__CppHeap__DELETE(heap: *mut Heap);
fn cppgc__make_garbage_collectable(
heap: *mut Heap,
size: usize,
) -> *mut RustObj;
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__Member(
visitor: *const Visitor,
member: *const MemberInner,
);
fn cppgc__Visitor__Trace__WeakMember(
visitor: *const Visitor,
member: *const WeakMemberInner,
);
fn cppgc__Visitor__Trace__TracedReference(
visitor: *const Visitor,
reference: *const TracedReference<Data>,
);
fn cppgc__Member__CONSTRUCT(member: *mut MemberInner, obj: *mut RustObj);
fn cppgc__Member__DESTRUCT(member: *mut MemberInner);
fn cppgc__Member__Get(member: *const MemberInner) -> *mut RustObj;
fn cppgc__Member__Assign(member: *mut MemberInner, other: *mut RustObj);
fn cppgc__WeakMember__CONSTRUCT(
member: *mut WeakMemberInner,
obj: *mut RustObj,
);
fn cppgc__WeakMember__DESTRUCT(member: *mut WeakMemberInner);
fn cppgc__WeakMember__Get(member: *const WeakMemberInner) -> *mut RustObj;
fn cppgc__WeakMember__Assign(
member: *mut WeakMemberInner,
other: *mut RustObj,
);
fn cppgc__Persistent__CONSTRUCT(obj: *mut RustObj) -> *mut PersistentInner;
fn cppgc__Persistent__DESTRUCT(this: *mut PersistentInner);
fn cppgc__Persistent__Assign(this: *mut PersistentInner, ptr: *mut RustObj);
fn cppgc__Persistent__Get(this: *const PersistentInner) -> *mut RustObj;
fn cppgc__WeakPersistent__CONSTRUCT(
obj: *mut RustObj,
) -> *mut WeakPersistentInner;
fn cppgc__WeakPersistent__DESTRUCT(this: *mut WeakPersistentInner);
fn cppgc__WeakPersistent__Assign(
this: *mut WeakPersistentInner,
ptr: *mut RustObj,
);
fn cppgc__WeakPersistent__Get(
this: *const WeakPersistentInner,
) -> *mut RustObj;
}
unsafe fn get_rust_obj<'s>(obj: *const RustObj) -> &'s dyn GarbageCollected {
&*std::mem::transmute::<[usize; 2], *mut dyn GarbageCollected>((*obj).data)
}
unsafe fn get_rust_obj_mut<'s>(
obj: *mut RustObj,
) -> &'s mut dyn GarbageCollected {
&mut *std::mem::transmute::<[usize; 2], *mut dyn GarbageCollected>(
(*obj).data,
)
}
#[no_mangle]
unsafe extern "C" fn rusty_v8_RustObj_trace(
obj: *const RustObj,
visitor: *mut Visitor,
) {
let r = get_rust_obj(obj);
r.trace(&*visitor);
}
#[no_mangle]
unsafe extern "C" fn rusty_v8_RustObj_get_name(
obj: *const RustObj,
) -> *const c_char {
let r = get_rust_obj(obj);
match r.get_name() {
Some(s) => s.as_ptr(),
None => std::ptr::null(),
}
}
#[no_mangle]
unsafe extern "C" fn rusty_v8_RustObj_drop(obj: *mut RustObj) {
let r = get_rust_obj_mut(obj);
std::ptr::drop_in_place(r);
}
fn object_offset_for_rust_obj<T: GarbageCollected>() -> usize {
#[repr(C)]
struct Calc<T> {
header: RustObj,
data: T,
}
std::mem::offset_of!(Calc<T>, data)
}
unsafe fn get_object_from_rust_obj<T: GarbageCollected>(
rust_obj: *const RustObj,
) -> *mut T {
unsafe { rust_obj.byte_add(object_offset_for_rust_obj::<T>()) as *mut T }
}
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 {
#[inline(always)]
pub fn trace(&self, member: &impl Traced) {
member.trace(self);
}
}
#[doc(hidden)]
pub trait Traced {
fn trace(&self, visitor: &Visitor);
}
impl<T> Traced for TracedReference<T> {
fn trace(&self, visitor: &Visitor) {
unsafe {
cppgc__Visitor__Trace__TracedReference(
visitor,
self as *const TracedReference<T> as *const TracedReference<Data>,
)
}
}
}
#[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 HeapCreateParams {
pub marking_support: MarkingType,
pub sweeping_support: SweepingType,
}
impl Default for HeapCreateParams {
fn default() -> Self {
Self {
marking_support: MarkingType::IncrementalAndConcurrent,
sweeping_support: SweepingType::IncrementalAndConcurrent,
}
}
}
#[repr(C)]
#[derive(Debug)]
pub struct Heap(Opaque);
impl Drop for Heap {
fn drop(&mut self) {
unsafe {
v8__CppHeap__DELETE(self);
}
}
}
impl Heap {
pub fn create(
platform: SharedRef<Platform>,
params: HeapCreateParams,
) -> UniqueRef<Heap> {
unsafe {
UniqueRef::from_raw(v8__CppHeap__Create(
&*platform as *const Platform as *mut _,
params.marking_support,
params.sweeping_support,
))
}
}
pub unsafe 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 fn terminate(&mut self) {
unsafe {
v8__CppHeap__Terminate(self);
}
}
}
pub trait GarbageCollected {
fn trace(&self, _visitor: &Visitor) {}
fn get_name(&self) -> Option<&'static CStr> {
None
}
}
pub unsafe fn make_garbage_collected<T: GarbageCollected + 'static>(
heap: &Heap,
obj: T,
) -> Ptr<T> {
let additional_bytes = (object_offset_for_rust_obj::<T>()
- std::mem::size_of::<RustObj>())
+ std::mem::size_of::<T>();
let pointer = unsafe {
cppgc__make_garbage_collectable(
heap as *const Heap as *mut _,
additional_bytes,
)
};
unsafe {
let inner = get_object_from_rust_obj::<T>(pointer);
inner.write(obj);
let rust_obj = &mut *pointer;
rust_obj.data = std::mem::transmute::<*mut dyn GarbageCollected, [usize; 2]>(
&mut *inner as &mut dyn GarbageCollected as *mut dyn GarbageCollected,
);
}
Ptr {
pointer: NonNull::new_unchecked(pointer),
_phantom: PhantomData,
}
}
#[doc(hidden)]
pub trait GetRustObj<T: GarbageCollected> {
fn get_rust_obj(&self) -> *mut RustObj;
}
impl<T: GarbageCollected> GetRustObj<T> for *mut RustObj {
fn get_rust_obj(&self) -> *mut RustObj {
*self
}
}
macro_rules! member {
($( # $attr:tt )* $name:ident) => {
paste::paste! {
#[repr(transparent)]
struct [< $name Inner >]([u8; crate::binding:: [< cppgc__ $name _SIZE >]]);
impl [< $name Inner >] {
fn new(ptr: *mut RustObj) -> Self {
let mut this = std::mem::MaybeUninit::uninit();
unsafe {
[< cppgc__ $name __CONSTRUCT >](this.as_mut_ptr(), ptr);
this.assume_init()
}
}
#[inline(always)]
fn get(&self) -> *mut RustObj {
unsafe { [< cppgc__ $name __Get >](self) }
}
#[inline(always)]
fn assign(&mut self, ptr: *mut RustObj) {
unsafe {
[< cppgc__ $name __Assign >](self, ptr);
}
}
}
impl Drop for [< $name Inner >] {
fn drop(&mut self) {
unsafe {
[< cppgc__ $name __DESTRUCT >](self);
}
}
}
$( # $attr )*
#[repr(transparent)]
pub struct $name<T: GarbageCollected> {
inner: [< $name Inner >],
_phantom: PhantomData<T>,
}
impl<T: GarbageCollected> $name<T> {
#[doc = "Create a new empty "]
#[doc = stringify!($name)]
#[doc = " which may be set later."]
pub fn empty() -> Self {
Self {
inner: [< $name Inner >]::new(std::ptr::null_mut()),
_phantom: PhantomData,
}
}
#[doc = "Create a new "]
#[doc = stringify!($name)]
#[doc = " and initialize it with an object."]
pub fn new(other: &impl GetRustObj<T>) -> Self {
Self {
inner: [< $name Inner >]::new(other.get_rust_obj()),
_phantom: PhantomData,
}
}
#[doc = "Set the object pointed to by this "]
#[doc = stringify!($name)]
#[doc = "."]
pub fn set(&mut self, other: &impl GetRustObj<T>) {
let ptr = other.get_rust_obj();
self.inner.assign(ptr);
}
#[doc = "Borrow the object pointed to by this "]
#[doc = stringify!($name)]
#[doc = "."]
pub fn borrow(&self) -> Option<&T> {
let ptr = self.inner.get();
if ptr.is_null() {
None
} else {
Some(unsafe { &*get_object_from_rust_obj(ptr) })
}
}
}
impl<T: GarbageCollected> GetRustObj<T> for $name<T> {
fn get_rust_obj(&self) -> *mut RustObj {
self.inner.get()
}
}
impl<T: GarbageCollected> Traced for $name<T> {
fn trace(&self, visitor: &Visitor) {
unsafe { [< cppgc__Visitor__Trace__ $name >](visitor, &self.inner) }
}
}
impl<T: GarbageCollected> std::fmt::Debug for $name<T> {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
fmt.debug_struct(stringify!($name)).finish()
}
}
}
}
}
member! {
Member
}
member! {
WeakMember
}
macro_rules! persistent {
($( # $attr:tt )* $name:ident) => {
paste::paste! {
#[repr(C)]
struct [< $name Inner >](Opaque);
$( # $attr )*
pub struct $name<T: GarbageCollected> {
inner: *mut [< $name Inner >],
_phantom: PhantomData<T>,
}
impl<T: GarbageCollected> $name<T> {
#[doc = "Create a new empty "]
#[doc = stringify!($name)]
#[doc = " which may be set later."]
pub fn empty() -> Self {
let this = unsafe { [< cppgc__ $name __CONSTRUCT >](std::ptr::null_mut()) };
Self {
inner: this,
_phantom: PhantomData,
}
}
#[doc = "Create a new "]
#[doc = stringify!($name)]
#[doc = " and initialize it with an object."]
pub fn new(other: &impl GetRustObj<T>) -> Self {
let this = unsafe { [< cppgc__ $name __CONSTRUCT >](other.get_rust_obj()) };
Self {
inner: this,
_phantom: PhantomData,
}
}
#[doc = "Set the object pointed to by this "]
#[doc = stringify!($name)]
#[doc = "."]
pub fn set(&mut self, other: &impl GetRustObj<T>) {
let ptr = other.get_rust_obj();
self.assign(ptr);
}
#[doc = "Borrow the object pointed to by this "]
#[doc = stringify!($name)]
#[doc = "."]
pub fn borrow(&self) -> Option<&T> {
let ptr = self.get();
if ptr.is_null() {
None
} else {
Some(unsafe { &*get_object_from_rust_obj(ptr) })
}
}
#[inline(always)]
fn assign(&mut self, ptr: *mut RustObj) {
unsafe {
[< cppgc__ $name __Assign >](self.inner, ptr);
}
}
#[inline(always)]
fn get(&self) -> *mut RustObj {
unsafe {
[< cppgc__ $name __Get >](self.inner)
}
}
}
impl<T: GarbageCollected> Drop for $name<T> {
fn drop(&mut self) {
unsafe {
[< cppgc__ $name __DESTRUCT >](self.inner);
}
}
}
impl<T: GarbageCollected> std::fmt::Debug for $name<T> {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
fmt.debug_struct(stringify!($name)).finish()
}
}
impl<T: GarbageCollected> GetRustObj<T> for $name<T> {
fn get_rust_obj(&self) -> *mut RustObj {
self.get()
}
}
}
};
}
persistent! {
Persistent
}
persistent! {
WeakPersistent
}
#[derive(Clone, Copy)]
pub struct Ptr<T: GarbageCollected> {
pointer: NonNull<RustObj>,
_phantom: PhantomData<T>,
}
impl<T: GarbageCollected> Ptr<T> {
pub unsafe fn new(other: &impl GetRustObj<T>) -> Option<Self> {
NonNull::new(other.get_rust_obj()).map(|pointer| Self {
pointer,
_phantom: PhantomData,
})
}
}
impl<T: GarbageCollected> std::ops::Deref for Ptr<T> {
type Target = T;
fn deref(&self) -> &T {
unsafe { &*get_object_from_rust_obj(self.pointer.as_ptr()) }
}
}
impl<T: GarbageCollected> GetRustObj<T> for Ptr<T> {
fn get_rust_obj(&self) -> *mut RustObj {
self.pointer.as_ptr()
}
}
impl<T: GarbageCollected + std::fmt::Debug> std::fmt::Debug for Ptr<T> {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
std::fmt::Debug::fmt(&**self, fmt)
}
}
impl<T: GarbageCollected + std::fmt::Display> std::fmt::Display for Ptr<T> {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
std::fmt::Display::fmt(&**self, fmt)
}
}