Skip to main content

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}