Could a task-local flag and property wrapper be used for opting in?
public enum DictionaryTaskLocals {
@TaskLocal
public static var shouldUseKeyedContainer: Bool = false
@propertyWrapper
public struct ShouldUseKeyedContainer<Wrapped> {
public var wrappedValue: Wrapped
public init(wrappedValue: Wrapped) {
self.wrappedValue = wrappedValue
}
}
}
They would only be available on OS versions that support the new behavior.
enum MyEnum: String, Codable { case one, two }
struct MyStruct: Codable {
@DictionaryTaskLocals.ShouldUseKeyedContainer
var array: [MyStruct]
@DictionaryTaskLocals.ShouldUseKeyedContainer
var dictionary: [MyEnum: MyStruct]
}
The property wrapper would bind to the task-local flag, and then forward calls to the dictionary.
extension DictionaryTaskLocals.ShouldUseKeyedContainer: Decodable
where Wrapped: Decodable {
public init(from decoder: Decoder) throws {
wrappedValue =
try DictionaryTaskLocals.$shouldUseKeyedContainer.withValue(true) {
try .init(from: decoder)
}
}
}
extension DictionaryTaskLocals.ShouldUseKeyedContainer: Encodable
where Wrapped: Encodable {
public func encode(to encoder: Encoder) throws {
try DictionaryTaskLocals.$shouldUseKeyedContainer.withValue(true) {
try wrappedValue.encode(to: encoder)
}
}
}
The dictionary would only attempt the new behavior if the task-local flag is set.
It would fallback to the old behavior when a keyed container isn't available.
(EDIT: Generalized the property wrapper.)