pin_arc/
generic_rc.rs

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
11/// The common implementation shared by [PinRcStorage](crate::PinRcStorage) and [PinArcStorage](crate::PinArcStorage).
12pub struct PinRcGenericStorage<T, C: Radium<Item = usize>> {
13    inner: UnsafeCell<Inner<T, C>>,
14    _p: PhantomPinned,
15    _ps: PhantomData<*const u32>, // prevent Send and Sync
16}
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            // A panic hook might run here.
51            // As this is called from the destructor, the memory of the storage has not been reused yet,
52            // so it would be fine for the hook to access the contained value.
53            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    /// Create a new storage containing the provided value.
69    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    /// Get a mutable reference to the contents if there are no handles referring to `self`.
81    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
98/// The common implementation shared by [PinRc](crate::PinRc) and [PinArc](crate::PinArc).
99pub 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 {}