| 1 | #![unstable (feature = "ptr_metadata" , issue = "81513" )] |
| 2 | |
| 3 | use crate::fmt; |
| 4 | use crate::hash::{Hash, Hasher}; |
| 5 | use crate::intrinsics::{aggregate_raw_ptr, ptr_metadata}; |
| 6 | use crate::marker::Freeze; |
| 7 | use 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] |
| 58 | pub 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? |
| 84 | pub 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 ] |
| 99 | pub 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 ] |
| 112 | pub 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, meta: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 ] |
| 125 | pub 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, meta: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" ] |
| 155 | pub struct DynMetadata<Dyn: ?Sized> { |
| 156 | _vtable_ptr: NonNull<VTable>, |
| 157 | _phantom: crate::marker::PhantomData<Dyn>, |
| 158 | } |
| 159 | |
| 160 | unsafe 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 | |
| 168 | impl<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 | |
| 209 | unsafe impl<Dyn: ?Sized> Send for DynMetadata<Dyn> {} |
| 210 | unsafe impl<Dyn: ?Sized> Sync for DynMetadata<Dyn> {} |
| 211 | |
| 212 | impl<Dyn: ?Sized> fmt::Debug for DynMetadata<Dyn> { |
| 213 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 214 | f.debug_tuple(name:"DynMetadata" ).field(&self.vtable_ptr()).finish() |
| 215 | } |
| 216 | } |
| 217 | |
| 218 | // Manual impls needed to avoid `Dyn: $Trait` bounds. |
| 219 | |
| 220 | impl<Dyn: ?Sized> Unpin for DynMetadata<Dyn> {} |
| 221 | |
| 222 | impl<Dyn: ?Sized> Copy for DynMetadata<Dyn> {} |
| 223 | |
| 224 | impl<Dyn: ?Sized> Clone for DynMetadata<Dyn> { |
| 225 | #[inline ] |
| 226 | fn clone(&self) -> Self { |
| 227 | *self |
| 228 | } |
| 229 | } |
| 230 | |
| 231 | impl<Dyn: ?Sized> Eq for DynMetadata<Dyn> {} |
| 232 | |
| 233 | impl<Dyn: ?Sized> PartialEq for DynMetadata<Dyn> { |
| 234 | #[inline ] |
| 235 | fn eq(&self, other: &Self) -> bool { |
| 236 | crate::ptr::eq::<VTable>(self.vtable_ptr(), b:other.vtable_ptr()) |
| 237 | } |
| 238 | } |
| 239 | |
| 240 | impl<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 | |
| 248 | impl<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 | |
| 255 | impl<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(), into:hasher) |
| 259 | } |
| 260 | } |
| 261 | |