Skip to content

Instantly share code, notes, and snippets.

@lokshunhung
Created April 9, 2023 15:13
Show Gist options
  • Save lokshunhung/ebd1762caa1172e2f7eea5438873322f to your computer and use it in GitHub Desktop.
Save lokshunhung/ebd1762caa1172e2f7eea5438873322f to your computer and use it in GitHub Desktop.
Swift 5 Type Metadata
import Foundation
// https://github.com/apple/swift/blob/main/include/swift/ABI/MetadataKind.def
struct MetadataKind: Equatable {
var rawValue: UInt
/// A class type.
static var `class`: Self {
.init(rawValue: 0) }
/// A struct type.
static var `struct`: Self {
.init(rawValue: 0 | k.MetadataKindIsNonHeap) }
/// An enum type.
/// If we add reference enums, that needs to go here.
static var `enum`: Self {
.init(rawValue: 1 | k.MetadataKindIsNonHeap) }
/// An optional type.
static var `optional`: Self {
.init(rawValue: 2 | k.MetadataKindIsNonHeap) }
/// A foreign class, such as a Core Foundation class.
static var `foreignClass`: Self {
.init(rawValue: 3 | k.MetadataKindIsNonHeap) }
/// A non-Swift non-Objective-C class type.
static var `foreignReferenceType`: Self {
.init(rawValue: 4 | k.MetadataKindIsNonHeap) }
/// A type whose value is not exposed in the metadata system.
static var `opaque`: Self {
.init(rawValue: 0 | k.MetadataKindIsRuntimePrivate | k.MetadataKindIsNonHeap) }
/// A tuple.
static var `tuple`: Self {
.init(rawValue: 1 | k.MetadataKindIsRuntimePrivate | k.MetadataKindIsNonHeap) }
/// A monomorphic function.
static var `function`: Self {
.init(rawValue: 2 | k.MetadataKindIsRuntimePrivate | k.MetadataKindIsNonHeap) }
/// An existential type.
static var `existential`: Self {
.init(rawValue: 3 | k.MetadataKindIsRuntimePrivate | k.MetadataKindIsNonHeap) }
/// A metatype.
static var `metatype`: Self {
.init(rawValue: 4 | k.MetadataKindIsRuntimePrivate | k.MetadataKindIsNonHeap) }
/// An ObjC class wrapper.
static var `objCClassWrapper`: Self {
.init(rawValue: 5 | k.MetadataKindIsRuntimePrivate | k.MetadataKindIsNonHeap) }
/// An existential metatype.
static var `existentialMetatype`: Self {
.init(rawValue: 6 | k.MetadataKindIsRuntimePrivate | k.MetadataKindIsNonHeap) }
/// An extended existential type.
static var `extendedExistential`: Self {
.init(rawValue: 7 | k.MetadataKindIsRuntimePrivate | k.MetadataKindIsNonHeap) }
/// A heap-allocated local variable using statically-generated metadata.
static var `heapLocalVariable`: Self {
.init(rawValue: 0 | k.MetadataKindIsNonType) }
/// A heap-allocated local variable using runtime-instantiated metadata.
static var `heapGenericLocalVariable`: Self {
.init(rawValue: 0 | k.MetadataKindIsNonType | k.MetadataKindIsRuntimePrivate) }
/// A native error object.
static var `errorObject`: Self {
.init(rawValue: 1 | k.MetadataKindIsNonType | k.MetadataKindIsRuntimePrivate) }
/// A heap-allocated task.
static var `task`: Self {
.init(rawValue: 2 | k.MetadataKindIsNonType | k.MetadataKindIsRuntimePrivate) }
/// A non-task async job.
static var `job`: Self {
.init(rawValue: 3 | k.MetadataKindIsNonType | k.MetadataKindIsRuntimePrivate) }
}
extension MetadataKind: CustomStringConvertible {
var description: String {
switch self {
case .class: return "class"
case .struct: return "struct"
case .enum: return "enum"
case .optional: return "optional"
case .foreignClass: return "foreignClass"
case .foreignReferenceType: return "foreignReferenceType"
case .opaque: return "opaque"
case .tuple: return "tuple"
case .function: return "function"
case .existential: return "existential"
case .metatype: return "metatype"
case .objCClassWrapper: return "objCClassWrapper"
case .existentialMetatype: return "existentialMetatype"
case .extendedExistential: return "extendedExistential"
case .heapLocalVariable: return "heapLocalVariable"
case .heapGenericLocalVariable: return "heapGenericLocalVariable"
case .errorObject: return "errorObject"
case .task: return "task"
case .job: return "job"
default: return "unknown"
}
}
}
extension MetadataKind {
/// https://github.com/apple/swift/blob/main/include/swift/ABI/MetadataValues.h
enum k {
/// Non-type metadata kinds have this bit set.
/// This flags is negative because the "class" kind has to be zero,
/// and class metadata is both type and heap metadata.
static let MetadataKindIsNonType: UInt = 0x400
/// Non-heap metadata kinds have this bit set.
/// This flags is negative because the "class" kind has to be zero,
/// and class metadata is both type and heap metadata.
static let MetadataKindIsNonHeap: UInt = 0x200;
/// Runtime-private metadata has this bit set. The compiler must not statically
/// generate metadata objects with these kinds, and external tools should not
/// rely on the stability of these values or the precise binary layout of
/// their associated data structures.
static let MetadataKindIsRuntimePrivate: UInt = 0x100;
}
}
func getTypeMetadata<T>(_ type: T.Type) -> String {
let ptr = unsafeBitCast(type, to: UnsafeRawPointer.self)
let kind = ptr.load(as: MetadataKind.self)
return kind.description
}
let type = (Int, Bool).self
print(getTypeMetadata(type)) // "tuple"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment