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 MacroKind {
226 ( Attr )
227 ( Bang )
228 ( Derive )
229 }
230}
231
232impl FixedSizeEncoding for Option<RawDefId> {
234 type ByteArray = [u8; 8];
235
236 #[inline]
237 fn from_bytes(encoded: &[u8; 8]) -> Self {
238 let (index, krate) = decode_interleaved(encoded);
239 let krate = u32::from_le_bytes(krate);
240 if krate == 0 {
241 return None;
242 }
243 let index = u32::from_le_bytes(index);
244
245 Some(RawDefId { krate: krate - 1, index })
246 }
247
248 #[inline]
249 fn write_to_bytes(self, dest: &mut [u8; 8]) {
250 match self {
251 None => unreachable!(),
252 Some(RawDefId { krate, index }) => {
253 debug_assert!(krate < u32::MAX);
254 let krate = (krate + 1).to_le_bytes();
256 let index = index.to_le_bytes();
257
258 encode_interleaved(index, krate, dest);
261 }
262 }
263 }
264}
265
266impl FixedSizeEncoding for AttrFlags {
267 type ByteArray = [u8; 1];
268
269 #[inline]
270 fn from_bytes(b: &[u8; 1]) -> Self {
271 AttrFlags::from_bits_truncate(b[0])
272 }
273
274 #[inline]
275 fn write_to_bytes(self, b: &mut [u8; 1]) {
276 debug_assert!(!self.is_default());
277 b[0] = self.bits();
278 }
279}
280
281impl FixedSizeEncoding for bool {
282 type ByteArray = [u8; 1];
283
284 #[inline]
285 fn from_bytes(b: &[u8; 1]) -> Self {
286 b[0] != 0
287 }
288
289 #[inline]
290 fn write_to_bytes(self, b: &mut [u8; 1]) {
291 debug_assert!(!self.is_default());
292 b[0] = self as u8
293 }
294}
295
296impl<T> FixedSizeEncoding for Option<LazyValue<T>> {
300 type ByteArray = [u8; 8];
301
302 #[inline]
303 fn from_bytes(b: &[u8; 8]) -> Self {
304 let position = NonZero::new(u64::from_bytes(b) as usize)?;
305 Some(LazyValue::from_position(position))
306 }
307
308 #[inline]
309 fn write_to_bytes(self, b: &mut [u8; 8]) {
310 match self {
311 None => unreachable!(),
312 Some(lazy) => {
313 let position = lazy.position.get();
314 let position: u64 = position.try_into().unwrap();
315 position.write_to_bytes(b)
316 }
317 }
318 }
319}
320
321impl<T> LazyArray<T> {
322 #[inline]
323 fn write_to_bytes_impl(self, dest: &mut [u8; 16]) {
324 let position = (self.position.get() as u64).to_le_bytes();
325 let len = (self.num_elems as u64).to_le_bytes();
326
327 encode_interleaved(position, len, dest)
328 }
329
330 fn from_bytes_impl(position: &[u8; 8], meta: &[u8; 8]) -> Option<LazyArray<T>> {
331 let position = NonZero::new(u64::from_bytes(position) as usize)?;
332 let len = u64::from_bytes(meta) as usize;
333 Some(LazyArray::from_position_and_num_elems(position, len))
334 }
335}
336
337#[inline]
340fn decode_interleaved<const N: usize, const M: usize>(encoded: &[u8; N]) -> ([u8; M], [u8; M]) {
341 assert_eq!(M * 2, N);
342 let mut first = [0u8; M];
343 let mut second = [0u8; M];
344 for i in 0..M {
345 first[i] = encoded[2 * i];
346 second[i] = encoded[2 * i + 1];
347 }
348 (first, second)
349}
350
351#[inline]
359fn encode_interleaved<const N: usize, const M: usize>(a: [u8; M], b: [u8; M], dest: &mut [u8; N]) {
360 assert_eq!(M * 2, N);
361 for i in 0..M {
362 dest[2 * i] = a[i];
363 dest[2 * i + 1] = b[i];
364 }
365}
366
367impl<T> FixedSizeEncoding for LazyArray<T> {
368 type ByteArray = [u8; 16];
369
370 #[inline]
371 fn from_bytes(b: &[u8; 16]) -> Self {
372 let (position, meta) = decode_interleaved(b);
373
374 if meta == [0; 8] {
375 return Default::default();
376 }
377 LazyArray::from_bytes_impl(&position, &meta).unwrap()
378 }
379
380 #[inline]
381 fn write_to_bytes(self, b: &mut [u8; 16]) {
382 assert!(!self.is_default());
383 self.write_to_bytes_impl(b)
384 }
385}
386
387impl<T> FixedSizeEncoding for Option<LazyArray<T>> {
388 type ByteArray = [u8; 16];
389
390 #[inline]
391 fn from_bytes(b: &[u8; 16]) -> Self {
392 let (position, meta) = decode_interleaved(b);
393
394 LazyArray::from_bytes_impl(&position, &meta)
395 }
396
397 #[inline]
398 fn write_to_bytes(self, b: &mut [u8; 16]) {
399 match self {
400 None => unreachable!(),
401 Some(lazy) => lazy.write_to_bytes_impl(b),
402 }
403 }
404}
405
406pub(super) struct TableBuilder<I: Idx, T: FixedSizeEncoding> {
408 width: usize,
409 blocks: IndexVec<I, T::ByteArray>,
410 _marker: PhantomData<T>,
411}
412
413impl<I: Idx, T: FixedSizeEncoding> Default for TableBuilder<I, T> {
414 fn default() -> Self {
415 TableBuilder { width: 0, blocks: Default::default(), _marker: PhantomData }
416 }
417}
418
419impl<I: Idx, const N: usize, T> TableBuilder<I, Option<T>>
420where
421 Option<T>: FixedSizeEncoding<ByteArray = [u8; N]>,
422{
423 pub(crate) fn set_some(&mut self, i: I, value: T) {
424 self.set(i, Some(value))
425 }
426}
427
428impl<I: Idx, const N: usize, T: FixedSizeEncoding<ByteArray = [u8; N]>> TableBuilder<I, T> {
429 pub(crate) fn set(&mut self, i: I, value: T) {
435 if !value.is_default() {
436 let block = self.blocks.ensure_contains_elem(i, || [0; N]);
442 value.write_to_bytes(block);
443 if self.width != N {
444 let width = N - trailing_zeros(block);
445 self.width = self.width.max(width);
446 }
447 }
448 }
449
450 pub(crate) fn encode(&self, buf: &mut FileEncoder) -> LazyTable<I, T> {
451 let pos = buf.position();
452
453 let width = self.width;
454 for block in &self.blocks {
455 buf.write_with(|dest| {
456 *dest = *block;
457 width
458 });
459 }
460
461 LazyTable::from_position_and_encoded_size(
462 NonZero::new(pos).unwrap(),
463 width,
464 self.blocks.len(),
465 )
466 }
467}
468
469fn trailing_zeros(x: &[u8]) -> usize {
470 x.iter().rev().take_while(|b| **b == 0).count()
471}
472
473impl<I: Idx, const N: usize, T: FixedSizeEncoding<ByteArray = [u8; N]> + ParameterizedOverTcx>
474 LazyTable<I, T>
475where
476 for<'tcx> T::Value<'tcx>: FixedSizeEncoding<ByteArray = [u8; N]>,
477{
478 pub(super) fn get<'a, 'tcx, M: Metadata<'a, 'tcx>>(&self, metadata: M, i: I) -> T::Value<'tcx> {
480 if i.index() >= self.len {
482 return Default::default();
483 }
484
485 let width = self.width;
486 let start = self.position.get() + (width * i.index());
487 let end = start + width;
488 let bytes = &metadata.blob()[start..end];
489
490 if let Ok(fixed) = bytes.try_into() {
491 FixedSizeEncoding::from_bytes(fixed)
492 } else {
493 let mut fixed = [0u8; N];
494 fixed[..width].copy_from_slice(bytes);
495 FixedSizeEncoding::from_bytes(&fixed)
496 }
497 }
498
499 pub(super) fn size(&self) -> usize {
501 self.len
502 }
503}