use std::cell::UnsafeCell;
use std::hint::unreachable_unchecked;
use std::mem::needs_drop;
use std::pin::{Pin, pin};
use std::ptr::{self, NonNull};
use std::sync::atomic::Ordering;
use std::sync::atomic::Ordering::Acquire;
use saa::lock::Mode;
use saa::{Lock, Pager};
use sdd::{AtomicRaw, Owned, PrivateCollector, RawPtr};
use crate::Guard;
#[derive(Default)]
pub(crate) struct AsyncGuard {
guard: UnsafeCell<Option<Guard>>,
}
pub(crate) struct AsyncPager {
pager: Pager<'static, Lock>,
}
pub(crate) trait LockPager {
#[must_use]
fn try_wait<const READ: bool>(&mut self, lock: &Lock) -> bool;
fn try_acquire<const READ: bool>(&mut self, lock: &Lock) -> Result<bool, ()>;
}
#[inline]
pub(crate) const fn deref_unchecked<T>(ptr: RawPtr<'_, T>) -> Option<&'_ T> {
unsafe { ptr.into_ptr().as_ref_unchecked() }
}
#[inline]
pub(crate) const fn unwrap_unchecked<T>(v: Option<T>) -> T {
unsafe { v.unwrap_unchecked() }
}
#[inline]
pub(crate) const fn snapshot<T>(v: &T) -> T {
unsafe { ptr::from_ref(v).read() }
}
#[inline]
pub(crate) fn get_owned<T>(ptr: RawPtr<'_, T>) -> Option<Owned<T>> {
unsafe { Owned::from_raw(ptr) }
}
#[inline]
pub(crate) fn drop_in_place<T>(ptr: RawPtr<'_, T>) {
unsafe {
if let Some(owned) = Owned::from_raw(ptr) {
owned.drop_in_place();
}
}
}
#[inline]
pub(crate) fn retire<D, T>(
ptr: RawPtr<'_, T>,
private_collector: &PrivateCollector,
guard: &Guard,
) {
if let Some(owned) = get_owned(ptr) {
if needs_drop::<D>() {
unsafe {
private_collector.collect_owned(owned, guard);
}
}
}
}
#[inline]
pub(crate) const fn fake_ref<'l, T, U>(v: &T) -> &'l U {
unsafe { &*ptr::from_ref(v).cast::<U>() }
}
#[inline]
pub const fn into_non_null<T: Sized>(t: &T) -> NonNull<T> {
unsafe { NonNull::new_unchecked(ptr::from_ref(t).cast_mut()) }
}
#[cold]
pub const fn cold_path() {}
#[allow(clippy::inline_always)]
#[inline(always)]
pub const fn likely(cond: bool) -> bool {
if cond {
true
} else {
cold_path();
false
}
}
#[inline]
pub(crate) const fn undefined() -> ! {
unsafe { unreachable_unchecked() }
}
impl AsyncGuard {
#[inline]
pub(crate) const fn has_guard(&self) -> bool {
unsafe { (*self.guard.get()).is_some() }
}
#[inline]
pub(crate) fn guard(&self) -> &Guard {
unsafe { (*self.guard.get()).get_or_insert_with(Guard::new) }
}
#[inline]
pub(crate) fn reset(&self) {
unsafe {
*self.guard.get() = None;
}
}
#[inline]
pub(crate) fn load_unchecked<T>(&self, atomic_ptr: &AtomicRaw<T>, mo: Ordering) -> Option<&T> {
deref_unchecked(atomic_ptr.load(mo, self.guard()))
}
#[inline]
pub(crate) fn check_ref<T>(&self, atomic_ptr: &AtomicRaw<T>, r: &T, mo: Ordering) -> bool {
self.load_unchecked(atomic_ptr, mo)
.is_some_and(|s| ptr::eq(s, r))
}
}
unsafe impl Send for AsyncGuard {}
unsafe impl Sync for AsyncGuard {}
impl AsyncPager {
#[inline]
pub async fn wait(self: &mut Pin<&mut Self>) {
let this = unsafe { ptr::read(self) };
let mut pinned_pager = unsafe { Pin::new_unchecked(&mut this.get_unchecked_mut().pager) };
let _result = pinned_pager.poll_async().await;
}
}
impl Default for AsyncPager {
#[inline]
fn default() -> Self {
Self {
pager: unsafe {
std::mem::transmute::<Pager<'_, Lock>, Pager<'static, Lock>>(Pager::default())
},
}
}
}
impl LockPager for Pin<&mut AsyncPager> {
#[inline]
fn try_wait<const READ: bool>(&mut self, lock: &Lock) -> bool {
let this = unsafe { ptr::read(self) };
let mut pinned_pager = unsafe {
let pager_ref = std::mem::transmute::<&mut Pager<'static, Lock>, &mut Pager<Lock>>(
&mut this.get_unchecked_mut().pager,
);
Pin::new_unchecked(pager_ref)
};
let mode = if READ {
Mode::WaitShared
} else {
Mode::WaitExclusive
};
lock.register_pager(&mut pinned_pager, mode, false);
false
}
#[inline]
fn try_acquire<const READ: bool>(&mut self, lock: &Lock) -> Result<bool, ()> {
if (READ && lock.try_share()) || (!READ && lock.try_lock()) {
return Ok(true);
} else if lock.is_poisoned(Acquire) {
return Ok(false);
}
let _: bool = self.try_wait::<READ>(lock);
Err(())
}
}
impl LockPager for () {
#[inline]
fn try_wait<const READ: bool>(&mut self, lock: &Lock) -> bool {
let mut pinned_pager = pin!(Pager::default());
let mode = if READ {
Mode::WaitShared
} else {
Mode::WaitExclusive
};
lock.register_pager(&mut pinned_pager, mode, true);
pinned_pager.poll_sync().is_ok_and(|r| r)
}
#[inline]
fn try_acquire<const READ: bool>(&mut self, lock: &Lock) -> Result<bool, ()> {
Ok((READ && lock.share_sync()) || (!READ && lock.lock_sync()))
}
}