use core::{convert::Infallible, fmt::Debug, marker::PhantomData, mem::ManuallyDrop, ptr::NonNull};
use alloc::boxed::Box;
use crate::{Dependent, Owner, drop_guard::DropGuard};
pub struct Pair<O: Owner + ?Sized> {
owner: NonNull<O>,
dependent: NonNull<()>,
prevent_covariance: PhantomData<*mut O>,
}
fn non_null_from_box<T: ?Sized>(value: Box<T>) -> NonNull<T> {
NonNull::from(Box::leak(value))
}
impl<O: Owner + ?Sized> Pair<O> {
pub fn try_new_with_context(owner: O, context: O::Context<'_>) -> Result<Self, (O, O::Error)>
where
O: Sized,
{
Self::try_new_from_box_with_context(Box::new(owner), context)
.map_err(|(owner, err)| (*owner, err))
}
pub fn try_new_from_box_with_context(
owner: Box<O>,
context: O::Context<'_>,
) -> Result<Self, (Box<O>, O::Error)> {
let owner = non_null_from_box(owner);
let panic_drop_guard = DropGuard(|| {
let owner: Box<O> = unsafe { Box::from_raw(owner.as_ptr()) };
drop(owner);
});
let maybe_dependent = {
unsafe { owner.as_ref() }.make_dependent(context)
};
core::mem::forget(panic_drop_guard);
let dependent = match maybe_dependent {
Ok(dependent) => dependent,
Err(err) => {
let owner: Box<O> = unsafe { Box::from_raw(owner.as_ptr()) };
return Err((owner, err));
}
};
let panic_drop_guard = DropGuard(|| {
let owner: Box<O> = unsafe { Box::from_raw(owner.as_ptr()) };
drop(owner);
});
let dependent = Box::new(dependent);
core::mem::forget(panic_drop_guard);
let dependent: NonNull<Dependent<'_, O>> = non_null_from_box(dependent);
let dependent: NonNull<()> = dependent.cast();
Ok(Self {
owner,
dependent,
prevent_covariance: PhantomData,
})
}
pub fn owner(&self) -> &O {
unsafe { self.owner.as_ref() }
}
pub fn with_dependent<'self_borrow, F, T>(&'self_borrow self, f: F) -> T
where
F: for<'any> FnOnce(&'self_borrow Dependent<'_, O>) -> T,
{
let dependent = unsafe { self.dependent.cast::<Dependent<'_, O>>().as_ref() };
f(dependent)
}
pub fn with_dependent_mut<'self_borrow, F, T>(&'self_borrow mut self, f: F) -> T
where
F: for<'any> FnOnce(&'self_borrow mut Dependent<'_, O>) -> T,
{
self.with_both_mut(|_, dependent| f(dependent))
}
pub fn with_both<'self_borrow, F, T>(&'self_borrow self, f: F) -> T
where
F: for<'any> FnOnce(&'self_borrow O, &'self_borrow Dependent<'_, O>) -> T,
{
self.with_dependent(|dependent| f(self.owner(), dependent))
}
pub fn with_both_mut<'self_borrow, F, T>(&'self_borrow mut self, f: F) -> T
where
F: for<'any> FnOnce(&'self_borrow O, &'self_borrow mut Dependent<'_, O>) -> T,
{
let owner: &O = self.owner();
let dependent = unsafe { self.dependent.cast::<Dependent<'_, O>>().as_mut() };
f(owner, dependent)
}
pub fn into_boxed_owner(self) -> Box<O> {
let this = ManuallyDrop::new(self);
let dependent: Box<Dependent<'_, O>> =
unsafe { Box::from_raw(this.dependent.cast::<Dependent<'_, O>>().as_ptr()) };
let panic_drop_guard = DropGuard(|| {
let owner: Box<O> = unsafe { Box::from_raw(this.owner.as_ptr()) };
drop(owner);
});
drop(dependent);
core::mem::forget(panic_drop_guard);
unsafe { Box::from_raw(this.owner.as_ptr()) }
}
pub fn into_owner(self) -> O
where
O: Sized,
{
*self.into_boxed_owner()
}
}
impl<O: for<'any> Owner<Context<'any> = (), Error = Infallible> + ?Sized> Pair<O> {
pub fn new(owner: O) -> Self
where
O: Sized,
{
Self::new_with_context(owner, ())
}
pub fn new_from_box(owner: Box<O>) -> Self {
Self::new_from_box_with_context(owner, ())
}
}
impl<O: for<'any> Owner<Context<'any> = ()> + ?Sized> Pair<O> {
pub fn try_new(owner: O) -> Result<Self, (O, O::Error)>
where
O: Sized,
{
Self::try_new_with_context(owner, ())
}
pub fn try_new_from_box(owner: Box<O>) -> Result<Self, (Box<O>, O::Error)> {
Self::try_new_from_box_with_context(owner, ())
}
}
impl<O: Owner<Error = Infallible> + ?Sized> Pair<O> {
pub fn new_with_context(owner: O, context: O::Context<'_>) -> Self
where
O: Sized,
{
let Ok(pair) = Self::try_new_with_context(owner, context);
pair
}
pub fn new_from_box_with_context(owner: Box<O>, context: O::Context<'_>) -> Self {
let Ok(pair) = Self::try_new_from_box_with_context(owner, context);
pair
}
}
impl<O: Owner + ?Sized> Drop for Pair<O> {
fn drop(&mut self) {
let dependent =
unsafe { Box::from_raw(self.dependent.cast::<Dependent<'_, O>>().as_ptr()) };
let panic_drop_guard = DropGuard(|| {
let owner: Box<O> = unsafe { Box::from_raw(self.owner.as_ptr()) };
drop(owner);
});
drop(dependent);
core::mem::forget(panic_drop_guard);
let owner = unsafe { Box::from_raw(self.owner.as_ptr()) };
drop(owner);
}
}
unsafe impl<O: Owner + ?Sized> Send for Pair<O>
where
O: Send,
for<'any> Dependent<'any, O>: Send,
{
}
unsafe impl<O: Owner + ?Sized> Sync for Pair<O>
where
O: Sync,
for<'any> Dependent<'any, O>: Sync,
{
}
impl<O: Owner + Debug + ?Sized> Debug for Pair<O>
where
for<'any> Dependent<'any, O>: Debug,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.with_dependent(|dependent| {
f.debug_struct("Pair")
.field("owner", &self.owner())
.field("dependent", dependent)
.finish()
})
}
}
impl<O: for<'any> Owner<Context<'any> = (), Error = Infallible> + Default> Default for Pair<O> {
fn default() -> Self {
Self::new(O::default())
}
}