]> git.proxmox.com Git - rustc.git/blame - vendor/rustc-ap-rustc_data_structures/src/tagged_ptr.rs
Update upstream source from tag 'upstream/1.52.1+dfsg1'
[rustc.git] / vendor / rustc-ap-rustc_data_structures / src / tagged_ptr.rs
CommitLineData
f20569fa
XL
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
16use std::mem::ManuallyDrop;
17use std::ops::Deref;
18use std::rc::Rc;
19use std::sync::Arc;
20
21mod copy;
22mod drop;
23
24pub use copy::CopyTaggedPtr;
25pub 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.
42pub 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.
80pub 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
91unsafe 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
105unsafe 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
119unsafe 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
133unsafe 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
146unsafe 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}