Skip to main content

runmat_thread_local/
lib.rs

1#[cfg(target_arch = "wasm32")]
2use std::cell::UnsafeCell;
3
4#[cfg(all(target_arch = "wasm32", target_feature = "atomics"))]
5compile_error!(
6    "runmat_thread_local wasm TLS shim assumes single-threaded wasm; use native thread_local semantics for wasm atomics builds"
7);
8
9#[cfg(target_arch = "wasm32")]
10pub struct WasmTlsCell<T> {
11    init: fn() -> T,
12    value: UnsafeCell<Option<T>>,
13}
14
15#[cfg(target_arch = "wasm32")]
16impl<T> WasmTlsCell<T> {
17    pub const fn new(init: fn() -> T) -> Self {
18        Self {
19            init,
20            value: UnsafeCell::new(None),
21        }
22    }
23
24    fn ensure(&self) -> *mut T {
25        unsafe {
26            let slot = &mut *self.value.get();
27            if slot.is_none() {
28                *slot = Some((self.init)());
29            }
30            slot.as_mut().expect("runmat wasm TLS slot init failed") as *mut T
31        }
32    }
33
34    pub fn with<R>(&self, f: impl FnOnce(&T) -> R) -> R {
35        let ptr = self.ensure();
36        unsafe { f(&*ptr) }
37    }
38}
39
40#[cfg(target_arch = "wasm32")]
41unsafe impl<T> Sync for WasmTlsCell<T> {}
42
43#[cfg(not(target_arch = "wasm32"))]
44#[macro_export]
45macro_rules! runmat_thread_local {
46    ($(#[$meta:meta])* $vis:vis static $name:ident : $ty:ty = const { $init:expr }; $($rest:tt)*) => {
47        thread_local! {
48            $(#[$meta])*
49            $vis static $name: $ty = const { $init };
50        }
51        $crate::runmat_thread_local! { $($rest)* }
52    };
53    ($(#[$meta:meta])* $vis:vis static $name:ident : $ty:ty = $init:expr; $($rest:tt)*) => {
54        thread_local! {
55            $(#[$meta])*
56            $vis static $name: $ty = $init;
57        }
58        $crate::runmat_thread_local! { $($rest)* }
59    };
60    () => {};
61}
62
63#[cfg(target_arch = "wasm32")]
64#[macro_export]
65macro_rules! runmat_thread_local {
66    ($(#[$meta:meta])* $vis:vis static $name:ident : $ty:ty = const { $init:expr }; $($rest:tt)*) => {
67        $crate::runmat_thread_local! {
68            $(#[$meta])*
69            $vis static $name : $ty = $init;
70            $($rest)*
71        }
72    };
73    ($(#[$meta:meta])* $vis:vis static $name:ident : $ty:ty = $init:expr; $($rest:tt)*) => {
74        $(#[$meta])*
75        $vis static $name: $crate::WasmTlsCell<$ty> = {
76            fn init() -> $ty {
77                $init
78            }
79            $crate::WasmTlsCell::new(init)
80        };
81        $crate::runmat_thread_local! { $($rest)* }
82    };
83    () => {};
84}