Reputation: 2033
I've been using Codable enums to encode my classes to JSON, and I've hit a roadblock:
enum MyEnum: Codable {
case case1(data: Data)
case case2(str: String)
case case3(url: URL)
}
// ...
myFunc(myEnumType: MyEnum.case1)
func myFunc(
myEnumType: MyEnum // ?
) -> MyEnum {
switch myEnumType {
case .case1:
// insert processing...
return myEnumType(data: ...)
case .case2:
// ...
return myEnumType(str: ...)
case .case3:
// ...
return myEnumType(url: ...)
}
}
Because MyEnum.case1
is of type function
, I couldn't use MyEnum
, so I had to resort to this very ugly solution[1] [2] [3]:
enum MyEnum: Codable {
case case1(data: Data)
case case2(str: String)
case case3(url: URL)
}
// :(
enum MyEnumType {
case case1
case case2
case case3
}
// ...
func myFunc(
myEnumType: MyEnumType // :(
) -> MyEnum {
How can I pass my case to the function as a parameter?
This is what I don't want:
typealias MyEnumType<Arg1> = (Arg1) -> MyEnum
As this could just be any function returning MyEnum
. This doesn't guarantee it's a case
of MyEnum
.
myFunc(myEnumType: MyEnum.case1(data: dummyData))
I don't want to initialize the case with dummy data. myFunc
is the one that's supposed to initialize the case with actual data, then return the initialized case.
myFunc(myEnumType: MyEnum)
This is irrelevant: I want to know what case
I'm looking at in the function in order to init each enum
uniquely.
Something like:
func myFunc<T>(myEnumType: MyEnum.T) -> MyEnum {
Which ensures the uninitialized case I've passed to the function is indeed a case of the MyEnum
enum.
I'm open to changing the function call or the function, as long as I'm not initializing the case or having to redeclare every case.
Upvotes: 2
Views: 75
Reputation: 274835
In your "ideal solution", you mention a nested type MyEnum.T
. This can be generated by a macro. Here is an example implementation:
// declaration:
@attached(member, names: named(T))
public macro RawCases() = #externalMacro(module: "...", type: "RawCases")
// implementation:
enum RawCases: MemberMacro {
static func expansion(of node: AttributeSyntax, providingMembersOf declaration: some DeclGroupSyntax, in context: some MacroExpansionContext) throws -> [DeclSyntax] {
let caseNames = declaration.memberBlock.members
.compactMap { $0.decl.as(EnumCaseDeclSyntax.self) }
.flatMap(\.elements)
.map(\.name)
return [DeclSyntax(
try EnumDeclSyntax("enum T") {
for name in caseNames {
"case \(name)"
}
}
)]
}
}
Usage:
@RawCases
enum MyEnum: Codable {
case case1(data: Data)
case case2(str: String)
case case3(url: URL)
}
func f(_ value: MyEnum.T) -> MyEnum {
switch value {
case .case1:
.case1(data: Data([1, 2, 3]))
case .case2:
.case2(str: "Something")
case .case3:
.case3(url: URL(filePath: "/foo/bar"))
}
}
Upvotes: 1