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