#![no_std]
#[doc(hidden)]
pub extern crate alloc;
#[doc(hidden)]
pub mod unsafe_self_cell;
#[macro_export]
macro_rules! self_cell {
(
$(#[$StructMeta:meta])*
$Vis:vis struct $StructName:ident $(<$OwnerLifetime:lifetime>)? {
owner: $Owner:ty,
#[$Covariance:ident $(, $AsyncBuilder:ident)?]
dependent: $Dependent:ident,
}
$(impl {$($AutomaticDerive:ident),*})?
) => {
#[repr(transparent)]
$(#[$StructMeta])*
$Vis struct $StructName $(<$OwnerLifetime>)? {
unsafe_self_cell: $crate::unsafe_self_cell::UnsafeSelfCell<
$StructName$(<$OwnerLifetime>)?,
$Owner,
$Dependent<'static>
>,
$(owner_marker: $crate::_covariant_owner_marker!($Covariance, $OwnerLifetime) ,)?
}
impl <$($OwnerLifetime)?> $StructName <$($OwnerLifetime)?> {
$crate::_self_cell_new!($Vis, $Owner $(=> $OwnerLifetime)?, $Dependent $(, $AsyncBuilder)?);
$crate::_self_cell_try_new!($Vis, $Owner $(=> $OwnerLifetime)?, $Dependent $(, $AsyncBuilder)?);
$crate::_self_cell_try_new_or_recover!($Vis, $Owner $(=> $OwnerLifetime)?, $Dependent $(, $AsyncBuilder)?);
$Vis fn borrow_owner<'_q>(&'_q self) -> &'_q $Owner {
unsafe { self.unsafe_self_cell.borrow_owner::<$Dependent<'_q>>() }
}
$Vis fn with_dependent<'outer_fn, Ret>(
&'outer_fn self,
func: impl for<'_q> ::core::ops::FnOnce(&'_q $Owner, &'outer_fn $Dependent<'_q>
) -> Ret) -> Ret {
unsafe {
func(
self.unsafe_self_cell.borrow_owner::<$Dependent>(),
self.unsafe_self_cell.borrow_dependent()
)
}
}
$Vis fn with_dependent_mut<'outer_fn, Ret>(
&'outer_fn mut self,
func: impl for<'_q> ::core::ops::FnOnce(&'_q $Owner, &'outer_fn mut $Dependent<'_q>) -> Ret
) -> Ret {
let (owner, dependent) = unsafe {
self.unsafe_self_cell.borrow_mut()
};
func(owner, dependent)
}
$crate::_covariant_access!($Covariance, $Vis, $Dependent);
$Vis fn into_owner(self) -> $Owner {
let unsafe_self_cell = unsafe { ::core::mem::transmute::<
Self,
$crate::unsafe_self_cell::UnsafeSelfCell<
$StructName$(<$OwnerLifetime>)?,
$Owner,
$Dependent<'static>
>
>(self) };
let owner = unsafe { unsafe_self_cell.into_owner::<$Dependent>() };
owner
}
}
impl $(<$OwnerLifetime>)? Drop for $StructName $(<$OwnerLifetime>)? {
fn drop(&mut self) {
unsafe {
self.unsafe_self_cell.drop_joined::<$Dependent>();
}
}
}
$($(
$crate::_impl_automatic_derive!($AutomaticDerive, $StructName);
)*)*
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! _covariant_access {
(covariant, $Vis:vis, $Dependent:ident) => {
$Vis fn borrow_dependent<'_q>(&'_q self) -> &'_q $Dependent<'_q> {
fn _assert_covariance<'x: 'y, 'y>(x: &'y $Dependent<'x>) -> &'y $Dependent<'y> {
x }
unsafe { self.unsafe_self_cell.borrow_dependent() }
}
};
(not_covariant, $Vis:vis, $Dependent:ident) => {
};
($x:ident, $Vis:vis, $Dependent:ident) => {
compile_error!("This macro only accepts `covariant` or `not_covariant`");
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! _covariant_owner_marker {
(covariant, $OwnerLifetime:lifetime) => {
::core::marker::PhantomData<&$OwnerLifetime ()>
};
(not_covariant, $OwnerLifetime:lifetime) => {
::core::marker::PhantomData<fn(&$OwnerLifetime ()) -> &$OwnerLifetime ()>
};
($x:ident, $OwnerLifetime:lifetime) => {
compile_error!("This macro only accepts `covariant` or `not_covariant`");
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! _covariant_owner_marker_ctor {
($OwnerLifetime:lifetime) => {
::core::marker::PhantomData
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! _self_cell_new {
($Vis:vis, $Owner:ty $(=> $OwnerLifetime:lifetime)?, $Dependent:ident) => {
$Vis fn new(
owner: $Owner,
dependent_builder: impl for<'_q> ::core::ops::FnOnce(&'_q $Owner) -> $Dependent<'_q>
) -> Self {
type JoinedCell<'_q $(, $OwnerLifetime)?> =
$crate::unsafe_self_cell::JoinedCell<$Owner, $Dependent<'_q>>;
unsafe {
$crate::_self_cell_new_body!(JoinedCell, owner $(=> $OwnerLifetime)?, dependent_builder)
}
}
};
($Vis:vis, $Owner:ty $(=> $OwnerLifetime:lifetime)?, $Dependent:ident, async_builder) => {
$Vis async fn new(
owner: $Owner,
dependent_builder: impl for<'_q> ::core::ops::AsyncFnOnce(&'_q $Owner) -> $Dependent<'_q>
) -> Self {
type JoinedCell<'_q $(, $OwnerLifetime)?> =
$crate::unsafe_self_cell::JoinedCell<$Owner, $Dependent<'_q>>;
unsafe {
$crate::_self_cell_new_body!(JoinedCell, owner $(=> $OwnerLifetime)?, dependent_builder, async_builder)
}
}
};
($Vis:vis, $Owner:ty, $Dependent:ident, $x:ident) => {
compile_error!("This macro only accepts `async_builder`");
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! _self_cell_new_body {
($JoinedCell:ty, $owner:expr $(=> $OwnerLifetime:lifetime)?, $dependent_builder:expr $(, $AsyncBuilder:ident)?) => {{
let layout = $crate::alloc::alloc::Layout::new::<$JoinedCell>();
assert!(layout.size() != 0);
let joined_void_ptr = ::core::ptr::NonNull::new($crate::alloc::alloc::alloc(layout)).unwrap();
let mut joined_ptr = joined_void_ptr.cast::<$JoinedCell>();
let (owner_ptr, dependent_ptr) = <$JoinedCell>::_field_pointers(joined_ptr.as_ptr());
owner_ptr.write($owner);
let drop_guard =
$crate::unsafe_self_cell::OwnerAndCellDropGuard::new(joined_ptr);
dependent_ptr.write($crate::_await_opt!($dependent_builder(&*owner_ptr) $(, $AsyncBuilder)?));
::core::mem::forget(drop_guard);
Self {
unsafe_self_cell: $crate::unsafe_self_cell::UnsafeSelfCell::new(
joined_void_ptr,
),
$(owner_marker: $crate::_covariant_owner_marker_ctor!($OwnerLifetime) ,)?
}
}}
}
#[doc(hidden)]
#[macro_export]
macro_rules! _self_cell_try_new {
($Vis:vis, $Owner:ty $(=> $OwnerLifetime:lifetime)?, $Dependent:ident) => {
$Vis fn try_new<Err>(
owner: $Owner,
dependent_builder:
impl for<'_q> ::core::ops::FnOnce(&'_q $Owner) -> ::core::result::Result<$Dependent<'_q>, Err>
) -> ::core::result::Result<Self, Err> {
type JoinedCell<'_q $(, $OwnerLifetime)?> =
$crate::unsafe_self_cell::JoinedCell<$Owner, $Dependent<'_q>>;
unsafe {
$crate::_self_cell_try_new_body!(JoinedCell, owner $(=> $OwnerLifetime)?, dependent_builder)
}
}
};
($Vis:vis, $Owner:ty $(=> $OwnerLifetime:lifetime)?, $Dependent:ident, async_builder) => {
$Vis async fn try_new<Err>(
owner: $Owner,
dependent_builder:
impl for<'_q> ::core::ops::AsyncFnOnce(&'_q $Owner) -> ::core::result::Result<$Dependent<'_q>, Err>
) -> ::core::result::Result<Self, Err> {
type JoinedCell<'_q $(, $OwnerLifetime)?> =
$crate::unsafe_self_cell::JoinedCell<$Owner, $Dependent<'_q>>;
unsafe {
$crate::_self_cell_try_new_body!(JoinedCell, owner $(=> $OwnerLifetime)?, dependent_builder, async_builder)
}
}
};
($Vis:vis, $Owner:ty, $Dependent:ident, $x:ident) => {
compile_error!("This macro only accepts `async_builder`");
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! _self_cell_try_new_body {
($JoinedCell:ty, $owner:expr $(=> $OwnerLifetime:lifetime)?, $dependent_builder:expr $(, $AsyncBuilder:ident)?) => {{
let layout = $crate::alloc::alloc::Layout::new::<$JoinedCell>();
assert!(layout.size() != 0);
let joined_void_ptr = ::core::ptr::NonNull::new($crate::alloc::alloc::alloc(layout)).unwrap();
let mut joined_ptr = joined_void_ptr.cast::<$JoinedCell>();
let (owner_ptr, dependent_ptr) = <$JoinedCell>::_field_pointers(joined_ptr.as_ptr());
owner_ptr.write($owner);
let mut drop_guard =
$crate::unsafe_self_cell::OwnerAndCellDropGuard::new(joined_ptr);
match $crate::_await_opt!($dependent_builder(&*owner_ptr) $(, $AsyncBuilder)?) {
::core::result::Result::Ok(dependent) => {
dependent_ptr.write(dependent);
::core::mem::forget(drop_guard);
::core::result::Result::Ok(Self {
unsafe_self_cell: $crate::unsafe_self_cell::UnsafeSelfCell::new(
joined_void_ptr,
),
$(owner_marker: $crate::_covariant_owner_marker_ctor!($OwnerLifetime) ,)?
})
}
::core::result::Result::Err(err) => ::core::result::Result::Err(err)
}
}}
}
#[doc(hidden)]
#[macro_export]
macro_rules! _self_cell_try_new_or_recover {
($Vis:vis, $Owner:ty $(=> $OwnerLifetime:lifetime)?, $Dependent:ident) => {
$Vis fn try_new_or_recover<Err>(
owner: $Owner,
dependent_builder:
impl for<'_q> ::core::ops::FnOnce(&'_q $Owner) -> ::core::result::Result<$Dependent<'_q>, Err>
) -> ::core::result::Result<Self, ($Owner, Err)> {
type JoinedCell<'_q $(, $OwnerLifetime)?> =
$crate::unsafe_self_cell::JoinedCell<$Owner, $Dependent<'_q>>;
unsafe {
$crate::_self_cell_try_new_or_recover_body!(JoinedCell, owner $(=> $OwnerLifetime)?, dependent_builder)
}
}
};
($Vis:vis, $Owner:ty $(=> $OwnerLifetime:lifetime)?, $Dependent:ident, async_builder) => {
$Vis async fn try_new_or_recover<Err>(
owner: $Owner,
dependent_builder:
impl for<'_q> ::core::ops::AsyncFnOnce(&'_q $Owner) -> ::core::result::Result<$Dependent<'_q>, Err>
) -> ::core::result::Result<Self, ($Owner, Err)> {
type JoinedCell<'_q $(, $OwnerLifetime)?> =
$crate::unsafe_self_cell::JoinedCell<$Owner, $Dependent<'_q>>;
unsafe {
$crate::_self_cell_try_new_or_recover_body!(JoinedCell, owner $(=> $OwnerLifetime)?, dependent_builder, async_builder)
}
}
};
($Vis:vis, $Owner:ty, $Dependent:ident, $x:ident) => {
compile_error!("This macro only accepts `async_builder`");
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! _self_cell_try_new_or_recover_body {
($JoinedCell:ty, $owner:expr $(=> $OwnerLifetime:lifetime)?, $dependent_builder:expr $(, $AsyncBuilder:ident)?) => {{
let layout = $crate::alloc::alloc::Layout::new::<$JoinedCell>();
assert!(layout.size() != 0);
let joined_void_ptr = ::core::ptr::NonNull::new($crate::alloc::alloc::alloc(layout)).unwrap();
let mut joined_ptr = joined_void_ptr.cast::<$JoinedCell>();
let (owner_ptr, dependent_ptr) = <$JoinedCell>::_field_pointers(joined_ptr.as_ptr());
owner_ptr.write($owner);
let mut drop_guard =
$crate::unsafe_self_cell::OwnerAndCellDropGuard::new(joined_ptr);
match $crate::_await_opt!($dependent_builder(&*owner_ptr) $(, $AsyncBuilder)?) {
::core::result::Result::Ok(dependent) => {
dependent_ptr.write(dependent);
::core::mem::forget(drop_guard);
::core::result::Result::Ok(Self {
unsafe_self_cell: $crate::unsafe_self_cell::UnsafeSelfCell::new(
joined_void_ptr,
),
$(owner_marker: $crate::_covariant_owner_marker_ctor!($OwnerLifetime) ,)?
})
}
::core::result::Result::Err(err) => {
let owner_on_err = ::core::ptr::read(owner_ptr);
::core::mem::forget(drop_guard);
$crate::alloc::alloc::dealloc(joined_void_ptr.as_ptr(), layout);
::core::result::Result::Err((owner_on_err, err))
}
}
}}
}
#[doc(hidden)]
#[macro_export]
macro_rules! _await_opt {
($val:expr) => {
$val
};
($future:expr, async_builder) => {
$future.await
};
($v:expr, $x:ident) => {
compile_error!("This macro only accepts `async_builder`");
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! _impl_automatic_derive {
(Debug, $StructName:ident) => {
impl ::core::fmt::Debug for $StructName {
fn fmt(
&self,
fmt: &mut ::core::fmt::Formatter,
) -> ::core::result::Result<(), ::core::fmt::Error> {
self.with_dependent(|owner, dependent| {
fmt.debug_struct(stringify!($StructName))
.field("owner", owner)
.field("dependent", dependent)
.finish()
})
}
}
};
(PartialEq, $StructName:ident) => {
impl ::core::cmp::PartialEq for $StructName {
fn eq(&self, other: &Self) -> bool {
*self.borrow_owner() == *other.borrow_owner()
}
}
};
(Eq, $StructName:ident) => {
impl ::core::cmp::Eq for $StructName {}
};
(Hash, $StructName:ident) => {
impl ::core::hash::Hash for $StructName {
fn hash<H: ::core::hash::Hasher>(&self, state: &mut H) {
self.borrow_owner().hash(state);
}
}
};
($x:ident, $StructName:ident) => {
compile_error!(concat!(
"No automatic trait impl for trait: ",
stringify!($x)
));
};
}
pub use unsafe_self_cell::MutBorrow;