Skip to main content

gc_alloc/
lib.rs

1use std::{cell::Cell, ffi::c_void};
2
3mod gc {
4    #![allow(non_upper_case_globals, non_camel_case_types, non_snake_case, unused)]
5
6    include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
7}
8
9pub mod boxed;
10pub mod cstring;
11pub mod string;
12pub mod vec;
13
14thread_local! {
15    static GC_REGISTERED: Cell<bool> = const { Cell::new(false) };
16}
17
18pub fn init() -> ThreadToken {
19    unsafe {
20        gc::GC_init();
21        gc::GC_allow_register_threads();
22    }
23
24    GC_REGISTERED.set(true);
25
26    ThreadToken {
27        _non_send: std::marker::PhantomData,
28    }
29}
30
31pub fn init_thread() -> ThreadGuard {
32    assert!(
33        !GC_REGISTERED.get() && unsafe { gc::GC_thread_is_registered() } == 0,
34        "Thread is already registered with the GC. "
35    );
36
37    unsafe extern "C" fn do_register(sb: *mut gc::GC_stack_base, _: *mut c_void) -> *mut c_void {
38        let result = unsafe { gc::GC_register_my_thread(sb) };
39        assert!(
40            result == gc::GC_SUCCESS as i32,
41            "Failed to register thread with GC. Error code: {}",
42            result
43        );
44        std::ptr::null_mut()
45    }
46
47    unsafe { gc::GC_call_with_stack_base(Some(do_register), std::ptr::null_mut()) };
48
49    GC_REGISTERED.set(true);
50
51    ThreadGuard {
52        _non_send: std::marker::PhantomData,
53    }
54}
55
56pub trait GcToken: private::Sealed {}
57
58pub struct ThreadToken {
59    _non_send: std::marker::PhantomData<*const ()>,
60}
61
62impl private::Sealed for ThreadToken {}
63impl GcToken for ThreadToken {}
64
65impl ThreadToken {
66    pub fn get() -> Self {
67        Self::try_get()
68            .expect("Thread is not registered with the GC. Please call init_thread() first.")
69    }
70
71    pub fn try_get() -> Option<Self> {
72        if GC_REGISTERED.get() {
73            Some(ThreadToken {
74                _non_send: std::marker::PhantomData,
75            })
76        } else {
77            None
78        }
79    }
80}
81
82pub struct ThreadGuard {
83    _non_send: std::marker::PhantomData<*const ()>,
84}
85
86impl private::Sealed for ThreadGuard {}
87impl GcToken for ThreadGuard {}
88
89impl Drop for ThreadGuard {
90    fn drop(&mut self) {
91        unsafe { gc::GC_unregister_my_thread() };
92    }
93}
94
95mod private {
96    pub trait Sealed {}
97}