Created
April 9, 2023 15:13
-
-
Save lokshunhung/ebd1762caa1172e2f7eea5438873322f to your computer and use it in GitHub Desktop.
Swift 5 Type Metadata
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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