use crate::{Binding, Sever, TrySever, shroud::Shroud};
use core::{
cell::{Ref, RefCell},
ops::Deref,
ptr::{self, NonNull},
};
use std::rc::{Rc, Weak};
pub struct Cell;
pub type Soul<'a> = crate::Soul<'a, Cell>;
pub type Lich<T> = crate::Lich<T, Cell>;
pub type Pair<'a, T> = crate::Pair<'a, T, Cell>;
pub struct Data<T: ?Sized>(Rc<RefCell<Option<NonNull<T>>>>);
pub struct Life<'a>(Weak<RefCell<dyn Slot + 'a>>);
pub struct Guard<'a, T: ?Sized>(Ref<'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 Rc<RefCell<Option<&'a T>>>: Send {}
unsafe impl<'a, T: ?Sized + 'a> Sync for Data<T> where Rc<RefCell<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 Rc::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 Cell {
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(Rc::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 {
Rc::weak_count(&data.0) > 0
}
}
impl<T: ?Sized> Lich<T> {
pub fn borrow(&self) -> Option<Guard<'_, T>> {
let guard = self.0.0.try_borrow().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 = Rc::new(RefCell::new(Some(S::shroud(value))));
let life = Rc::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>(cell: &RefCell<T>) -> bool {
cell.borrow_mut().sever()
}
fn try_sever<T: TrySever + ?Sized>(cell: &RefCell<T>) -> Option<bool> {
cell.try_borrow_mut().ok()?.try_sever()
}