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