1use std::{ffi::c_void, ptr::NonNull};
2
3use crate::{GcToken, gc};
4
5pub fn alloc<T>(_token: &impl GcToken, val: T) -> GcBox<T> {
6 let ptr =
7 unsafe { gc::GC_memalign(std::mem::size_of::<T>(), std::mem::align_of::<T>()) as *mut T };
8 let ptr = NonNull::new(ptr).expect("GC_malloc failed");
9 unsafe { ptr.write(val) };
10
11 register_finalizer(ptr.as_ptr());
12 GcBox(ptr)
13}
14
15pub struct GcBox<T>(NonNull<T>);
16
17impl<T> GcBox<T> {
18 pub fn as_ptr(&self) -> *mut T {
19 self.0.as_ptr()
20 }
21
22 pub fn as_ref<'gc>(&self, _token: &'gc impl GcToken) -> &'gc T {
23 unsafe { &*self.as_ptr() }
24 }
25
26 #[allow(clippy::mut_from_ref)]
27 pub fn as_mut<'gc>(&mut self, _token: &'gc impl GcToken) -> &'gc mut T {
28 unsafe { &mut *self.as_ptr() }
29 }
30
31 pub unsafe fn as_ref_unconstrained(&self) -> &'static mut T {
34 unsafe { &mut *self.as_ptr() }
35 }
36}
37
38fn register_finalizer<T>(ptr: *mut T) {
39 if std::mem::needs_drop::<T>() {
40 extern "C" fn finalizer<T>(obj: *mut c_void, _: *mut c_void) {
41 let ptr = obj as *mut T;
42 unsafe { std::ptr::drop_in_place(ptr) };
43 }
44
45 unsafe {
46 gc::GC_register_finalizer(
47 ptr as *mut std::ffi::c_void,
48 Some(finalizer::<T>),
49 std::ptr::null_mut(),
50 std::ptr::null_mut(),
51 std::ptr::null_mut(),
52 );
53 }
54 }
55}