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