use std::{ cell::{self, RefCell, UnsafeCell}, error::Error, fmt, mem::{ManuallyDrop, MaybeUninit}, ops::{Deref, DerefMut}, sync::Arc, }; use parking_lot::{Once, ReentrantMutex, ReentrantMutexGuard}; #[derive(Debug)] pub struct BorrowFail; impl fmt::Display for BorrowFail { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "failed to borrow global value twice in same thread") } } impl Error for BorrowFail {} type InnerPointer = Arc>>; pub struct Global(Immutable>); unsafe impl Sync for Global {} unsafe impl Send for Global {} impl Global { pub const fn new() -> Self { Self(Immutable::new()) } } impl Global { pub fn with(&self, f: F) -> R where F: FnOnce(&T) -> R, { f(&*self.lock().expect("Couldn't immutably access global variable")) } pub fn with_mut(&self, f: F) -> R where F: FnOnce(&mut T) -> R, { f(&mut *self.lock_mut().expect("Couldn't mutably access global variable")) } pub fn lock(&self) -> Result, BorrowFail> { let mutex: Arc<_> = Arc::clone(&*self.0); let mutex_ptr = &*mutex as *const ReentrantMutex>; let mutex_guard = unsafe { (*mutex_ptr).lock() }; let mutex_guard_ptr = &*mutex_guard as *const RefCell; let ref_cell_guard = unsafe { (*mutex_guard_ptr).try_borrow().map_err(|_| BorrowFail)? }; Ok(GlobalGuard { mutex: ManuallyDrop::new(mutex), mutex_guard: ManuallyDrop::new(mutex_guard), ref_cell_guard: ManuallyDrop::new(ref_cell_guard), }) } pub fn lock_mut(&self) -> Result, BorrowFail> { let mutex: Arc<_> = Arc::clone(&*self.0); let mutex_ptr = &*mutex as *const ReentrantMutex>; let mutex_guard = unsafe { (*mutex_ptr).lock() }; let mutex_guard_ptr = &*mutex_guard as *const RefCell; let ref_cell_guard = unsafe { (*mutex_guard_ptr).try_borrow_mut().map_err(|_| BorrowFail)? }; Ok(GlobalGuardMut { mutex: ManuallyDrop::new(mutex), mutex_guard: ManuallyDrop::new(mutex_guard), ref_cell_guard: ManuallyDrop::new(ref_cell_guard), }) } pub fn force_init(&self) { self.0.ensure_exists(); } } pub struct GlobalGuardMut { mutex: ManuallyDrop>>>, mutex_guard: ManuallyDrop>>, ref_cell_guard: ManuallyDrop>, } impl Drop for GlobalGuardMut { fn drop(&mut self) { unsafe { ManuallyDrop::drop(&mut self.ref_cell_guard); ManuallyDrop::drop(&mut self.mutex_guard); ManuallyDrop::drop(&mut self.mutex); } } } impl Deref for GlobalGuardMut { type Target = T; fn deref(&self) -> &T { &*self.ref_cell_guard } } impl DerefMut for GlobalGuardMut { fn deref_mut(&mut self) -> &mut T { &mut *self.ref_cell_guard } } pub struct GlobalGuard { mutex: ManuallyDrop>>>, mutex_guard: ManuallyDrop>>, ref_cell_guard: ManuallyDrop>, } impl Drop for GlobalGuard { fn drop(&mut self) { unsafe { ManuallyDrop::drop(&mut self.ref_cell_guard); ManuallyDrop::drop(&mut self.mutex_guard); ManuallyDrop::drop(&mut self.mutex); } } } impl Deref for GlobalGuard { type Target = T; fn deref(&self) -> &T { &*self.ref_cell_guard } } pub struct Immutable { once: Once, inner: UnsafeCell>, } impl Drop for Immutable { fn drop(&mut self) { if let parking_lot::OnceState::Done = self.once.state() { unsafe { std::ptr::drop_in_place((*self.inner.get()).as_mut_ptr()); } } } } unsafe impl Send for Immutable {} unsafe impl Sync for Immutable {} impl Immutable { fn ensure_exists(&self) { self.once.call_once(|| unsafe { *self.inner.get() = MaybeUninit::new(T::default()); }); } pub fn force_init(&self) { self.ensure_exists(); } } impl Immutable { pub const fn new() -> Self { Self { once: Once::new(), inner: UnsafeCell::new(MaybeUninit::uninit()), } } } impl Deref for Immutable { type Target = T; fn deref(&self) -> &Self::Target { self.ensure_exists(); unsafe { &*(*self.inner.get()).as_ptr() } } }