@@ -83,9 +83,9 @@ First, let’s get some boilerplate out of the way:
83
83
use std :: marker :: {PhantomData , Unsize };
84
84
use std :: ptr :: {self , DynMetadata };
85
85
86
- trait DynTrait = Pointee <Metadata = DynMetadata >;
86
+ trait DynTrait < Dyn > = Pointee <Metadata = DynMetadata < Dyn > >;
87
87
88
- pub struct ThinBox <Dyn : ? Sized + DynTrait > {
88
+ pub struct ThinBox <Dyn : ? Sized + DynTrait < Dyn > > {
89
89
ptr : ptr :: NonNull <WithMeta <()>>,
90
90
phantom : PhantomData <Dyn >,
91
91
}
@@ -125,7 +125,7 @@ Accessing the value requires knowing its alignment:
125
125
impl <Dyn : ? Sized + DynTrait > ThinBox <Dyn > {
126
126
fn data_ptr (& self ) -> * mut () {
127
127
unsafe {
128
- let offset = std :: mem :: size_of :: <DynMetadata >();
128
+ let offset = std :: mem :: size_of :: <DynMetadata < Dyn >();
129
129
let value_align = self . ptr. as_ref (). vtable. align ();
130
130
let offset = align_up_to (offset , value_align );
131
131
(self . ptr. as_ptr () as * mut u8 ). add (offset ) as * mut ()
@@ -218,15 +218,17 @@ This similarly includes extern types.
218
218
/// * For structs whose last field is a DST, metadata is the metadata for the last field
219
219
/// * For the `str` type, metadata is the length in bytes as `usize`
220
220
/// * 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>`).
222
223
///
223
224
/// In the future, the Rust language may gain new kinds of types
224
225
/// that have different pointer metadata.
225
226
///
226
227
/// Pointer metadata can be extracted from a pointer or reference with the [`metadata`] function.
227
228
/// 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::<()>()`.
230
232
///
231
233
/// [dst]: https://doc.rust-lang.org/nomicon/exotic-sizes.html#dynamically-sized-types-dsts
232
234
#[lang = " pointee" ]
@@ -282,7 +284,7 @@ impl<T: ?Sized> NonNull<T> {
282
284
}
283
285
}
284
286
285
- /// The metadata for a `dyn SomeTrait` trait object type.
287
+ /// The metadata for a `DynTrait = dyn SomeTrait` trait object type.
286
288
///
287
289
/// It is a pointer to a vtable (virtual call table)
288
290
/// that represents all the necessary information
@@ -297,17 +299,16 @@ impl<T: ?Sized> NonNull<T> {
297
299
/// Note that the first three are special because they’re necessary to allocate, drop,
298
300
/// and deallocate any trait object.
299
301
///
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.
305
304
#[derive(Copy , Clone )]
306
- pub struct DynMetadata {
305
+ pub struct DynMetadata <DynTrait : ? Sized > {
306
+ // Private fields
307
307
vtable_ptr : ptr :: NonNull <()>,
308
+ phantom : PhantomData <DynTrait >
308
309
}
309
310
310
- impl DynMetadata {
311
+ impl < DynTrait : ? Sized > DynMetadata < DynTrait > {
311
312
/// Returns the size of the type associated with this vtable.
312
313
pub fn size (self ) -> usize { ... }
313
314
@@ -343,12 +344,8 @@ In addition to being more general
343
344
and (hopefully) more compatible with future custom DSTs proposals,
344
345
this RFC resolves the question of what happens
345
346
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>) ` .)
352
349
353
350
[ 2579 ] : https://github.com/rust-lang/rfcs/pull/2579
354
351
@@ -372,11 +369,11 @@ Except for `DynMetadata`’s methods, this RFC proposes a subset of what that th
372
369
373
370
* The location of ` DynMetadata ` . Is another module more appropriate than ` std::ptr ` ?
374
371
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 .
380
377
381
378
* The name of ` Thin ` .
382
379
This name is short and sweet but ` T: Thin ` suggests that ` T ` itself is thin,
0 commit comments