1 use super::{Pointer, Tag};
2 use crate::stable_hasher::{HashStable, StableHasher};
4 use std::marker::PhantomData;
5 use std::num::NonZeroUsize;
7 /// A `Copy` TaggedPtr.
9 /// You should use this instead of the `TaggedPtr` type in all cases where
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.
15 pub struct CopyTaggedPtr<P, T, const COMPARE_PACKED: bool>
21 data: PhantomData<(P, T)>,
24 impl<P, T, const COMPARE_PACKED: bool> Copy for CopyTaggedPtr<P, T, COMPARE_PACKED>
32 impl<P, T, const COMPARE_PACKED: bool> Clone for CopyTaggedPtr<P, T, COMPARE_PACKED>
38 fn clone(&self) -> Self {
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.
46 impl<P, T, const COMPARE_PACKED: bool> CopyTaggedPtr<P, T, COMPARE_PACKED>
51 const TAG_BIT_SHIFT: usize = (8 * std::mem::size_of::<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>());
58 pub fn new(pointer: P, tag: T) -> Self {
60 let () = Self::ASSERTION;
61 let packed_tag = tag.into_usize() << Self::TAG_BIT_SHIFT;
64 // SAFETY: We know that the pointer is non-null, as it must be
65 // dereferenceable per `Pointer` safety contract.
67 NonZeroUsize::new_unchecked((P::into_usize(pointer) >> T::BITS) | packed_tag)
73 pub(super) fn pointer_raw(&self) -> usize {
74 self.packed.get() << T::BITS
76 pub fn pointer(self) -> P
80 // SAFETY: pointer_raw returns the original pointer
82 // Note that this isn't going to double-drop or anything because we have
84 unsafe { P::from_usize(self.pointer_raw()) }
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()) }
90 pub fn pointer_mut(&mut self) -> &mut P::Target
92 P: std::ops::DerefMut,
94 // SAFETY: pointer_raw returns the original pointer
95 unsafe { std::mem::transmute_copy(&self.pointer_raw()) }
97 pub fn tag(&self) -> T {
98 unsafe { T::from_usize(self.packed.get() >> Self::TAG_BIT_SHIFT) }
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);
106 self.packed = unsafe { NonZeroUsize::new_unchecked(packed) };
110 impl<P, T, const COMPARE_PACKED: bool> std::ops::Deref for CopyTaggedPtr<P, T, COMPARE_PACKED>
115 type Target = P::Target;
116 fn deref(&self) -> &Self::Target {
121 impl<P, T, const COMPARE_PACKED: bool> std::ops::DerefMut for CopyTaggedPtr<P, T, COMPARE_PACKED>
123 P: Pointer + std::ops::DerefMut,
126 fn deref_mut(&mut self) -> &mut Self::Target {
131 impl<P, T, const COMPARE_PACKED: bool> fmt::Debug for CopyTaggedPtr<P, T, COMPARE_PACKED>
134 P::Target: fmt::Debug,
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())
145 impl<P, T> PartialEq for CopyTaggedPtr<P, T, true>
150 fn eq(&self, other: &Self) -> bool {
151 self.packed == other.packed
155 impl<P, T> Eq for CopyTaggedPtr<P, T, true>
162 impl<P, T> std::hash::Hash for CopyTaggedPtr<P, T, true>
167 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
168 self.packed.hash(state);
172 impl<P, T, HCX, const COMPARE_PACKED: bool> HashStable<HCX> for CopyTaggedPtr<P, T, COMPARE_PACKED>
174 P: Pointer + HashStable<HCX>,
175 T: Tag + HashStable<HCX>,
177 fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
179 Pointer::with_ref(self.pointer_raw(), |p: &P| p.hash_stable(hcx, hasher));
181 self.tag().hash_stable(hcx, hasher);