use crate::pg_sys;
use core::mem::MaybeUninit;
use std::{cell::UnsafeCell, marker::PhantomData};
#[doc(alias = "slock_t")]
pub struct PgSpinLock<T> {
item: UnsafeCell<T>,
lock: UnsafeCell<pg_sys::slock_t>,
}
unsafe impl<T: Send> Send for PgSpinLock<T> {}
unsafe impl<T: Send> Sync for PgSpinLock<T> {}
impl<T> PgSpinLock<T> {
#[inline]
pub fn new(value: T) -> Self {
let mut slock = MaybeUninit::zeroed();
unsafe {
pg_sys::SpinLockInit(slock.as_mut_ptr());
Self { item: UnsafeCell::new(value), lock: UnsafeCell::new(slock.assume_init()) }
}
}
#[inline]
#[doc(alias = "SpinLockFree")]
pub fn is_locked(&self) -> bool {
unsafe { !pg_sys::SpinLockFree(self.lock.get()) }
}
#[inline]
#[doc(alias = "SpinLockAcquire")]
pub fn lock(&self) -> PgSpinLockGuard<'_, T> {
unsafe { pg_sys::SpinLockAcquire(self.lock.get()) };
PgSpinLockGuard { lock: self, _marker: PhantomData }
}
}
pub struct PgSpinLockGuard<'a, T: 'a> {
lock: &'a PgSpinLock<T>,
_marker: PhantomData<*mut T>,
}
unsafe impl<T: Sync> Sync for PgSpinLockGuard<'_, T> {}
impl<'a, T> Drop for PgSpinLockGuard<'a, T> {
#[inline]
fn drop(&mut self) {
unsafe { pg_sys::SpinLockRelease(self.lock.lock.get()) };
}
}
impl<'a, T> core::ops::Deref for PgSpinLockGuard<'a, T> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
unsafe { &*self.lock.item.get() }
}
}
impl<'a, T> core::ops::DerefMut for PgSpinLockGuard<'a, T> {
#[inline]
fn deref_mut(&mut self) -> &mut T {
unsafe { &mut *self.lock.item.get() }
}
}