]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_data_structures/src/tagged_ptr.rs
Auto merge of #91182 - ChrisDenton:command-broken-symlink, r=m-ou-se
[rust.git] / compiler / rustc_data_structures / src / tagged_ptr.rs
1 //! This module implements tagged pointers.
2 //!
3 //! In order to utilize the pointer packing, you must have two types: a pointer,
4 //! and a tag.
5 //!
6 //! The pointer must implement the `Pointer` trait, with the primary requirement
7 //! being conversion to and from a usize. Note that the pointer must be
8 //! dereferenceable, so raw pointers generally cannot implement the `Pointer`
9 //! trait. This implies that the pointer must also be nonzero.
10 //!
11 //! Many common pointer types already implement the `Pointer` trait.
12 //!
13 //! The tag must implement the `Tag` trait. We assert that the tag and `Pointer`
14 //! are compatible at compile time.
15
16 use std::mem::ManuallyDrop;
17 use std::ops::Deref;
18 use std::rc::Rc;
19 use std::sync::Arc;
20
21 mod copy;
22 mod drop;
23
24 pub use copy::CopyTaggedPtr;
25 pub use drop::TaggedPtr;
26
27 /// This describes the pointer type encapsulated by TaggedPtr.
28 ///
29 /// # Safety
30 ///
31 /// The usize returned from `into_usize` must be a valid, dereferenceable,
32 /// pointer to `<Self as Deref>::Target`. Note that pointers to `Pointee` must
33 /// be thin, even though `Pointee` may not be sized.
34 ///
35 /// Note that the returned pointer from `into_usize` should be castable to `&mut
36 /// <Self as Deref>::Target` if `Pointer: DerefMut`.
37 ///
38 /// The BITS constant must be correct. At least `BITS` bits, least-significant,
39 /// must be zero on all returned pointers from `into_usize`.
40 ///
41 /// For example, if the alignment of `Pointee` is 2, then `BITS` should be 1.
42 pub unsafe trait Pointer: Deref {
43     /// Most likely the value you want to use here is the following, unless
44     /// your Pointee type is unsized (e.g., `ty::List<T>` in rustc) in which
45     /// case you'll need to manually figure out what the right type to pass to
46     /// align_of is.
47     ///
48     /// ```rust
49     /// std::mem::align_of::<<Self as Deref>::Target>().trailing_zeros() as usize;
50     /// ```
51     const BITS: usize;
52     fn into_usize(self) -> usize;
53
54     /// # Safety
55     ///
56     /// The passed `ptr` must be returned from `into_usize`.
57     ///
58     /// This acts as `ptr::read` semantically, it should not be called more than
59     /// once on non-`Copy` `Pointer`s.
60     unsafe fn from_usize(ptr: usize) -> Self;
61
62     /// This provides a reference to the `Pointer` itself, rather than the
63     /// `Deref::Target`. It is used for cases where we want to call methods that
64     /// may be implement differently for the Pointer than the Pointee (e.g.,
65     /// `Rc::clone` vs cloning the inner value).
66     ///
67     /// # Safety
68     ///
69     /// The passed `ptr` must be returned from `into_usize`.
70     unsafe fn with_ref<R, F: FnOnce(&Self) -> R>(ptr: usize, f: F) -> R;
71 }
72
73 /// This describes tags that the `TaggedPtr` struct can hold.
74 ///
75 /// # Safety
76 ///
77 /// The BITS constant must be correct.
78 ///
79 /// No more than `BITS` least significant bits may be set in the returned usize.
80 pub unsafe trait Tag: Copy {
81     const BITS: usize;
82
83     fn into_usize(self) -> usize;
84
85     /// # Safety
86     ///
87     /// The passed `tag` must be returned from `into_usize`.
88     unsafe fn from_usize(tag: usize) -> Self;
89 }
90
91 unsafe impl<T> Pointer for Box<T> {
92     const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize;
93     #[inline]
94     fn into_usize(self) -> usize {
95         Box::into_raw(self) as usize
96     }
97     #[inline]
98     unsafe fn from_usize(ptr: usize) -> Self {
99         Box::from_raw(ptr as *mut T)
100     }
101     unsafe fn with_ref<R, F: FnOnce(&Self) -> R>(ptr: usize, f: F) -> R {
102         let raw = ManuallyDrop::new(Self::from_usize(ptr));
103         f(&raw)
104     }
105 }
106
107 unsafe impl<T> Pointer for Rc<T> {
108     const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize;
109     #[inline]
110     fn into_usize(self) -> usize {
111         Rc::into_raw(self) as usize
112     }
113     #[inline]
114     unsafe fn from_usize(ptr: usize) -> Self {
115         Rc::from_raw(ptr as *const T)
116     }
117     unsafe fn with_ref<R, F: FnOnce(&Self) -> R>(ptr: usize, f: F) -> R {
118         let raw = ManuallyDrop::new(Self::from_usize(ptr));
119         f(&raw)
120     }
121 }
122
123 unsafe impl<T> Pointer for Arc<T> {
124     const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize;
125     #[inline]
126     fn into_usize(self) -> usize {
127         Arc::into_raw(self) as usize
128     }
129     #[inline]
130     unsafe fn from_usize(ptr: usize) -> Self {
131         Arc::from_raw(ptr as *const T)
132     }
133     unsafe fn with_ref<R, F: FnOnce(&Self) -> R>(ptr: usize, f: F) -> R {
134         let raw = ManuallyDrop::new(Self::from_usize(ptr));
135         f(&raw)
136     }
137 }
138
139 unsafe impl<'a, T: 'a> Pointer for &'a T {
140     const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize;
141     #[inline]
142     fn into_usize(self) -> usize {
143         self as *const T as usize
144     }
145     #[inline]
146     unsafe fn from_usize(ptr: usize) -> Self {
147         &*(ptr as *const T)
148     }
149     unsafe fn with_ref<R, F: FnOnce(&Self) -> R>(ptr: usize, f: F) -> R {
150         f(&*(&ptr as *const usize as *const Self))
151     }
152 }
153
154 unsafe impl<'a, T: 'a> Pointer for &'a mut T {
155     const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize;
156     #[inline]
157     fn into_usize(self) -> usize {
158         self as *mut T as usize
159     }
160     #[inline]
161     unsafe fn from_usize(ptr: usize) -> Self {
162         &mut *(ptr as *mut T)
163     }
164     unsafe fn with_ref<R, F: FnOnce(&Self) -> R>(ptr: usize, f: F) -> R {
165         f(&*(&ptr as *const usize as *const Self))
166     }
167 }