Skip to main content

runmat_thread_local/
lib.rs

1#[cfg(target_arch = "wasm32")]
2use std::cell::UnsafeCell;
3
4#[cfg(target_arch = "wasm32")]
5pub struct WasmTlsCell<T> {
6    init: fn() -> T,
7    value: UnsafeCell<Option<T>>,
8}
9
10#[cfg(target_arch = "wasm32")]
11impl<T> WasmTlsCell<T> {
12    pub const fn new(init: fn() -> T) -> Self {
13        Self {
14            init,
15            value: UnsafeCell::new(None),
16        }
17    }
18
19    fn ensure(&self) -> *mut T {
20        unsafe {
21            let slot = &mut *self.value.get();
22            if slot.is_none() {
23                *slot = Some((self.init)());
24            }
25            slot.as_mut().expect("runmat wasm TLS slot init failed") as *mut T
26        }
27    }
28
29    pub fn with<R>(&self, f: impl FnOnce(&T) -> R) -> R {
30        let ptr = self.ensure();
31        unsafe { f(&*ptr) }
32    }
33
34    pub fn with_mut<R>(&self, f: impl FnOnce(&mut T) -> R) -> R {
35        let ptr = self.ensure();
36        unsafe { f(&mut *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])* static $name:ident : $ty:ty = const { $init:expr }; $($rest:tt)*) => {
47        thread_local! {
48            $(#[$meta])*
49            static $name: $ty = const { $init };
50        }
51        $crate::runmat_thread_local! { $($rest)* }
52    };
53    ($(#[$meta:meta])* static $name:ident : $ty:ty = $init:expr; $($rest:tt)*) => {
54        thread_local! {
55            $(#[$meta])*
56            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])* static $name:ident : $ty:ty = const { $init:expr }; $($rest:tt)*) => {
67        $crate::runmat_thread_local! {
68            $(#[$meta])*
69            static $name : $ty = $init;
70            $($rest)*
71        }
72    };
73    ($(#[$meta:meta])* static $name:ident : $ty:ty = $init:expr; $($rest:tt)*) => {
74        $(#[$meta])*
75        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}