1 | #![unstable (feature = "ptr_metadata" , issue = "81513" )] |
2 | |
3 | use crate::fmt; |
4 | use crate::hash::{Hash, Hasher}; |
5 | #[cfg (not(bootstrap))] |
6 | use crate::intrinsics::aggregate_raw_ptr; |
7 | use crate::marker::Freeze; |
8 | |
9 | /// Provides the pointer metadata type of any pointed-to type. |
10 | /// |
11 | /// # Pointer metadata |
12 | /// |
13 | /// Raw pointer types and reference types in Rust can be thought of as made of two parts: |
14 | /// a data pointer that contains the memory address of the value, and some metadata. |
15 | /// |
16 | /// For statically-sized types (that implement the `Sized` traits) |
17 | /// as well as for `extern` types, |
18 | /// pointers are said to be “thin”: metadata is zero-sized and its type is `()`. |
19 | /// |
20 | /// Pointers to [dynamically-sized types][dst] are said to be “wide” or “fat”, |
21 | /// they have non-zero-sized metadata: |
22 | /// |
23 | /// * For structs whose last field is a DST, metadata is the metadata for the last field |
24 | /// * For the `str` type, metadata is the length in bytes as `usize` |
25 | /// * For slice types like `[T]`, metadata is the length in items as `usize` |
26 | /// * For trait objects like `dyn SomeTrait`, metadata is [`DynMetadata<Self>`][DynMetadata] |
27 | /// (e.g. `DynMetadata<dyn SomeTrait>`) |
28 | /// |
29 | /// In the future, the Rust language may gain new kinds of types |
30 | /// that have different pointer metadata. |
31 | /// |
32 | /// [dst]: https://doc.rust-lang.org/nomicon/exotic-sizes.html#dynamically-sized-types-dsts |
33 | /// |
34 | /// |
35 | /// # The `Pointee` trait |
36 | /// |
37 | /// The point of this trait is its `Metadata` associated type, |
38 | /// which is `()` or `usize` or `DynMetadata<_>` as described above. |
39 | /// It is automatically implemented for every type. |
40 | /// It can be assumed to be implemented in a generic context, even without a corresponding bound. |
41 | /// |
42 | /// |
43 | /// # Usage |
44 | /// |
45 | /// Raw pointers can be decomposed into the data pointer and metadata components |
46 | /// with their [`to_raw_parts`] method. |
47 | /// |
48 | /// Alternatively, metadata alone can be extracted with the [`metadata`] function. |
49 | /// A reference can be passed to [`metadata`] and implicitly coerced. |
50 | /// |
51 | /// A (possibly-wide) pointer can be put back together from its data pointer and metadata |
52 | /// with [`from_raw_parts`] or [`from_raw_parts_mut`]. |
53 | /// |
54 | /// [`to_raw_parts`]: *const::to_raw_parts |
55 | #[lang = "pointee_trait" ] |
56 | #[rustc_deny_explicit_impl (implement_via_object = false)] |
57 | pub trait Pointee { |
58 | /// The type for metadata in pointers and references to `Self`. |
59 | #[lang = "metadata_type" ] |
60 | // NOTE: Keep trait bounds in `static_assert_expected_bounds_for_metadata` |
61 | // in `library/core/src/ptr/metadata.rs` |
62 | // in sync with those here: |
63 | type Metadata: fmt::Debug + Copy + Send + Sync + Ord + Hash + Unpin + Freeze; |
64 | } |
65 | |
66 | /// Pointers to types implementing this trait alias are “thin”. |
67 | /// |
68 | /// This includes statically-`Sized` types and `extern` types. |
69 | /// |
70 | /// # Example |
71 | /// |
72 | /// ```rust |
73 | /// #![feature(ptr_metadata)] |
74 | /// |
75 | /// fn this_never_panics<T: std::ptr::Thin>() { |
76 | /// assert_eq!(std::mem::size_of::<&T>(), std::mem::size_of::<usize>()) |
77 | /// } |
78 | /// ``` |
79 | #[unstable (feature = "ptr_metadata" , issue = "81513" )] |
80 | // NOTE: don’t stabilize this before trait aliases are stable in the language? |
81 | pub trait Thin = Pointee<Metadata = ()>; |
82 | |
83 | /// Extract the metadata component of a pointer. |
84 | /// |
85 | /// Values of type `*mut T`, `&T`, or `&mut T` can be passed directly to this function |
86 | /// as they implicitly coerce to `*const T`. |
87 | /// |
88 | /// # Example |
89 | /// |
90 | /// ``` |
91 | /// #![feature(ptr_metadata)] |
92 | /// |
93 | /// assert_eq!(std::ptr::metadata("foo" ), 3_usize); |
94 | /// ``` |
95 | #[rustc_const_unstable (feature = "ptr_metadata" , issue = "81513" )] |
96 | #[inline ] |
97 | pub const fn metadata<T: ?Sized>(ptr: *const T) -> <T as Pointee>::Metadata { |
98 | // SAFETY: Accessing the value from the `PtrRepr` union is safe since *const T |
99 | // and PtrComponents<T> have the same memory layouts. Only std can make this |
100 | // guarantee. |
101 | unsafe { PtrRepr { const_ptr: ptr }.components.metadata } |
102 | } |
103 | |
104 | /// Forms a (possibly-wide) raw pointer from a data pointer and metadata. |
105 | /// |
106 | /// This function is safe but the returned pointer is not necessarily safe to dereference. |
107 | /// For slices, see the documentation of [`slice::from_raw_parts`] for safety requirements. |
108 | /// For trait objects, the metadata must come from a pointer to the same underlying erased type. |
109 | /// |
110 | /// [`slice::from_raw_parts`]: crate::slice::from_raw_parts |
111 | #[unstable (feature = "ptr_metadata" , issue = "81513" )] |
112 | #[rustc_const_unstable (feature = "ptr_metadata" , issue = "81513" )] |
113 | #[inline ] |
114 | pub const fn from_raw_parts<T: ?Sized>( |
115 | data_pointer: *const (), |
116 | metadata: <T as Pointee>::Metadata, |
117 | ) -> *const T { |
118 | #[cfg (bootstrap)] |
119 | { |
120 | // SAFETY: Accessing the value from the `PtrRepr` union is safe since *const T |
121 | // and PtrComponents<T> have the same memory layouts. Only std can make this |
122 | // guarantee. |
123 | unsafe { PtrRepr { components: PtrComponents { data_pointer, metadata } }.const_ptr } |
124 | } |
125 | #[cfg (not(bootstrap))] |
126 | { |
127 | aggregate_raw_ptr(data_pointer, _meta:metadata) |
128 | } |
129 | } |
130 | |
131 | /// Performs the same functionality as [`from_raw_parts`], except that a |
132 | /// raw `*mut` pointer is returned, as opposed to a raw `*const` pointer. |
133 | /// |
134 | /// See the documentation of [`from_raw_parts`] for more details. |
135 | #[unstable (feature = "ptr_metadata" , issue = "81513" )] |
136 | #[rustc_const_unstable (feature = "ptr_metadata" , issue = "81513" )] |
137 | #[inline ] |
138 | pub const fn from_raw_parts_mut<T: ?Sized>( |
139 | data_pointer: *mut (), |
140 | metadata: <T as Pointee>::Metadata, |
141 | ) -> *mut T { |
142 | #[cfg (bootstrap)] |
143 | { |
144 | // SAFETY: Accessing the value from the `PtrRepr` union is safe since *const T |
145 | // and PtrComponents<T> have the same memory layouts. Only std can make this |
146 | // guarantee. |
147 | unsafe { PtrRepr { components: PtrComponents { data_pointer, metadata } }.mut_ptr } |
148 | } |
149 | #[cfg (not(bootstrap))] |
150 | { |
151 | aggregate_raw_ptr(data_pointer, _meta:metadata) |
152 | } |
153 | } |
154 | |
155 | #[repr (C)] |
156 | union PtrRepr<T: ?Sized> { |
157 | const_ptr: *const T, |
158 | mut_ptr: *mut T, |
159 | components: PtrComponents<T>, |
160 | } |
161 | |
162 | #[repr (C)] |
163 | struct PtrComponents<T: ?Sized> { |
164 | data_pointer: *const (), |
165 | metadata: <T as Pointee>::Metadata, |
166 | } |
167 | |
168 | // Manual impl needed to avoid `T: Copy` bound. |
169 | impl<T: ?Sized> Copy for PtrComponents<T> {} |
170 | |
171 | // Manual impl needed to avoid `T: Clone` bound. |
172 | impl<T: ?Sized> Clone for PtrComponents<T> { |
173 | fn clone(&self) -> Self { |
174 | *self |
175 | } |
176 | } |
177 | |
178 | /// The metadata for a `Dyn = dyn SomeTrait` trait object type. |
179 | /// |
180 | /// It is a pointer to a vtable (virtual call table) |
181 | /// that represents all the necessary information |
182 | /// to manipulate the concrete type stored inside a trait object. |
183 | /// The vtable notably contains: |
184 | /// |
185 | /// * type size |
186 | /// * type alignment |
187 | /// * a pointer to the type’s `drop_in_place` impl (may be a no-op for plain-old-data) |
188 | /// * pointers to all the methods for the type’s implementation of the trait |
189 | /// |
190 | /// Note that the first three are special because they’re necessary to allocate, drop, |
191 | /// and deallocate any trait object. |
192 | /// |
193 | /// It is possible to name this struct with a type parameter that is not a `dyn` trait object |
194 | /// (for example `DynMetadata<u64>`) but not to obtain a meaningful value of that struct. |
195 | /// |
196 | /// Note that while this type implements `PartialEq`, comparing vtable pointers is unreliable: |
197 | /// pointers to vtables of the same type for the same trait can compare inequal (because vtables are |
198 | /// duplicated in multiple codegen units), and pointers to vtables of *different* types/traits can |
199 | /// compare equal (since identical vtables can be deduplicated within a codegen unit). |
200 | #[lang = "dyn_metadata" ] |
201 | pub struct DynMetadata<Dyn: ?Sized> { |
202 | vtable_ptr: &'static VTable, |
203 | phantom: crate::marker::PhantomData<Dyn>, |
204 | } |
205 | |
206 | extern "C" { |
207 | /// Opaque type for accessing vtables. |
208 | /// |
209 | /// Private implementation detail of `DynMetadata::size_of` etc. |
210 | /// There is conceptually not actually any Abstract Machine memory behind this pointer. |
211 | type VTable; |
212 | } |
213 | |
214 | impl<Dyn: ?Sized> DynMetadata<Dyn> { |
215 | /// Returns the size of the type associated with this vtable. |
216 | #[inline ] |
217 | pub fn size_of(self) -> usize { |
218 | // Note that "size stored in vtable" is *not* the same as "result of size_of_val_raw". |
219 | // Consider a reference like `&(i32, dyn Send)`: the vtable will only store the size of the |
220 | // `Send` part! |
221 | // SAFETY: DynMetadata always contains a valid vtable pointer |
222 | return unsafe { |
223 | crate::intrinsics::vtable_size(self.vtable_ptr as *const VTable as *const ()) |
224 | }; |
225 | } |
226 | |
227 | /// Returns the alignment of the type associated with this vtable. |
228 | #[inline ] |
229 | pub fn align_of(self) -> usize { |
230 | // SAFETY: DynMetadata always contains a valid vtable pointer |
231 | return unsafe { |
232 | crate::intrinsics::vtable_align(self.vtable_ptr as *const VTable as *const ()) |
233 | }; |
234 | } |
235 | |
236 | /// Returns the size and alignment together as a `Layout` |
237 | #[inline ] |
238 | pub fn layout(self) -> crate::alloc::Layout { |
239 | // SAFETY: the compiler emitted this vtable for a concrete Rust type which |
240 | // is known to have a valid layout. Same rationale as in `Layout::for_value`. |
241 | unsafe { crate::alloc::Layout::from_size_align_unchecked(self.size_of(), self.align_of()) } |
242 | } |
243 | } |
244 | |
245 | unsafe impl<Dyn: ?Sized> Send for DynMetadata<Dyn> {} |
246 | unsafe impl<Dyn: ?Sized> Sync for DynMetadata<Dyn> {} |
247 | |
248 | impl<Dyn: ?Sized> fmt::Debug for DynMetadata<Dyn> { |
249 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
250 | f.debug_tuple(name:"DynMetadata" ).field(&(self.vtable_ptr as *const VTable)).finish() |
251 | } |
252 | } |
253 | |
254 | // Manual impls needed to avoid `Dyn: $Trait` bounds. |
255 | |
256 | impl<Dyn: ?Sized> Unpin for DynMetadata<Dyn> {} |
257 | |
258 | impl<Dyn: ?Sized> Copy for DynMetadata<Dyn> {} |
259 | |
260 | impl<Dyn: ?Sized> Clone for DynMetadata<Dyn> { |
261 | #[inline ] |
262 | fn clone(&self) -> Self { |
263 | *self |
264 | } |
265 | } |
266 | |
267 | impl<Dyn: ?Sized> Eq for DynMetadata<Dyn> {} |
268 | |
269 | impl<Dyn: ?Sized> PartialEq for DynMetadata<Dyn> { |
270 | #[inline ] |
271 | fn eq(&self, other: &Self) -> bool { |
272 | crate::ptr::eq::<VTable>(self.vtable_ptr, b:other.vtable_ptr) |
273 | } |
274 | } |
275 | |
276 | impl<Dyn: ?Sized> Ord for DynMetadata<Dyn> { |
277 | #[inline ] |
278 | #[allow (ambiguous_wide_pointer_comparisons)] |
279 | fn cmp(&self, other: &Self) -> crate::cmp::Ordering { |
280 | (self.vtable_ptr as *const VTable).cmp(&(other.vtable_ptr as *const VTable)) |
281 | } |
282 | } |
283 | |
284 | impl<Dyn: ?Sized> PartialOrd for DynMetadata<Dyn> { |
285 | #[inline ] |
286 | fn partial_cmp(&self, other: &Self) -> Option<crate::cmp::Ordering> { |
287 | Some(self.cmp(other)) |
288 | } |
289 | } |
290 | |
291 | impl<Dyn: ?Sized> Hash for DynMetadata<Dyn> { |
292 | #[inline ] |
293 | fn hash<H: Hasher>(&self, hasher: &mut H) { |
294 | crate::ptr::hash::<VTable, _>(self.vtable_ptr, into:hasher) |
295 | } |
296 | } |
297 | |