scope_lock/pointer_like.rs
1use core::ops::{Deref, DerefMut};
2use core::pin::Pin;
3
4use crate::RefOnce;
5
6pub mod erased_static;
7
8/// Trait to convert various kinds of smart pointers and references into
9/// a single raw pointer. Allows to implement more generic API.
10///
11/// # Safety
12///
13/// Implementation of this trait must satisfy several safety requirements:
14///
15/// - A raw pointer returned from [`PointerLike::into_ptr`] and passed to
16/// [`PointerLike::from_ptr`] must not be null;
17/// - The target type shall not be [subtyped] or unsized unless explicitly
18/// allowed otherwise;
19/// - A raw pointer passed to [`Self::from_ptr`] shall be returned from
20/// [`Self::into_ptr`] implementation of the same type unless explicitly
21/// allowed;
22/// - A raw pointer may be able to outlive lifetime of the original smart
23/// pointer, so user shall consider such pointer invalid outside of the
24/// original lifetime.
25///
26/// [subtyped]: https://doc.rust-lang.org/reference/subtyping.html
27pub unsafe trait PointerLike {
28 /// The type our pointer points at.
29 type Pointee;
30
31 /// Convert smart pointer into a raw pointer, possibly leaking it.
32 ///
33 /// # Safety
34 ///
35 /// Dereferencing the returned pointer in any manner, writing to it
36 /// or reading from it is disallowed unless it is specified otherwise.
37 fn into_ptr(self) -> *mut Self::Pointee;
38
39 /// Convert a raw pointer back into a smart pointer.
40 ///
41 /// # Safety
42 ///
43 /// `ptr` must be one returned from [`Self::into_ptr`] unless
44 /// explicitly allowed otherwise. Be careful raw pointer must not
45 /// outlive original smart pointer's lifetime. Do not call this
46 /// function twice on the same argument.
47 unsafe fn from_ptr(ptr: *mut Self::Pointee) -> Self;
48}
49
50/// Trait that allows to create immutable references to the pointed-at
51/// object.
52///
53/// # Safety
54///
55/// Implementer must guarantee safety of creating, using and
56/// keeping of immutable references from the raw pointer returned by
57/// [`PointerLike::into_ptr`]. It must also be allowed to operate on
58/// this raw pointer in the manner of an immutable reference.
59pub unsafe trait PointerDeref: PointerLike + Deref<Target = Self::Pointee> {}
60
61/// Trait that allows to create a mutable reference to the pointed-at
62/// object.
63///
64/// # Safety
65///
66/// Implementer must guarantee safety of creating, using and
67/// keeping of mutable reference from the raw pointer returned by
68/// [`PointerLike::into_ptr`]. It must also be allowed to operate on
69/// this raw pointer in the manner of a mutable reference.
70pub unsafe trait PointerDerefMut: PointerDeref + DerefMut {}
71
72/// Trait that allows to move pointed-at object out of a smart-pointer,
73/// and then, presumably, deallocating the smart-pointer.
74///
75/// # Safety
76///
77/// Implementer must guarantee safety of moving out of the
78/// original smart-pointer and a raw pointer returned from
79/// [`PointerLike::into_ptr`] via the [`Self::into_inner`] method.
80pub unsafe trait PointerIntoInner: PointerDerefMut + DerefMut {
81 fn into_inner(self) -> Self::Pointee;
82}
83
84/// Trait that allows to create pinned mutable references to the
85/// pointed-at object, when assuming that the original smart-pointer
86/// won't leak.
87///
88/// Such specific definition of this trait is needed to ensure
89/// [pin's drop guarantee] in the context of extending lifetimes. If
90/// something is unclear, so please refer to implementations and their
91/// documentation. Specifically [`RefOnce`] impl might give you enough
92/// insight.
93///
94/// # Safety
95///
96/// Implementer must guarantee safety of creating, using and keeping
97/// of **pinned** mutable reference from the raw pointer returned by
98/// [`PointerLike::into_ptr`], if the original smart-pointer won't
99/// leak. It must also be allowed to operate on this raw pointer in the
100/// manner of a **pinned** mutable reference.
101///
102/// [pin's drop guarantee]: https://doc.rust-lang.org/nightly/std/pin/index.html#subtle-details-and-the-drop-guarantee
103pub unsafe trait PointerPinUnforgotten: PointerLike + PointerDeref {}
104
105unsafe impl<T> PointerLike for &T {
106 type Pointee = T;
107
108 fn into_ptr(self) -> *mut Self::Pointee {
109 self as *const T as *mut T
110 }
111
112 unsafe fn from_ptr(ptr: *mut Self::Pointee) -> Self {
113 unsafe { &*(ptr as *const T) }
114 }
115}
116unsafe impl<T> PointerDeref for &T {}
117
118unsafe impl<T> PointerLike for &mut T {
119 type Pointee = T;
120
121 fn into_ptr(self) -> *mut Self::Pointee {
122 self
123 }
124
125 unsafe fn from_ptr(ptr: *mut Self::Pointee) -> Self {
126 unsafe { &mut *ptr }
127 }
128}
129unsafe impl<T> PointerDeref for &mut T {}
130unsafe impl<T> PointerDerefMut for &mut T {}
131/// Same as [`PointerDerefMut`] implementation because of [`Unpin`]
132unsafe impl<T: Unpin> PointerPinUnforgotten for &mut T {}
133
134unsafe impl<T> PointerLike for Box<T> {
135 type Pointee = T;
136
137 fn into_ptr(self) -> *mut Self::Pointee {
138 Box::into_raw(self)
139 }
140
141 unsafe fn from_ptr(ptr: *mut Self::Pointee) -> Self {
142 unsafe { Box::from_raw(ptr) }
143 }
144}
145unsafe impl<T> PointerDeref for Box<T> {}
146unsafe impl<T> PointerDerefMut for Box<T> {}
147unsafe impl<T> PointerIntoInner for Box<T> {
148 fn into_inner(self) -> Self::Pointee {
149 *self
150 }
151}
152/// Safe because of [`Box::into_pin`]
153unsafe impl<T> PointerPinUnforgotten for Box<T> {}
154
155unsafe impl<T> PointerLike for alloc::rc::Rc<T> {
156 type Pointee = T;
157
158 fn into_ptr(self) -> *mut Self::Pointee {
159 alloc::rc::Rc::into_raw(self) as *mut T
160 }
161
162 unsafe fn from_ptr(ptr: *mut Self::Pointee) -> Self {
163 unsafe { alloc::rc::Rc::from_raw(ptr as *const T) }
164 }
165}
166unsafe impl<T> PointerDeref for alloc::rc::Rc<T> {}
167
168unsafe impl<T> PointerLike for alloc::sync::Arc<T> {
169 type Pointee = T;
170
171 fn into_ptr(self) -> *mut Self::Pointee {
172 alloc::sync::Arc::into_raw(self) as *mut T
173 }
174
175 unsafe fn from_ptr(ptr: *mut Self::Pointee) -> Self {
176 unsafe { alloc::sync::Arc::from_raw(ptr as *const T) }
177 }
178}
179unsafe impl<T> PointerDeref for alloc::sync::Arc<T> {}
180
181unsafe impl<Ptr: PointerDeref> PointerLike for Pin<Ptr> {
182 type Pointee = Ptr::Pointee;
183
184 fn into_ptr(self) -> *mut Self::Pointee {
185 unsafe { Pin::into_inner_unchecked(self) }.into_ptr()
186 }
187
188 unsafe fn from_ptr(ptr: *mut Self::Pointee) -> Self {
189 unsafe { Pin::new_unchecked(Ptr::from_ptr(ptr)) }
190 }
191}
192unsafe impl<Ptr: PointerDeref> PointerDeref for Pin<Ptr> {}
193unsafe impl<Ptr: PointerDerefMut> PointerDerefMut for Pin<Ptr> where Ptr::Pointee: Unpin {}
194unsafe impl<Ptr: PointerIntoInner> PointerIntoInner for Pin<Ptr>
195where
196 Ptr::Pointee: Unpin,
197{
198 fn into_inner(self) -> Self::Pointee {
199 unsafe { Pin::into_inner_unchecked(self) }.into_inner()
200 }
201}
202/// We are already pinned, so this is fine
203unsafe impl<Ptr: PointerDerefMut> PointerPinUnforgotten for Pin<Ptr> {}
204
205unsafe impl<'a, T> PointerLike for RefOnce<'a, T> {
206 type Pointee = T;
207
208 fn into_ptr(self) -> *mut Self::Pointee {
209 RefOnce::into_raw(self)
210 }
211
212 unsafe fn from_ptr(ptr: *mut Self::Pointee) -> Self {
213 unsafe { RefOnce::from_raw(ptr) }
214 }
215}
216unsafe impl<T> PointerDeref for RefOnce<'_, T> {}
217unsafe impl<T> PointerDerefMut for RefOnce<'_, T> {}
218unsafe impl<T> PointerIntoInner for RefOnce<'_, T> {
219 fn into_inner(self) -> Self::Pointee {
220 RefOnce::into_inner(self)
221 }
222}
223/// Note that `RefOnce::into_pin` implementation, mimicking the
224/// [`Box::into_pin`] would be unsound because [`RefOnce`] stores object
225/// within the [`std::mem::MaybeUninit`] slot allocated somewhere
226/// (including on a stack) which would allow us to deallocate pinned
227/// object without first calling drop on it, thus violating the [pin's
228/// drop guarantee]. However we can safely assume that this pointer won't
229/// be forgotten and drop will "eventually" run, so we are safe here.
230///
231/// [pin's drop guarantee]: https://doc.rust-lang.org/nightly/std/pin/index.html#subtle-details-and-the-drop-guarantee
232unsafe impl<T> PointerPinUnforgotten for RefOnce<'_, T> {}