core/ptr/
metadata.rs

1#![unstable(feature = "ptr_metadata", issue = "81513")]
2
3use crate::fmt;
4use crate::hash::{Hash, Hasher};
5use crate::intrinsics::{aggregate_raw_ptr, ptr_metadata};
6use crate::marker::Freeze;
7use crate::ptr::NonNull;
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]
57#[rustc_do_not_implement_via_object]
58pub trait Pointee {
59    /// The type for metadata in pointers and references to `Self`.
60    #[lang = "metadata_type"]
61    // NOTE: Keep trait bounds in `static_assert_expected_bounds_for_metadata`
62    // in `library/core/src/ptr/metadata.rs`
63    // in sync with those here:
64    type Metadata: fmt::Debug + Copy + Send + Sync + Ord + Hash + Unpin + Freeze;
65}
66
67/// Pointers to types implementing this trait alias are “thin”.
68///
69/// This includes statically-`Sized` types and `extern` types.
70///
71/// # Example
72///
73/// ```rust
74/// #![feature(ptr_metadata)]
75///
76/// fn this_never_panics<T: std::ptr::Thin>() {
77///     assert_eq!(std::mem::size_of::<&T>(), std::mem::size_of::<usize>())
78/// }
79/// ```
80#[unstable(feature = "ptr_metadata", issue = "81513")]
81// NOTE: don’t stabilize this before trait aliases are stable in the language?
82pub trait Thin = Pointee<Metadata = ()>;
83
84/// Extracts the metadata component of a pointer.
85///
86/// Values of type `*mut T`, `&T`, or `&mut T` can be passed directly to this function
87/// as they implicitly coerce to `*const T`.
88///
89/// # Example
90///
91/// ```
92/// #![feature(ptr_metadata)]
93///
94/// assert_eq!(std::ptr::metadata("foo"), 3_usize);
95/// ```
96#[inline]
97pub const fn metadata<T: ?Sized>(ptr: *const T) -> <T as Pointee>::Metadata {
98    ptr_metadata(ptr)
99}
100
101/// Forms a (possibly-wide) raw pointer from a data pointer 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#[inline]
110pub const fn from_raw_parts<T: ?Sized>(
111    data_pointer: *const impl Thin,
112    metadata: <T as Pointee>::Metadata,
113) -> *const T {
114    aggregate_raw_ptr(data_pointer, metadata)
115}
116
117/// Performs the same functionality as [`from_raw_parts`], except that a
118/// raw `*mut` pointer is returned, as opposed to a raw `*const` pointer.
119///
120/// See the documentation of [`from_raw_parts`] for more details.
121#[unstable(feature = "ptr_metadata", issue = "81513")]
122#[inline]
123pub const fn from_raw_parts_mut<T: ?Sized>(
124    data_pointer: *mut impl Thin,
125    metadata: <T as Pointee>::Metadata,
126) -> *mut T {
127    aggregate_raw_ptr(data_pointer, metadata)
128}
129
130/// The metadata for a `Dyn = dyn SomeTrait` trait object type.
131///
132/// It is a pointer to a vtable (virtual call table)
133/// that represents all the necessary information
134/// to manipulate the concrete type stored inside a trait object.
135/// The vtable notably contains:
136///
137/// * type size
138/// * type alignment
139/// * a pointer to the type’s `drop_in_place` impl (may be a no-op for plain-old-data)
140/// * pointers to all the methods for the type’s implementation of the trait
141///
142/// Note that the first three are special because they’re necessary to allocate, drop,
143/// and deallocate any trait object.
144///
145/// It is possible to name this struct with a type parameter that is not a `dyn` trait object
146/// (for example `DynMetadata<u64>`) but not to obtain a meaningful value of that struct.
147///
148/// Note that while this type implements `PartialEq`, comparing vtable pointers is unreliable:
149/// pointers to vtables of the same type for the same trait can compare inequal (because vtables are
150/// duplicated in multiple codegen units), and pointers to vtables of *different* types/traits can
151/// compare equal (since identical vtables can be deduplicated within a codegen unit).
152#[lang = "dyn_metadata"]
153pub struct DynMetadata<Dyn: ?Sized> {
154    _vtable_ptr: NonNull<VTable>,
155    _phantom: crate::marker::PhantomData<Dyn>,
156}
157
158unsafe extern "C" {
159    /// Opaque type for accessing vtables.
160    ///
161    /// Private implementation detail of `DynMetadata::size_of` etc.
162    /// There is conceptually not actually any Abstract Machine memory behind this pointer.
163    type VTable;
164}
165
166impl<Dyn: ?Sized> DynMetadata<Dyn> {
167    /// When `DynMetadata` appears as the metadata field of a wide pointer, the rustc_middle layout
168    /// computation does magic and the resulting layout is *not* a `FieldsShape::Aggregate`, instead
169    /// it is a `FieldsShape::Primitive`. This means that the same type can have different layout
170    /// depending on whether it appears as the metadata field of a wide pointer or as a stand-alone
171    /// type, which understandably confuses codegen and leads to ICEs when trying to project to a
172    /// field of `DynMetadata`. To work around that issue, we use `transmute` instead of using a
173    /// field projection.
174    #[inline]
175    fn vtable_ptr(self) -> *const VTable {
176        // SAFETY: this layout assumption is hard-coded into the compiler.
177        // If it's somehow not a size match, the transmute will error.
178        unsafe { crate::mem::transmute::<Self, *const VTable>(self) }
179    }
180
181    /// Returns the size of the type associated with this vtable.
182    #[inline]
183    pub fn size_of(self) -> usize {
184        // Note that "size stored in vtable" is *not* the same as "result of size_of_val_raw".
185        // Consider a reference like `&(i32, dyn Send)`: the vtable will only store the size of the
186        // `Send` part!
187        // SAFETY: DynMetadata always contains a valid vtable pointer
188        unsafe { crate::intrinsics::vtable_size(self.vtable_ptr() as *const ()) }
189    }
190
191    /// Returns the alignment of the type associated with this vtable.
192    #[inline]
193    pub fn align_of(self) -> usize {
194        // SAFETY: DynMetadata always contains a valid vtable pointer
195        unsafe { crate::intrinsics::vtable_align(self.vtable_ptr() as *const ()) }
196    }
197
198    /// Returns the size and alignment together as a `Layout`
199    #[inline]
200    pub fn layout(self) -> crate::alloc::Layout {
201        // SAFETY: the compiler emitted this vtable for a concrete Rust type which
202        // is known to have a valid layout. Same rationale as in `Layout::for_value`.
203        unsafe { crate::alloc::Layout::from_size_align_unchecked(self.size_of(), self.align_of()) }
204    }
205}
206
207unsafe impl<Dyn: ?Sized> Send for DynMetadata<Dyn> {}
208unsafe impl<Dyn: ?Sized> Sync for DynMetadata<Dyn> {}
209
210impl<Dyn: ?Sized> fmt::Debug for DynMetadata<Dyn> {
211    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
212        f.debug_tuple("DynMetadata").field(&self.vtable_ptr()).finish()
213    }
214}
215
216// Manual impls needed to avoid `Dyn: $Trait` bounds.
217
218impl<Dyn: ?Sized> Unpin for DynMetadata<Dyn> {}
219
220impl<Dyn: ?Sized> Copy for DynMetadata<Dyn> {}
221
222impl<Dyn: ?Sized> Clone for DynMetadata<Dyn> {
223    #[inline]
224    fn clone(&self) -> Self {
225        *self
226    }
227}
228
229impl<Dyn: ?Sized> Eq for DynMetadata<Dyn> {}
230
231impl<Dyn: ?Sized> PartialEq for DynMetadata<Dyn> {
232    #[inline]
233    fn eq(&self, other: &Self) -> bool {
234        crate::ptr::eq::<VTable>(self.vtable_ptr(), other.vtable_ptr())
235    }
236}
237
238impl<Dyn: ?Sized> Ord for DynMetadata<Dyn> {
239    #[inline]
240    #[allow(ambiguous_wide_pointer_comparisons)]
241    fn cmp(&self, other: &Self) -> crate::cmp::Ordering {
242        <*const VTable>::cmp(&self.vtable_ptr(), &other.vtable_ptr())
243    }
244}
245
246impl<Dyn: ?Sized> PartialOrd for DynMetadata<Dyn> {
247    #[inline]
248    fn partial_cmp(&self, other: &Self) -> Option<crate::cmp::Ordering> {
249        Some(self.cmp(other))
250    }
251}
252
253impl<Dyn: ?Sized> Hash for DynMetadata<Dyn> {
254    #[inline]
255    fn hash<H: Hasher>(&self, hasher: &mut H) {
256        crate::ptr::hash::<VTable, _>(self.vtable_ptr(), hasher)
257    }
258}