1use core::{ffi::c_void, marker::PhantomData};
2
3use sys::os::tls::*;
4
5use alloc::boxed::Box;
6
7pub struct ThreadLocal<T> {
12 slot: TlsSlot,
13 init: fn() -> T,
14 _marker: PhantomData<*mut T>,
15}
16
17unsafe impl<T: Send> Send for ThreadLocal<T> {}
18unsafe impl<T: Send> Sync for ThreadLocal<T> {}
19
20impl<T> ThreadLocal<T> {
21 pub fn new(init: fn() -> T) -> Self {
23 let mut slot = TlsSlot::new();
24 let result = unsafe { nnosAllocateTlsSlot(&mut slot, Self::destructor) };
25
26 if result != 0 || !slot.valid() {
27 panic!("Failed to allocate TLS Slot");
28 }
29
30 Self {
31 slot,
32 init,
33 _marker: Default::default(),
34 }
35 }
36
37 pub fn with<R>(&self, f: impl FnOnce(&T) -> R) -> R {
39 f(self.get_or_init())
40 }
41
42 pub fn with_mut<R>(&self, f: impl FnOnce(&mut T) -> R) -> R {
44 f(self.get_or_init())
45 }
46
47 fn get_or_init(&self) -> &mut T {
48 let ptr = unsafe { nnosGetTlsValue(self.slot) };
49
50 if !ptr.is_null() {
51 unsafe { &mut *(ptr as *mut T) }
52 } else {
53 let val = Box::leak(Box::new((self.init)()));
54 unsafe { nnosSetTlsValue(self.slot, val as *mut T as *mut c_void) };
55 val
56 }
57 }
58
59 unsafe extern "C" fn destructor(value: *mut c_void) {
60 if !value.is_null() {
61 drop(unsafe { Box::from_raw(value as *mut T) })
62 }
63 }
64}
65
66impl<T> Drop for ThreadLocal<T> {
67 fn drop(&mut self) {
68 unsafe { nnosFreeTlsSlot(self.slot) };
69 }
70}