metadata.rs - source
Description: Source of the Rust file `library/core/src/ptr/metadata.rs`.

#
core/ptr/
metadata.rs

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