use crate::{PGRXSharedMemory, pg_sys};
use core::mem::MaybeUninit;
use core::ops::{Deref, DerefMut};
use std::cell::UnsafeCell;
#[doc(alias = "slock_t")]
pub struct PgSpinLock<T> {
data: UnsafeCell<T>,
lock: UnsafeCell<pg_sys::slock_t>,
}
unsafe impl<T: PGRXSharedMemory> Sync for PgSpinLock<T> {}
unsafe impl<T: PGRXSharedMemory> PGRXSharedMemory for PgSpinLock<T> {}
impl<T> PgSpinLock<T> {
#[inline]
#[doc(alias = "SpinLockInit")]
pub fn new(value: T) -> Self {
let mut slock = MaybeUninit::zeroed();
unsafe {
pg_sys::SpinLockInit(slock.as_mut_ptr());
Self { data: UnsafeCell::new(value), lock: UnsafeCell::new(slock.assume_init()) }
}
}
}
impl<T: PGRXSharedMemory> PgSpinLock<T> {
#[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 { data: &mut *self.data.get(), lock: self.lock.get() }
}
}
}
pub struct PgSpinLockGuard<'a, T: 'a> {
data: &'a mut T,
lock: *mut pg_sys::slock_t,
}
unsafe impl<T: PGRXSharedMemory> Sync for PgSpinLockGuard<'_, T> {}
impl<T> Drop for PgSpinLockGuard<'_, T> {
#[inline]
#[doc(alias = "SpinLockRelease")]
fn drop(&mut self) {
unsafe { pg_sys::SpinLockRelease(self.lock) };
}
}
impl<T> Deref for PgSpinLockGuard<'_, T> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
self.data
}
}
impl<T> DerefMut for PgSpinLockGuard<'_, T> {
#[inline]
fn deref_mut(&mut self) -> &mut T {
self.data
}
}