#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ContextDescriptorKind {
Module,
Extension,
Anonymous,
Protocol,
OpaqueType,
Class,
Struct,
Enum,
Other(u8),
}
impl ContextDescriptorKind {
pub(crate) fn from_bits(raw: u8) -> Self {
match raw & 0x1F {
0 => Self::Module,
1 => Self::Extension,
2 => Self::Anonymous,
3 => Self::Protocol,
4 => Self::OpaqueType,
16 => Self::Class,
17 => Self::Struct,
18 => Self::Enum,
other => Self::Other(other),
}
}
pub fn is_type(self) -> bool {
matches!(self, Self::Class | Self::Struct | Self::Enum)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ContextDescriptorFlags(pub u32);
impl ContextDescriptorFlags {
pub fn kind(self) -> ContextDescriptorKind {
ContextDescriptorKind::from_bits((self.0 & 0x1F) as u8)
}
pub fn has_invertible_protocols(self) -> bool {
(self.0 & (1 << 5)) != 0
}
pub fn is_unique(self) -> bool {
(self.0 & (1 << 6)) != 0
}
pub fn is_generic(self) -> bool {
(self.0 & (1 << 7)) != 0
}
pub fn kind_specific(self) -> u16 {
(self.0 >> 16) as u16
}
pub fn type_flags(self) -> TypeContextDescriptorFlags {
TypeContextDescriptorFlags(self.kind_specific())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MetadataInitializationKind {
None,
Singleton,
Foreign,
Other,
}
impl MetadataInitializationKind {
pub(crate) fn from_bits(raw: u8) -> Self {
match raw & 0x3 {
0 => Self::None,
1 => Self::Singleton,
2 => Self::Foreign,
_ => Self::Other,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct TypeContextDescriptorFlags(pub u16);
impl TypeContextDescriptorFlags {
pub fn metadata_initialization(self) -> MetadataInitializationKind {
MetadataInitializationKind::from_bits((self.0 & 0x3) as u8)
}
pub fn has_import_info(self) -> bool {
(self.0 & (1 << 2)) != 0
}
pub fn has_canonical_metadata_prespecializations_or_singleton(self) -> bool {
(self.0 & (1 << 3)) != 0
}
pub fn has_canonical_metadata_prespecializations(self) -> bool {
self.has_canonical_metadata_prespecializations_or_singleton()
&& !matches!(
self.metadata_initialization(),
MetadataInitializationKind::Singleton
)
}
pub fn has_singleton_metadata_pointer(self) -> bool {
self.has_canonical_metadata_prespecializations_or_singleton()
&& matches!(
self.metadata_initialization(),
MetadataInitializationKind::Singleton
)
}
pub fn has_layout_string(self) -> bool {
(self.0 & (1 << 4)) != 0
}
pub fn class_has_default_override_table(self) -> bool {
(self.0 & (1 << 6)) != 0
}
pub fn class_is_actor(self) -> bool {
(self.0 & (1 << 7)) != 0
}
pub fn class_is_default_actor(self) -> bool {
(self.0 & (1 << 8)) != 0
}
pub fn class_resilient_superclass_reference_kind(self) -> TypeReferenceKind {
TypeReferenceKind::from_bits(((self.0 >> 9) & 0x7) as u8)
}
pub fn class_immediate_members_negative(self) -> bool {
(self.0 & (1 << 12)) != 0
}
pub fn class_has_resilient_superclass(self) -> bool {
(self.0 & (1 << 13)) != 0
}
pub fn class_has_override_table(self) -> bool {
(self.0 & (1 << 14)) != 0
}
pub fn class_has_vtable(self) -> bool {
(self.0 & (1 << 15)) != 0
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TypeReferenceKind {
DirectTypeDescriptor,
IndirectTypeDescriptor,
DirectObjCClassName,
IndirectObjCClass,
Other(u8),
}
impl TypeReferenceKind {
pub(crate) fn from_bits(raw: u8) -> Self {
match raw & 0x7 {
0 => Self::DirectTypeDescriptor,
1 => Self::IndirectTypeDescriptor,
2 => Self::DirectObjCClassName,
3 => Self::IndirectObjCClass,
other => Self::Other(other),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ConformanceFlags(pub u32);
impl ConformanceFlags {
pub fn type_reference_kind(self) -> TypeReferenceKind {
TypeReferenceKind::from_bits(((self.0 >> 3) & 0x7) as u8)
}
pub fn is_retroactive(self) -> bool {
(self.0 & (1 << 6)) != 0
}
pub fn is_synthesized_non_unique(self) -> bool {
(self.0 & (1 << 7)) != 0
}
pub fn num_conditional_requirements(self) -> u8 {
((self.0 >> 8) & 0xff) as u8
}
pub fn has_resilient_witnesses(self) -> bool {
(self.0 & (1 << 16)) != 0
}
pub fn has_generic_witness_table(self) -> bool {
(self.0 & (1 << 17)) != 0
}
pub fn is_conformance_of_protocol(self) -> bool {
(self.0 & (1 << 18)) != 0
}
pub fn has_global_actor_isolation(self) -> bool {
(self.0 & (1 << 19)) != 0
}
pub fn num_conditional_pack_descriptors(self) -> u8 {
((self.0 >> 24) & 0xff) as u8
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FieldDescriptorKind {
Struct,
Class,
Enum,
MultiPayloadEnum,
Protocol,
ClassProtocol,
ObjCProtocol,
ObjCClass,
Other(u16),
}
impl FieldDescriptorKind {
pub(crate) fn from_bits(raw: u16) -> Self {
match raw {
0 => Self::Struct,
1 => Self::Class,
2 => Self::Enum,
3 => Self::MultiPayloadEnum,
4 => Self::Protocol,
5 => Self::ClassProtocol,
6 => Self::ObjCProtocol,
7 => Self::ObjCClass,
other => Self::Other(other),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct FieldRecordFlags(pub u32);
impl FieldRecordFlags {
pub fn is_indirect_case(self) -> bool {
(self.0 & (1 << 0)) != 0
}
pub fn is_var(self) -> bool {
(self.0 & (1 << 1)) != 0
}
pub fn is_artificial(self) -> bool {
(self.0 & (1 << 2)) != 0
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SwiftMethodKind {
Method,
Init,
Getter,
Setter,
ModifyCoroutine,
ReadCoroutine,
Other(u8),
}
impl SwiftMethodKind {
pub(crate) fn from_bits(raw: u8) -> Self {
match raw & 0xF {
0 => Self::Method,
1 => Self::Init,
2 => Self::Getter,
3 => Self::Setter,
4 => Self::ModifyCoroutine,
5 => Self::ReadCoroutine,
other => Self::Other(other),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct MethodDescriptorFlags(pub u32);
impl MethodDescriptorFlags {
pub fn kind(self) -> SwiftMethodKind {
SwiftMethodKind::from_bits((self.0 & 0xF) as u8)
}
pub fn is_instance(self) -> bool {
(self.0 & (1 << 4)) != 0
}
pub fn is_dynamic(self) -> bool {
(self.0 & (1 << 5)) != 0
}
pub fn is_async(self) -> bool {
(self.0 & (1 << 6)) != 0
}
pub fn has_extended_context(self) -> bool {
(self.0 & (1 << 7)) != 0
}
pub fn extra_discriminator(self) -> u16 {
(self.0 >> 16) as u16
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn context_descriptor_kind_round_trips() {
for (raw, expected) in [
(0u8, ContextDescriptorKind::Module),
(1, ContextDescriptorKind::Extension),
(2, ContextDescriptorKind::Anonymous),
(3, ContextDescriptorKind::Protocol),
(4, ContextDescriptorKind::OpaqueType),
(16, ContextDescriptorKind::Class),
(17, ContextDescriptorKind::Struct),
(18, ContextDescriptorKind::Enum),
] {
assert_eq!(ContextDescriptorKind::from_bits(raw), expected);
}
assert_eq!(
ContextDescriptorKind::from_bits(19),
ContextDescriptorKind::Other(19)
);
assert_eq!(
ContextDescriptorKind::from_bits(0xFF),
ContextDescriptorKind::Other(31)
);
}
#[test]
fn context_descriptor_flags_decode() {
let f = ContextDescriptorFlags(0x0080_0090);
assert_eq!(f.kind(), ContextDescriptorKind::Class);
assert!(f.is_generic());
assert!(!f.is_unique());
assert_eq!(f.kind_specific(), 0x0080);
}
#[test]
fn type_context_flags_class_bits() {
let t = TypeContextDescriptorFlags(0x8000); assert!(t.class_has_vtable());
assert!(!t.class_has_override_table());
assert!(!t.class_has_resilient_superclass());
}
#[test]
fn type_context_metadata_init() {
assert_eq!(
TypeContextDescriptorFlags(0).metadata_initialization(),
MetadataInitializationKind::None
);
assert_eq!(
TypeContextDescriptorFlags(1).metadata_initialization(),
MetadataInitializationKind::Singleton
);
assert_eq!(
TypeContextDescriptorFlags(2).metadata_initialization(),
MetadataInitializationKind::Foreign
);
assert_eq!(
TypeContextDescriptorFlags(3).metadata_initialization(),
MetadataInitializationKind::Other
);
}
#[test]
fn type_context_singleton_pointer_aliasing_with_bit3() {
let with_singleton = TypeContextDescriptorFlags(0b0000_1001);
assert!(with_singleton.has_singleton_metadata_pointer());
assert!(!with_singleton.has_canonical_metadata_prespecializations());
let with_canonical = TypeContextDescriptorFlags(0b0000_1000);
assert!(with_canonical.has_canonical_metadata_prespecializations());
assert!(!with_canonical.has_singleton_metadata_pointer());
}
#[test]
fn conformance_flags_decode() {
let cf = ConformanceFlags((1 << 3) | (2 << 8) | (1 << 16));
assert_eq!(
cf.type_reference_kind(),
TypeReferenceKind::IndirectTypeDescriptor
);
assert_eq!(cf.num_conditional_requirements(), 2);
assert!(cf.has_resilient_witnesses());
assert!(!cf.is_retroactive());
assert!(!cf.has_generic_witness_table());
}
#[test]
fn type_reference_kind_round_trips() {
for (raw, expected) in [
(0u8, TypeReferenceKind::DirectTypeDescriptor),
(1, TypeReferenceKind::IndirectTypeDescriptor),
(2, TypeReferenceKind::DirectObjCClassName),
(3, TypeReferenceKind::IndirectObjCClass),
] {
assert_eq!(TypeReferenceKind::from_bits(raw), expected);
}
assert_eq!(TypeReferenceKind::from_bits(7), TypeReferenceKind::Other(7));
}
#[test]
fn field_descriptor_kind_round_trips() {
assert_eq!(
FieldDescriptorKind::from_bits(0),
FieldDescriptorKind::Struct
);
assert_eq!(
FieldDescriptorKind::from_bits(7),
FieldDescriptorKind::ObjCClass
);
assert_eq!(
FieldDescriptorKind::from_bits(99),
FieldDescriptorKind::Other(99)
);
}
#[test]
fn field_record_flags_decode() {
let f = FieldRecordFlags(0b110);
assert!(!f.is_indirect_case());
assert!(f.is_var());
assert!(f.is_artificial());
}
#[test]
fn method_descriptor_flags_decode() {
let m = MethodDescriptorFlags(0xBEEF_0052);
assert_eq!(m.kind(), SwiftMethodKind::Getter);
assert!(m.is_instance());
assert!(!m.is_dynamic());
assert!(m.is_async());
assert!(!m.has_extended_context());
assert_eq!(m.extra_discriminator(), 0xBEEF);
}
}