]> git.proxmox.com Git - rustc.git/blame - vendor/rustc-ap-rustc_data_structures/src/tagged_ptr/copy.rs
Update upstream source from tag 'upstream/1.52.1+dfsg1'
[rustc.git] / vendor / rustc-ap-rustc_data_structures / src / tagged_ptr / copy.rs
CommitLineData
f20569fa
XL
1use super::{Pointer, Tag};
2use crate::stable_hasher::{HashStable, StableHasher};
3use std::fmt;
4use std::marker::PhantomData;
5use std::num::NonZeroUsize;
6
7/// A `Copy` TaggedPtr.
8///
9/// You should use this instead of the `TaggedPtr` type in all cases where
10/// `P: Copy`.
11///
12/// If `COMPARE_PACKED` is true, then the pointers will be compared and hashed without
13/// unpacking. Otherwise we don't implement PartialEq/Eq/Hash; if you want that,
14/// wrap the TaggedPtr.
15pub struct CopyTaggedPtr<P, T, const COMPARE_PACKED: bool>
16where
17 P: Pointer,
18 T: Tag,
19{
20 packed: NonZeroUsize,
21 data: PhantomData<(P, T)>,
22}
23
24impl<P, T, const COMPARE_PACKED: bool> Copy for CopyTaggedPtr<P, T, COMPARE_PACKED>
25where
26 P: Pointer,
27 T: Tag,
28 P: Copy,
29{
30}
31
32impl<P, T, const COMPARE_PACKED: bool> Clone for CopyTaggedPtr<P, T, COMPARE_PACKED>
33where
34 P: Pointer,
35 T: Tag,
36 P: Copy,
37{
38 fn clone(&self) -> Self {
39 *self
40 }
41}
42
43// We pack the tag into the *upper* bits of the pointer to ease retrieval of the
44// value; a left shift is a multiplication and those are embeddable in
45// instruction encoding.
46impl<P, T, const COMPARE_PACKED: bool> CopyTaggedPtr<P, T, COMPARE_PACKED>
47where
48 P: Pointer,
49 T: Tag,
50{
51 const TAG_BIT_SHIFT: usize = usize::BITS as usize - T::BITS;
52 const ASSERTION: () = {
53 assert!(T::BITS <= P::BITS);
54 // Used for the transmute_copy's below
55 assert!(std::mem::size_of::<&P::Target>() == std::mem::size_of::<usize>());
56 };
57
58 pub fn new(pointer: P, tag: T) -> Self {
59 // Trigger assert!
60 let () = Self::ASSERTION;
61 let packed_tag = tag.into_usize() << Self::TAG_BIT_SHIFT;
62
63 Self {
64 // SAFETY: We know that the pointer is non-null, as it must be
65 // dereferenceable per `Pointer` safety contract.
66 packed: unsafe {
67 NonZeroUsize::new_unchecked((P::into_usize(pointer) >> T::BITS) | packed_tag)
68 },
69 data: PhantomData,
70 }
71 }
72
73 pub(super) fn pointer_raw(&self) -> usize {
74 self.packed.get() << T::BITS
75 }
76 pub fn pointer(self) -> P
77 where
78 P: Copy,
79 {
80 // SAFETY: pointer_raw returns the original pointer
81 //
82 // Note that this isn't going to double-drop or anything because we have
83 // P: Copy
84 unsafe { P::from_usize(self.pointer_raw()) }
85 }
86 pub fn pointer_ref(&self) -> &P::Target {
87 // SAFETY: pointer_raw returns the original pointer
88 unsafe { std::mem::transmute_copy(&self.pointer_raw()) }
89 }
90 pub fn pointer_mut(&mut self) -> &mut P::Target
91 where
92 P: std::ops::DerefMut,
93 {
94 // SAFETY: pointer_raw returns the original pointer
95 unsafe { std::mem::transmute_copy(&self.pointer_raw()) }
96 }
97 pub fn tag(&self) -> T {
98 unsafe { T::from_usize(self.packed.get() >> Self::TAG_BIT_SHIFT) }
99 }
100 pub fn set_tag(&mut self, tag: T) {
101 let mut packed = self.packed.get();
102 let new_tag = T::into_usize(tag) << Self::TAG_BIT_SHIFT;
103 let tag_mask = (1 << T::BITS) - 1;
104 packed &= !(tag_mask << Self::TAG_BIT_SHIFT);
105 packed |= new_tag;
106 self.packed = unsafe { NonZeroUsize::new_unchecked(packed) };
107 }
108}
109
110impl<P, T, const COMPARE_PACKED: bool> std::ops::Deref for CopyTaggedPtr<P, T, COMPARE_PACKED>
111where
112 P: Pointer,
113 T: Tag,
114{
115 type Target = P::Target;
116 fn deref(&self) -> &Self::Target {
117 self.pointer_ref()
118 }
119}
120
121impl<P, T, const COMPARE_PACKED: bool> std::ops::DerefMut for CopyTaggedPtr<P, T, COMPARE_PACKED>
122where
123 P: Pointer + std::ops::DerefMut,
124 T: Tag,
125{
126 fn deref_mut(&mut self) -> &mut Self::Target {
127 self.pointer_mut()
128 }
129}
130
131impl<P, T, const COMPARE_PACKED: bool> fmt::Debug for CopyTaggedPtr<P, T, COMPARE_PACKED>
132where
133 P: Pointer,
134 P::Target: fmt::Debug,
135 T: Tag + fmt::Debug,
136{
137 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
138 f.debug_struct("CopyTaggedPtr")
139 .field("pointer", &self.pointer_ref())
140 .field("tag", &self.tag())
141 .finish()
142 }
143}
144
145impl<P, T> PartialEq for CopyTaggedPtr<P, T, true>
146where
147 P: Pointer,
148 T: Tag,
149{
150 fn eq(&self, other: &Self) -> bool {
151 self.packed == other.packed
152 }
153}
154
155impl<P, T> Eq for CopyTaggedPtr<P, T, true>
156where
157 P: Pointer,
158 T: Tag,
159{
160}
161
162impl<P, T> std::hash::Hash for CopyTaggedPtr<P, T, true>
163where
164 P: Pointer,
165 T: Tag,
166{
167 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
168 self.packed.hash(state);
169 }
170}
171
172impl<P, T, HCX, const COMPARE_PACKED: bool> HashStable<HCX> for CopyTaggedPtr<P, T, COMPARE_PACKED>
173where
174 P: Pointer + HashStable<HCX>,
175 T: Tag + HashStable<HCX>,
176{
177 fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
178 unsafe {
179 Pointer::with_ref(self.pointer_raw(), |p: &P| p.hash_stable(hcx, hasher));
180 }
181 self.tag().hash_stable(hcx, hasher);
182 }
183}