luaur_common/functions/get_thread_context.rs
1//! Source: `Common/src/TimeTrace.cpp:253-261` (hand-ported)
2//! C++:
3//! ```cpp
4//! ThreadContext& getThreadContext()
5//! {
6//! if (auto provider = threadContextProvider())
7//! return provider();
8//! thread_local ThreadContext context;
9//! return context;
10//! }
11//! ```
12use crate::functions::thread_context_provider::thread_context_provider;
13use crate::records::thread_context::ThreadContext;
14
15thread_local! {
16 // `thread_local ThreadContext context;` — boxed so its address is stable for
17 // the life of the thread, allowing a `&'static mut` to be handed out exactly
18 // as the C++ returns a reference to the thread-local object.
19 static CONTEXT: core::cell::UnsafeCell<alloc::boxed::Box<ThreadContext>> =
20 core::cell::UnsafeCell::new(alloc::boxed::Box::new(ThreadContext::thread_context()));
21}
22
23pub fn get_thread_context() -> &'static mut ThreadContext {
24 // Check the custom provider, which might implement a custom TLS.
25 let provider = *thread_context_provider();
26 let provided = provider();
27 if !provided.is_null() {
28 return unsafe { &mut *provided };
29 }
30
31 CONTEXT.with(|cell| {
32 // Safety: the boxed `ThreadContext` lives for the duration of the thread;
33 // its heap address is stable, so a reference promoted to `'static` is sound
34 // for single-threaded TimeTrace use (the C++ object has the same property).
35 let boxed: &mut alloc::boxed::Box<ThreadContext> = unsafe { &mut *cell.get() };
36 unsafe { &mut *(boxed.as_mut() as *mut ThreadContext) }
37 })
38}