intrusive_collections/
pointer_ops.rs

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")]
9use crate::alloc::boxed::Box;
10#[cfg(feature = "alloc")]
11use crate::alloc::rc::Rc;
12#[cfg(feature = "alloc")]
13use crate::alloc::sync::Arc;
14use crate::UnsafeRef;
15use core::marker::PhantomData;
16use core::mem::ManuallyDrop;
17use core::ops::Deref;
18use core::pin::Pin;
19
20/// Trait for pointer conversion operations.
21///
22/// `Value` is the actual object type managed by the collection. This type will
23/// typically have a link as a struct field.
24///
25/// `Pointer` is a pointer type which "owns" an object of type `Value`.
26/// Operations which insert an element into an intrusive collection will accept
27/// such a pointer and operations which remove an element will return this type.
28pub unsafe trait PointerOps {
29    /// Object type which is inserted into an intrusive collection.
30    type Value: ?Sized;
31    /// Pointer type which owns an instance of a value.
32    type Pointer;
33
34    /// Constructs an owned pointer from a raw pointer.
35    ///
36    /// # Safety
37    /// The raw pointer must have been previously returned by `into_raw`.
38    ///
39    /// An implementation of `from_raw` must not panic.
40    unsafe fn from_raw(&self, value: *const Self::Value) -> Self::Pointer;
41
42    /// Consumes the owned pointer and returns a raw pointer to the owned object.
43    fn into_raw(&self, ptr: Self::Pointer) -> *const Self::Value;
44}
45
46/// The `PointerOps` type used by an `Adapter` generated by `intrusive_adapter!`.
47pub struct DefaultPointerOps<Pointer>(PhantomData<Pointer>);
48
49impl<Pointer> DefaultPointerOps<Pointer> {
50    /// Constructs an instance of `DefaultPointerOps`.
51    #[inline]
52    pub const fn new() -> DefaultPointerOps<Pointer> {
53        DefaultPointerOps(PhantomData)
54    }
55}
56
57impl<Pointer> Clone for DefaultPointerOps<Pointer> {
58    #[inline]
59    fn clone(&self) -> Self {
60        *self
61    }
62}
63
64impl<Pointer> Copy for DefaultPointerOps<Pointer> {}
65
66impl<Pointer> Default for DefaultPointerOps<Pointer> {
67    #[inline]
68    fn default() -> Self {
69        Self::new()
70    }
71}
72
73unsafe impl<'a, T: ?Sized> PointerOps for DefaultPointerOps<&'a T> {
74    type Value = T;
75    type Pointer = &'a T;
76
77    #[inline]
78    unsafe fn from_raw(&self, raw: *const T) -> &'a T {
79        &*raw
80    }
81
82    #[inline]
83    fn into_raw(&self, ptr: &'a T) -> *const T {
84        ptr
85    }
86}
87
88unsafe impl<'a, T: ?Sized> PointerOps for DefaultPointerOps<Pin<&'a T>> {
89    type Value = T;
90    type Pointer = Pin<&'a T>;
91
92    #[inline]
93    unsafe fn from_raw(&self, raw: *const T) -> Pin<&'a T> {
94        Pin::new_unchecked(&*raw)
95    }
96
97    #[inline]
98    fn into_raw(&self, ptr: Pin<&'a T>) -> *const T {
99        unsafe { Pin::into_inner_unchecked(ptr) as *const T }
100    }
101}
102
103unsafe impl<T: ?Sized> PointerOps for DefaultPointerOps<UnsafeRef<T>> {
104    type Value = T;
105    type Pointer = UnsafeRef<T>;
106
107    #[inline]
108    unsafe fn from_raw(&self, raw: *const T) -> UnsafeRef<T> {
109        UnsafeRef::from_raw(raw as *mut T)
110    }
111
112    #[inline]
113    fn into_raw(&self, ptr: UnsafeRef<T>) -> *const T {
114        UnsafeRef::into_raw(ptr) as *const T
115    }
116}
117
118unsafe impl<T: ?Sized> PointerOps for DefaultPointerOps<Pin<UnsafeRef<T>>> {
119    type Value = T;
120    type Pointer = Pin<UnsafeRef<T>>;
121
122    #[inline]
123    unsafe fn from_raw(&self, raw: *const T) -> Pin<UnsafeRef<T>> {
124        Pin::new_unchecked(UnsafeRef::from_raw(raw as *mut T))
125    }
126
127    #[inline]
128    fn into_raw(&self, ptr: Pin<UnsafeRef<T>>) -> *const T {
129        UnsafeRef::into_raw(unsafe { Pin::into_inner_unchecked(ptr) }) as *const T
130    }
131}
132
133#[cfg(feature = "alloc")]
134unsafe impl<T: ?Sized> PointerOps for DefaultPointerOps<Box<T>> {
135    type Value = T;
136    type Pointer = Box<T>;
137
138    #[inline]
139    unsafe fn from_raw(&self, raw: *const T) -> Box<T> {
140        Box::from_raw(raw as *mut T)
141    }
142
143    #[inline]
144    fn into_raw(&self, ptr: Box<T>) -> *const T {
145        Box::into_raw(ptr) as *const T
146    }
147}
148
149#[cfg(feature = "alloc")]
150unsafe impl<T: ?Sized> PointerOps for DefaultPointerOps<Pin<Box<T>>> {
151    type Value = T;
152    type Pointer = Pin<Box<T>>;
153
154    #[inline]
155    unsafe fn from_raw(&self, raw: *const T) -> Pin<Box<T>> {
156        Pin::new_unchecked(Box::from_raw(raw as *mut T))
157    }
158
159    #[inline]
160    fn into_raw(&self, ptr: Pin<Box<T>>) -> *const T {
161        Box::into_raw(unsafe { Pin::into_inner_unchecked(ptr) }) as *const T
162    }
163}
164
165#[cfg(feature = "alloc")]
166unsafe impl<T: ?Sized> PointerOps for DefaultPointerOps<Rc<T>> {
167    type Value = T;
168    type Pointer = Rc<T>;
169
170    #[inline]
171    unsafe fn from_raw(&self, raw: *const T) -> Rc<T> {
172        Rc::from_raw(raw)
173    }
174
175    #[inline]
176    fn into_raw(&self, ptr: Rc<T>) -> *const T {
177        Rc::into_raw(ptr)
178    }
179}
180
181#[cfg(feature = "alloc")]
182unsafe impl<T: ?Sized> PointerOps for DefaultPointerOps<Pin<Rc<T>>> {
183    type Value = T;
184    type Pointer = Pin<Rc<T>>;
185
186    #[inline]
187    unsafe fn from_raw(&self, raw: *const T) -> Pin<Rc<T>> {
188        Pin::new_unchecked(Rc::from_raw(raw))
189    }
190
191    #[inline]
192    fn into_raw(&self, ptr: Pin<Rc<T>>) -> *const T {
193        Rc::into_raw(unsafe { Pin::into_inner_unchecked(ptr) })
194    }
195}
196
197#[cfg(feature = "alloc")]
198unsafe impl<T: ?Sized> PointerOps for DefaultPointerOps<Arc<T>> {
199    type Value = T;
200    type Pointer = Arc<T>;
201
202    #[inline]
203    unsafe fn from_raw(&self, raw: *const T) -> Arc<T> {
204        Arc::from_raw(raw)
205    }
206
207    #[inline]
208    fn into_raw(&self, ptr: Arc<T>) -> *const T {
209        Arc::into_raw(ptr)
210    }
211}
212
213#[cfg(feature = "alloc")]
214unsafe impl<T: ?Sized> PointerOps for DefaultPointerOps<Pin<Arc<T>>> {
215    type Value = T;
216    type Pointer = Pin<Arc<T>>;
217
218    #[inline]
219    unsafe fn from_raw(&self, raw: *const T) -> Pin<Arc<T>> {
220        Pin::new_unchecked(Arc::from_raw(raw))
221    }
222
223    #[inline]
224    fn into_raw(&self, ptr: Pin<Arc<T>>) -> *const T {
225        Arc::into_raw(unsafe { Pin::into_inner_unchecked(ptr) })
226    }
227}
228
229/// Clones a `PointerOps::Pointer` from a `*const PointerOps::Value`
230///
231/// This method is only safe to call if the raw pointer is known to be
232/// managed by the provided `PointerOps` type.
233#[inline]
234pub(crate) unsafe fn clone_pointer_from_raw<T: PointerOps>(
235    pointer_ops: &T,
236    ptr: *const T::Value,
237) -> T::Pointer
238where
239    T::Pointer: Clone,
240{
241    /// Guard which converts an pointer back into its raw version
242    /// when it gets dropped. This makes sure we also perform a full
243    /// `from_raw` and `into_raw` round trip - even in the case of panics.
244    struct PointerGuard<'a, T: PointerOps> {
245        pointer: ManuallyDrop<T::Pointer>,
246        pointer_ops: &'a T,
247    }
248
249    impl<'a, T: PointerOps> Drop for PointerGuard<'a, T> {
250        #[inline]
251        fn drop(&mut self) {
252            // Prevent shared pointers from being released by converting them
253            // back into the raw pointers
254            // SAFETY: `pointer` is never dropped. `ManuallyDrop::take` is not stable until 1.42.0.
255            let _ = self
256                .pointer_ops
257                .into_raw(unsafe { core::ptr::read(&*self.pointer) });
258        }
259    }
260
261    let holder = PointerGuard {
262        pointer: ManuallyDrop::new(pointer_ops.from_raw(ptr)),
263        pointer_ops,
264    };
265    holder.pointer.deref().clone()
266}
267
268#[cfg(test)]
269mod tests {
270    use super::{DefaultPointerOps, PointerOps};
271    use std::boxed::Box;
272    use std::fmt::Debug;
273    use std::mem;
274    use std::pin::Pin;
275    use std::rc::Rc;
276    use std::sync::Arc;
277
278    #[test]
279    fn test_box() {
280        unsafe {
281            let pointer_ops = DefaultPointerOps::<Box<_>>::new();
282            let p = Box::new(1);
283            let a: *const i32 = &*p;
284            let r = pointer_ops.into_raw(p);
285            assert_eq!(a, r);
286            let p2: Box<i32> = pointer_ops.from_raw(r);
287            let a2: *const i32 = &*p2;
288            assert_eq!(a, a2);
289        }
290    }
291
292    #[test]
293    fn test_rc() {
294        unsafe {
295            let pointer_ops = DefaultPointerOps::<Rc<_>>::new();
296            let p = Rc::new(1);
297            let a: *const i32 = &*p;
298            let r = pointer_ops.into_raw(p);
299            assert_eq!(a, r);
300            let p2: Rc<i32> = pointer_ops.from_raw(r);
301            let a2: *const i32 = &*p2;
302            assert_eq!(a, a2);
303        }
304    }
305
306    #[test]
307    fn test_arc() {
308        unsafe {
309            let pointer_ops = DefaultPointerOps::<Arc<_>>::new();
310            let p = Arc::new(1);
311            let a: *const i32 = &*p;
312            let r = pointer_ops.into_raw(p);
313            assert_eq!(a, r);
314            let p2: Arc<i32> = pointer_ops.from_raw(r);
315            let a2: *const i32 = &*p2;
316            assert_eq!(a, a2);
317        }
318    }
319
320    #[test]
321    fn test_box_unsized() {
322        unsafe {
323            let pointer_ops = DefaultPointerOps::<Box<_>>::new();
324            let p = Box::new(1) as Box<dyn Debug>;
325            let a: *const dyn Debug = &*p;
326            let b: (usize, usize) = mem::transmute(a);
327            let r = pointer_ops.into_raw(p);
328            assert_eq!(a, r);
329            assert_eq!(b, mem::transmute(r));
330            let p2: Box<dyn Debug> = pointer_ops.from_raw(r);
331            let a2: *const dyn Debug = &*p2;
332            assert_eq!(a, a2);
333            assert_eq!(b, mem::transmute(a2));
334        }
335    }
336
337    #[test]
338    fn test_rc_unsized() {
339        unsafe {
340            let pointer_ops = DefaultPointerOps::<Rc<_>>::new();
341            let p = Rc::new(1) as Rc<dyn Debug>;
342            let a: *const dyn Debug = &*p;
343            let b: (usize, usize) = mem::transmute(a);
344            let r = pointer_ops.into_raw(p);
345            assert_eq!(a, r);
346            assert_eq!(b, mem::transmute(r));
347            let p2: Rc<dyn Debug> = pointer_ops.from_raw(r);
348            let a2: *const dyn Debug = &*p2;
349            assert_eq!(a, a2);
350            assert_eq!(b, mem::transmute(a2));
351        }
352    }
353
354    #[test]
355    fn test_arc_unsized() {
356        unsafe {
357            let pointer_ops = DefaultPointerOps::<Arc<_>>::new();
358            let p = Arc::new(1) as Arc<dyn Debug>;
359            let a: *const dyn Debug = &*p;
360            let b: (usize, usize) = mem::transmute(a);
361            let r = pointer_ops.into_raw(p);
362            assert_eq!(a, r);
363            assert_eq!(b, mem::transmute(r));
364            let p2: Arc<dyn Debug> = pointer_ops.from_raw(r);
365            let a2: *const dyn Debug = &*p2;
366            assert_eq!(a, a2);
367            assert_eq!(b, mem::transmute(a2));
368        }
369    }
370
371    #[test]
372    fn clone_arc_from_raw() {
373        use super::clone_pointer_from_raw;
374        unsafe {
375            let pointer_ops = DefaultPointerOps::<Arc<_>>::new();
376            let p = Arc::new(1);
377            let raw = Arc::as_ptr(&p);
378            let p2: Arc<i32> = clone_pointer_from_raw(&pointer_ops, raw);
379            assert_eq!(2, Arc::strong_count(&p2));
380        }
381    }
382
383    #[test]
384    fn clone_rc_from_raw() {
385        use super::clone_pointer_from_raw;
386        unsafe {
387            let pointer_ops = DefaultPointerOps::<Rc<_>>::new();
388            let p = Rc::new(1);
389            let raw = Rc::as_ptr(&p);
390            let p2: Rc<i32> = clone_pointer_from_raw(&pointer_ops, raw);
391            assert_eq!(2, Rc::strong_count(&p2));
392        }
393    }
394
395    #[test]
396    fn test_pin_box() {
397        unsafe {
398            let pointer_ops = DefaultPointerOps::<Pin<Box<_>>>::new();
399            let p = Pin::new(Box::new(1));
400            let a: *const i32 = &*p;
401            let r = pointer_ops.into_raw(p);
402            assert_eq!(a, r);
403            let p2: Pin<Box<i32>> = pointer_ops.from_raw(r);
404            let a2: *const i32 = &*p2;
405            assert_eq!(a, a2);
406        }
407    }
408
409    #[test]
410    fn test_pin_rc() {
411        unsafe {
412            let pointer_ops = DefaultPointerOps::<Pin<Rc<_>>>::new();
413            let p = Pin::new(Rc::new(1));
414            let a: *const i32 = &*p;
415            let r = pointer_ops.into_raw(p);
416            assert_eq!(a, r);
417            let p2: Pin<Rc<i32>> = pointer_ops.from_raw(r);
418            let a2: *const i32 = &*p2;
419            assert_eq!(a, a2);
420        }
421    }
422
423    #[test]
424    fn test_pin_arc() {
425        unsafe {
426            let pointer_ops = DefaultPointerOps::<Pin<Arc<_>>>::new();
427            let p = Pin::new(Arc::new(1));
428            let a: *const i32 = &*p;
429            let r = pointer_ops.into_raw(p);
430            assert_eq!(a, r);
431            let p2: Pin<Arc<i32>> = pointer_ops.from_raw(r);
432            let a2: *const i32 = &*p2;
433            assert_eq!(a, a2);
434        }
435    }
436
437    #[test]
438    fn test_pin_box_unsized() {
439        unsafe {
440            let pointer_ops = DefaultPointerOps::<Pin<Box<_>>>::new();
441            let p = Pin::new(Box::new(1)) as Pin<Box<dyn Debug>>;
442            let a: *const dyn Debug = &*p;
443            let b: (usize, usize) = mem::transmute(a);
444            let r = pointer_ops.into_raw(p);
445            assert_eq!(a, r);
446            assert_eq!(b, mem::transmute(r));
447            let p2: Pin<Box<dyn Debug>> = pointer_ops.from_raw(r);
448            let a2: *const dyn Debug = &*p2;
449            assert_eq!(a, a2);
450            assert_eq!(b, mem::transmute(a2));
451        }
452    }
453
454    #[test]
455    fn test_pin_rc_unsized() {
456        unsafe {
457            let pointer_ops = DefaultPointerOps::<Pin<Rc<_>>>::new();
458            let p = Pin::new(Rc::new(1)) as Pin<Rc<dyn Debug>>;
459            let a: *const dyn Debug = &*p;
460            let b: (usize, usize) = mem::transmute(a);
461            let r = pointer_ops.into_raw(p);
462            assert_eq!(a, r);
463            assert_eq!(b, mem::transmute(r));
464            let p2: Pin<Rc<dyn Debug>> = pointer_ops.from_raw(r);
465            let a2: *const dyn Debug = &*p2;
466            assert_eq!(a, a2);
467            assert_eq!(b, mem::transmute(a2));
468        }
469    }
470
471    #[test]
472    fn test_pin_arc_unsized() {
473        unsafe {
474            let pointer_ops = DefaultPointerOps::<Pin<Arc<_>>>::new();
475            let p = Pin::new(Arc::new(1)) as Pin<Arc<dyn Debug>>;
476            let a: *const dyn Debug = &*p;
477            let b: (usize, usize) = mem::transmute(a);
478            let r = pointer_ops.into_raw(p);
479            assert_eq!(a, r);
480            assert_eq!(b, mem::transmute(r));
481            let p2: Pin<Arc<dyn Debug>> = pointer_ops.from_raw(r);
482            let a2: *const dyn Debug = &*p2;
483            assert_eq!(a, a2);
484            assert_eq!(b, mem::transmute(a2));
485        }
486    }
487
488    #[test]
489    fn clone_pin_arc_from_raw() {
490        use super::clone_pointer_from_raw;
491        unsafe {
492            let pointer_ops = DefaultPointerOps::<Pin<Arc<_>>>::new();
493            let p = Pin::new(Arc::new(1));
494            let raw = pointer_ops.into_raw(p);
495            let p2: Pin<Arc<i32>> = clone_pointer_from_raw(&pointer_ops, raw);
496            let _p = pointer_ops.from_raw(raw);
497            assert_eq!(2, Arc::strong_count(&Pin::into_inner(p2)));
498        }
499    }
500
501    #[test]
502    fn clone_pin_rc_from_raw() {
503        use super::clone_pointer_from_raw;
504        unsafe {
505            let pointer_ops = DefaultPointerOps::<Pin<Rc<_>>>::new();
506            let p = Pin::new(Rc::new(1));
507            let raw = pointer_ops.into_raw(p);
508            let p2: Pin<Rc<i32>> = clone_pointer_from_raw(&pointer_ops, raw);
509            let _p = pointer_ops.from_raw(raw);
510            assert_eq!(2, Rc::strong_count(&Pin::into_inner(p2)));
511        }
512    }
513}