Skip to main content

archery/shared_pointer/kind/rc/
mod.rs

1use crate::shared_pointer::kind::SharedPointerKind;
2use crate::shared_pointer::kind::erased_ptr::ErasedPtr;
3use alloc::boxed::Box;
4use alloc::rc::Rc;
5use core::fmt;
6use core::fmt::Debug;
7use core::fmt::Formatter;
8use core::mem::ManuallyDrop;
9
10/// [Type constructors](https://en.wikipedia.org/wiki/Type_constructor) for
11/// [`Rc`] pointers.
12pub struct RcK {
13    /// A pointer previously obtained from [`Rc::into_raw()`] for the `T` this instance was
14    /// constructed with, and round-tripped through [`Rc::from_raw()`] on every operation. This
15    /// avoids relying on the layout of `Rc<T>` (which is not part of Rust's stable ABI) to
16    /// perform the type erasure.
17    ///
18    /// The referenced [`Rc`] allocation is kept alive by this pointer (which owns one strong
19    /// reference) until [`SharedPointerKind::drop()`] is called.
20    inner: ErasedPtr,
21}
22
23impl RcK {
24    #[inline(always)]
25    fn new_from_inner<T>(rc: Rc<T>) -> RcK {
26        RcK { inner: ErasedPtr::new(Rc::into_raw(rc)) }
27    }
28
29    /// Reconstructs a non-owning view of the inner [`Rc<T>`].
30    ///
31    /// The returned [`ManuallyDrop`] must not be unwrapped: dropping the inner [`Rc`] would
32    /// decrement a refcount that this instance still logically owns.
33    ///
34    /// # Safety
35    ///
36    /// `Self` must have been constructed with the same `T`.
37    #[inline(always)]
38    unsafe fn as_inner<T>(&self) -> ManuallyDrop<Rc<T>> {
39        // SAFETY: By the type-parameter invariant, `self.inner` was produced by
40        // `Rc::into_raw::<T>` and points to a live `Rc<T>` allocation. Wrapping the
41        // reconstructed `Rc` in `ManuallyDrop` prevents it from decrementing the strong count
42        // when this local goes out of scope.
43        ManuallyDrop::new(unsafe { Rc::from_raw(self.inner.cast::<T>()) })
44    }
45
46    /// Takes ownership of the inner [`Rc<T>`], consuming `self`.
47    ///
48    /// # Safety
49    ///
50    /// `Self` must have been constructed with the same `T`.
51    #[inline(always)]
52    unsafe fn take_inner<T>(self) -> Rc<T> {
53        // SAFETY: By the type-parameter invariant, `self.inner` was produced by
54        // `Rc::into_raw::<T>`. `self` is consumed by value and `RcK` has no `Drop` impl, so the
55        // ownership of the strong reference transfers cleanly to the returned `Rc<T>`.
56        unsafe { Rc::from_raw(self.inner.cast::<T>()) }
57    }
58}
59
60unsafe impl SharedPointerKind for RcK {
61    #[inline(always)]
62    fn new<T>(v: T) -> RcK {
63        RcK::new_from_inner(Rc::new(v))
64    }
65
66    #[inline(always)]
67    fn from_box<T>(v: Box<T>) -> RcK {
68        RcK::new_from_inner::<T>(Rc::from(v))
69    }
70
71    #[inline(always)]
72    unsafe fn as_ptr<T>(&self) -> *const T {
73        // SAFETY: The type-parameter invariant is forwarded to `ErasedPtr::cast`.
74        unsafe { self.inner.cast::<T>() }
75    }
76
77    #[inline(always)]
78    unsafe fn deref<T>(&self) -> &T {
79        // SAFETY: By the type-parameter invariant, `self.inner` was produced by
80        // `Rc::into_raw::<T>`, so it points to a valid `T` inside an allocation that is kept
81        // alive by `self`. The returned reference is tied to the lifetime of `&self`.
82        unsafe { &*self.inner.cast::<T>() }
83    }
84
85    #[inline(always)]
86    unsafe fn try_unwrap<T>(self) -> Result<T, RcK> {
87        // SAFETY: The type-parameter invariant is forwarded to `take_inner`.
88        let rc: Rc<T> = unsafe { self.take_inner::<T>() };
89
90        Rc::try_unwrap(rc).map_err(RcK::new_from_inner)
91    }
92
93    #[inline(always)]
94    unsafe fn get_mut<T>(&mut self) -> Option<&mut T> {
95        // SAFETY: The type-parameter invariant is forwarded to `map_owned`; `Rc::from_raw` and
96        // `Rc::into_raw` are an inverse pair for `Rc<T>`.
97        let ret: Option<*mut T> = unsafe {
98            self.inner.map_owned::<T, Rc<T>, _>(Rc::from_raw, Rc::as_ptr, |rc| {
99                Rc::get_mut(rc).map(core::ptr::from_mut)
100            })
101        };
102
103        // SAFETY: If `Rc::get_mut` returned `Some`, no other strong or weak reference existed
104        // at the time of the call, so we have exclusive access to the `T`. The allocation is
105        // kept alive for at least as long as `self` because `self.inner` still owns a strong
106        // reference. The returned reference's lifetime is bound to `&mut self`, so no other
107        // access through `self` can occur while it is live.
108        ret.map(|p| unsafe { &mut *p })
109    }
110
111    #[inline(always)]
112    unsafe fn make_mut<T: Clone>(&mut self) -> &mut T {
113        // SAFETY: The type-parameter invariant is forwarded to `map_owned`; `Rc::from_raw` and
114        // `Rc::into_raw` are an inverse pair for `Rc<T>`.
115        let ret: *mut T = unsafe {
116            self.inner.map_owned::<T, Rc<T>, _>(Rc::from_raw, Rc::as_ptr, |rc| {
117                core::ptr::from_mut(Rc::make_mut(rc))
118            })
119        };
120
121        // SAFETY: `Rc::make_mut` guarantees exclusive access to the (possibly freshly cloned)
122        // `T`. The allocation is kept alive by `self.inner`. The returned reference's lifetime
123        // is bound to `&mut self`, so no other access through `self` can occur while it is
124        // live.
125        unsafe { &mut *ret }
126    }
127
128    #[inline(always)]
129    unsafe fn strong_count<T>(&self) -> usize {
130        // SAFETY: The type-parameter invariant is forwarded to `as_inner`.
131        let rc: ManuallyDrop<Rc<T>> = unsafe { self.as_inner::<T>() };
132
133        Rc::strong_count(&*rc)
134    }
135
136    #[inline(always)]
137    unsafe fn clone<T>(&self) -> RcK {
138        // SAFETY: The type-parameter invariant is forwarded to `as_inner`.
139        let rc: ManuallyDrop<Rc<T>> = unsafe { self.as_inner::<T>() };
140
141        RcK::new_from_inner(Rc::clone(&*rc))
142    }
143
144    #[inline(always)]
145    unsafe fn drop<T>(&mut self) {
146        // SAFETY: By the type-parameter invariant, `self.inner` was produced by
147        // `Rc::into_raw::<T>`. Reconstructing the `Rc<T>` and letting it drop decrements the
148        // strong count matching the initial `Rc::into_raw`. The caller guarantees this is the
149        // last use of `self`.
150        drop(unsafe { Rc::from_raw(self.inner.cast::<T>()) });
151    }
152}
153
154impl Debug for RcK {
155    #[inline(always)]
156    fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
157        f.write_str("RcK")
158    }
159}
160
161#[cfg(test)]
162mod test;