1use core::cell::{Cell, UnsafeCell};
2use core::marker::{PhantomData, PhantomPinned};
3use core::pin::Pin;
4use core::ptr::NonNull;
5use core::sync::atomic::AtomicUsize;
6use core::sync::atomic::Ordering::{Acquire, Relaxed, Release};
7use radium::Radium;
8
9const MAX_REFCOUNT: usize = usize::MAX / 2;
10
11pub struct PinRcGenericStorage<T, C: Radium<Item = usize>> {
13 inner: UnsafeCell<Inner<T, C>>,
14 _p: PhantomPinned,
15 _ps: PhantomData<*const u32>, }
17
18pub(crate) struct Inner<T, C> {
19 count: C,
20 value: T,
21}
22
23impl<T, C: Radium<Item = usize>> Inner<T, C> {
24 pub(crate) fn count(&self) -> usize {
25 self.count.load(Relaxed)
26 }
27
28 pub(crate) fn value_pin(self: Pin<&Self>) -> Pin<&T> {
29 unsafe { Pin::new_unchecked(&self.get_ref().value) }
30 }
31
32 pub(crate) fn value_unpin(&self) -> &T {
33 &self.value
34 }
35
36 pub(crate) fn create_handle(self: Pin<&Self>) -> PinRcGeneric<T, C> {
37 let old_count = self.count.fetch_add(1, Relaxed);
38 if old_count > MAX_REFCOUNT {
39 abort()
40 }
41 PinRcGeneric(NonNull::from(self.get_ref()))
42 }
43}
44
45fn abort() -> ! {
46 if cfg!(feature = "unsafe_disable_abort") {
47 panic!()
48 } else {
49 extern "C" fn force_abort() -> ! {
50 panic!()
54 }
55 force_abort()
56 }
57}
58
59impl<T, C: Radium<Item = usize>> Drop for PinRcGenericStorage<T, C> {
60 fn drop(&mut self) {
61 if self.inner_unpin().count.load(Acquire) != 0 {
62 abort()
63 }
64 }
65}
66
67impl<T, C: Radium<Item = usize>> PinRcGenericStorage<T, C> {
68 pub fn new(value: T) -> Self {
70 Self {
71 inner: UnsafeCell::new(Inner {
72 value,
73 count: C::new(0),
74 }),
75 _p: Default::default(),
76 _ps: PhantomData,
77 }
78 }
79
80 pub fn get_pin_mut(self: Pin<&mut Self>) -> Option<Pin<&mut T>> {
82 if self.as_ref().inner_unpin().count.load(Acquire) == 0 {
83 Some(unsafe { Pin::new_unchecked(&mut (*self.inner.get()).value) })
84 } else {
85 None
86 }
87 }
88
89 pub(crate) fn inner_pin(self: Pin<&Self>) -> Pin<&Inner<T, C>> {
90 unsafe { Pin::new_unchecked(&*self.inner.get()) }
91 }
92
93 pub(crate) fn inner_unpin(&self) -> &Inner<T, C> {
94 unsafe { &*self.inner.get() }
95 }
96}
97
98pub struct PinRcGeneric<T, C: Radium<Item = usize>>(NonNull<Inner<T, C>>);
100
101impl<T, C: Radium<Item = usize>> PinRcGeneric<T, C> {
102 pub(crate) fn inner_pin(&self) -> Pin<&Inner<T, C>> {
103 unsafe { Pin::new_unchecked(self.0.as_ref()) }
104 }
105
106 pub(crate) fn inner_unpin(&self) -> &Inner<T, C> {
107 self.inner_pin().get_ref()
108 }
109}
110
111impl<T, C: Radium<Item = usize>> Drop for PinRcGeneric<T, C> {
112 fn drop(&mut self) {
113 let c = self.inner_unpin().count.fetch_sub(1, Release);
114 debug_assert!(c > 0);
115 }
116}
117
118pub type PinRc<T> = PinRcGeneric<T, Cell<usize>>;
119pub type PinRcStorage<T> = PinRcGenericStorage<T, Cell<usize>>;
120pub type PinArc<T> = PinRcGeneric<T, AtomicUsize>;
121pub type PinArcStorage<T> = PinRcGenericStorage<T, AtomicUsize>;
122
123unsafe impl<T> Sync for PinArc<T> where T: Sync {}
124unsafe impl<T> Sync for PinArcStorage<T> where T: Sync {}
125unsafe impl<T> Send for PinArc<T> where T: Sync {}
126unsafe impl<T> Send for PinArcStorage<T> where T: Send + Sync {}