Skip to content

Commit 9ab83b9

Browse files
committed
Add size_of, align_of, and layout methods to DynMetadata
1 parent b1e15fa commit 9ab83b9

File tree

2 files changed

+58
-8
lines changed

2 files changed

+58
-8
lines changed

library/core/src/ptr/metadata.rs

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
use crate::fmt;
44
use crate::hash::{Hash, Hasher};
5-
use crate::ptr::NonNull;
65

76
/// FIXME docs
87
#[lang = "pointee_trait"]
@@ -62,17 +61,48 @@ impl<T: ?Sized> Clone for PtrComponents<T> {
6261
/// The metadata for a `dyn SomeTrait` trait object type.
6362
#[lang = "dyn_metadata"]
6463
pub struct DynMetadata<Dyn: ?Sized> {
65-
#[allow(unused)]
66-
vtable_ptr: NonNull<()>,
64+
vtable_ptr: &'static VTable,
6765
phantom: crate::marker::PhantomData<Dyn>,
6866
}
6967

68+
/// The common prefix of all vtables. It is followed by function pointers for trait methods.
69+
///
70+
/// Private implementation detail of `DynMetadata::size_of` etc.
71+
#[repr(C)]
72+
struct VTable {
73+
drop_in_place: fn(*mut ()),
74+
size_of: usize,
75+
align_of: usize,
76+
}
77+
78+
impl<Dyn: ?Sized> DynMetadata<Dyn> {
79+
/// Returns the size of the type associated with this vtable.
80+
#[inline]
81+
pub fn size_of(self) -> usize {
82+
self.vtable_ptr.size_of
83+
}
84+
85+
/// Returns the alignment of the type associated with this vtable.
86+
#[inline]
87+
pub fn align_of(self) -> usize {
88+
self.vtable_ptr.align_of
89+
}
90+
91+
/// Returns the size and alignment together as a `Layout`
92+
#[inline]
93+
pub fn layout(self) -> crate::alloc::Layout {
94+
// SAFETY: the compiler emitted this vtable for a concrete Rust type which
95+
// is known to have a valid layout. Same rationale as in `Layout::for_value`.
96+
unsafe { crate::alloc::Layout::from_size_align_unchecked(self.size_of(), self.align_of()) }
97+
}
98+
}
99+
70100
unsafe impl<Dyn: ?Sized> Send for DynMetadata<Dyn> {}
71101
unsafe impl<Dyn: ?Sized> Sync for DynMetadata<Dyn> {}
72102

73103
impl<Dyn: ?Sized> fmt::Debug for DynMetadata<Dyn> {
74104
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
75-
f.write_str("DynMetadata { … }")
105+
f.debug_tuple("DynMetadata").field(&(self.vtable_ptr as *const VTable)).finish()
76106
}
77107
}
78108

@@ -94,27 +124,27 @@ impl<Dyn: ?Sized> Eq for DynMetadata<Dyn> {}
94124
impl<Dyn: ?Sized> PartialEq for DynMetadata<Dyn> {
95125
#[inline]
96126
fn eq(&self, other: &Self) -> bool {
97-
self.vtable_ptr == other.vtable_ptr
127+
crate::ptr::eq::<VTable>(self.vtable_ptr, other.vtable_ptr)
98128
}
99129
}
100130

101131
impl<Dyn: ?Sized> Ord for DynMetadata<Dyn> {
102132
#[inline]
103133
fn cmp(&self, other: &Self) -> crate::cmp::Ordering {
104-
self.vtable_ptr.cmp(&other.vtable_ptr)
134+
(self.vtable_ptr as *const VTable).cmp(&(other.vtable_ptr as *const VTable))
105135
}
106136
}
107137

108138
impl<Dyn: ?Sized> PartialOrd for DynMetadata<Dyn> {
109139
#[inline]
110140
fn partial_cmp(&self, other: &Self) -> Option<crate::cmp::Ordering> {
111-
Some(self.vtable_ptr.cmp(&other.vtable_ptr))
141+
Some(self.cmp(other))
112142
}
113143
}
114144

115145
impl<Dyn: ?Sized> Hash for DynMetadata<Dyn> {
116146
#[inline]
117147
fn hash<H: Hasher>(&self, hasher: &mut H) {
118-
self.vtable_ptr.hash(hasher)
148+
crate::ptr::hash::<VTable, _>(self.vtable_ptr, hasher)
119149
}
120150
}

library/core/tests/ptr.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -505,3 +505,23 @@ fn ptr_metadata_bounds() {
505505
{
506506
}
507507
}
508+
509+
#[test]
510+
#[cfg(not(bootstrap))]
511+
fn dyn_metadata() {
512+
#[derive(Debug)]
513+
#[repr(align(32))]
514+
struct Something([u8; 47]);
515+
516+
let value = Something([0; 47]);
517+
let trait_object: &dyn Debug = &value;
518+
let meta = metadata(trait_object);
519+
520+
assert_eq!(meta.size_of(), 64);
521+
assert_eq!(meta.size_of(), std::mem::size_of::<Something>());
522+
assert_eq!(meta.align_of(), 32);
523+
assert_eq!(meta.align_of(), std::mem::align_of::<Something>());
524+
assert_eq!(meta.layout(), std::alloc::Layout::new::<Something>());
525+
526+
assert!(format!("{:?}", meta).starts_with("DynMetadata(0x"));
527+
}

0 commit comments

Comments
 (0)