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