Skip to content

Instantly share code, notes, and snippets.

@kateinoigakukun
Created June 24, 2019 15:43
Show Gist options
  • Save kateinoigakukun/7f59e8b442045ac1fb3c207328ae05b3 to your computer and use it in GitHub Desktop.
Save kateinoigakukun/7f59e8b442045ac1fb3c207328ae05b3 to your computer and use it in GitHub Desktop.
struct RelativePointer<Pointee> {
let offset: Int32
mutating func advanced() -> UnsafeMutablePointer<Pointee> {
withUnsafePointer(to: &self) { [offset] ptr in
let raw = UnsafeRawPointer(ptr)
let advanced = raw.advanced(by: Int(offset))
let pointer = advanced.assumingMemoryBound(to: Pointee.self)
return UnsafeMutablePointer(mutating: pointer)
}
}
}
struct VectorPointer<Pointee> {
let offset: Int32
mutating func vector(size: Int) -> [Pointee] {
withUnsafePointer(to: &self) { ptr in
let base = UnsafeRawPointer(ptr).assumingMemoryBound(to: Pointee.self)
return (0..<size).map { base.advanced(by: $0).pointee }
}
}
mutating func map<U>(size: Int, transform: (UnsafeMutablePointer<Pointee>) -> U) -> [U] {
withUnsafePointer(to: &self) { ptr in
let base = UnsafeRawPointer(ptr).assumingMemoryBound(to: Pointee.self)
return (0..<size).map {
transform(UnsafeMutablePointer(mutating: base.advanced(by: $0)))
}
}
}
}
struct StructMetadata {
var kind: Int
var nominalTypeDescriptor: UnsafeMutablePointer<StructDescriptor>
}
struct StructDescriptor {
let sp1, sp2: Int64
var fieldDescriptor: RelativePointer<FieldDescriptor>
var numberOfFields: Int32
}
struct FieldDescriptor {
var mangledTypeName: RelativePointer<CChar>
var sp1: Int32
let sp2: Int32
var numFields: Int32
var fields: VectorPointer<FieldRecord>
}
struct FieldRecord {
let sp: Int32
var mangledTypeName: RelativePointer<CChar>
var fieldName: RelativePointer<CChar>
}
func properties(of type: Any.Type) -> [(name: String, typeName: String)] {
let metadata = unsafeBitCast(type, to: UnsafeMutablePointer<StructMetadata>.self)
let numberOfFields = Int(metadata.pointee.nominalTypeDescriptor.pointee.numberOfFields)
return metadata.pointee.nominalTypeDescriptor.pointee
.fieldDescriptor.advanced().pointee
.fields
.map(size: numberOfFields) { record -> (String, String) in
let mangledTypeName = String(
cString: record.pointee.mangledTypeName.advanced()
)
return (
String(cString: record.pointee.fieldName.advanced()),
_typeByName(mangledTypeName).map { _typeName($0) } ?? mangledTypeName
)
}
}
struct Foo {
let name: String
}
print(properties(of: Foo.self))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment