Repository: rust
Issue: Tracking Issue for pointer metadata APIs
Labels: T-lang,T-libs-api,C-tracking-issue,S-tracking-design-concerns

This is a tracking issue for the RFC 2580 "Pointer metadata & VTable" (rust-lang/rfcs#2580).
The feature gate for the issue is `#![feature(ptr_metadata)]`.

### About tracking issues

Tracking issues are used to record the overall progress of implementation.
They are also used as hubs connecting to other relevant issues, e.g., bugs or open design questions.
A tracking issue is however *not* meant for large scale discussion, questions, or bug reports about a feature.
Instead, open a dedicated issue for the specific matter and add the relevant feature gate label.

### Steps

- [x] Implement the RFC (cc @rust-lang/libs @rust-lang/lang -- can anyone write up mentoring
      instructions?)
- [ ] Adjust documentation ([see instructions on rustc-dev-guide][doc-guide])
- [ ] Stabilization PR ([see instructions on rustc-dev-guide][stabilization-guide])

[stabilization-guide]: https://rustc-dev-guide.rust-lang.org/stabilization_guide.html#stabilization-pr
[doc-guide]: https://rustc-dev-guide.rust-lang.org/stabilization_guide.html#documentation-prs

### Unresolved Questions

Language-level:

* Is it, or should it be UB (through validity or safety invariants) to have a raw trait object wide pointer with an dangling vtable pointer? A null vtable pointer? If not, `DynMetadata` methods like `size` may need to be `unsafe fn`. Or maybe something like `*const ()` should be metadata of trait objects instead of `DynMetadata`. <br>Right now, there is some inconsistency here: `size_of_val_raw(ptr)` is unsafe, but `metadta(ptr).size_of()` does the same thing and is safe.<br>Update (2024-10-04): It is definitely the case that the *safety* invariant for raw trait objects requires a valid vtable. So  `metadta(ptr).size_of()` being safe is fine. `size_of_val_raw(ptr)`  must be unsafe because of slices, so there is no inconsistency here.
* should `Metadata` be required to be `Freeze`

API level:

* Is `*const ()` appropriate for the data component of pointers? Or should it be `*const u8`? Or `*const Opaque` with some new `Opaque` type? (Respectively `*mut ()` and `NonNull<()>`)
* Should `ptr::from_raw_parts` and friends be `unsafe fn`?
* Should `Thin` be added as a supertrait of `Sized`? Or could it ever make sense to have fat pointers to statically-sized types?
* Should `DynMetadata` not have a type parameter? This might reduce monomorphization cost, but would force that the size, alignment, and destruction pointers be in the same location (offset) for every vtable. But keeping them in the same location is probaly desirable anyway to keep code size small.
* https://github.com/rust-lang/libs-team/issues/246
* `DynMetadata::size_of` does not always return the same value as `size_of_val` since the former only reads the size from the vtable, but the latter computes the size of the entire type. That seems like a pretty bad footgun?

API bikesheds:

* Name of new items: `Pointee` (v.s. Referent?), `Thin` (`ThinPointee`?), `DynMetadata` (`VTablePtr`?), etc
* Location of new items in `core::ptr`. For example: should `Thin` be in `core::marker` instead?


### Implementation history

- #81172 Initial implementation
- #125701 
- #132895

### Tracked APIs

Last updated for https://github.com/rust-lang/rust/pull/81172.

```rust
pub trait Pointee {
    /// One of `()`, `usize`, or `DynMetadata<dyn SomeTrait>`
    type Metadata;
}

pub trait Thin = Pointee<Metadata = ()>;

pub const fn metadata<T: ?Sized>(ptr: *const T) -> <T as Pointee>::Metadata {}

pub const fn from_raw_parts<T: ?Sized>(*const impl Thin, <T as Pointee>::Metadata) -> *const T {}
pub const fn from_raw_parts_mut<T: ?Sized>(*mut impl Thin, <T as Pointee>::Metadata) -> *mut T {}

impl<T: ?Sized> NonNull<T> {
    pub const fn from_raw_parts(NonNull<impl Thin>, <T as Pointee>::Metadata) -> NonNull<T> {}

    /// Convenience for `(ptr.cast(), metadata(ptr))`
    pub const fn to_raw_parts(self) -> (NonNull<()>, <T as Pointee>::Metadata) {}
}

impl<T: ?Sized> *const T {
    pub const fn to_raw_parts(self) -> (*const (), <T as Pointee>::Metadata) {}
}

impl<T: ?Sized> *mut T {
    pub const fn to_raw_parts(self) -> (*mut (), <T as Pointee>::Metadata) {}
}

/// `<dyn SomeTrait as Pointee>::Metadata == DynMetadata<dyn SomeTrait>`
pub struct DynMetadata<Dyn: ?Sized> {
    // Private pointer to vtable
}

impl<Dyn: ?Sized> DynMetadata<Dyn> {
    pub fn size_of(self) -> usize {}
    pub fn align_of(self) -> usize {}
    pub fn layout(self) -> crate::alloc::Layout {}
}

unsafe impl<Dyn: ?Sized> Send for DynMetadata<Dyn> {}
unsafe impl<Dyn: ?Sized> Sync for DynMetadata<Dyn> {}
impl<Dyn: ?Sized> Debug for DynMetadata<Dyn> {}
impl<Dyn: ?Sized> Unpin for DynMetadata<Dyn> {}
impl<Dyn: ?Sized> Copy for DynMetadata<Dyn> {}
impl<Dyn: ?Sized> Clone for DynMetadata<Dyn> {}
impl<Dyn: ?Sized> Eq for DynMetadata<Dyn> {}
impl<Dyn: ?Sized> PartialEq for DynMetadata<Dyn> {}
impl<Dyn: ?Sized> Ord for DynMetadata<Dyn> {}
impl<Dyn: ?Sized> PartialOrd for DynMetadata<Dyn> {}
impl<Dyn: ?Sized> Hash for DynMetadata<Dyn> {}
```