Skip to main content

vtcode_commons/
thread_safety.rs

1//! # Thread Safety Primitives
2//!
3//! Based on "Formal methods for the unsafe side of the Force" (Antithesis, 2026).
4//! Provides rigorously defined primitives for bridging FFI and multi-threaded boundaries.
5
6use std::marker::PhantomData;
7use std::sync::OnceLock;
8use std::thread::{self, ThreadId};
9
10/// Stores the `ThreadId` designated as the application's main thread.
11///
12/// Populated exactly once by [`designate_main_thread`]; subsequent calls are no-ops
13/// so that callers can re-assert designation from defensive initialization paths
14/// without panicking.
15static MAIN_THREAD_ID: OnceLock<ThreadId> = OnceLock::new();
16
17/// Designate the calling thread as the application's main thread.
18///
19/// Should be invoked once, early in `main`, before spawning any worker threads
20/// that may try to obtain a [`MainThreadToken`]. Subsequent calls have no effect.
21pub fn designate_main_thread() {
22    let _ = MAIN_THREAD_ID.set(thread::current().id());
23}
24
25/// Returns the `ThreadId` previously designated as the main thread, if any.
26pub fn main_thread_id() -> Option<ThreadId> {
27    MAIN_THREAD_ID.get().copied()
28}
29
30/// A witness of execution that exists solely on a designated "Main Thread".
31///
32/// In FFI contexts, many libraries (especially legacy C++ or UI frameworks)
33/// are not thread-safe and must only be initialized, called, or dropped from
34/// the same thread that originally created them.
35///
36/// `MainThreadToken` is a zero-sized proof carrier. Possessing it proves
37/// (at a type-system level) that the holder previously executed on the
38/// designated main thread. The `PhantomData<*mut ()>` makes the token
39/// `!Send + !Sync`, so a token obtained on the main thread cannot leak to
40/// another thread through ordinary safe code.
41#[derive(Debug, Clone, Copy, PartialEq, Eq)]
42pub struct MainThreadToken(PhantomData<*mut ()>);
43
44impl MainThreadToken {
45    /// Create a new `MainThreadToken` without verifying the current thread.
46    ///
47    /// # Safety
48    ///
49    /// The caller must guarantee that:
50    /// 1. They are executing on the thread that was (or will be) passed to
51    ///    [`designate_main_thread`], and
52    /// 2. The resulting token will not be transmitted to another thread
53    ///    through `unsafe` channels (the type is `!Send + !Sync`, which
54    ///    prevents safe channels from doing so).
55    #[expect(
56        unsafe_code,
57        reason = "phantom data marker; !Send + !Sync prevents token leakage"
58    )]
59    pub unsafe fn new_unchecked() -> Self {
60        Self(PhantomData)
61    }
62
63    /// Obtain a token if the current thread matches the one previously passed
64    /// to [`designate_main_thread`].
65    ///
66    /// Returns `None` if [`designate_main_thread`] has never been called, or
67    /// if the current thread is not the designated main thread.
68    pub fn try_new() -> Option<Self> {
69        let designated = MAIN_THREAD_ID.get()?;
70        if *designated == thread::current().id() {
71            Some(Self(PhantomData))
72        } else {
73            None
74        }
75    }
76}
77
78/// A wrapper that allows sending non-`Send` types across thread boundaries.
79///
80/// Re-exported from the `send_wrapper` crate. It implements `Send` and `Sync`
81/// regardless of whether the wrapped type is thread-safe. However, it will
82/// panic at runtime if the wrapped value is accessed from any thread other
83/// than the one that created it.
84pub use send_wrapper::SendWrapper;
85
86#[cfg(test)]
87mod tests {
88    use super::*;
89    use std::thread;
90
91    #[test]
92    fn worker_thread_never_obtains_token() {
93        // A spawned worker thread is never the designated main thread, even if
94        // some other test in this process has called `designate_main_thread`
95        // on a different thread. The token type is `!Send`, so we materialize
96        // it inside the worker and return only its presence as a `bool`.
97        let on_worker = thread::spawn(|| MainThreadToken::try_new().is_some())
98            .join()
99            .expect("worker thread");
100        assert!(!on_worker);
101    }
102
103    #[test]
104    fn try_new_returns_some_after_designation_on_same_thread() {
105        designate_main_thread();
106        // If this test happens to run on the same thread that another test
107        // designated, we still get a token; if a different thread was
108        // designated first, `try_new` correctly returns `None`.
109        match main_thread_id() {
110            Some(id) if id == thread::current().id() => {
111                assert!(MainThreadToken::try_new().is_some());
112            }
113            _ => {
114                assert!(MainThreadToken::try_new().is_none());
115            }
116        }
117    }
118}