Skip to content

Commit 7b0175e

Browse files
committed
Pointer metadata: parameterize DynMetadata over its dyn Trait type
1 parent 236e657 commit 7b0175e

File tree

1 file changed

+22
-25
lines changed

1 file changed

+22
-25
lines changed

text/0000-ptr-meta.md

Lines changed: 22 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,9 @@ First, let’s get some boilerplate out of the way:
8383
use std::marker::{PhantomData, Unsize};
8484
use std::ptr::{self, DynMetadata};
8585

86-
trait DynTrait = Pointee<Metadata=DynMetadata>;
86+
trait DynTrait<Dyn> = Pointee<Metadata=DynMetadata<Dyn>>;
8787

88-
pub struct ThinBox<Dyn: ?Sized + DynTrait> {
88+
pub struct ThinBox<Dyn: ?Sized + DynTrait<Dyn>> {
8989
ptr: ptr::NonNull<WithMeta<()>>,
9090
phantom: PhantomData<Dyn>,
9191
}
@@ -125,7 +125,7 @@ Accessing the value requires knowing its alignment:
125125
impl<Dyn: ?Sized + DynTrait> ThinBox<Dyn> {
126126
fn data_ptr(&self) -> *mut () {
127127
unsafe {
128-
let offset = std::mem::size_of::<DynMetadata>();
128+
let offset = std::mem::size_of::<DynMetadata<Dyn>();
129129
let value_align = self.ptr.as_ref().vtable.align();
130130
let offset = align_up_to(offset, value_align);
131131
(self.ptr.as_ptr() as *mut u8).add(offset) as *mut ()
@@ -218,15 +218,17 @@ This similarly includes extern types.
218218
/// * For structs whose last field is a DST, metadata is the metadata for the last field
219219
/// * For the `str` type, metadata is the length in bytes as `usize`
220220
/// * For slice types like `[T]`, metadata is the length in items as `usize`
221-
/// * For trait objects like `dyn SomeTrait`, metadata is [`DynMetadata`].
221+
/// * For trait objects like `dyn SomeTrait`, metadata is [`DynMetadata<Self>`][DynMetadata]
222+
/// (e.g. `DynMetadata<dyn SomeTrait>`).
222223
///
223224
/// In the future, the Rust language may gain new kinds of types
224225
/// that have different pointer metadata.
225226
///
226227
/// Pointer metadata can be extracted from a pointer or reference with the [`metadata`] function.
227228
/// The data pointer can be extracted by casting a (fat) pointer
228-
/// to a (thin) pointer to a `Sized` type the `as` operator,
229-
/// for example `(x: &dyn SomeTrait) as *const SomeTrait as *const ()`.
229+
/// to a (thin) pointer to a `Sized` type with the `as` operator,
230+
/// for example `(x: &dyn SomeTrait) as *const SomeTrait as *const ()`
231+
/// or `(x: *const dyn SomeTrait).cast::<()>()`.
230232
///
231233
/// [dst]: https://doc.rust-lang.org/nomicon/exotic-sizes.html#dynamically-sized-types-dsts
232234
#[lang = "pointee"]
@@ -282,7 +284,7 @@ impl<T: ?Sized> NonNull<T> {
282284
}
283285
}
284286

285-
/// The metadata for a `dyn SomeTrait` trait object type.
287+
/// The metadata for a `DynTrait = dyn SomeTrait` trait object type.
286288
///
287289
/// It is a pointer to a vtable (virtual call table)
288290
/// that represents all the necessary information
@@ -297,17 +299,16 @@ impl<T: ?Sized> NonNull<T> {
297299
/// Note that the first three are special because they’re necessary to allocate, drop,
298300
/// and deallocate any trait object.
299301
///
300-
/// The layout of vtables is still unspecified, so this type is a more-type-safe
301-
/// convenience for accessing those 3 special values. Note however that `DynMetadata` does
302-
/// not actually know the trait it’s associated with, indicating that, at very least,
303-
/// the location of `size`, `align`, and `drop_in_place` is identical for all
304-
/// trait object vtables in a single program.
302+
/// It is possible to name this struct with a type parameter that is not a `dyn` trait object
303+
/// (for example `DynMetadata<u64>`) but not to obtain a meaningful value of that struct.
305304
#[derive(Copy, Clone)]
306-
pub struct DynMetadata {
305+
pub struct DynMetadata<DynTrait: ?Sized> {
306+
// Private fields
307307
vtable_ptr: ptr::NonNull<()>,
308+
phantom: PhantomData<DynTrait>
308309
}
309310

310-
impl DynMetadata {
311+
impl<DynTrait: ?Sized> DynMetadata<DynTrait> {
311312
/// Returns the size of the type associated with this vtable.
312313
pub fn size(self) -> usize { ... }
313314

@@ -343,12 +344,8 @@ In addition to being more general
343344
and (hopefully) more compatible with future custom DSTs proposals,
344345
this RFC resolves the question of what happens
345346
if trait objects with super-fat pointers with multiple vtable pointers are ever added.
346-
(Answer: they can use a different metadata type like `[DynMetadata; N]`.)
347-
348-
`DynMetadata` could be made generic with a type parameter for the trait object type that it describes.
349-
This would avoid forcing that the size, alignment, and destruction pointers
350-
be in the same location (offset) for every vtable.
351-
But keeping them in the same location is probaly desirable anyway to keep code size small.
347+
(Answer: they can use a different metadata type,
348+
possibly like `(DynMetadata<dyn Trait>, DynMetadata<dyn OtherTrait>)`.)
352349

353350
[2579]: https://github.com/rust-lang/rfcs/pull/2579
354351

@@ -372,11 +369,11 @@ Except for `DynMetadata`’s methods, this RFC proposes a subset of what that th
372369

373370
* The location of `DynMetadata`. Is another module more appropriate than `std::ptr`?
374371

375-
* Should `DynMetadata` have a type parameter for what trait object type it is a metadata of?
376-
Such that `<dyn SomeTrait as Pointee>::Metadata` is `DynMetadata<dyn SomTrait>`.
377-
This would allow the memory layout to change based on the trait object type
378-
(potentially super-wide pointers with multiple vtable pointers for multi-trait objects?)
379-
or to have different methods.
372+
* Should `DynMetadata` not have a type parameter?
373+
This might reduce monomorphization cost,
374+
but would force that the size, alignment, and destruction pointers
375+
be in the same location (offset) for every vtable.
376+
But keeping them in the same location is probaly desirable anyway to keep code size small.
380377

381378
* The name of `Thin`.
382379
This name is short and sweet but `T: Thin` suggests that `T` itself is thin,

0 commit comments

Comments
 (0)