use crate::batch::with_runtime;
use core::{mem::ManuallyDrop, panic::Location};
pub struct JsThreadLocal<T: 'static> {
key: ThreadLocalKey<'static>,
init: fn() -> T,
}
impl<T> JsThreadLocal<T> {
#[doc(hidden)]
#[track_caller]
pub const fn new(init: fn() -> T, index: u32) -> Self {
let caller = Location::caller();
Self {
key: ThreadLocalKey {
file: caller.file(),
line: caller.line(),
column: caller.column(),
index,
},
init,
}
}
pub fn with<F, R>(&'static self, f: F) -> R
where
F: FnOnce(&T) -> R,
{
let init = self.init;
let initialized = with_runtime(|runtime| runtime.has_thread_local(self.key));
if !initialized {
let value = init();
with_runtime(|runtime| {
runtime.insert_thread_local(self.key, ManuallyDrop::new(value));
});
}
let value: ManuallyDrop<T> = with_runtime(|runtime| runtime.take_thread_local(self.key));
let result = f(&value);
with_runtime(|runtime| {
runtime.insert_thread_local(self.key, value);
});
result
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub(crate) struct ThreadLocalKey<'a> {
file: &'a str,
line: u32,
column: u32,
index: u32,
}