Skip to main content

rustc_metadata/rmeta/
table.rs

1use rustc_hir::def::CtorOf;
2use rustc_index::Idx;
3
4use crate::rmeta::decoder::MetaBlob;
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
47/// Helper trait, for encoding to, and decoding from, a fixed number of bytes.
48/// Used mainly for Lazy positions and lengths.
49///
50/// Invariant: `Self::default()` should encode as `[0; BYTE_LEN]`,
51/// but this has no impact on safety.
52/// In debug builds, this invariant is checked in `[TableBuilder::set]`
53pub(super) trait FixedSizeEncoding: IsDefault {
54    /// This should be `[u8; BYTE_LEN]`;
55    /// Cannot use an associated `const BYTE_LEN: usize` instead due to const eval limitations.
56    type ByteArray;
57
58    fn from_bytes(b: &Self::ByteArray) -> Self;
59    fn write_to_bytes(self, b: &mut Self::ByteArray);
60}
61
62impl FixedSizeEncoding for u64 {
63    type ByteArray = [u8; 8];
64
65    #[inline]
66    fn from_bytes(b: &[u8; 8]) -> Self {
67        Self::from_le_bytes(*b)
68    }
69
70    #[inline]
71    fn write_to_bytes(self, b: &mut [u8; 8]) {
72        *b = self.to_le_bytes();
73    }
74}
75
76macro_rules! fixed_size_enum {
77    ($ty:ty { $(($($pat:tt)*))* } $( unreachable { $(($($upat:tt)*))+ } )?) => {
78        impl FixedSizeEncoding for Option<$ty> {
79            type ByteArray = [u8;1];
80
81            #[inline]
82            fn from_bytes(b: &[u8;1]) -> Self {
83                use $ty::*;
84                if b[0] == 0 {
85                    return None;
86                }
87                match b[0] - 1 {
88                    $(${index()} => Some($($pat)*),)*
89                    _ => panic!("Unexpected {} code: {:?}", stringify!($ty), b[0]),
90                }
91            }
92
93            #[inline]
94            fn write_to_bytes(self, b: &mut [u8;1]) {
95                use $ty::*;
96                b[0] = match self {
97                    None => unreachable!(),
98                    $(Some($($pat)*) => 1 + ${index()},)*
99                    $(Some($($($upat)*)|+) => unreachable!(),)?
100                }
101            }
102        }
103    }
104}
105
106macro_rules! defaulted_enum {
107    ($ty:ty { $(($($pat:tt)*))* } $( unreachable { $(($($upat:tt)*))+ } )?) => {
108        impl FixedSizeEncoding for $ty {
109            type ByteArray = [u8; 1];
110
111            #[inline]
112            fn from_bytes(b: &[u8; 1]) -> Self {
113                use $ty::*;
114                let val = match b[0] {
115                    $(${index()} => $($pat)*,)*
116                    _ => panic!("Unexpected {} code: {:?}", stringify!($ty), b[0]),
117                };
118                // Make sure the first entry is always the default value,
119                // and none of the other values are the default value
120                debug_assert_ne!((b[0] != 0), IsDefault::is_default(&val));
121                val
122            }
123
124            #[inline]
125            fn write_to_bytes(self, b: &mut [u8; 1]) {
126                debug_assert!(!IsDefault::is_default(&self));
127                use $ty::*;
128                b[0] = match self {
129                    $($($pat)* => ${index()},)*
130                    $($($($upat)*)|+ => unreachable!(),)?
131                };
132                debug_assert_ne!(b[0], 0);
133            }
134        }
135        impl IsDefault for $ty {
136            fn is_default(&self) -> bool {
137                <$ty as Default>::default() == *self
138            }
139        }
140    }
141}
142
143// Workaround; need const traits to construct bitflags in a const
144macro_rules! const_macro_kinds {
145    ($($name:ident),+$(,)?) => (MacroKinds::from_bits_truncate($(MacroKinds::$name.bits())|+))
146}
147const MACRO_KINDS_ATTR_BANG: MacroKinds = MacroKinds::from_bits_truncate(MacroKinds::ATTR.bits() |
        MacroKinds::BANG.bits())const_macro_kinds!(ATTR, BANG);
148const MACRO_KINDS_DERIVE_BANG: MacroKinds = MacroKinds::from_bits_truncate(MacroKinds::DERIVE.bits() |
        MacroKinds::BANG.bits())const_macro_kinds!(DERIVE, BANG);
149const MACRO_KINDS_DERIVE_ATTR: MacroKinds = MacroKinds::from_bits_truncate(MacroKinds::DERIVE.bits() |
        MacroKinds::ATTR.bits())const_macro_kinds!(DERIVE, ATTR);
150const MACRO_KINDS_DERIVE_ATTR_BANG: MacroKinds = MacroKinds::from_bits_truncate(MacroKinds::DERIVE.bits() |
            MacroKinds::ATTR.bits() | MacroKinds::BANG.bits())const_macro_kinds!(DERIVE, ATTR, BANG);
