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