jay-compositor 1.13.0

The Jay compositor
use {
    crate::utils::{stack::Stack, thread_id::ThreadId},
    isnt::std_1::primitive::IsntConstPtrExt,
    std::{any::Any, cell::Cell, convert::Infallible, rc::Rc},
};

#[cfg(test)]
mod tests;

pub struct ThreadLocalData<T>
where
    T: 'static,
{
    thread_id: ThreadId,
    ptr: Cell<*const T>,
}

thread_local! {
    static HOLDER: Stack<Rc<dyn Any>> = const { Stack::new() };
}

unsafe impl<T> Send for ThreadLocalData<T> {}
unsafe impl<T> Sync for ThreadLocalData<T> {}

impl<T> ThreadLocalData<T>
where
    T: 'static,
{
    pub fn new(thread_id: ThreadId) -> Self {
        Self {
            thread_id,
            ptr: Default::default(),
        }
    }

    #[cfg_attr(not(test), expect(dead_code))]
    pub fn get_or_create(&self, init: impl FnOnce() -> Rc<T>) -> Rc<T> {
        self.get_or_try_create::<Infallible>(|| Ok(init())).unwrap()
    }

    pub fn get_or_try_create<E>(
        &self,
        init: impl FnOnce() -> Result<Rc<T>, E>,
    ) -> Result<Rc<T>, E> {
        assert!(self.thread_id.is_current());
        HOLDER.with(|h| {
            let ptr = self.ptr.get();
            if ptr.is_not_null() {
                unsafe {
                    Rc::increment_strong_count(ptr);
                    return Ok(Rc::from_raw(ptr));
                }
            }
            let rc = init()?;
            h.push(rc.clone());
            self.ptr.set(Rc::as_ptr(&rc));
            Ok(rc)
        })
    }
}