151// Ensure that we get a compilation error if MacroKinds gets extended without updating metadata.
152const _: () = if !MACRO_KINDS_DERIVE_ATTR_BANG.is_all() {
    ::core::panicking::panic("assertion failed: MACRO_KINDS_DERIVE_ATTR_BANG.is_all()")
}assert!(MACRO_KINDS_DERIVE_ATTR_BANG.is_all());
153
154impl FixedSizeEncoding for Option<DefKind> {
    type ByteArray = [u8; 1];
    #[inline]
    fn from_bytes(b: &[u8; 1]) -> Self {
        use DefKind::*;
        if b[0] == 0 { return None; }
        match b[0] - 1 {
            0 => Some(Mod),
            1 => Some(Struct),
            2 => Some(Union),
            3 => Some(Enum),
            4 => Some(Variant),
            5 => Some(Trait),
            6 => Some(TyAlias),
            7 => Some(ForeignTy),
            8 => Some(TraitAlias),
            9 => Some(AssocTy),
            10 => Some(TyParam),
            11 => Some(Fn),
            12 => Some(Const { is_type_const: true }),
            13 => Some(Const { is_type_const: false }),
            14 => Some(ConstParam),
            15 => Some(AssocFn),
            16 => Some(AssocConst { is_type_const: true }),
            17 => Some(AssocConst { is_type_const: false }),
            18 => Some(ExternCrate),
            19 => Some(Use),
            20 => Some(ForeignMod),
            21 => Some(AnonConst),
            22 => Some(InlineConst),
            23 => Some(OpaqueTy),
            24 => Some(Field),
            25 => Some(LifetimeParam),
            26 => Some(GlobalAsm),
            27 => Some(Impl { of_trait: false }),
            28 => Some(Impl { of_trait: true }),
            29 => Some(Closure),
            30 =>
                Some(Static {
                        safety: hir::Safety::Unsafe,
                        mutability: ast::Mutability::Not,
                        nested: false,
                    }),
            31 =>
                Some(Static {
                        safety: hir::Safety::Safe,
                        mutability: ast::Mutability::Not,
                        nested: false,
                    }),
            32 =>
                Some(Static {
                        safety: hir::Safety::Unsafe,
                        mutability: ast::Mutability::Mut,
                        nested: false,
                    }),
            33 =>
                Some(Static {
                        safety: hir::Safety::Safe,
                        mutability: ast::Mutability::Mut,
                        nested: false,
                    }),
            34 =>
                Some(Static {
                        safety: hir::Safety::Unsafe,
                        mutability: ast::Mutability::Not,
                        nested: true,
                    }),
            35 =>
                Some(Static {
                        safety: hir::Safety::Safe,
                        mutability: ast::Mutability::Not,
                        nested: true,
                    }),
            36 =>
                Some(Static {
                        safety: hir::Safety::Unsafe,
                        mutability: ast::Mutability::Mut,
                        nested: true,
                    }),
            37 =>
                Some(Static {
                        safety: hir::Safety::Safe,
                        mutability: ast::Mutability::Mut,
                        nested: true,
                    }),
            38 => Some(Ctor(CtorOf::Struct, CtorKind::Fn)),
            39 => Some(Ctor(CtorOf::Struct, CtorKind::Const)),
            40 => Some(Ctor(CtorOf::Variant, CtorKind::Fn)),
            41 => Some(Ctor(CtorOf::Variant, CtorKind::Const)),
            42 => Some(Macro(MacroKinds::BANG)),
            43 => Some(Macro(MacroKinds::ATTR)),
            44 => Some(Macro(MacroKinds::DERIVE)),
            45 => Some(Macro(MACRO_KINDS_ATTR_BANG)),
            46 => Some(Macro(MACRO_KINDS_DERIVE_ATTR)),
            47 => Some(Macro(MACRO_KINDS_DERIVE_BANG)),
            48 => Some(Macro(MACRO_KINDS_DERIVE_ATTR_BANG)),
            49 => Some(SyntheticCoroutineBody),
            _ => {
                ::core::panicking::panic_fmt(format_args!("Unexpected {0} code: {1:?}",
                        "DefKind", b[0]));
            }
        }
    }
    #[inline]
    fn write_to_bytes(self, b: &mut [u8; 1]) {
        use DefKind::*;
        b[0] =
            match self {
                None =>
                    ::core::panicking::panic("internal error: entered unreachable code"),
                Some(Mod) => 1 + 0,
                Some(Struct) => 1 + 1,
                Some(Union) => 1 + 2,
                Some(Enum) => 1 + 3,
                Some(Variant) => 1 + 4,
                Some(Trait) => 1 + 5,
                Some(TyAlias) => 1 + 6,
                Some(ForeignTy) => 1 + 7,
                Some(TraitAlias) => 1 + 8,
                Some(AssocTy) => 1 + 9,
                Some(TyParam) => 1 + 10,
                Some(Fn) => 1 + 11,
                Some(Const { is_type_const: true }) => 1 + 12,
                Some(Const { is_type_const: false }) => 1 + 13,
                Some(ConstParam) => 1 + 14,
                Some(AssocFn) => 1 + 15,
                Some(AssocConst { is_type_const: true }) => 1 + 16,
                Some(AssocConst { is_type_const: false }) => 1 + 17,
                Some(ExternCrate) => 1 + 18,
                Some(Use) => 1 + 19,
                Some(ForeignMod) => 1 + 20,
                Some(AnonConst) => 1 + 21,
                Some(InlineConst) => 1 + 22,
                Some(OpaqueTy) => 1 + 23,
                Some(Field) => 1 + 24,
                Some(LifetimeParam) => 1 + 25,
                Some(GlobalAsm) => 1 + 26,
                Some(Impl { of_trait: false }) => 1 + 27,
                Some(Impl { of_trait: true }) => 1 + 28,
                Some(Closure) => 1 + 29,
                Some(Static {
                    safety: hir::Safety::Unsafe,
                    mutability: ast::Mutability::Not,
                    nested: false }) => 1 + 30,
                Some(Static {
                    safety: hir::Safety::Safe,
                    mutability: ast::Mutability::Not,
                    nested: false }) => 1 + 31,
                Some(Static {
                    safety: hir::Safety::Unsafe,
                    mutability: ast::Mutability::Mut,
                    nested: false }) => 1 + 32,
                Some(Static {
                    safety: hir::Safety::Safe,
                    mutability: ast::Mutability::Mut,
                    nested: false }) => 1 + 33,
                Some(Static {
                    safety: hir::Safety::Unsafe,
                    mutability: ast::Mutability::Not,
                    nested: true }) => 1 + 34,
                Some(Static {
                    safety: hir::Safety::Safe,
                    mutability: ast::Mutability::Not,
                    nested: true }) => 1 + 35,
                Some(Static {
                    safety: hir::Safety::Unsafe,
                    mutability: ast::Mutability::Mut,
                    nested: true }) => 1 + 36,
                Some(Static {
                    safety: hir::Safety::Safe,
                    mutability: ast::Mutability::Mut,
                    nested: true }) => 1 + 37,
                Some(Ctor(CtorOf::Struct, CtorKind::Fn)) => 1 + 38,
                Some(Ctor(CtorOf::Struct, CtorKind::Const)) => 1 + 39,
                Some(Ctor(CtorOf::Variant, CtorKind::Fn)) => 1 + 40,
                Some(Ctor(CtorOf::Variant, CtorKind::Const)) => 1 + 41,
                Some(Macro(MacroKinds::BANG)) => 1 + 42,
                Some(Macro(MacroKinds::ATTR)) => 1 + 43,
                Some(Macro(MacroKinds::DERIVE)) => 1 + 44,
                Some(Macro(MACRO_KINDS_ATTR_BANG)) => 1 + 45,
                Some(Macro(MACRO_KINDS_DERIVE_ATTR)) => 1 + 46,
                Some(Macro(MACRO_KINDS_DERIVE_BANG)) => 1 + 47,
                Some(Macro(MACRO_KINDS_DERIVE_ATTR_BANG)) => 1 + 48,
                Some(SyntheticCoroutineBody) => 1 + 49,
                Some(Macro(_)) =>
                    ::core::panicking::panic("internal error: entered unreachable code"),
            }
    }
}fixed_size_enum! {
155    DefKind {
156        ( Mod                                      )
157        ( Struct                                   )
158        ( Union                                    )
159        ( Enum                                     )
160        ( Variant                                  )
161        ( Trait                                    )
162        ( TyAlias                                  )
163        ( ForeignTy                                )
164        ( TraitAlias                               )
165        ( AssocTy                                  )
166        ( TyParam                                  )
167        ( Fn                                       )
168        ( Const { is_type_const: true}             )
169        ( Const { is_type_const: false}            )
170        ( ConstParam                               )
171        ( AssocFn                                  )
172        ( AssocConst { is_type_const:true }        )
173        ( AssocConst { is_type_const:false }       )
174        ( ExternCrate                              )
175        ( Use                                      )
176        ( ForeignMod                               )
177        ( AnonConst                                )
178        ( InlineConst                              )
179        ( OpaqueTy                                 )
180        ( Field                                    )
181        ( LifetimeParam                            )
182        ( GlobalAsm                                )
183        ( Impl { of_trait: false }                 )
184        ( Impl { of_trait: true }                  )
185        ( Closure                                  )
186        ( Static { safety: hir::Safety::Unsafe, mutability: ast::Mutability::Not, nested: false } )
187        ( Static { safety: hir::Safety::Safe, mutability: ast::Mutability::Not, nested: false } )
188        ( Static { safety: hir::Safety::Unsafe, mutability: ast::Mutability::Mut, nested: false } )
189        ( Static { safety: hir::Safety::Safe, mutability: ast::Mutability::Mut, nested: false } )
190        ( Static { safety: hir::Safety::Unsafe, mutability: ast::Mutability::Not, nested: true } )
191        ( Static { safety: hir::Safety::Safe, mutability: ast::Mutability::Not, nested: true } )
192        ( Static { safety: hir::Safety::Unsafe, mutability: ast::Mutability::Mut, nested: true } )
193        ( Static { safety: hir::Safety::Safe, mutability: ast::Mutability::Mut, nested: true } )
194        ( Ctor(CtorOf::Struct, CtorKind::Fn)       )
195        ( Ctor(CtorOf::Struct, CtorKind::Const)    )
196        ( Ctor(CtorOf::Variant, CtorKind::Fn)      )
197        ( Ctor(CtorOf::Variant, CtorKind::Const)   )
198        ( Macro(MacroKinds::BANG)                  )
199        ( Macro(MacroKinds::ATTR)                  )
200        ( Macro(MacroKinds::DERIVE)                )
201        ( Macro(MACRO_KINDS_ATTR_BANG)             )
202        ( Macro(MACRO_KINDS_DERIVE_ATTR)           )
203        ( Macro(MACRO_KINDS_DERIVE_BANG)           )
204        ( Macro(MACRO_KINDS_DERIVE_ATTR_BANG)      )
205        ( SyntheticCoroutineBody                   )
206    } unreachable {
207        ( Macro(_)                                 )
208    }
209}
210
211impl FixedSizeEncoding for hir::Defaultness {
    type ByteArray = [u8; 1];
    #[inline]
    fn from_bytes(b: &[u8; 1]) -> Self {
        use hir::Defaultness::*;
        let val =
            match b[0] {
                0 => Final,
                1 => Default { has_value: false },
                2 => Default { has_value: true },
                _ => {
                    ::core::panicking::panic_fmt(format_args!("Unexpected {0} code: {1:?}",
                            "hir::Defaultness", b[0]));
                }
            };
        if true {
            match (&(b[0] != 0), &IsDefault::is_default(&val)) {
                (left_val, right_val) => {
                    if *left_val == *right_val {
                        let kind = ::core::panicking::AssertKind::Ne;
                        ::core::panicking::assert_failed(kind, &*left_val,
                            &*right_val, ::core::option::Option::None);
                    }
                }
            };
        };
        val
    }
    #[inline]
    fn write_to_bytes(self, b: &mut [u8; 1]) {
        if true {
            if !!IsDefault::is_default(&self) {
                ::core::panicking::panic("assertion failed: !IsDefault::is_default(&self)")
            };
        };
        use hir::Defaultness::*;
        b[0] =
            match self {
                Final => 0,
                Default { has_value: false } => 1,
                Default { has_value: true } => 2,
            };
        if true {
            match (&b[0], &0) {
                (left_val, right_val) => {
                    if *left_val == *right_val {
                        let kind = ::core::panicking::AssertKind::Ne;
                        ::core::panicking::assert_failed(kind, &*left_val,
                            &*right_val, ::core::option::Option::None);
                    }
                }
            };
        };
    }
}
impl IsDefault for hir::Defaultness {
    fn is_default(&self) -> bool {
        <hir::Defaultness as Default>::default() == *self
    }
}defaulted_enum! {
212    hir::Defaultness {
213        ( Final                        )
214        ( Default { has_value: false } )
215        ( Default { has_value: true }  )
216    }
217}
218
219impl FixedSizeEncoding for ty::Asyncness {
    type ByteArray = [u8; 1];
    #[inline]
    fn from_bytes(b: &[u8; 1]) -> Self {
        use ty::Asyncness::*;
        let val =
            match b[0] {
                0 => No,
                1 => Yes,
                _ => {
                    ::core::panicking::panic_fmt(format_args!("Unexpected {0} code: {1:?}",
                            "ty::Asyncness", b[0]));
                }
            };
        if true {
            match (&(b[0] != 0), &IsDefault::is_default(&val)) {
                (left_val, right_val) => {
                    if *left_val == *right_val {
                        let kind = ::core::panicking::AssertKind::Ne;
                        ::core::panicking::assert_failed(kind, &*left_val,
                            &*right_val, ::core::option::Option::None);
                    }
                }
            };
        };
        val
    }
    #[inline]
    fn write_to_bytes(self, b: &mut [u8; 1]) {
        if true {
            if !!IsDefault::is_default(&self) {
                ::core::panicking::panic("assertion failed: !IsDefault::is_default(&self)")
            };
        };
        use ty::Asyncness::*;
        b[0] = match self { No => 0, Yes => 1, };
        if true {
            match (&b[0], &0) {
                (left_val, right_val) => {
                    if *left_val == *right_val {
                        let kind = ::core::panicking::AssertKind::Ne;
                        ::core::panicking::assert_failed(kind, &*left_val,
                            &*right_val, ::core::option::Option::None);
                    }
                }
            };
        };
    }
}
impl IsDefault for ty::Asyncness {
    fn is_default(&self) -> bool {
        <ty::Asyncness as Default>::default() == *self
    }
}defaulted_enum! {
220    ty::Asyncness {
221        ( No  )
222        ( Yes )
223    }
224}
225
226impl FixedSizeEncoding for hir::Constness {
    type ByteArray = [u8; 1];
    #[inline]
    fn from_bytes(b: &[u8; 1]) -> Self {
        use hir::Constness::*;
        let val =
            match b[0] {
                0 => Const { always: false },
                1 => NotConst,
                2 => Const { always: true },
                _ => {
                    ::core::panicking::panic_fmt(format_args!("Unexpected {0} code: {1:?}",
                            "hir::Constness", b[0]));
                }
            };
        if true {
            match (&(b[0] != 0), &IsDefault::is_default(&val)) {
                (left_val, right_val) => {
                    if *left_val == *right_val {
                        let kind = ::core::panicking::AssertKind::Ne;
                        ::core::panicking::assert_failed(kind, &*left_val,
                            &*right_val, ::core::option::Option::None);
                    }
                }
            };
        };
        val
    }
    #[inline]
    fn write_to_bytes(self, b: &mut [u8; 1]) {
        if true {
            if !!IsDefault::is_default(&self) {
                ::core::panicking::panic("assertion failed: !IsDefault::is_default(&self)")
            };
        };
        use hir::Constness::*;
        b[0] =
            match self {
                Const { always: false } => 0,
                NotConst => 1,
                Const { always: true } => 2,
            };
        if true {
            match (&b[0], &0) {
                (left_val, right_val) => {
                    if *left_val == *right_val {
                        let kind = ::core::panicking::AssertKind::Ne;
                        ::core::panicking::assert_failed(kind, &*left_val,
                            &*right_val, ::core::option::Option::None);
                    }
                }
            };
        };
    }
}
impl IsDefault for hir::Constness {
    fn is_default(&self) -> bool {
        <hir::Constness as Default>::default() == *self
    }
}defaulted_enum! {
227    hir::Constness {
228        ( Const { always: false } )
229        ( NotConst )
230        ( Const { always: true } )
231    }
232}
233
234impl FixedSizeEncoding for hir::Safety {
    type ByteArray = [u8; 1];
    #[inline]
    fn from_bytes(b: &[u8; 1]) -> Self {
        use hir::Safety::*;
        let val =
            match b[0] {
                0 => Unsafe,
                1 => Safe,
                _ => {
                    ::core::panicking::panic_fmt(format_args!("Unexpected {0} code: {1:?}",
                            "hir::Safety", b[0]));
                }
            };
        if true {
            match (&(b[0] != 0), &IsDefault::is_default(&val)) {
                (left_val, right_val) => {
                    if *left_val == *right_val {
                        let kind = ::core::panicking::AssertKind::Ne;
                        ::core::panicking::assert_failed(kind, &*left_val,
                            &*right_val, ::core::option::Option::None);
                    }
                }
            };
        };
        val
    }
    #[inline]
    fn write_to_bytes(self, b: &mut [u8; 1]) {
        if true {
            if !!IsDefault::is_default(&self) {
                ::core::panicking::panic("assertion failed: !IsDefault::is_default(&self)")
            };
        };
        use hir::Safety::*;
        b[0] = match self { Unsafe => 0, Safe => 1, };
        if true {
            match (&b[0], &0) {
                (left_val, right_val) => {
                    if *left_val == *right_val {
                        let kind = ::core::panicking::AssertKind::Ne;
                        ::core::panicking::assert_failed(kind, &*left_val,
                            &*right_val, ::core::option::Option::None);
                    }
                }
            };
        };
    }
}
impl IsDefault for hir::Safety {
    fn is_default(&self) -> bool {
        <hir::Safety as Default>::default() == *self
    }
}defaulted_enum! {
235    hir::Safety {
236        ( Unsafe )
237        ( Safe   )
238    }
239}
240
241impl FixedSizeEncoding for Option<hir::CoroutineKind> {
    type ByteArray = [u8; 1];
    #[inline]
    fn from_bytes(b: &[u8; 1]) -> Self {
        use hir::CoroutineKind::*;
        if b[0] == 0 { return None; }
        match b[0] - 1 {
            0 => Some(Coroutine(hir::Movability::Movable)),
            1 => Some(Coroutine(hir::Movability::Static)),
            2 =>
                Some(Desugared(hir::CoroutineDesugaring::Gen,
                        hir::CoroutineSource::Block)),
            3 =>
                Some(Desugared(hir::CoroutineDesugaring::Gen,
                        hir::CoroutineSource::Fn)),
            4 =>
                Some(Desugared(hir::CoroutineDesugaring::Gen,
                        hir::CoroutineSource::Closure)),
            5 =>
                Some(Desugared(hir::CoroutineDesugaring::Async,
                        hir::CoroutineSource::Block)),
            6 =>
                Some(Desugared(hir::CoroutineDesugaring::Async,
                        hir::CoroutineSource::Fn)),
            7 =>
                Some(Desugared(hir::CoroutineDesugaring::Async,
                        hir::CoroutineSource::Closure)),
            8 =>
                Some(Desugared(hir::CoroutineDesugaring::AsyncGen,
                        hir::CoroutineSource::Block)),
            9 =>
                Some(Desugared(hir::CoroutineDesugaring::AsyncGen,
                        hir::CoroutineSource::Fn)),
            10 =>
                Some(Desugared(hir::CoroutineDesugaring::AsyncGen,
                        hir::CoroutineSource::Closure)),
            _ => {
                ::core::panicking::panic_fmt(format_args!("Unexpected {0} code: {1:?}",
                        "hir::CoroutineKind", b[0]));
            }
        }
    }
    #[inline]
    fn write_to_bytes(self, b: &mut [u8; 1]) {
        use hir::CoroutineKind::*;
        b[0] =
            match self {
                None =>
                    ::core::panicking::panic("internal error: entered unreachable code"),
                Some(Coroutine(hir::Movability::Movable)) => 1 + 0,
                Some(Coroutine(hir::Movability::Static)) => 1 + 1,
                Some(Desugared(hir::CoroutineDesugaring::Gen,
                    hir::CoroutineSource::Block)) => 1 + 2,
                Some(Desugared(hir::CoroutineDesugaring::Gen,
                    hir::CoroutineSource::Fn)) => 1 + 3,
                Some(Desugared(hir::CoroutineDesugaring::Gen,
                    hir::CoroutineSource::Closure)) => 1 + 4,
                Some(Desugared(hir::CoroutineDesugaring::Async,
                    hir::CoroutineSource::Block)) => 1 + 5,
                Some(Desugared(hir::CoroutineDesugaring::Async,
                    hir::CoroutineSource::Fn)) => 1 + 6,
                Some(Desugared(hir::CoroutineDesugaring::Async,
                    hir::CoroutineSource::Closure)) => 1 + 7,
                Some(Desugared(hir::CoroutineDesugaring::AsyncGen,
                    hir::CoroutineSource::Block)) => 1 + 8,
                Some(Desugared(hir::CoroutineDesugaring::AsyncGen,
                    hir::CoroutineSource::Fn)) => 1 + 9,
                Some(Desugared(hir::CoroutineDesugaring::AsyncGen,
                    hir::CoroutineSource::Closure)) => 1 + 10,
            }
    }
}fixed_size_enum! {
242    hir::CoroutineKind {
243        ( Coroutine(hir::Movability::Movable)                                          )
244        ( Coroutine(hir::Movability::Static)                                           )
245        ( Desugared(hir::CoroutineDesugaring::Gen, hir::CoroutineSource::Block)        )
246        ( Desugared(hir::CoroutineDesugaring::Gen, hir::CoroutineSource::Fn)           )
247        ( Desugared(hir::CoroutineDesugaring::Gen, hir::CoroutineSource::Closure)      )
248        ( Desugared(hir::CoroutineDesugaring::Async, hir::CoroutineSource::Block)      )
249        ( Desugared(hir::CoroutineDesugaring::Async, hir::CoroutineSource::Fn)         )
250        ( Desugared(hir::CoroutineDesugaring::Async, hir::CoroutineSource::Closure)    )
251        ( Desugared(hir::CoroutineDesugaring::AsyncGen, hir::CoroutineSource::Block)   )
252        ( Desugared(hir::CoroutineDesugaring::AsyncGen, hir::CoroutineSource::Fn)      )
253        ( Desugared(hir::CoroutineDesugaring::AsyncGen, hir::CoroutineSource::Closure) )
254    }
255}
256
257impl FixedSizeEncoding for Option<MacroKind> {
    type ByteArray = [u8; 1];
    #[inline]
    fn from_bytes(b: &[u8; 1]) -> Self {
        use MacroKind::*;
        if b[0] == 0 { return None; }
        match b[0] - 1 {
            0 => Some(Attr),
            1 => Some(Bang),
            2 => Some(Derive),
            _ => {
                ::core::panicking::panic_fmt(format_args!("Unexpected {0} code: {1:?}",
                        "MacroKind", b[0]));
            }
        }
    }
    #[inline]
    fn write_to_bytes(self, b: &mut [u8; 1]) {
        use MacroKind::*;
        b[0] =
            match self {
                None =>
                    ::core::panicking::panic("internal error: entered unreachable code"),
                Some(Attr) => 1 + 0,
                Some(Bang) => 1 + 1,
                Some(Derive) => 1 + 2,
            }
    }
}fixed_size_enum! {
258    MacroKind {
259        ( Attr   )
260        ( Bang   )
261        ( Derive )
262    }
263}
264
265// We directly encode RawDefId because using a `LazyValue` would incur a 50% overhead in the worst case.
266impl FixedSizeEncoding for Option<RawDefId> {
267    type ByteArray = [u8; 8];
268
269    #[inline]
270    fn from_bytes(encoded: &[u8; 8]) -> Self {
271        let (index, krate) = decode_interleaved(encoded);
272        let krate = u32::from_le_bytes(krate);
273        if krate == 0 {
274            return None;
275        }
276        let index = u32::from_le_bytes(index);
277
278        Some(RawDefId { krate: krate - 1, index })
279    }
280
281    #[inline]
282    fn write_to_bytes(self, dest: &mut [u8; 8]) {
283        match self {
284            None => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
285            Some(RawDefId { krate, index }) => {
286                if true {
    if !(krate < u32::MAX) {
        ::core::panicking::panic("assertion failed: krate < u32::MAX")
    };
};debug_assert!(krate < u32::MAX);
287                // CrateNum is less than `CrateNum::MAX_AS_U32`.
288                let krate = (krate + 1).to_le_bytes();
289                let index = index.to_le_bytes();
290
291                // CrateNum is usually much smaller than the index within the crate, so put it in
292                // the second slot.
293                encode_interleaved(index, krate, dest);
294            }
295        }
296    }
297}
298
299impl FixedSizeEncoding for AttrFlags {
300    type ByteArray = [u8; 1];
301
302    #[inline]
303    fn from_bytes(b: &[u8; 1]) -> Self {
304        AttrFlags::from_bits_truncate(b[0])
305    }
306
307    #[inline]
308    fn write_to_bytes(self, b: &mut [u8; 1]) {
309        if true {
    if !!self.is_default() {
        ::core::panicking::panic("assertion failed: !self.is_default()")
    };
};debug_assert!(!self.is_default());
310        b[0] = self.bits();
311    }
312}
313
314impl FixedSizeEncoding for bool {
315    type ByteArray = [u8; 1];
316
317    #[inline]
318    fn from_bytes(b: &[u8; 1]) -> Self {
319        b[0] != 0
320    }
321
322    #[inline]
323    fn write_to_bytes(self, b: &mut [u8; 1]) {
324        if true {
    if !!self.is_default() {
        ::core::panicking::panic("assertion failed: !self.is_default()")
    };
};debug_assert!(!self.is_default());
325        b[0] = self as u8
326    }
327}
328
329// NOTE(eddyb) there could be an impl for `usize`, which would enable a more
330// generic `LazyValue<T>` impl, but in the general case we might not need / want
331// to fit every `usize` in `u32`.
332impl<T> FixedSizeEncoding for Option<LazyValue<T>> {
333    type ByteArray = [u8; 8];
334
335    #[inline]
336    fn from_bytes(b: &[u8; 8]) -> Self {
337        let position = NonZero::new(u64::from_bytes(b) as usize)?;
338        Some(LazyValue::from_position(position))
339    }
340
341    #[inline]
342    fn write_to_bytes(self, b: &mut [u8; 8]) {
343        match self {
344            None => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
345            Some(lazy) => {
346                let position = lazy.position.get();
347                let position: u64 = position.try_into().unwrap();
348                position.write_to_bytes(b)
349            }
350        }
351    }
352}
353
354impl<T> LazyArray<T> {
355    #[inline]
356    fn write_to_bytes_impl(self, dest: &mut [u8; 16]) {
357        let position = (self.position.get() as u64).to_le_bytes();
358        let len = (self.num_elems as u64).to_le_bytes();
359
360        encode_interleaved(position, len, dest)
361    }
362
363    fn from_bytes_impl(position: &[u8; 8], meta: &[u8; 8]) -> Option<LazyArray<T>> {
364        let position = NonZero::new(u64::from_bytes(position) as usize)?;
365        let len = u64::from_bytes(meta) as usize;
366        Some(LazyArray::from_position_and_num_elems(position, len))
367    }
368}
369
370// Interleaving the bytes of the two integers exposes trailing bytes in the first integer
371// to the varint scheme that we use for tables.
372#[inline]
373fn decode_interleaved<const N: usize, const M: usize>(encoded: &[u8; N]) -> ([u8; M], [u8; M]) {
374    match (&(M * 2), &N) {
    (left_val, right_val) => {
        if !(*left_val == *right_val) {
            let kind = ::core::panicking::AssertKind::Eq;
            ::core::panicking::assert_failed(kind, &*left_val, &*right_val,
                ::core::option::Option::None);
        }
    }
};assert_eq!(M * 2, N);
375    let mut first = [0u8; M];
376    let mut second = [0u8; M];
377    for i in 0..M {
378        first[i] = encoded[2 * i];
379        second[i] = encoded[2 * i + 1];
380    }
381    (first, second)
382}
383
384// Element width is selected at runtime on a per-table basis by omitting trailing
385// zero bytes in table elements. This works very naturally when table elements are
386// simple numbers but sometimes we have a pair of integers. If naively encoded, the second element
387// would shield the trailing zeroes in the first. Interleaving the bytes exposes trailing zeroes in
388// both to the optimization.
389//
390// Prefer passing a and b such that `b` is usually smaller.
391#[inline]
392fn encode_interleaved<const N: usize, const M: usize>(a: [u8; M], b: [u8; M], dest: &mut [u8; N]) {
393    match (&(M * 2), &N) {
    (left_val, right_val) => {
        if !(*left_val == *right_val) {
            let kind = ::core::panicking::AssertKind::Eq;
            ::core::panicking::assert_failed(kind, &*left_val, &*right_val,
                ::core::option::Option::None);
        }
    }
};assert_eq!(M * 2, N);
394    for i in 0..M {
395        dest[2 * i] = a[i];
396        dest[2 * i + 1] = b[i];
397    }
398}
399
400impl<T> FixedSizeEncoding for LazyArray<T> {
401    type ByteArray = [u8; 16];
402
403    #[inline]
404    fn from_bytes(b: &[u8; 16]) -> Self {
405        let (position, meta) = decode_interleaved(b);
406
407        if meta == [0; 8] {
408            return Default::default();
409        }
410        LazyArray::from_bytes_impl(&position, &meta).unwrap()
411    }
412
413    #[inline]
414    fn write_to_bytes(self, b: &mut [u8; 16]) {
415        if !!self.is_default() {
    ::core::panicking::panic("assertion failed: !self.is_default()")
};assert!(!self.is_default());
416        self.write_to_bytes_impl(b)
417    }
418}
419
420impl<T> FixedSizeEncoding for Option<LazyArray<T>> {
421    type ByteArray = [u8; 16];
422
423    #[inline]
424    fn from_bytes(b: &[u8; 16]) -> Self {
425        let (position, meta) = decode_interleaved(b);
426
427        LazyArray::from_bytes_impl(&position, &meta)
428    }
429
430    #[inline]
431    fn write_to_bytes(self, b: &mut [u8; 16]) {
432        match self {
433            None => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
434            Some(lazy) => lazy.write_to_bytes_impl(b),
435        }
436    }
437}
438
439/// Helper for constructing a table's serialization (also see `Table`).
440pub(super) struct TableBuilder<I: Idx, T: FixedSizeEncoding> {
441    width: usize,
442    blocks: IndexVec<I, T::ByteArray>,
443    _marker: PhantomData<T>,
444}
445
446impl<I: Idx, T: FixedSizeEncoding> Default for TableBuilder<I, T> {
447    fn default() -> Self {
448        TableBuilder { width: 0, blocks: Default::default(), _marker: PhantomData }
449    }
450}
451
452impl<I: Idx, const N: usize, T> TableBuilder<I, Option<T>>
453where
454    Option<T>: FixedSizeEncoding<ByteArray = [u8; N]>,
455{
456    pub(crate) fn set_some(&mut self, i: I, value: T) {
457        self.set(i, Some(value))
458    }
459}
460
461impl<I: Idx, const N: usize, T: FixedSizeEncoding<ByteArray = [u8; N]>> TableBuilder<I, T> {
462    /// Sets the table value if it is not default.
463    /// ATTENTION: For optimization default values are simply ignored by this function, because
464    /// right now metadata tables never need to reset non-default values to default. If such need
465    /// arises in the future then a new method (e.g. `clear` or `reset`) will need to be introduced
466    /// for doing that explicitly.
467    pub(crate) fn set(&mut self, i: I, value: T) {
468        #[cfg(debug_assertions)]
469        {
470            if true {
    if !T::from_bytes(&[0; N]).is_default() {
        {
            ::core::panicking::panic_fmt(format_args!("expected all-zeroes to decode to the default value, as per the invariant of FixedSizeEncoding"));
        }
    };
};debug_assert!(
471                T::from_bytes(&[0; N]).is_default(),
472                "expected all-zeroes to decode to the default value, as per the invariant of FixedSizeEncoding"
473            );
474        }
475        if !value.is_default() {
476            // FIXME(eddyb) investigate more compact encodings for sparse tables.
477            // On the PR @michaelwoerister mentioned:
478            // > Space requirements could perhaps be optimized by using the HAMT `popcnt`
479            // > trick (i.e. divide things into buckets of 32 or 64 items and then
480            // > store bit-masks of which item in each bucket is actually serialized).
481            let block = self.blocks.ensure_contains_elem(i, || [0; N]);
482            value.write_to_bytes(block);
483            if self.width != N {
484                let width = N - trailing_zeros(block);
485                self.width = self.width.max(width);
486            }
487        }
488    }
489
490    pub(crate) fn encode(&self, buf: &mut FileEncoder<'_>) -> LazyTable<I, T> {
491        let pos = buf.position();
492
493        let width = self.width;
494        for block in &self.blocks {
495            buf.write_with(|dest| {
496                *dest = *block;
497                width
498            });
499        }
500
501        LazyTable::from_position_and_encoded_size(
502            NonZero::new(pos).unwrap(),
503            width,
504            self.blocks.len(),
505        )
506    }
507}
508
509fn trailing_zeros(x: &[u8]) -> usize {
510    x.iter().rev().take_while(|b| **b == 0).count()
511}
512
513impl<I: Idx, const N: usize, T: FixedSizeEncoding<ByteArray = [u8; N]> + ParameterizedOverTcx>
514    LazyTable<I, T>
515where
516    for<'tcx> T::Value<'tcx>: FixedSizeEncoding<ByteArray = [u8; N]>,
517{
518    /// Given the metadata, extract out the value at a particular index (if any).
519    pub(super) fn get<'a, 'tcx, M: MetaBlob<'a>>(&self, metadata: M, i: I) -> T::Value<'tcx> {
520        // Access past the end of the table returns a Default
521        if i.index() >= self.len {
522            return Default::default();
523        }
524
525        let width = self.width;
526        let start = self.position.get() + (width * i.index());
527        let end = start + width;
528        let bytes = &metadata.blob()[start..end];
529
530        if let Ok(fixed) = bytes.try_into() {
531            FixedSizeEncoding::from_bytes(fixed)
532        } else {
533            let mut fixed = [0u8; N];
534            fixed[..width].copy_from_slice(bytes);
535            FixedSizeEncoding::from_bytes(&fixed)
536        }
537    }
538
539    /// Size of the table in entries, including possible gaps.
540    pub(super) fn size(&self) -> usize {
541        self.len
542    }
543}