pin_arc/
generic_rc.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
use core::cell::{Cell, UnsafeCell};
use core::marker::{PhantomData, PhantomPinned};
use core::pin::Pin;
use core::ptr::NonNull;
use core::sync::atomic::AtomicUsize;
use core::sync::atomic::Ordering::{Acquire, Relaxed, Release};
use radium::Radium;

const MAX_REFCOUNT: usize = usize::MAX / 2;

/// The common implementation shared by [PinRcStorage](crate::PinRcStorage) and [PinArcStorage](crate::PinArcStorage).
pub struct PinRcGenericStorage<T, C: Radium<Item = usize>> {
    inner: UnsafeCell<Inner<T, C>>,
    _p: PhantomPinned,
    _ps: PhantomData<*const u32>, // prevent Send and Sync
}

pub(crate) struct Inner<T, C> {
    count: C,
    value: T,
}

impl<T, C: Radium<Item = usize>> Inner<T, C> {
    pub(crate) fn count(&self) -> usize {
        self.count.load(Relaxed)
    }

    pub(crate) fn value(&self) -> Pin<&T> {
        unsafe { Pin::new_unchecked(&self.value) }
    }

    pub(crate) fn create_handle(&self) -> PinRcGeneric<T, C> {
        let old_count = self.count.fetch_add(1, Relaxed);
        if old_count > MAX_REFCOUNT {
            abort()
        }
        PinRcGeneric(NonNull::from(self))
    }
}

fn abort() -> ! {
    if cfg!(feature = "unsafe_disable_abort") {
        panic!()
    } else {
        extern "C" fn force_abort() -> ! {
            // A panic hook might run here.
            // As this is called from the destructor, the memory of the storage has not been reused yet,
            // so it would be fine for the hook to access the contained value.
            panic!()
        }
        force_abort()
    }
}

impl<T, C: Radium<Item = usize>> Drop for PinRcGenericStorage<T, C> {
    fn drop(&mut self) {
        if self.inner().count.load(Acquire) != 0 {
            abort()
        }
    }
}

impl<T, C: Radium<Item = usize>> PinRcGenericStorage<T, C> {
    /// Create a new storage containing the provided value.
    pub fn new(value: T) -> Self {
        Self {
            inner: UnsafeCell::new(Inner {
                value,
                count: C::new(0),
            }),
            _p: Default::default(),
            _ps: PhantomData,
        }
    }

    /// Get a mutable reference to the contents if there are no handles referring to `self`.
    pub fn get_pin_mut(self: Pin<&mut Self>) -> Option<Pin<&mut T>> {
        if self.inner().count.load(Acquire) == 0 {
            Some(unsafe { Pin::new_unchecked(&mut (*self.inner.get()).value) })
        } else {
            None
        }
    }

    pub(crate) fn inner(&self) -> &Inner<T, C> {
        unsafe { &*self.inner.get() }
    }
}

/// The common implementation shared by [PinRc](crate::PinRc) and [PinArc](crate::PinArc).
pub struct PinRcGeneric<T, C: Radium<Item = usize>>(NonNull<Inner<T, C>>);

impl<T, C: Radium<Item = usize>> PinRcGeneric<T, C> {
    pub(crate) fn inner(&self) -> &Inner<T, C> {
        unsafe { self.0.as_ref() }
    }
}

impl<T, C: Radium<Item = usize>> Drop for PinRcGeneric<T, C> {
    fn drop(&mut self) {
        let c = self.inner().count.fetch_sub(1, Release);
        debug_assert!(c > 0);
    }
}

pub type PinRc<T> = PinRcGeneric<T, Cell<usize>>;
pub type PinRcStorage<T> = PinRcGenericStorage<T, Cell<usize>>;
pub type PinArc<T> = PinRcGeneric<T, AtomicUsize>;
pub type PinArcStorage<T> = PinRcGenericStorage<T, AtomicUsize>;

unsafe impl<T> Sync for PinArc<T> where T: Sync {}
unsafe impl<T> Sync for PinArcStorage<T> where T: Sync {}
unsafe impl<T> Send for PinArc<T> where T: Sync {}
unsafe impl<T> Send for PinArcStorage<T> where T: Send + Sync {}