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

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy