Created
June 24, 2019 15:43
-
-
Save kateinoigakukun/7f59e8b442045ac1fb3c207328ae05b3 to your computer and use it in GitHub Desktop.
This file contains 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
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