Created
April 23, 2021 15:22
-
-
Save svenmuennich/0c43b4f3cb7a7904ccf7ff0a54a71349 to your computer and use it in GitHub Desktop.
A Swift `Codable` type for representing nested data structures
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
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) | |
} | |
} | |
} |
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
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) |
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
{ | |
"foo": { | |
"bar": { | |
"baz": {} | |
}, | |
"baz": {} | |
}, | |
"bar": { | |
"baz": {} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment