]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_data_structures/src/tagged_ptr.rs
fix most compiler/ doctests
[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     /// ```ignore UNSOLVED (what to do about the Self)
49     /// # use std::ops::Deref;
50     /// std::mem::align_of::<<Self as Deref>::Target>().trailing_zeros() as usize;
51     /// ```
52     const BITS: usize;
53     fn into_usize(self) -> usize;
54
55     /// # Safety
56     ///
57     /// The passed `ptr` must be returned from `into_usize`.
58     ///
59     /// This acts as `ptr::read` semantically, it should not be called more than
60     /// once on non-`Copy` `Pointer`s.
61     unsafe fn from_usize(ptr: usize) -> Self;
62
63     /// This provides a reference to the `Pointer` itself, rather than the
64     /// `Deref::Target`. It is used for cases where we want to call methods that
65     /// may be implement differently for the Pointer than the Pointee (e.g.,
66     /// `Rc::clone` vs cloning the inner value).
67     ///
68     /// # Safety
69     ///
70     /// The passed `ptr` must be returned from `into_usize`.
71     unsafe fn with_ref<R, F: FnOnce(&Self) -> R>(ptr: usize, f: F) -> R;
72 }
73
74 /// This describes tags that the `TaggedPtr` struct can hold.
75 ///
76 /// # Safety
77 ///
78 /// The BITS constant must be correct.
79 ///
80 /// No more than `BITS` least significant bits may be set in the returned usize.
81 pub unsafe trait Tag: Copy {
82     const BITS: usize;
83
84     fn into_usize(self) -> usize;
85
86     /// # Safety
87     ///
88     /// The passed `tag` must be returned from `into_usize`.
89     unsafe fn from_usize(tag: usize) -> Self;
90 }
91
92 unsafe impl<T> Pointer for Box<T> {
93     const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize;
94     #[inline]
95     fn into_usize(self) -> usize {
96         Box::into_raw(self) as usize
97     }
98     #[inline]
99     unsafe fn from_usize(ptr: usize) -> Self {
100         Box::from_raw(ptr as *mut T)
101     }
102     unsafe fn with_ref<R, F: FnOnce(&Self) -> R>(ptr: usize, f: F) -> R {
103         let raw = ManuallyDrop::new(Self::from_usize(ptr));
104         f(&raw)
105     }
106 }
107
108 unsafe impl<T> Pointer for Rc<T> {
109     const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize;
110     #[inline]
111     fn into_usize(self) -> usize {
112         Rc::into_raw(self) as usize
113     }
114     #[inline]
115     unsafe fn from_usize(ptr: usize) -> Self {
116         Rc::from_raw(ptr as *const T)
117     }
118     unsafe fn with_ref<R, F: FnOnce(&Self) -> R>(ptr: usize, f: F) -> R {
119         let raw = ManuallyDrop::new(Self::from_usize(ptr));
120         f(&raw)
121     }
122 }
123
124 unsafe impl<T> Pointer for Arc<T> {
125     const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize;
126     #[inline]
127     fn into_usize(self) -> usize {
128         Arc::into_raw(self) as usize
129     }
130     #[inline]
131     unsafe fn from_usize(ptr: usize) -> Self {
132         Arc::from_raw(ptr as *const T)
133     }
134     unsafe fn with_ref<R, F: FnOnce(&Self) -> R>(ptr: usize, f: F) -> R {
135         let raw = ManuallyDrop::new(Self::from_usize(ptr));
136         f(&raw)
137     }
138 }
139
140 unsafe impl<'a, T: 'a> Pointer for &'a T {
141     const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize;
142     #[inline]
143     fn into_usize(self) -> usize {
144         self as *const T as usize
145     }
146     #[inline]
147     unsafe fn from_usize(ptr: usize) -> Self {
148         &*(ptr as *const T)
149     }
150     unsafe fn with_ref<R, F: FnOnce(&Self) -> R>(ptr: usize, f: F) -> R {
151         f(&*(&ptr as *const usize as *const Self))
152     }
153 }
154
155 unsafe impl<'a, T: 'a> Pointer for &'a mut T {
156     const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize;
157     #[inline]
158     fn into_usize(self) -> usize {
159         self as *mut T as usize
160     }
161     #[inline]
162     unsafe fn from_usize(ptr: usize) -> Self {
163         &mut *(ptr as *mut T)
164     }
165     unsafe fn with_ref<R, F: FnOnce(&Self) -> R>(ptr: usize, f: F) -> R {
166         f(&*(&ptr as *const usize as *const Self))
167     }
168 }