I'm trying to make a thing wrapper type for an ID
, and parse some JSON using it as my keys (rather than raw String
s).
import Foundation
// Some wrapper type
struct ID: Hashable {
let value: String
}
extension ID: Codable {
init(from decoder: Decoder) throws {
self.init(value: try decoder
.singleValueContainer()
.decode(String.self)
)
}
func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
try container.encode(value)
}
}
let testData: Dictionary<ID, Int> = [ // Note: it's a dict.
ID(value: "a.b.c"): 1,
ID(value: "com.example"): 2,
ID(value: "x.y.z"): 3,
]
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
let jsonData = try encoder.encode(testData)
print(String(data: jsonData, encoding: .utf8) ?? "<nil>")
To my surprise, this code results in an array:
[
"com.example",
2,
"x.y.z",
3,
"a.b.c",
1
]
The Yams
package has a YAMLEncoder
, which causes the same fundamental issue:
- x.y.z
- 3
- com.example
- 2
- a.b.c
- 1
Looks to me like this is a quirk of Dictionary's implementation of Codable
. I know I can get around this by not using Dict
, and using a custom wrapper type that implements Codable using a keyed container, using a custom key type. Is that the right way to do this?