runmat_thread_local/
lib.rs1#[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}