Last active
January 22, 2022 00:23
-
-
Save jaredsinclair/6a6754dd7a49f2f8f2d4222385bf42a3 to your computer and use it in GitHub Desktop.
[Notion]: Automatic Codable synthesis for Enums with Codable associated values.
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
enum MyEnum: Codable { | |
case foo | |
case bar(Int) | |
case baz(label: String) | |
case qux(Bool, label: String, Int) | |
case anotherCase(discriminator: String, anotherCase_1: Int) | |
} | |
// Begin synthesized code... | |
extension MyEnum { | |
enum Discriminator: String, Codable { | |
case foo, bar, baz, qux, anotherCase | |
} | |
enum CodingKeys: String, CodingKey { | |
case discriminator | |
case bar_arg0 | |
case baz_label | |
case qux_arg0, qux_label, qux_arg2 | |
case anotherCase_discriminator, anotherCase_anotherCase_1 | |
} | |
init(from decoder: Decoder) throws { | |
let container = try decoder.container(keyedBy: CodingKeys.self) | |
let discriminator = try container.decode(Discriminator.self, forKey: .discriminator) | |
switch discriminator { | |
case .foo: | |
self = .foo | |
case .bar: | |
let arg0 = try container.decode(Int.self, forKey: .bar_arg0) | |
self = .bar(arg0) | |
case .baz: | |
let label = try container.decode(String.self, forKey: .baz_label) | |
self = .baz(label: label) | |
case .qux: | |
let arg0 = try container.decode(Bool.self, forKey: .qux_arg0) | |
let label = try container.decode(String.self, forKey: .qux_label) | |
let arg2 = try container.decode(Int.self, forKey: .qux_arg2) | |
self = .qux(arg0, label: label, arg2) | |
case .anotherCase: | |
let discriminator = try container.decode(String.self, forKey: .anotherCase_discriminator) | |
let anotherCase_1 = try container.decode(Int.self, forKey: .anotherCase_anotherCase_1) | |
self = .anotherCase(discriminator: discriminator, anotherCase_1: anotherCase_1) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
The code synthesis algorithm for
Decodable
conformance (in broad strokes) would be:Discriminator
enum that is a 1x1 mapping of the target enum's discriminators, but without any associated values, and using a rawString
type so it can participate in automatic Codable conformance.CodingKeys
enum used to create a decoding container. CodingKeys should start with a.discriminator
case which will be used to decode theDiscriminator
. For each case of the target enum that has associated values, append a case toCodingKeys
for each associated value. If an associated value has a label, use the label as the key. If not, use the index of the associated value's position in the list of values (e.g.2
for the third position). Prefix the names of all the associated value keys with something (perhaps the relevant discriminator) to prevent naming collisions between aCodingKey
and any associated value with an otherwise identical label (see the.anotherCase
example above). Using the relevant discriminator as a prefix also prevents naming collisions between synthesized CodingKeys (the alternative would be to enforce uniquing of the synthesized keys, re-using keys across cases as needed).init(from:)
, first by decoding the Discriminator. Switch on the discriminator, implementing each case so that it attempts to decode only associated values for the relevant case of the target enum. There should already be the required CodingKey cases necessary to perform this decoding. Once all associated values are decoded (if any), decoding is complete.The corresponding synthesis for
Encodable
should be obvious given the above description.