use core::fmt::{Debug, Error, Formatter};
use core::hash::{Hash, Hasher};
use core::mem::transmute;
use crate::OnceCellCompatible;
pub type VoidPtr = *mut u8;
pub type DependentInner = (VoidPtr, fn(VoidPtr));
pub struct OnceSelfCell<Owner, DependentCell: OnceCellCompatible<DependentInner>> {
owner_ptr: *mut Owner,
dependent_cell: DependentCell,
}
impl<Owner, DependentCell> OnceSelfCell<Owner, DependentCell>
where
DependentCell: OnceCellCompatible<DependentInner>,
{
pub fn new(owner: Owner) -> Self {
OnceSelfCell {
owner_ptr: Box::into_raw(Box::new(owner)),
dependent_cell: DependentCell::new(),
}
}
pub fn get_owner<'a>(&'a self) -> &'a Owner {
unsafe { &*self.owner_ptr }
}
pub fn get_or_init_dependent<'a, Dependent>(
&'a self,
make_dependent: impl FnOnce(&'a Owner) -> Dependent,
) -> &'a Dependent {
let (dependent_void_ptr, _) = self.dependent_cell.get_or_init(|| {
let owner = unsafe { transmute::<*mut Owner, &'a Owner>(self.owner_ptr) };
let dependent_ptr = Box::into_raw(Box::new(make_dependent(owner)));
let dependent_void_ptr = unsafe { transmute::<*mut Dependent, VoidPtr>(dependent_ptr) };
let drop_fn = |dependent_void_ptr: VoidPtr| {
let dependent_ptr =
unsafe { transmute::<VoidPtr, *mut Dependent>(dependent_void_ptr) };
let dependent_box = unsafe { Box::from_raw(dependent_ptr) };
drop(dependent_box);
};
(dependent_void_ptr, drop_fn)
});
let dependent_ptr = unsafe { transmute::<VoidPtr, *mut Dependent>(*dependent_void_ptr) };
unsafe { &*dependent_ptr }
}
pub fn dependent_is_none(&self) -> bool {
self.dependent_cell.get().is_none()
}
}
impl<Owner, DependentCell> Drop for OnceSelfCell<Owner, DependentCell>
where
DependentCell: OnceCellCompatible<DependentInner>,
{
fn drop(&mut self) {
unsafe {
drop(Box::from_raw(self.owner_ptr));
}
if let Some((dependent_void_ptr, drop_fn)) = self.dependent_cell.take() {
drop_fn(dependent_void_ptr);
}
}
}
unsafe impl<Owner, DependentCell> Send for OnceSelfCell<Owner, DependentCell>
where
Owner: Send,
DependentCell: OnceCellCompatible<DependentInner> + Send,
{
}
unsafe impl<Owner, DependentCell> Sync for OnceSelfCell<Owner, DependentCell>
where
Owner: Sync,
DependentCell: OnceCellCompatible<DependentInner> + Sync,
{
}
impl<Owner, DependentCell> Clone for OnceSelfCell<Owner, DependentCell>
where
Owner: Clone,
DependentCell: OnceCellCompatible<DependentInner>,
{
fn clone(&self) -> Self {
OnceSelfCell {
owner_ptr: Box::into_raw(Box::new(self.get_owner().clone())),
dependent_cell: DependentCell::new(),
}
}
}
impl<Owner, DependentCell> PartialEq for OnceSelfCell<Owner, DependentCell>
where
Owner: PartialEq,
DependentCell: OnceCellCompatible<DependentInner>,
{
fn eq(&self, other: &Self) -> bool {
*self.get_owner() == *other.get_owner()
}
}
impl<Owner, DependentCell> Eq for OnceSelfCell<Owner, DependentCell>
where
Owner: Eq,
DependentCell: OnceCellCompatible<DependentInner>,
{
}
impl<Owner, DependentCell> Hash for OnceSelfCell<Owner, DependentCell>
where
Owner: Hash,
DependentCell: OnceCellCompatible<DependentInner>,
{
fn hash<H: Hasher>(&self, state: &mut H) {
self.get_owner().hash(state);
}
}
impl<Owner, DependentCell> Debug for OnceSelfCell<Owner, DependentCell>
where
Owner: Debug,
DependentCell: Debug + OnceCellCompatible<DependentInner>,
{
fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
write!(
fmt,
"OnceSelfCell {{ owner: {:?}, dependent_cell: {:?} }}",
self.get_owner(),
self.dependent_cell
)
}
}