wasm_bindgen_test/rt/
scoped_tls.rs

1//! See <https://github.com/alexcrichton/scoped-tls/blob/0b6f66a582340bb3363f21a84b70ff40caa98774/src/lib.rs>.
2
3use core::cell::Cell;
4use core::marker::PhantomData;
5
6/// `no_std` polyfill for [`scoped_tls`](https://crates.io/crates/scoped-tls).
7#[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            // Safety: nothing else can access FOO since it's hidden in its own scope
14            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    /// # Safety
39    /// `inner` must only be accessed through `ScopedKey`'s API
40    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    /// Test whether this TLS key has been `set` for the current thread.
82    pub fn is_set(&'static self) -> bool {
83        !self.inner.0.get().is_null()
84    }
85}