1use rustc_hir::def::CtorOf;
2use rustc_index::Idx;
3
4use crate::rmeta::*;
5
6pub(super) trait IsDefault: Default {
7 fn is_default(&self) -> bool;
8}
9
10impl<T> IsDefault for Option<T> {
11 fn is_default(&self) -> bool {
12 self.is_none()
13 }
14}
15
16impl IsDefault for AttrFlags {
17 fn is_default(&self) -> bool {
18 self.is_empty()
19 }
20}
21
22impl IsDefault for bool {
23 fn is_default(&self) -> bool {
24 !self
25 }
26}
27
28impl IsDefault for u32 {
29 fn is_default(&self) -> bool {
30 *self == 0
31 }
32}
33
34impl IsDefault for u64 {
35 fn is_default(&self) -> bool {
36 *self == 0
37 }
38}
39
40impl<T> IsDefault for LazyArray<T> {
41 fn is_default(&self) -> bool {
42 self.num_elems == 0
43 }
44}
45
46impl IsDefault for UnusedGenericParams {
47 fn is_default(&self) -> bool {
48 let is_default = self.bits() == 0;
51 debug_assert_eq!(is_default, self.all_used());
52 is_default
53 }
54}
55
56pub(super) trait FixedSizeEncoding: IsDefault {
61 type ByteArray;
64
65 fn from_bytes(b: &Self::ByteArray) -> Self;
66 fn write_to_bytes(self, b: &mut Self::ByteArray);
67}
68
69impl FixedSizeEncoding for u64 {
70 type ByteArray = [u8; 8];
71
72 #[inline]
73 fn from_bytes(b: &[u8; 8]) -> Self {
74 Self::from_le_bytes(*b)
75 }
76
77 #[inline]
78 fn write_to_bytes(self, b: &mut [u8; 8]) {
79 *b = self.to_le_bytes();
80 }
81}
82
83macro_rules! fixed_size_enum {
84 ($ty:ty { $(($($pat:tt)*))* } $( unreachable { $(($($upat:tt)*))+ } )?) => {
85 impl FixedSizeEncoding for Option<$ty> {
86 type ByteArray = [u8;1];
87
88 #[inline]
89 fn from_bytes(b: &[u8;1]) -> Self {
90 use $ty::*;
91 if b[0] == 0 {
92 return None;
93 }
94 match b[0] - 1 {
95 $(${index()} => Some($($pat)*),)*
96 _ => panic!("Unexpected {} code: {:?}", stringify!($ty), b[0]),
97 }
98 }
99
100 #[inline]
101 fn write_to_bytes(self, b: &mut [u8;1]) {
102 use $ty::*;
103 b[0] = match self {
104 None => unreachable!(),
105 $(Some($($pat)*) => 1 + ${index()},)*
106 $(Some($($($upat)*)|+) => unreachable!(),)?
107 }
108 }
109 }
110 }
111}
112
113macro_rules! const_macro_kinds {
115 ($($name:ident),+$(,)?) => (MacroKinds::from_bits_truncate($(MacroKinds::$name.bits())|+))
116}
117const MACRO_KINDS_ATTR_BANG: MacroKinds = const_macro_kinds!(ATTR, BANG);
118const MACRO_KINDS_DERIVE_BANG: MacroKinds = const_macro_kinds!(DERIVE, BANG);
119const MACRO_KINDS_DERIVE_ATTR: MacroKinds = const_macro_kinds!(DERIVE, ATTR);
120const MACRO_KINDS_DERIVE_ATTR_BANG: MacroKinds = const_macro_kinds!(DERIVE, ATTR, BANG);
121const _: () = assert!(MACRO_KINDS_DERIVE_ATTR_BANG.is_all());
123
124fixed_size_enum! {
125 DefKind {
126 ( Mod )
127 ( Struct )
128 ( Union )
129 ( Enum )
130 ( Variant )
131 ( Trait )
132 ( TyAlias )
133 ( ForeignTy )
134 ( TraitAlias )
135 ( AssocTy )
136 ( TyParam )
137 ( Fn )
138 ( Const )
139 ( ConstParam )
140 ( AssocFn )
141 ( AssocConst )
142 ( ExternCrate )
143 ( Use )
144 ( ForeignMod )
145 ( AnonConst )
146 ( InlineConst )
147 ( OpaqueTy )
148 ( Field )
149 ( LifetimeParam )
150 ( GlobalAsm )
151 ( Impl { of_trait: false } )
152 ( Impl { of_trait: true } )
153 ( Closure )
154 ( Static { safety: hir::Safety::Unsafe, mutability: ast::Mutability::Not, nested: false } )
155 ( Static { safety: hir::Safety::Safe, mutability: ast::Mutability::Not, nested: false } )
156 ( Static { safety: hir::Safety::Unsafe, mutability: ast::Mutability::Mut, nested: false } )
157 ( Static { safety: hir::Safety::Safe, mutability: ast::Mutability::Mut, nested: false } )
158 ( Static { safety: hir::Safety::Unsafe, mutability: ast::Mutability::Not, nested: true } )
159 ( Static { safety: hir::Safety::Safe, mutability: ast::Mutability::Not, nested: true } )
160 ( Static { safety: hir::Safety::Unsafe, mutability: ast::Mutability::Mut, nested: true } )
161 ( Static { safety: hir::Safety::Safe, mutability: ast::Mutability::Mut, nested: true } )
162 ( Ctor(CtorOf::Struct, CtorKind::Fn) )
163 ( Ctor(CtorOf::Struct, CtorKind::Const) )
164 ( Ctor(CtorOf::Variant, CtorKind::Fn) )
165 ( Ctor(CtorOf::Variant, CtorKind::Const) )
166 ( Macro(MacroKinds::BANG) )
167 ( Macro(MacroKinds::ATTR) )
168 ( Macro(MacroKinds::DERIVE) )
169 ( Macro(MACRO_KINDS_ATTR_BANG) )
170 ( Macro(MACRO_KINDS_DERIVE_ATTR) )
171 ( Macro(MACRO_KINDS_DERIVE_BANG) )
172 ( Macro(MACRO_KINDS_DERIVE_ATTR_BANG) )
173 ( SyntheticCoroutineBody )
174 } unreachable {
175 ( Macro(_) )
176 }
177}
178
179fixed_size_enum! {
180 hir::Constness {
181 ( NotConst )
182 ( Const )
183 }
184}
185
186fixed_size_enum! {
187 hir::Defaultness {
188 ( Final )
189 ( Default { has_value: false } )
190 ( Default { has_value: true } )
191 }
192}
193
194fixed_size_enum! {
195 hir::Safety {
196 ( Unsafe )
197 ( Safe )
198 }
199}
200
201fixed_size_enum! {
202 ty::Asyncness {
203 ( Yes )
204 ( No )
205 }
206}
207
208fixed_size_enum! {
209 hir::CoroutineKind {
210 ( Coroutine(hir::Movability::Movable) )
211 ( Coroutine(hir::Movability::Static) )
212 ( Desugared(hir::CoroutineDesugaring::Gen, hir::CoroutineSource::Block) )
213 ( Desugared(hir::CoroutineDesugaring::Gen, hir::CoroutineSource::Fn) )
214 ( Desugared(hir::CoroutineDesugaring::Gen, hir::CoroutineSource::Closure) )
215 ( Desugared(hir::CoroutineDesugaring::Async, hir::CoroutineSource::Block) )
216 ( Desugared(hir::CoroutineDesugaring::Async, hir::CoroutineSource::Fn) )
217 ( Desugared(hir::CoroutineDesugaring::Async, hir::CoroutineSource::Closure) )
218 ( Desugared(hir::CoroutineDesugaring::AsyncGen, hir::CoroutineSource::Block) )
219 ( Desugared(hir::CoroutineDesugaring::AsyncGen, hir::CoroutineSource::Fn) )
220 ( Desugared(hir::CoroutineDesugaring::AsyncGen, hir::CoroutineSource::Closure) )
221 }
222}
223
224fixed_size_enum! {
225 ty::AssocItemContainer {
226 ( Trait )
227 ( Impl )
228 }
229}
230
231fixed_size_enum! {
232 MacroKind {
233 ( Attr )
234 ( Bang )
235 ( Derive )
236 }
237}
238
239impl FixedSizeEncoding for Option<RawDefId> {
241 type ByteArray = [u8; 8];
242
243 #[inline]
244 fn from_bytes(encoded: &[u8; 8]) -> Self {
245 let (index, krate) = decode_interleaved(encoded);
246 let krate = u32::from_le_bytes(krate);
247 if krate == 0 {
248 return None;
249 }
250 let index = u32::from_le_bytes(index);
251
252 Some(RawDefId { krate: krate - 1, index })
253 }
254
255 #[inline]
256 fn write_to_bytes(self, dest: &mut [u8; 8]) {
257 match self {
258 None => unreachable!(),
259 Some(RawDefId { krate, index }) => {
260 debug_assert!(krate < u32::MAX);
261 let krate = (krate + 1).to_le_bytes();
263 let index = index.to_le_bytes();
264
265 encode_interleaved(index, krate, dest);
268 }
269 }
270 }
271}
272
273impl FixedSizeEncoding for AttrFlags {
274 type ByteArray = [u8; 1];
275
276 #[inline]
277 fn from_bytes(b: &[u8; 1]) -> Self {
278 AttrFlags::from_bits_truncate(b[0])
279 }
280
281 #[inline]
282 fn write_to_bytes(self, b: &mut [u8; 1]) {
283 debug_assert!(!self.is_default());
284 b[0] = self.bits();
285 }
286}
287
288impl FixedSizeEncoding for bool {
289 type ByteArray = [u8; 1];
290
291 #[inline]
292 fn from_bytes(b: &[u8; 1]) -> Self {
293 b[0] != 0
294 }
295
296 #[inline]
297 fn write_to_bytes(self, b: &mut [u8; 1]) {
298 debug_assert!(!self.is_default());
299 b[0] = self as u8
300 }
301}
302
303impl<T> FixedSizeEncoding for Option<LazyValue<T>> {
307 type ByteArray = [u8; 8];
308
309 #[inline]
310 fn from_bytes(b: &[u8; 8]) -> Self {
311 let position = NonZero::new(u64::from_bytes(b) as usize)?;
312 Some(LazyValue::from_position(position))
313 }
314
315 #[inline]
316 fn write_to_bytes(self, b: &mut [u8; 8]) {
317 match self {
318 None => unreachable!(),
319 Some(lazy) => {
320 let position = lazy.position.get();
321 let position: u64 = position.try_into().unwrap();
322 position.write_to_bytes(b)
323 }
324 }
325 }
326}
327
328impl<T> LazyArray<T> {
329 #[inline]
330 fn write_to_bytes_impl(self, dest: &mut [u8; 16]) {
331 let position = (self.position.get() as u64).to_le_bytes();
332 let len = (self.num_elems as u64).to_le_bytes();
333
334 encode_interleaved(position, len, dest)
335 }
336
337 fn from_bytes_impl(position: &[u8; 8], meta: &[u8; 8]) -> Option<LazyArray<T>> {
338 let position = NonZero::new(u64::from_bytes(position) as usize)?;
339 let len = u64::from_bytes(meta) as usize;
340 Some(LazyArray::from_position_and_num_elems(position, len))
341 }
342}
343
344#[inline]
347fn decode_interleaved<const N: usize, const M: usize>(encoded: &[u8; N]) -> ([u8; M], [u8; M]) {
348 assert_eq!(M * 2, N);
349 let mut first = [0u8; M];
350 let mut second = [0u8; M];
351 for i in 0..M {
352 first[i] = encoded[2 * i];
353 second[i] = encoded[2 * i + 1];
354 }
355 (first, second)
356}
357
358#[inline]
366fn encode_interleaved<const N: usize, const M: usize>(a: [u8; M], b: [u8; M], dest: &mut [u8; N]) {
367 assert_eq!(M * 2, N);
368 for i in 0..M {
369 dest[2 * i] = a[i];
370 dest[2 * i + 1] = b[i];
371 }
372}
373
374impl<T> FixedSizeEncoding for LazyArray<T> {
375 type ByteArray = [u8; 16];
376
377 #[inline]
378 fn from_bytes(b: &[u8; 16]) -> Self {
379 let (position, meta) = decode_interleaved(b);
380
381 if meta == [0; 8] {
382 return Default::default();
383 }
384 LazyArray::from_bytes_impl(&position, &meta).unwrap()
385 }
386
387 #[inline]
388 fn write_to_bytes(self, b: &mut [u8; 16]) {
389 assert!(!self.is_default());
390 self.write_to_bytes_impl(b)
391 }
392}
393
394impl<T> FixedSizeEncoding for Option<LazyArray<T>> {
395 type ByteArray = [u8; 16];
396
397 #[inline]
398 fn from_bytes(b: &[u8; 16]) -> Self {
399 let (position, meta) = decode_interleaved(b);
400
401 LazyArray::from_bytes_impl(&position, &meta)
402 }
403
404 #[inline]
405 fn write_to_bytes(self, b: &mut [u8; 16]) {
406 match self {
407 None => unreachable!(),
408 Some(lazy) => lazy.write_to_bytes_impl(b),
409 }
410 }
411}
412
413pub(super) struct TableBuilder<I: Idx, T: FixedSizeEncoding> {
415 width: usize,
416 blocks: IndexVec<I, T::ByteArray>,
417 _marker: PhantomData<T>,
418}
419
420impl<I: Idx, T: FixedSizeEncoding> Default for TableBuilder<I, T> {
421 fn default() -> Self {
422 TableBuilder { width: 0, blocks: Default::default(), _marker: PhantomData }
423 }
424}
425
426impl<I: Idx, const N: usize, T> TableBuilder<I, Option<T>>
427where
428 Option<T>: FixedSizeEncoding<ByteArray = [u8; N]>,
429{
430 pub(crate) fn set_some(&mut self, i: I, value: T) {
431 self.set(i, Some(value))
432 }
433}
434
435impl<I: Idx, const N: usize, T: FixedSizeEncoding<ByteArray = [u8; N]>> TableBuilder<I, T> {
436 pub(crate) fn set(&mut self, i: I, value: T) {
442 if !value.is_default() {
443 let block = self.blocks.ensure_contains_elem(i, || [0; N]);
449 value.write_to_bytes(block);
450 if self.width != N {
451 let width = N - trailing_zeros(block);
452 self.width = self.width.max(width);
453 }
454 }
455 }
456
457 pub(crate) fn encode(&self, buf: &mut FileEncoder) -> LazyTable<I, T> {
458 let pos = buf.position();
459
460 let width = self.width;
461 for block in &self.blocks {
462 buf.write_with(|dest| {
463 *dest = *block;
464 width
465 });
466 }
467
468 LazyTable::from_position_and_encoded_size(
469 NonZero::new(pos).unwrap(),
470 width,
471 self.blocks.len(),
472 )
473 }
474}
475
476fn trailing_zeros(x: &[u8]) -> usize {
477 x.iter().rev().take_while(|b| **b == 0).count()
478}
479
480impl<I: Idx, const N: usize, T: FixedSizeEncoding<ByteArray = [u8; N]> + ParameterizedOverTcx>
481 LazyTable<I, T>
482where
483 for<'tcx> T::Value<'tcx>: FixedSizeEncoding<ByteArray = [u8; N]>,
484{
485 pub(super) fn get<'a, 'tcx, M: Metadata<'a, 'tcx>>(&self, metadata: M, i: I) -> T::Value<'tcx> {
487 if i.index() >= self.len {
489 return Default::default();
490 }
491
492 let width = self.width;
493 let start = self.position.get() + (width * i.index());
494 let end = start + width;
495 let bytes = &metadata.blob()[start..end];
496
497 if let Ok(fixed) = bytes.try_into() {
498 FixedSizeEncoding::from_bytes(fixed)
499 } else {
500 let mut fixed = [0u8; N];
501 fixed[..width].copy_from_slice(bytes);
502 FixedSizeEncoding::from_bytes(&fixed)
503 }
504 }
505
506 pub(super) fn size(&self) -> usize {
508 self.len
509 }
510}