|
81 | 81 | /// E::A, |
82 | 82 | /// } |
83 | 83 | /// ``` |
84 | | -#[cfg(bootstrap)] |
85 | | -#[macro_export] |
86 | | -macro_rules! impl_tag { |
87 | | - ( |
88 | | - impl Tag for $Self:ty; |
89 | | - $( |
90 | | - $($path:ident)::* $( { $( $fields:tt )* })?, |
91 | | - )* |
92 | | - ) => { |
93 | | - // Safety: |
94 | | - // `bits_for_tags` is called on the same `${index()}`-es as |
95 | | - // `into_usize` returns, thus `BITS` constant is correct. |
96 | | - unsafe impl $crate::tagged_ptr::Tag for $Self { |
97 | | - const BITS: u32 = $crate::tagged_ptr::bits_for_tags(&[ |
98 | | - $( |
99 | | - ${index()}, |
100 | | - $( ${ignore(path)} )* |
101 | | - )* |
102 | | - ]); |
103 | | - |
104 | | - #[inline] |
105 | | - fn into_usize(self) -> usize { |
106 | | - // This forbids use of repeating patterns (`Enum::V`&`Enum::V`, etc) |
107 | | - // (or at least it should, see <https://github.com/rust-lang/rust/issues/110613>) |
108 | | - #[forbid(unreachable_patterns)] |
109 | | - match self { |
110 | | - // `match` is doing heavy lifting here, by requiring exhaustiveness |
111 | | - $( |
112 | | - $($path)::* $( { $( $fields )* } )? => ${index()}, |
113 | | - )* |
114 | | - } |
115 | | - } |
116 | | - |
117 | | - #[inline] |
118 | | - unsafe fn from_usize(tag: usize) -> Self { |
119 | | - match tag { |
120 | | - $( |
121 | | - ${index()} => $($path)::* $( { $( $fields )* } )?, |
122 | | - )* |
123 | | - |
124 | | - // Safety: |
125 | | - // `into_usize` only returns `${index()}` of the same |
126 | | - // repetition as we are filtering above, thus if this is |
127 | | - // reached, the safety contract of this function was |
128 | | - // already breached. |
129 | | - _ => unsafe { |
130 | | - debug_assert!( |
131 | | - false, |
132 | | - "invalid tag: {tag}\ |
133 | | - (this is a bug in the caller of `from_usize`)" |
134 | | - ); |
135 | | - std::hint::unreachable_unchecked() |
136 | | - }, |
137 | | - } |
138 | | - } |
139 | | - |
140 | | - } |
141 | | - }; |
142 | | -} |
143 | | - |
144 | | -/// Implements [`Tag`] for a given type. |
145 | | -/// |
146 | | -/// You can use `impl_tag` on structs and enums. |
147 | | -/// You need to specify the type and all its possible values, |
148 | | -/// which can only be paths with optional fields. |
149 | | -/// |
150 | | -/// [`Tag`]: crate::tagged_ptr::Tag |
151 | | -/// |
152 | | -/// # Examples |
153 | | -/// |
154 | | -/// Basic usage: |
155 | | -/// |
156 | | -/// ``` |
157 | | -/// #![feature(macro_metavar_expr)] |
158 | | -/// use rustc_data_structures::{impl_tag, tagged_ptr::Tag}; |
159 | | -/// |
160 | | -/// #[derive(Copy, Clone, PartialEq, Debug)] |
161 | | -/// enum SomeTag { |
162 | | -/// A, |
163 | | -/// B, |
164 | | -/// X { v: bool }, |
165 | | -/// Y(bool, bool), |
166 | | -/// } |
167 | | -/// |
168 | | -/// impl_tag! { |
169 | | -/// // The type for which the `Tag` will be implemented |
170 | | -/// impl Tag for SomeTag; |
171 | | -/// // You need to specify all possible tag values: |
172 | | -/// SomeTag::A, // 0 |
173 | | -/// SomeTag::B, // 1 |
174 | | -/// // For variants with fields, you need to specify the fields: |
175 | | -/// SomeTag::X { v: true }, // 2 |
176 | | -/// SomeTag::X { v: false }, // 3 |
177 | | -/// // For tuple variants use named syntax: |
178 | | -/// SomeTag::Y { 0: true, 1: true }, // 4 |
179 | | -/// SomeTag::Y { 0: false, 1: true }, // 5 |
180 | | -/// SomeTag::Y { 0: true, 1: false }, // 6 |
181 | | -/// SomeTag::Y { 0: false, 1: false }, // 7 |
182 | | -/// } |
183 | | -/// |
184 | | -/// // Tag values are assigned in order: |
185 | | -/// assert_eq!(SomeTag::A.into_usize(), 0); |
186 | | -/// assert_eq!(SomeTag::X { v: false }.into_usize(), 3); |
187 | | -/// assert_eq!(SomeTag::Y(false, true).into_usize(), 5); |
188 | | -/// |
189 | | -/// assert_eq!(unsafe { SomeTag::from_usize(1) }, SomeTag::B); |
190 | | -/// assert_eq!(unsafe { SomeTag::from_usize(2) }, SomeTag::X { v: true }); |
191 | | -/// assert_eq!(unsafe { SomeTag::from_usize(7) }, SomeTag::Y(false, false)); |
192 | | -/// ``` |
193 | | -/// |
194 | | -/// Structs are supported: |
195 | | -/// |
196 | | -/// ``` |
197 | | -/// #![feature(macro_metavar_expr)] |
198 | | -/// # use rustc_data_structures::impl_tag; |
199 | | -/// #[derive(Copy, Clone)] |
200 | | -/// struct Flags { a: bool, b: bool } |
201 | | -/// |
202 | | -/// impl_tag! { |
203 | | -/// impl Tag for Flags; |
204 | | -/// Flags { a: true, b: true }, |
205 | | -/// Flags { a: false, b: true }, |
206 | | -/// Flags { a: true, b: false }, |
207 | | -/// Flags { a: false, b: false }, |
208 | | -/// } |
209 | | -/// ``` |
210 | | -/// |
211 | | -/// Not specifying all values results in a compile error: |
212 | | -/// |
213 | | -/// ```compile_fail,E0004 |
214 | | -/// #![feature(macro_metavar_expr)] |
215 | | -/// # use rustc_data_structures::impl_tag; |
216 | | -/// #[derive(Copy, Clone)] |
217 | | -/// enum E { |
218 | | -/// A, |
219 | | -/// B, |
220 | | -/// } |
221 | | -/// |
222 | | -/// impl_tag! { |
223 | | -/// impl Tag for E; |
224 | | -/// E::A, |
225 | | -/// } |
226 | | -/// ``` |
227 | | -#[cfg(not(bootstrap))] |
228 | 84 | #[macro_export] |
229 | 85 | macro_rules! impl_tag { |
230 | 86 | ( |
|
0 commit comments