]> git.lizzy.rs Git - rust.git/blob - library/core/src/ptr/metadata.rs
0661ccc020014864d335e1fe011f72ac5049cffd
[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 #[rustc_const_unstable(feature = "ptr_metadata", issue = /* FIXME */ "none")]
32 #[inline]
33 pub const fn metadata<T: ?Sized>(ptr: *const T) -> <T as Pointee>::Metadata {
34     // SAFETY: Accessing the value from the `PtrRepr` union is safe since *const T
35     // and PtrComponents<T> have the same memory layouts. Only std can make this
36     // guarantee.
37     unsafe { PtrRepr { const_ptr: ptr }.components.metadata }
38 }
39
40 /// Forms a raw pointer from a data address and metadata.
41 #[unstable(feature = "ptr_metadata", issue = /* FIXME */ "none")]
42 #[rustc_const_unstable(feature = "ptr_metadata", issue = /* FIXME */ "none")]
43 #[inline]
44 pub const fn from_raw_parts<T: ?Sized>(
45     data_address: *const (),
46     metadata: <T as Pointee>::Metadata,
47 ) -> *const T {
48     // SAFETY: Accessing the value from the `PtrRepr` union is safe since *const T
49     // and PtrComponents<T> have the same memory layouts. Only std can make this
50     // guarantee.
51     unsafe { PtrRepr { components: PtrComponents { data_address, metadata } }.const_ptr }
52 }
53
54 /// Performs the same functionality as [`from_raw_parts`], except that a
55 /// raw `*mut` pointer is returned, as opposed to a raw `*const` pointer.
56 ///
57 /// See the documentation of [`from_raw_parts`] for more details.
58 #[unstable(feature = "ptr_metadata", issue = /* FIXME */ "none")]
59 #[rustc_const_unstable(feature = "ptr_metadata", issue = /* FIXME */ "none")]
60 #[inline]
61 pub const fn from_raw_parts_mut<T: ?Sized>(
62     data_address: *mut (),
63     metadata: <T as Pointee>::Metadata,
64 ) -> *mut T {
65     // SAFETY: Accessing the value from the `PtrRepr` union is safe since *const T
66     // and PtrComponents<T> have the same memory layouts. Only std can make this
67     // guarantee.
68     unsafe { PtrRepr { components: PtrComponents { data_address, metadata } }.mut_ptr }
69 }
70
71 #[repr(C)]
72 pub(crate) union PtrRepr<T: ?Sized> {
73     pub(crate) const_ptr: *const T,
74     pub(crate) mut_ptr: *mut T,
75     pub(crate) components: PtrComponents<T>,
76 }
77
78 #[repr(C)]
79 pub(crate) struct PtrComponents<T: ?Sized> {
80     pub(crate) data_address: *const (),
81     pub(crate) metadata: <T as Pointee>::Metadata,
82 }
83
84 // Manual impl needed to avoid `T: Copy` bound.
85 impl<T: ?Sized> Copy for PtrComponents<T> {}
86
87 // Manual impl needed to avoid `T: Clone` bound.
88 impl<T: ?Sized> Clone for PtrComponents<T> {
89     fn clone(&self) -> Self {
90         *self
91     }
92 }
93
94 /// The metadata for a `dyn SomeTrait` trait object type.
95 #[lang = "dyn_metadata"]
96 pub struct DynMetadata<Dyn: ?Sized> {
97     vtable_ptr: &'static VTable,
98     phantom: crate::marker::PhantomData<Dyn>,
99 }
100
101 /// The common prefix of all vtables. It is followed by function pointers for trait methods.
102 ///
103 /// Private implementation detail of `DynMetadata::size_of` etc.
104 #[repr(C)]
105 struct VTable {
106     drop_in_place: fn(*mut ()),
107     size_of: usize,
108     align_of: usize,
109 }
110
111 impl<Dyn: ?Sized> DynMetadata<Dyn> {
112     /// Returns the size of the type associated with this vtable.
113     #[inline]
114     pub fn size_of(self) -> usize {
115         self.vtable_ptr.size_of
116     }
117
118     /// Returns the alignment of the type associated with this vtable.
119     #[inline]
120     pub fn align_of(self) -> usize {
121         self.vtable_ptr.align_of
122     }
123
124     /// Returns the size and alignment together as a `Layout`
125     #[inline]
126     pub fn layout(self) -> crate::alloc::Layout {
127         // SAFETY: the compiler emitted this vtable for a concrete Rust type which
128         // is known to have a valid layout. Same rationale as in `Layout::for_value`.
129         unsafe { crate::alloc::Layout::from_size_align_unchecked(self.size_of(), self.align_of()) }
130     }
131 }
132
133 unsafe impl<Dyn: ?Sized> Send for DynMetadata<Dyn> {}
134 unsafe impl<Dyn: ?Sized> Sync for DynMetadata<Dyn> {}
135
136 impl<Dyn: ?Sized> fmt::Debug for DynMetadata<Dyn> {
137     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
138         f.debug_tuple("DynMetadata").field(&(self.vtable_ptr as *const VTable)).finish()
139     }
140 }
141
142 // Manual impls needed to avoid `Dyn: $Trait` bounds.
143
144 impl<Dyn: ?Sized> Unpin for DynMetadata<Dyn> {}
145
146 impl<Dyn: ?Sized> Copy for DynMetadata<Dyn> {}
147
148 impl<Dyn: ?Sized> Clone for DynMetadata<Dyn> {
149     #[inline]
150     fn clone(&self) -> Self {
151         *self
152     }
153 }
154
155 impl<Dyn: ?Sized> Eq for DynMetadata<Dyn> {}
156
157 impl<Dyn: ?Sized> PartialEq for DynMetadata<Dyn> {
158     #[inline]
159     fn eq(&self, other: &Self) -> bool {
160         crate::ptr::eq::<VTable>(self.vtable_ptr, other.vtable_ptr)
161     }
162 }
163
164 impl<Dyn: ?Sized> Ord for DynMetadata<Dyn> {
165     #[inline]
166     fn cmp(&self, other: &Self) -> crate::cmp::Ordering {
167         (self.vtable_ptr as *const VTable).cmp(&(other.vtable_ptr as *const VTable))
168     }
169 }
170
171 impl<Dyn: ?Sized> PartialOrd for DynMetadata<Dyn> {
172     #[inline]
173     fn partial_cmp(&self, other: &Self) -> Option<crate::cmp::Ordering> {
174         Some(self.cmp(other))
175     }
176 }
177
178 impl<Dyn: ?Sized> Hash for DynMetadata<Dyn> {
179     #[inline]
180     fn hash<H: Hasher>(&self, hasher: &mut H) {
181         crate::ptr::hash::<VTable, _>(self.vtable_ptr, hasher)
182     }
183 }