Skip to content

Commit

Permalink
Merge pull request #68 from wickwirew/enum-payload
Browse files Browse the repository at this point in the history
Added ability to inspect enum payload type
  • Loading branch information
wickwirew committed Apr 9, 2020
2 parents 69886eb + f157fc7 commit d563445
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 3 deletions.
7 changes: 6 additions & 1 deletion Sources/Runtime/Layouts/EnumTypeDescriptor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,12 @@ struct EnumTypeDescriptor: TypeDescriptor {
var accessFunctionPointer: RelativePointer<Int32, UnsafeRawPointer>
var fieldDescriptor: RelativePointer<Int32, FieldDescriptor>
var numPayloadCasesAndPayloadSizeOffset: UInt32
var numberOfFields: Int32 // numEmptyCases
var numEmptyCases: UInt32
var offsetToTheFieldOffsetVector: RelativeVectorPointer<Int32, Int32>
var genericContextHeader: TargetTypeGenericContextDescriptorHeader

var numberOfFields: Int32 {
get { return 0 }
set { }
}
}
22 changes: 20 additions & 2 deletions Sources/Runtime/Metadata/EnumMetadata.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,36 @@ struct EnumMetadata: NominalMetadataType {

var pointer: UnsafeMutablePointer<EnumMetadataLayout>

var numberOfPayloadCases: UInt32 {
return pointer.pointee.typeDescriptor.pointee.numPayloadCasesAndPayloadSizeOffset & 0x00FFFFFF
}

var numberOfCases: UInt32 {
return pointer.pointee.typeDescriptor.pointee.numEmptyCases + numberOfPayloadCases
}

mutating func cases() -> [Case] {
let fieldDescriptor = pointer.pointee.typeDescriptor.pointee
.fieldDescriptor
.advanced()

return (0..<fieldDescriptor.pointee.numFields).map { i in
let genericVector = genericArgumentVector()

return (0..<numberOfCases).map { i in
let record = fieldDescriptor
.pointee
.fields
.element(at: Int(i))

return Case(name: record.pointee.fieldName())
return Case(
name: record.pointee.fieldName(),
payloadType: record.pointee._mangledTypeName.offset == 0
? nil
: record.pointee.type(
genericContext: pointer.pointee.typeDescriptor,
genericArguments: genericVector
)
)
}
}

Expand Down
1 change: 1 addition & 0 deletions Sources/Runtime/Models/Case.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,5 @@
/// An enum case
public struct Case {
public let name: String
public let payloadType: Any.Type?
}
21 changes: 21 additions & 0 deletions Tests/RuntimeTests/MetadataTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,27 @@ class MetadataTests: XCTestCase {
XCTAssert(info.cases[3].name == "d")
}

func testEnumTestEnumWithPayload() {
enum Foo {
case a,b,c
case hasPayload(Int)
case hasTuplePayload(Bool, Int)
}

var md = EnumMetadata(type: Foo.self)
let info = md.toTypeInfo()

guard let hasPayload = info.cases.first(where: { $0.name == "hasPayload" }),
let hasTuplePayload = info.cases.first(where: { $0.name == "hasTuplePayload" }) else {
return XCTFail("Missing payload cases")
}

XCTAssertEqual(md.numberOfCases, 5)
XCTAssertEqual(md.numberOfPayloadCases, 2)
XCTAssert(hasPayload.payloadType == Int.self)
XCTAssert(hasTuplePayload.payloadType == (Bool, Int).self)
}

func testOptional() throws {
let info = try typeInfo(of: Double?.self)
XCTAssert(info.cases[0].name == "some")
Expand Down

0 comments on commit d563445

Please sign in to comment.