use crate::alloc::{AllocError, Flags};
use crate::prelude::*;
use crate::sync::atomic::{ordering, AtomicFlag};
use crate::sync::{Arc, ArcBorrow, UniqueArc};
use core::marker::PhantomPinned;
use core::ops::Deref;
use core::pin::Pin;
pub trait ListArcSafe<const ID: u64 = 0> {
unsafe fn on_create_list_arc_from_unique(self: Pin<&mut Self>);
unsafe fn on_drop_list_arc(&self);
}
pub unsafe trait TryNewListArc<const ID: u64 = 0>: ListArcSafe<ID> {
fn try_new_list_arc(&self) -> bool;
}
#[macro_export]
#[doc(hidden)]
macro_rules! impl_list_arc_safe {
(impl$({$($generics:tt)*})? ListArcSafe<$num:tt> for $t:ty { untracked; } $($rest:tt)*) => {
impl$(<$($generics)*>)? $crate::list::ListArcSafe<$num> for $t {
unsafe fn on_create_list_arc_from_unique(self: ::core::pin::Pin<&mut Self>) {}
unsafe fn on_drop_list_arc(&self) {}
}
$crate::list::impl_list_arc_safe! { $($rest)* }
};
(impl$({$($generics:tt)*})? ListArcSafe<$num:tt> for $t:ty {
tracked_by $field:ident : $fty:ty;
} $($rest:tt)*) => {
impl$(<$($generics)*>)? $crate::list::ListArcSafe<$num> for $t {
unsafe fn on_create_list_arc_from_unique(self: ::core::pin::Pin<&mut Self>) {
::pin_init::assert_pinned!($t, $field, $fty, inline);
let field = unsafe {
::core::pin::Pin::map_unchecked_mut(self, |me| &mut me.$field)
};
unsafe {
<$fty as $crate::list::ListArcSafe<$num>>::on_create_list_arc_from_unique(field)
};
}
unsafe fn on_drop_list_arc(&self) {
unsafe { <$fty as $crate::list::ListArcSafe<$num>>::on_drop_list_arc(&self.$field) };
}
}
unsafe impl$(<$($generics)*>)? $crate::list::TryNewListArc<$num> for $t
where
$fty: TryNewListArc<$num>,
{
fn try_new_list_arc(&self) -> bool {
<$fty as $crate::list::TryNewListArc<$num>>::try_new_list_arc(&self.$field)
}
}
$crate::list::impl_list_arc_safe! { $($rest)* }
};
() => {};
}
pub use impl_list_arc_safe;
#[repr(transparent)]
#[derive(core::marker::CoercePointee)]
pub struct ListArc<T, const ID: u64 = 0>
where
T: ListArcSafe<ID> + ?Sized,
{
arc: Arc<T>,
}
impl<T: ListArcSafe<ID>, const ID: u64> ListArc<T, ID> {
#[inline]
pub fn new(contents: T, flags: Flags) -> Result<Self, AllocError> {
Ok(Self::from(UniqueArc::new(contents, flags)?))
}
#[inline]
pub fn pin_init<E>(init: impl PinInit<T, E>, flags: Flags) -> Result<Self, E>
where
E: From<AllocError>,
{
Ok(Self::from(UniqueArc::try_pin_init(init, flags)?))
}
#[inline]
pub fn init<E>(init: impl Init<T, E>, flags: Flags) -> Result<Self, E>
where
E: From<AllocError>,
{
Ok(Self::from(UniqueArc::try_init(init, flags)?))
}
}
impl<T, const ID: u64> From<UniqueArc<T>> for ListArc<T, ID>
where
T: ListArcSafe<ID> + ?Sized,
{
#[inline]
fn from(unique: UniqueArc<T>) -> Self {
Self::from(Pin::from(unique))
}
}
impl<T, const ID: u64> From<Pin<UniqueArc<T>>> for ListArc<T, ID>
where
T: ListArcSafe<ID> + ?Sized,
{
#[inline]
fn from(mut unique: Pin<UniqueArc<T>>) -> Self {
unsafe { T::on_create_list_arc_from_unique(unique.as_mut()) };
let arc = Arc::from(unique);
unsafe { Self::transmute_from_arc(arc) }
}
}
impl<T, const ID: u64> ListArc<T, ID>
where
T: ListArcSafe<ID> + ?Sized,
{
#[inline]
pub fn pair_from_unique<const ID2: u64>(unique: UniqueArc<T>) -> (Self, ListArc<T, ID2>)
where
T: ListArcSafe<ID2>,
{
Self::pair_from_pin_unique(Pin::from(unique))
}
#[inline]
pub fn pair_from_pin_unique<const ID2: u64>(
mut unique: Pin<UniqueArc<T>>,
) -> (Self, ListArc<T, ID2>)
where
T: ListArcSafe<ID2>,
{
build_assert!(ID != ID2);
unsafe { <T as ListArcSafe<ID>>::on_create_list_arc_from_unique(unique.as_mut()) };
unsafe { <T as ListArcSafe<ID2>>::on_create_list_arc_from_unique(unique.as_mut()) };
let arc1 = Arc::from(unique);
let arc2 = Arc::clone(&arc1);
unsafe {
(
Self::transmute_from_arc(arc1),
ListArc::transmute_from_arc(arc2),
)
}
}
pub fn try_from_arc(arc: Arc<T>) -> Result<Self, Arc<T>>
where
T: TryNewListArc<ID>,
{
if arc.try_new_list_arc() {
Ok(unsafe { Self::transmute_from_arc(arc) })
} else {
Err(arc)
}
}
pub fn try_from_arc_borrow(arc: ArcBorrow<'_, T>) -> Option<Self>
where
T: TryNewListArc<ID>,
{
if arc.try_new_list_arc() {
Some(unsafe { Self::transmute_from_arc(Arc::from(arc)) })
} else {
None
}
}
pub fn try_from_arc_or_drop(arc: Arc<T>) -> Option<Self>
where
T: TryNewListArc<ID>,
{
match Self::try_from_arc(arc) {
Ok(list_arc) => Some(list_arc),
Err(arc) => Arc::into_unique_or_drop(arc).map(Self::from),
}
}
#[inline]
unsafe fn transmute_from_arc(arc: Arc<T>) -> Self {
Self { arc }
}
#[inline]
fn transmute_to_arc(self) -> Arc<T> {
unsafe { core::mem::transmute(self) }
}
#[inline]
pub fn into_raw(self) -> *const T {
Arc::into_raw(Self::transmute_to_arc(self))
}
#[inline]
pub unsafe fn from_raw(ptr: *const T) -> Self {
let arc = unsafe { Arc::from_raw(ptr) };
unsafe { Self::transmute_from_arc(arc) }
}
#[inline]
pub fn into_arc(self) -> Arc<T> {
let arc = Self::transmute_to_arc(self);
unsafe { T::on_drop_list_arc(&arc) };
arc
}
#[inline]
pub fn clone_arc(&self) -> Arc<T> {
self.arc.clone()
}
#[inline]
pub fn as_arc(&self) -> &Arc<T> {
&self.arc
}
#[inline]
pub fn as_arc_borrow(&self) -> ArcBorrow<'_, T> {
self.arc.as_arc_borrow()
}
#[inline]
pub fn ptr_eq(this: &Self, other: &Self) -> bool {
Arc::ptr_eq(&this.arc, &other.arc)
}
}
impl<T, const ID: u64> Deref for ListArc<T, ID>
where
T: ListArcSafe<ID> + ?Sized,
{
type Target = T;
#[inline]
fn deref(&self) -> &Self::Target {
self.arc.deref()
}
}
impl<T, const ID: u64> Drop for ListArc<T, ID>
where
T: ListArcSafe<ID> + ?Sized,
{
#[inline]
fn drop(&mut self) {
unsafe { T::on_drop_list_arc(&self.arc) };
}
}
impl<T, const ID: u64> AsRef<Arc<T>> for ListArc<T, ID>
where
T: ListArcSafe<ID> + ?Sized,
{
#[inline]
fn as_ref(&self) -> &Arc<T> {
self.as_arc()
}
}
#[repr(transparent)]
pub struct AtomicTracker<const ID: u64 = 0> {
inner: AtomicFlag,
_pin: PhantomPinned,
}
impl<const ID: u64> AtomicTracker<ID> {
pub fn new() -> impl PinInit<Self> {
Self {
inner: AtomicFlag::new(false),
_pin: PhantomPinned,
}
}
fn project_inner(self: Pin<&mut Self>) -> &mut AtomicFlag {
unsafe { &mut Pin::into_inner_unchecked(self).inner }
}
}
impl<const ID: u64> ListArcSafe<ID> for AtomicTracker<ID> {
unsafe fn on_create_list_arc_from_unique(self: Pin<&mut Self>) {
*self.project_inner().get_mut() = true;
}
unsafe fn on_drop_list_arc(&self) {
self.inner.store(false, ordering::Release);
}
}
unsafe impl<const ID: u64> TryNewListArc<ID> for AtomicTracker<ID> {
fn try_new_list_arc(&self) -> bool {
self.inner.cmpxchg(false, true, ordering::Acquire).is_ok()
}
}