Skip to content

Instantly share code, notes, and snippets.

@svenmuennich
Created April 23, 2021 15:22
Show Gist options
  • Save svenmuennich/0c43b4f3cb7a7904ccf7ff0a54a71349 to your computer and use it in GitHub Desktop.
Save svenmuennich/0c43b4f3cb7a7904ccf7ff0a54a71349 to your computer and use it in GitHub Desktop.
A Swift `Codable` type for representing nested data structures
internal class Foo: Codable {
internal struct CodingKey: Swift.CodingKey {
internal let stringValue: String
internal let intValue: Int?
internal init?(stringValue: String) {
self.stringValue = stringValue
self.intValue = Int(stringValue)
}
internal init?(intValue: Int) {
self.stringValue = String(intValue)
self.intValue = intValue
}
}
internal let key: String
internal var children: [Foo]
internal init(path: String, children: [Foo] = []) {
self.key = path
self.children = children
}
// MARK: - Decodable
internal required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKey.self)
guard let key = container.allKeys.first else {
throw DecodingError.dataCorrupted(.init(
codingPath: decoder.codingPath,
debugDescription: "Invalid structure."
))
}
self.key = key.stringValue
self.children = try container.decode([Foo].self, forKey: key)
}
// MARK: - Encodable
internal func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKey.self)
for child in self.children {
guard let codingKey = CodingKey(stringValue: child.key) else {
throw EncodingError.invalidValue(
child.key,
.init(
codingPath: encoder.codingPath,
debugDescription: "Failed to make coding key from \(child.key)"
)
)
}
try container.encode(child, forKey: codingKey)
}
}
}
let baz = Foo(key: "baz")
let bar = Foo(key: "bar", children: [baz])
let foo = Foo(key: "foo", children: [bar, baz])
let root = Foo(key: ".", children: [foo, bar])
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
let result = String(data: try! encoder.encode(root), encoding: .utf8)
print(result)
{
"foo": {
"bar": {
"baz": {}
},
"baz": {}
},
"bar": {
"baz": {}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment