use crate::{Binding, Sever, TrySever, shroud::Shroud};
use core::{
ops::Deref,
ptr::{self, NonNull},
};
use std::sync::{Arc, RwLock, RwLockReadGuard, TryLockError, Weak};
pub struct Lock;
pub type Soul<'a> = crate::Soul<'a, Lock>;
pub type Lich<T> = crate::Lich<T, Lock>;
pub type Pair<'a, T> = crate::Pair<'a, T, Lock>;
pub struct Data<T: ?Sized>(Arc<RwLock<Option<NonNull<T>>>>);
pub struct Life<'a>(Weak<RwLock<dyn Slot + 'a>>);
pub struct Guard<'a, T: ?Sized>(RwLockReadGuard<'a, Option<NonNull<T>>>);
trait Slot: Sever + TrySever {}
impl<S: Sever + TrySever> Slot for S {}
unsafe impl<'a, T: ?Sized + 'a> Send for Data<T> where Arc<RwLock<Option<&'a T>>>: Send {}
unsafe impl<'a, T: ?Sized + 'a> Sync for Data<T> where Arc<RwLock<Option<&'a T>>>: Sync {}
impl<T: ?Sized> Default for Data<T> {
fn default() -> Self {
Self(Default::default())
}
}
impl<T: ?Sized> Clone for Data<T> {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
impl<T: ?Sized> Sever for Data<T> {
fn sever(&mut self) -> bool {
sever(&self.0)
}
}
impl<T: ?Sized> TrySever for Data<T> {
fn try_sever(&mut self) -> Option<bool> {
if Arc::strong_count(&self.0) == 1 {
try_sever(&self.0)
} else {
None
}
}
}
impl Sever for Life<'_> {
fn sever(&mut self) -> bool {
self.0.upgrade().as_deref().is_some_and(sever)
}
}
impl TrySever for Life<'_> {
fn try_sever(&mut self) -> Option<bool> {
self.0.upgrade().as_deref().map_or(Some(false), try_sever)
}
}
impl Binding for Lock {
type Data<T: ?Sized> = Data<T>;
type Life<'a> = Life<'a>;
fn are_bound<'a, T: ?Sized>(data: &Self::Data<T>, life: &Self::Life<'a>) -> bool {
ptr::addr_eq(Arc::as_ptr(&data.0), Weak::as_ptr(&life.0))
}
fn is_life_bound(life: &Self::Life<'_>) -> bool {
Weak::strong_count(&life.0) > 0
}
fn is_data_bound<T: ?Sized>(data: &Self::Data<T>) -> bool {
Arc::weak_count(&data.0) > 0
}
}
impl<T: ?Sized> Lich<T> {
pub fn borrow(&self) -> Option<Guard<'_, T>> {
let guard = self.0.0.try_read().ok()?;
if guard.is_some() {
Some(Guard(guard))
} else {
None
}
}
}
impl<T: ?Sized> Deref for Guard<'_, T> {
type Target = T;
fn deref(&self) -> &T {
unsafe { self.0.as_ref().unwrap_unchecked().as_ref() }
}
}
impl<T: ?Sized> AsRef<T> for Guard<'_, T> {
fn as_ref(&self) -> &T {
self.deref()
}
}
pub fn ritual<'a, T: ?Sized + 'a, S: Shroud<T> + ?Sized + 'a>(value: &'a T) -> Pair<'a, S> {
let data = Arc::new(RwLock::new(Some(S::shroud(value))));
let life = Arc::downgrade(&data);
(crate::Lich(Data(data)), crate::Soul(Life(life)))
}
pub fn redeem<'a, T: ?Sized + 'a>(
lich: Lich<T>,
soul: Soul<'a>,
) -> Result<Option<Soul<'a>>, Pair<'a, T>> {
crate::redeem::<_, _, true>(lich, soul)
}
fn sever<T: Sever + ?Sized>(lock: &RwLock<T>) -> bool {
match lock.write() {
Ok(mut guard) => guard.sever(),
Err(mut error) => error.get_mut().sever(),
}
}
fn try_sever<T: TrySever + ?Sized>(lock: &RwLock<T>) -> Option<bool> {
match lock.try_write() {
Ok(mut guard) => guard.try_sever(),
Err(TryLockError::Poisoned(mut error)) => error.get_mut().try_sever(),
Err(TryLockError::WouldBlock) => None,
}
}