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> {}