]> git.lizzy.rs Git - rust.git/blob - library/core/src/ptr/metadata.rs
Add `size_of`, `align_of`, and `layout` methods to `DynMetadata`
[rust.git] / library / core / src / ptr / metadata.rs
1 #![unstable(feature = "ptr_metadata", issue = /* FIXME */ "none")]
2
3 use crate::fmt;
4 use crate::hash::{Hash, Hasher};
5
6 /// FIXME docs
7 #[lang = "pointee_trait"]
8 pub trait Pointee {
9     /// The type for metadata in pointers and references to `Self`.
10     #[lang = "metadata_type"]
11     // NOTE: Keep trait bounds in `static_assert_expected_bounds_for_metadata`
12     // in `library/core/src/ptr/metadata.rs`
13     // in sync with those here:
14     type Metadata: Copy + Send + Sync + Ord + Hash + Unpin;
15 }
16
17 /// Pointers to types implementing this trait alias are “thin”
18 ///
19 /// ```rust
20 /// #![feature(ptr_metadata)]
21 ///
22 /// fn this_never_panics<T: std::ptr::Thin>() {
23 ///     assert_eq!(std::mem::size_of::<&T>(), std::mem::size_of::<usize>())
24 /// }
25 /// ```
26 #[unstable(feature = "ptr_metadata", issue = /* FIXME */ "none")]
27 // NOTE: don’t stabilize this before trait aliases are stable in the language?
28 pub trait Thin = Pointee<Metadata = ()>;
29
30 /// Extract the metadata component of a pointer.
31 #[inline]
32 pub fn metadata<T: ?Sized>(ptr: *const T) -> <T as Pointee>::Metadata {
33     // SAFETY: Accessing the value from the `PtrRepr` union is safe since *const T
34     // and PtrComponents<T> have the same memory layouts. Only std can make this
35     // guarantee.
36     unsafe { PtrRepr { const_ptr: ptr }.components.metadata }
37 }
38
39 #[repr(C)]
40 union PtrRepr<T: ?Sized> {
41     const_ptr: *const T,
42     components: PtrComponents<T>,
43 }
44
45 #[repr(C)]
46 struct PtrComponents<T: ?Sized> {
47     data_address: usize,
48     metadata: <T as Pointee>::Metadata,
49 }
50
51 // Manual impl needed to avoid `T: Copy` bound.
52 impl<T: ?Sized> Copy for PtrComponents<T> {}
53
54 // Manual impl needed to avoid `T: Clone` bound.
55 impl<T: ?Sized> Clone for PtrComponents<T> {
56     fn clone(&self) -> Self {
57         *self
58     }
59 }
60
61 /// The metadata for a `dyn SomeTrait` trait object type.
62 #[lang = "dyn_metadata"]
63 pub struct DynMetadata<Dyn: ?Sized> {
64     vtable_ptr: &'static VTable,
65     phantom: crate::marker::PhantomData<Dyn>,
66 }
67
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
100 unsafe impl<Dyn: ?Sized> Send for DynMetadata<Dyn> {}
101 unsafe impl<Dyn: ?Sized> Sync for DynMetadata<Dyn> {}
102
103 impl<Dyn: ?Sized> fmt::Debug for DynMetadata<Dyn> {
104     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
105         f.debug_tuple("DynMetadata").field(&(self.vtable_ptr as *const VTable)).finish()
106     }
107 }
108
109 // Manual impls needed to avoid `Dyn: $Trait` bounds.
110
111 impl<Dyn: ?Sized> Unpin for DynMetadata<Dyn> {}
112
113 impl<Dyn: ?Sized> Copy for DynMetadata<Dyn> {}
114
115 impl<Dyn: ?Sized> Clone for DynMetadata<Dyn> {
116     #[inline]
117     fn clone(&self) -> Self {
118         *self
119     }
120 }
121
122 impl<Dyn: ?Sized> Eq for DynMetadata<Dyn> {}
123
124 impl<Dyn: ?Sized> PartialEq for DynMetadata<Dyn> {
125     #[inline]
126     fn eq(&self, other: &Self) -> bool {
127         crate::ptr::eq::<VTable>(self.vtable_ptr, other.vtable_ptr)
128     }
129 }
130
131 impl<Dyn: ?Sized> Ord for DynMetadata<Dyn> {
132     #[inline]
133     fn cmp(&self, other: &Self) -> crate::cmp::Ordering {
134         (self.vtable_ptr as *const VTable).cmp(&(other.vtable_ptr as *const VTable))
135     }
136 }
137
138 impl<Dyn: ?Sized> PartialOrd for DynMetadata<Dyn> {
139     #[inline]
140     fn partial_cmp(&self, other: &Self) -> Option<crate::cmp::Ordering> {
141         Some(self.cmp(other))
142     }
143 }
144
145 impl<Dyn: ?Sized> Hash for DynMetadata<Dyn> {
146     #[inline]
147     fn hash<H: Hasher>(&self, hasher: &mut H) {
148         crate::ptr::hash::<VTable, _>(self.vtable_ptr, hasher)
149     }
150 }