]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_data_structures/src/tagged_ptr.rs
Auto merge of #79336 - camelid:rename-feature-oibit-to-auto, r=oli-obk
[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     fn into_usize(self) -> usize {
94         Box::into_raw(self) as usize
95     }
96     unsafe fn from_usize(ptr: usize) -> Self {
97         Box::from_raw(ptr as *mut T)
98     }
99     unsafe fn with_ref<R, F: FnOnce(&Self) -> R>(ptr: usize, f: F) -> R {
100         let raw = ManuallyDrop::new(Self::from_usize(ptr));
101         f(&raw)
102     }
103 }
104
105 unsafe impl<T> Pointer for Rc<T> {
106     const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize;
107     fn into_usize(self) -> usize {
108         Rc::into_raw(self) as usize
109     }
110     unsafe fn from_usize(ptr: usize) -> Self {
111         Rc::from_raw(ptr as *const T)
112     }
113     unsafe fn with_ref<R, F: FnOnce(&Self) -> R>(ptr: usize, f: F) -> R {
114         let raw = ManuallyDrop::new(Self::from_usize(ptr));
115         f(&raw)
116     }
117 }
118
119 unsafe impl<T> Pointer for Arc<T> {
120     const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize;
121     fn into_usize(self) -> usize {
122         Arc::into_raw(self) as usize
123     }
124     unsafe fn from_usize(ptr: usize) -> Self {
125         Arc::from_raw(ptr as *const T)
126     }
127     unsafe fn with_ref<R, F: FnOnce(&Self) -> R>(ptr: usize, f: F) -> R {
128         let raw = ManuallyDrop::new(Self::from_usize(ptr));
129         f(&raw)
130     }
131 }
132
133 unsafe impl<'a, T: 'a> Pointer for &'a T {
134     const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize;
135     fn into_usize(self) -> usize {
136         self as *const T as usize
137     }
138     unsafe fn from_usize(ptr: usize) -> Self {
139         &*(ptr as *const T)
140     }
141     unsafe fn with_ref<R, F: FnOnce(&Self) -> R>(ptr: usize, f: F) -> R {
142         f(&*(&ptr as *const usize as *const Self))
143     }
144 }
145
146 unsafe impl<'a, T: 'a> Pointer for &'a mut T {
147     const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize;
148     fn into_usize(self) -> usize {
149         self as *mut T as usize
150     }
151     unsafe fn from_usize(ptr: usize) -> Self {
152         &mut *(ptr as *mut T)
153     }
154     unsafe fn with_ref<R, F: FnOnce(&Self) -> R>(ptr: usize, f: F) -> R {
155         f(&*(&ptr as *const usize as *const Self))
156     }
157 }