]>
Commit | Line | Data |
---|---|---|
f20569fa XL |
1 | //! This module implements tagged pointers. |
2 | //! | |
3 | //! In order to utilize the pointer packing, you must have two types: a pointer, | |
4 | //! and a tag. | |
5 | //! | |
6 | //! The pointer must implement the `Pointer` trait, with the primary requirement | |
7 | //! being conversion to and from a usize. Note that the pointer must be | |
8 | //! dereferenceable, so raw pointers generally cannot implement the `Pointer` | |
9 | //! trait. This implies that the pointer must also be nonzero. | |
10 | //! | |
11 | //! Many common pointer types already implement the `Pointer` trait. | |
12 | //! | |
13 | //! The tag must implement the `Tag` trait. We assert that the tag and `Pointer` | |
14 | //! are compatible at compile time. | |
15 | ||
16 | use std::mem::ManuallyDrop; | |
17 | use std::ops::Deref; | |
18 | use std::rc::Rc; | |
19 | use std::sync::Arc; | |
20 | ||
21 | mod copy; | |
22 | mod drop; | |
23 | ||
24 | pub use copy::CopyTaggedPtr; | |
25 | pub use drop::TaggedPtr; | |
26 | ||
27 | /// This describes the pointer type encapsulated by TaggedPtr. | |
28 | /// | |
29 | /// # Safety | |
30 | /// | |
31 | /// The usize returned from `into_usize` must be a valid, dereferenceable, | |
32 | /// pointer to `<Self as Deref>::Target`. Note that pointers to `Pointee` must | |
33 | /// be thin, even though `Pointee` may not be sized. | |
34 | /// | |
35 | /// Note that the returned pointer from `into_usize` should be castable to `&mut | |
36 | /// <Self as Deref>::Target` if `Pointer: DerefMut`. | |
37 | /// | |
38 | /// The BITS constant must be correct. At least `BITS` bits, least-significant, | |
39 | /// must be zero on all returned pointers from `into_usize`. | |
40 | /// | |
41 | /// For example, if the alignment of `Pointee` is 2, then `BITS` should be 1. | |
42 | pub unsafe trait Pointer: Deref { | |
43 | /// Most likely the value you want to use here is the following, unless | |
44 | /// your Pointee type is unsized (e.g., `ty::List<T>` in rustc) in which | |
45 | /// case you'll need to manually figure out what the right type to pass to | |
46 | /// align_of is. | |
47 | /// | |
48 | /// ```rust | |
49 | /// std::mem::align_of::<<Self as Deref>::Target>().trailing_zeros() as usize; | |
50 | /// ``` | |
51 | const BITS: usize; | |
52 | fn into_usize(self) -> usize; | |
53 | ||
54 | /// # Safety | |
55 | /// | |
56 | /// The passed `ptr` must be returned from `into_usize`. | |
57 | /// | |
58 | /// This acts as `ptr::read` semantically, it should not be called more than | |
59 | /// once on non-`Copy` `Pointer`s. | |
60 | unsafe fn from_usize(ptr: usize) -> Self; | |
61 | ||
62 | /// This provides a reference to the `Pointer` itself, rather than the | |
63 | /// `Deref::Target`. It is used for cases where we want to call methods that | |
64 | /// may be implement differently for the Pointer than the Pointee (e.g., | |
65 | /// `Rc::clone` vs cloning the inner value). | |
66 | /// | |
67 | /// # Safety | |
68 | /// | |
69 | /// The passed `ptr` must be returned from `into_usize`. | |
70 | unsafe fn with_ref<R, F: FnOnce(&Self) -> R>(ptr: usize, f: F) -> R; | |
71 | } | |
72 | ||
73 | /// This describes tags that the `TaggedPtr` struct can hold. | |
74 | /// | |
75 | /// # Safety | |
76 | /// | |
77 | /// The BITS constant must be correct. | |
78 | /// | |
79 | /// No more than `BITS` least significant bits may be set in the returned usize. | |
80 | pub unsafe trait Tag: Copy { | |
81 | const BITS: usize; | |
82 | ||
83 | fn into_usize(self) -> usize; | |
84 | ||
85 | /// # Safety | |
86 | /// | |
87 | /// The passed `tag` must be returned from `into_usize`. | |
88 | unsafe fn from_usize(tag: usize) -> Self; | |
89 | } | |
90 | ||
91 | unsafe impl<T> Pointer for Box<T> { | |
92 | const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize; | |
93 | fn into_usize(self) -> usize { | |
94 | Box::into_raw(self) as usize | |
95 | } | |
96 | unsafe fn from_usize(ptr: usize) -> Self { | |
97 | Box::from_raw(ptr as *mut T) | |
98 | } | |
99 | unsafe fn with_ref<R, F: FnOnce(&Self) -> R>(ptr: usize, f: F) -> R { | |
100 | let raw = ManuallyDrop::new(Self::from_usize(ptr)); | |
101 | f(&raw) | |
102 | } | |
103 | } | |
104 | ||
105 | unsafe impl<T> Pointer for Rc<T> { | |
106 | const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize; | |
107 | fn into_usize(self) -> usize { | |
108 | Rc::into_raw(self) as usize | |
109 | } | |
110 | unsafe fn from_usize(ptr: usize) -> Self { | |
111 | Rc::from_raw(ptr as *const T) | |
112 | } | |
113 | unsafe fn with_ref<R, F: FnOnce(&Self) -> R>(ptr: usize, f: F) -> R { | |
114 | let raw = ManuallyDrop::new(Self::from_usize(ptr)); | |
115 | f(&raw) | |
116 | } | |
117 | } | |
118 | ||
119 | unsafe impl<T> Pointer for Arc<T> { | |
120 | const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize; | |
121 | fn into_usize(self) -> usize { | |
122 | Arc::into_raw(self) as usize | |
123 | } | |
124 | unsafe fn from_usize(ptr: usize) -> Self { | |
125 | Arc::from_raw(ptr as *const T) | |
126 | } | |
127 | unsafe fn with_ref<R, F: FnOnce(&Self) -> R>(ptr: usize, f: F) -> R { | |
128 | let raw = ManuallyDrop::new(Self::from_usize(ptr)); | |
129 | f(&raw) | |
130 | } | |
131 | } | |
132 | ||
133 | unsafe impl<'a, T: 'a> Pointer for &'a T { | |
134 | const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize; | |
135 | fn into_usize(self) -> usize { | |
136 | self as *const T as usize | |
137 | } | |
138 | unsafe fn from_usize(ptr: usize) -> Self { | |
139 | &*(ptr as *const T) | |
140 | } | |
141 | unsafe fn with_ref<R, F: FnOnce(&Self) -> R>(ptr: usize, f: F) -> R { | |
142 | f(&*(&ptr as *const usize as *const Self)) | |
143 | } | |
144 | } | |
145 | ||
146 | unsafe impl<'a, T: 'a> Pointer for &'a mut T { | |
147 | const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize; | |
148 | fn into_usize(self) -> usize { | |
149 | self as *mut T as usize | |
150 | } | |
151 | unsafe fn from_usize(ptr: usize) -> Self { | |
152 | &mut *(ptr as *mut T) | |
153 | } | |
154 | unsafe fn with_ref<R, F: FnOnce(&Self) -> R>(ptr: usize, f: F) -> R { | |
155 | f(&*(&ptr as *const usize as *const Self)) | |
156 | } | |
157 | } |