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}