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;