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