]> git.lizzy.rs Git - rust.git/blob - library/core/src/ptr/metadata.rs
Parameterize `DynMetadata` over its `dyn SomeTrait` type
[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 use crate::ptr::NonNull;
6
7 /// FIXME docs
8 #[lang = "pointee_trait"]
9 pub trait Pointee {
10     /// The type for metadata in pointers and references to `Self`.
11     #[lang = "metadata_type"]
12     // NOTE: Keep trait bounds in `static_assert_expected_bounds_for_metadata`
13     // in `library/core/src/ptr/metadata.rs`
14     // in sync with those here:
15     type Metadata: Copy + Send + Sync + Ord + Hash + Unpin;
16 }
17
18 /// Pointers to types implementing this trait alias are “thin”
19 ///
20 /// ```rust
21 /// #![feature(ptr_metadata)]
22 ///
23 /// fn this_never_panics<T: std::ptr::Thin>() {
24 ///     assert_eq!(std::mem::size_of::<&T>(), std::mem::size_of::<usize>())
25 /// }
26 /// ```
27 #[unstable(feature = "ptr_metadata", issue = /* FIXME */ "none")]
28 // NOTE: don’t stabilize this before trait aliases are stable in the language?
29 pub trait Thin = Pointee<Metadata = ()>;
30
31 /// Extract the metadata component of a pointer.
32 #[inline]
33 pub 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 #[repr(C)]
41 union PtrRepr<T: ?Sized> {
42     const_ptr: *const T,
43     components: PtrComponents<T>,
44 }
45
46 #[repr(C)]
47 struct PtrComponents<T: ?Sized> {
48     data_address: usize,
49     metadata: <T as Pointee>::Metadata,
50 }
51
52 // Manual impl needed to avoid `T: Copy` bound.
53 impl<T: ?Sized> Copy for PtrComponents<T> {}
54
55 // Manual impl needed to avoid `T: Clone` bound.
56 impl<T: ?Sized> Clone for PtrComponents<T> {
57     fn clone(&self) -> Self {
58         *self
59     }
60 }
61
62 /// The metadata for a `dyn SomeTrait` trait object type.
63 #[lang = "dyn_metadata"]
64 pub struct DynMetadata<Dyn: ?Sized> {
65     #[allow(unused)]
66     vtable_ptr: NonNull<()>,
67     phantom: crate::marker::PhantomData<Dyn>,
68 }
69
70 unsafe impl<Dyn: ?Sized> Send for DynMetadata<Dyn> {}
71 unsafe impl<Dyn: ?Sized> Sync for DynMetadata<Dyn> {}
72
73 impl<Dyn: ?Sized> fmt::Debug for DynMetadata<Dyn> {
74     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
75         f.write_str("DynMetadata { … }")
76     }
77 }
78
79 // Manual impls needed to avoid `Dyn: $Trait` bounds.
80
81 impl<Dyn: ?Sized> Unpin for DynMetadata<Dyn> {}
82
83 impl<Dyn: ?Sized> Copy for DynMetadata<Dyn> {}
84
85 impl<Dyn: ?Sized> Clone for DynMetadata<Dyn> {
86     #[inline]
87     fn clone(&self) -> Self {
88         *self
89     }
90 }
91
92 impl<Dyn: ?Sized> Eq for DynMetadata<Dyn> {}
93
94 impl<Dyn: ?Sized> PartialEq for DynMetadata<Dyn> {
95     #[inline]
96     fn eq(&self, other: &Self) -> bool {
97         self.vtable_ptr == other.vtable_ptr
98     }
99 }
100
101 impl<Dyn: ?Sized> Ord for DynMetadata<Dyn> {
102     #[inline]
103     fn cmp(&self, other: &Self) -> crate::cmp::Ordering {
104         self.vtable_ptr.cmp(&other.vtable_ptr)
105     }
106 }
107
108 impl<Dyn: ?Sized> PartialOrd for DynMetadata<Dyn> {
109     #[inline]
110     fn partial_cmp(&self, other: &Self) -> Option<crate::cmp::Ordering> {
111         Some(self.vtable_ptr.cmp(&other.vtable_ptr))
112     }
113 }
114
115 impl<Dyn: ?Sized> Hash for DynMetadata<Dyn> {
116     #[inline]
117     fn hash<H: Hasher>(&self, hasher: &mut H) {
118         self.vtable_ptr.hash(hasher)
119     }
120 }