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 hidden or 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) | |
| } | |
| } | |
| } |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
The code synthesis algorithm for
Decodableconformance (in broad strokes) would be:Discriminatorenum that is a 1x1 mapping of the target enum's discriminators, but without any associated values, and using a rawStringtype so it can participate in automatic Codable conformance.CodingKeysenum used to create a decoding container. CodingKeys should start with a.discriminatorcase which will be used to decode theDiscriminator. For each case of the target enum that has associated values, append a case toCodingKeysfor 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.2for the third position). Prefix the names of all the associated value keys with something (perhaps the relevant discriminator) to prevent naming collisions between aCodingKeyand any associated value with an otherwise identical label (see the.anotherCaseexample 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
Encodableshould be obvious given the above description.