1 // Copyright 2020 Amari Robinson
2 //
3 // Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4 // http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5 // http://opensource.org/licenses/MIT>, at your option. This file may not be
6 // copied, modified, or distributed except according to those terms.
7
8 #[cfg(feature = "alloc")]
9 use crate::alloc::boxed::Box;
10 #[cfg(feature = "alloc")]
11 use crate::alloc::rc::Rc;
12 #[cfg(feature = "alloc")]
13 use crate::alloc::sync::Arc;
14 use crate::UnsafeRef;
15 use core::marker::PhantomData;
16 use core::mem::ManuallyDrop;
17 use core::ops::Deref;
18
19 /// Trait for pointer conversion operations.
20 ///
21 /// `Value` is the actual object type managed by the collection. This type will
22 /// typically have a link as a struct field.
23 ///
24 /// `Pointer` is a pointer type which "owns" an object of type `Value`.
25 /// Operations which insert an element into an intrusive collection will accept
26 /// such a pointer and operations which remove an element will return this type.
27 pub unsafe trait PointerOps {
28 /// Object type which is inserted into an intrusive collection.
29 type Value: ?Sized;
30 /// Pointer type which owns an instance of a value.
31 type Pointer;
32
33 /// Constructs an owned pointer from a raw pointer.
34 ///
35 /// # Safety
36 /// The raw pointer must have been previously returned by `into_raw`.
37 ///
38 /// An implementation of `from_raw` must not panic.
from_raw(&self, value: *const Self::Value) -> Self::Pointer39 unsafe fn from_raw(&self, value: *const Self::Value) -> Self::Pointer;
40
41 /// Consumes the owned pointer and returns a raw pointer to the owned object.
into_raw(&self, ptr: Self::Pointer) -> *const Self::Value42 fn into_raw(&self, ptr: Self::Pointer) -> *const Self::Value;
43 }
44
45 /// The `PointerOps` type used by an `Adapter` generated by `intrusive_adapter!`.
46 pub struct DefaultPointerOps<Pointer>(PhantomData<Pointer>);
47
48 impl<Pointer> DefaultPointerOps<Pointer> {
49 /// Constructs an instance of `DefaultPointerOps`.
50 #[inline]
new() -> DefaultPointerOps<Pointer>51 pub const fn new() -> DefaultPointerOps<Pointer> {
52 DefaultPointerOps(PhantomData)
53 }
54 }
55
56 impl<Pointer> Clone for DefaultPointerOps<Pointer> {
57 #[inline]
clone(&self) -> Self58 fn clone(&self) -> Self {
59 *self
60 }
61 }
62
63 impl<Pointer> Copy for DefaultPointerOps<Pointer> {}
64
65 impl<Pointer> Default for DefaultPointerOps<Pointer> {
66 #[inline]
default() -> Self67 fn default() -> Self {
68 Self::new()
69 }
70 }
71
72 unsafe impl<'a, T: ?Sized> PointerOps for DefaultPointerOps<&'a T> {
73 type Value = T;
74 type Pointer = &'a T;
75
76 #[inline]
from_raw(&self, raw: *const T) -> &'a T77 unsafe fn from_raw(&self, raw: *const T) -> &'a T {
78 &*raw
79 }
80
81 #[inline]
into_raw(&self, ptr: &'a T) -> *const T82 fn into_raw(&self, ptr: &'a T) -> *const T {
83 ptr
84 }
85 }
86
87 unsafe impl<T: ?Sized> PointerOps for DefaultPointerOps<UnsafeRef<T>> {
88 type Value = T;
89 type Pointer = UnsafeRef<T>;
90
91 #[inline]
from_raw(&self, raw: *const T) -> UnsafeRef<T>92 unsafe fn from_raw(&self, raw: *const T) -> UnsafeRef<T> {
93 UnsafeRef::from_raw(raw as *mut T)
94 }
95
96 #[inline]
into_raw(&self, ptr: UnsafeRef<T>) -> *const T97 fn into_raw(&self, ptr: UnsafeRef<T>) -> *const T {
98 UnsafeRef::into_raw(ptr) as *const T
99 }
100 }
101
102 #[cfg(feature = "alloc")]
103 unsafe impl<T: ?Sized> PointerOps for DefaultPointerOps<Box<T>> {
104 type Value = T;
105 type Pointer = Box<T>;
106
107 #[inline]
from_raw(&self, raw: *const T) -> Box<T>108 unsafe fn from_raw(&self, raw: *const T) -> Box<T> {
109 Box::from_raw(raw as *mut T)
110 }
111
112 #[inline]
into_raw(&self, ptr: Box<T>) -> *const T113 fn into_raw(&self, ptr: Box<T>) -> *const T {
114 Box::into_raw(ptr) as *const T
115 }
116 }
117
118 #[cfg(feature = "alloc")]
119 unsafe impl<T: ?Sized> PointerOps for DefaultPointerOps<Rc<T>> {
120 type Value = T;
121 type Pointer = Rc<T>;
122
123 #[inline]
from_raw(&self, raw: *const T) -> Rc<T>124 unsafe fn from_raw(&self, raw: *const T) -> Rc<T> {
125 Rc::from_raw(raw)
126 }
127
128 #[inline]
into_raw(&self, ptr: Rc<T>) -> *const T129 fn into_raw(&self, ptr: Rc<T>) -> *const T {
130 Rc::into_raw(ptr)
131 }
132 }
133
134 #[cfg(feature = "alloc")]
135 unsafe impl<T: ?Sized> PointerOps for DefaultPointerOps<Arc<T>> {
136 type Value = T;
137 type Pointer = Arc<T>;
138
139 #[inline]
from_raw(&self, raw: *const T) -> Arc<T>140 unsafe fn from_raw(&self, raw: *const T) -> Arc<T> {
141 Arc::from_raw(raw)
142 }
143
144 #[inline]
into_raw(&self, ptr: Arc<T>) -> *const T145 fn into_raw(&self, ptr: Arc<T>) -> *const T {
146 Arc::into_raw(ptr)
147 }
148 }
149
150 /// Clones a `PointerOps::Pointer` from a `*const PointerOps::Value`
151 ///
152 /// This method is only safe to call if the raw pointer is known to be
153 /// managed by the provided `PointerOps` type.
154 #[inline]
clone_pointer_from_raw<T: PointerOps>( pointer_ops: &T, ptr: *const T::Value, ) -> T::Pointer where T::Pointer: Clone,155 pub(crate) unsafe fn clone_pointer_from_raw<T: PointerOps>(
156 pointer_ops: &T,
157 ptr: *const T::Value,
158 ) -> T::Pointer
159 where
160 T::Pointer: Clone,
161 {
162 /// Guard which converts an pointer back into its raw version
163 /// when it gets dropped. This makes sure we also perform a full
164 /// `from_raw` and `into_raw` round trip - even in the case of panics.
165 struct PointerGuard<'a, T: PointerOps> {
166 pointer: ManuallyDrop<T::Pointer>,
167 pointer_ops: &'a T,
168 }
169
170 impl<'a, T: PointerOps> Drop for PointerGuard<'a, T> {
171 #[inline]
172 fn drop(&mut self) {
173 // Prevent shared pointers from being released by converting them
174 // back into the raw pointers
175 // SAFETY: `pointer` is never dropped. `ManuallyDrop::take` is not stable until 1.42.0.
176 let _ = self
177 .pointer_ops
178 .into_raw(unsafe { core::ptr::read(&*self.pointer) });
179 }
180 }
181
182 let holder = PointerGuard {
183 pointer: ManuallyDrop::new(pointer_ops.from_raw(ptr)),
184 pointer_ops,
185 };
186 holder.pointer.deref().clone()
187 }
188
189 #[cfg(test)]
190 mod tests {
191 use super::{DefaultPointerOps, PointerOps};
192 use std::boxed::Box;
193 use std::fmt::Debug;
194 use std::mem;
195 use std::rc::Rc;
196 use std::sync::Arc;
197
198 #[test]
test_box()199 fn test_box() {
200 unsafe {
201 let pointer_ops = DefaultPointerOps::<Box<_>>::new();
202 let p = Box::new(1);
203 let a: *const i32 = &*p;
204 let r = pointer_ops.into_raw(p);
205 assert_eq!(a, r);
206 let p2: Box<i32> = pointer_ops.from_raw(r);
207 let a2: *const i32 = &*p2;
208 assert_eq!(a, a2);
209 }
210 }
211
212 #[test]
test_rc()213 fn test_rc() {
214 unsafe {
215 let pointer_ops = DefaultPointerOps::<Rc<_>>::new();
216 let p = Rc::new(1);
217 let a: *const i32 = &*p;
218 let r = pointer_ops.into_raw(p);
219 assert_eq!(a, r);
220 let p2: Rc<i32> = pointer_ops.from_raw(r);
221 let a2: *const i32 = &*p2;
222 assert_eq!(a, a2);
223 }
224 }
225
226 #[test]
test_arc()227 fn test_arc() {
228 unsafe {
229 let pointer_ops = DefaultPointerOps::<Arc<_>>::new();
230 let p = Arc::new(1);
231 let a: *const i32 = &*p;
232 let r = pointer_ops.into_raw(p);
233 assert_eq!(a, r);
234 let p2: Arc<i32> = pointer_ops.from_raw(r);
235 let a2: *const i32 = &*p2;
236 assert_eq!(a, a2);
237 }
238 }
239
240 #[test]
test_box_unsized()241 fn test_box_unsized() {
242 unsafe {
243 let pointer_ops = DefaultPointerOps::<Box<_>>::new();
244 let p = Box::new(1) as Box<dyn Debug>;
245 let a: *const dyn Debug = &*p;
246 let b: (usize, usize) = mem::transmute(a);
247 let r = pointer_ops.into_raw(p);
248 assert_eq!(a, r);
249 assert_eq!(b, mem::transmute(r));
250 let p2: Box<dyn Debug> = pointer_ops.from_raw(r);
251 let a2: *const dyn Debug = &*p2;
252 assert_eq!(a, a2);
253 assert_eq!(b, mem::transmute(a2));
254 }
255 }
256
257 #[test]
test_rc_unsized()258 fn test_rc_unsized() {
259 unsafe {
260 let pointer_ops = DefaultPointerOps::<Rc<_>>::new();
261 let p = Rc::new(1) as Rc<dyn Debug>;
262 let a: *const dyn Debug = &*p;
263 let b: (usize, usize) = mem::transmute(a);
264 let r = pointer_ops.into_raw(p);
265 assert_eq!(a, r);
266 assert_eq!(b, mem::transmute(r));
267 let p2: Rc<dyn Debug> = pointer_ops.from_raw(r);
268 let a2: *const dyn Debug = &*p2;
269 assert_eq!(a, a2);
270 assert_eq!(b, mem::transmute(a2));
271 }
272 }
273
274 #[test]
test_arc_unsized()275 fn test_arc_unsized() {
276 unsafe {
277 let pointer_ops = DefaultPointerOps::<Arc<_>>::new();
278 let p = Arc::new(1) as Arc<dyn Debug>;
279 let a: *const dyn Debug = &*p;
280 let b: (usize, usize) = mem::transmute(a);
281 let r = pointer_ops.into_raw(p);
282 assert_eq!(a, r);
283 assert_eq!(b, mem::transmute(r));
284 let p2: Arc<dyn Debug> = pointer_ops.from_raw(r);
285 let a2: *const dyn Debug = &*p2;
286 assert_eq!(a, a2);
287 assert_eq!(b, mem::transmute(a2));
288 }
289 }
290
291 #[test]
clone_arc_from_raw()292 fn clone_arc_from_raw() {
293 use super::clone_pointer_from_raw;
294 unsafe {
295 let pointer_ops = DefaultPointerOps::<Arc<_>>::new();
296 let p = Arc::new(1);
297 let raw = &*p as *const i32;
298 let p2: Arc<i32> = clone_pointer_from_raw(&pointer_ops, raw);
299 assert_eq!(2, Arc::strong_count(&p2));
300 }
301 }
302
303 #[test]
clone_rc_from_raw()304 fn clone_rc_from_raw() {
305 use super::clone_pointer_from_raw;
306 unsafe {
307 let pointer_ops = DefaultPointerOps::<Rc<_>>::new();
308 let p = Rc::new(1);
309 let raw = &*p as *const i32;
310 let p2: Rc<i32> = clone_pointer_from_raw(&pointer_ops, raw);
311 assert_eq!(2, Rc::strong_count(&p2));
312 }
313 }
314 }
315