• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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