1use std::any::TypeId;
4
5struct CppGcObject<T> {
6 tag: TypeId,
7 member: T,
8}
9
10impl<T> v8::cppgc::GarbageCollected for CppGcObject<T> {
11 fn trace(&self, _: &v8::cppgc::Visitor) {}
12}
13
14pub(crate) const DEFAULT_CPP_GC_EMBEDDER_ID: u16 = 0xde90;
15
16const EMBEDDER_ID_OFFSET: i32 = 0;
17const SLOT_OFFSET: i32 = 1;
18const FIELD_COUNT: usize = 2;
19
20pub fn make_cppgc_object<'a, T: 'static>(
21 scope: &mut v8::HandleScope<'a>,
22 t: T,
23) -> v8::Local<'a, v8::Object> {
24 let templ = v8::ObjectTemplate::new(scope);
25 templ.set_internal_field_count(FIELD_COUNT);
26
27 let obj = templ.new_instance(scope).unwrap();
28 let member = v8::cppgc::make_garbage_collected(
29 scope.get_cpp_heap().unwrap(),
30 Box::new(CppGcObject {
31 tag: TypeId::of::<T>(),
32 member: t,
33 }),
34 );
35
36 obj.set_aligned_pointer_in_internal_field(
37 EMBEDDER_ID_OFFSET,
38 &DEFAULT_CPP_GC_EMBEDDER_ID as *const u16 as _,
39 );
40 obj.set_aligned_pointer_in_internal_field(SLOT_OFFSET, member.handle as _);
41 obj
42}
43
44pub fn try_unwrap_cppgc_object<'sc, T: 'static>(
45 val: v8::Local<v8::Value>,
46) -> Option<&'sc T> {
47 let Ok(obj): Result<v8::Local<v8::Object>, _> = val.try_into() else {
48 return None;
49 };
50
51 if obj.internal_field_count() != FIELD_COUNT {
52 return None;
53 }
54
55 let member = unsafe {
61 let ptr = obj.get_aligned_pointer_from_internal_field(SLOT_OFFSET);
62 let obj = &*(ptr as *const v8::cppgc::InnerMember);
63 obj.get::<CppGcObject<T>>()
64 };
65
66 if member.tag != TypeId::of::<T>() {
67 return None;
68 }
69
70 Some(&member.member)
71}