wasm_bindgen_test/rt/
scoped_tls.rs1use core::cell::Cell;
4use core::marker::PhantomData;
5
6#[macro_export]
8macro_rules! scoped_thread_local {
9 (static $name:ident: $ty:ty) => {
10 static $name: scoped_tls::ScopedKey<$ty> = unsafe {
11 static FOO: scoped_tls::Wrapper<::core::cell::Cell<*const ()>> =
12 scoped_tls::Wrapper::new(::core::cell::Cell::new(::core::ptr::null()));
13 scoped_tls::ScopedKey::new(&FOO)
15 };
16 };
17}
18
19pub(super) struct Wrapper<T>(T);
20
21impl<T> Wrapper<T> {
22 pub(super) const fn new(value: T) -> Self {
23 Self(value)
24 }
25}
26
27unsafe impl<T> Sync for Wrapper<T> {}
28
29pub struct ScopedKey<T> {
30 inner: &'static Wrapper<Cell<*const ()>>,
31 _marker: PhantomData<T>,
32}
33
34unsafe impl<T> Sync for ScopedKey<T> {}
35
36impl<T> ScopedKey<T> {
37 #[doc(hidden)]
38 pub(super) const unsafe fn new(inner: &'static Wrapper<Cell<*const ()>>) -> Self {
41 Self {
42 inner,
43 _marker: PhantomData,
44 }
45 }
46
47 pub fn set<F, R>(&'static self, t: &T, f: F) -> R
48 where
49 F: FnOnce() -> R,
50 {
51 struct Reset {
52 key: &'static Wrapper<Cell<*const ()>>,
53 val: *const (),
54 }
55 impl Drop for Reset {
56 fn drop(&mut self) {
57 self.key.0.set(self.val);
58 }
59 }
60 let prev = self.inner.0.get();
61 self.inner.0.set(t as *const T as *const ());
62 let _reset = Reset {
63 key: self.inner,
64 val: prev,
65 };
66 f()
67 }
68
69 pub fn with<F, R>(&'static self, f: F) -> R
70 where
71 F: FnOnce(&T) -> R,
72 {
73 let val = self.inner.0.get();
74 assert!(
75 !val.is_null(),
76 "cannot access a scoped thread local variable without calling `set` first"
77 );
78 unsafe { f(&*(val as *const T)) }
79 }
80
81 pub fn is_set(&'static self) -> bool {
83 !self.inner.0.get().is_null()
84 }
85}