-
Notifications
You must be signed in to change notification settings - Fork 499
Description
To use SwiftProtobuf types in SwiftData models, they must conform to Codable.
Suppose you have:
@Model
final class Foo {
var bar: Bar?
init(bar: Bar? = nil) {
self.bar = bar
}
}where Bar is a protobuf message type.
We cannot simply do:
extension Bar: Codable {}
public extension Message {
init(from decoder: Swift.Decoder) throws {
let container = try decoder.singleValueContainer()
let data = try container.decode(Data.self)
self = try Self(serializedBytes: data)
}
func encode(to encoder: Swift.Encoder) throws {
let data = try serializedData()
var container = encoder.singleValueContainer()
try container.encode(data)
}
}because it will crash at runtime as SwiftData expects things to use a keyed container, and not a single-value one.
Ofc one can implement a custom init(from:) and encode(to:) per each message, but this is cumbersome.
It would be possible to write the implementation in one place (like above), if there were access to field names that SwiftProtobuf already generates, yet all related APIs are internal only (like visitors or _NampingMap).
So there are two possibilities:
- make Protobuf types
Codable(the default synthesized behavior already relies on keyed containers) - this has nothing to do with how Protobuf encodes things (so might be confusing for some people)
OR (probably preferable)
- expose a way (like a custom
DecoderandVisitor) to traverse each field and decode/encode into a keyed container, so folks wishing to opt intoCodablecan easily do this with just anextension Bar: Codable
Something like:
public extension Message {
init(from decoder: Swift.Decoder) throws {
init()
try decodeMessage(decoder: CodableDecoder(decoder))
}
func encode(to encoder: Swift.Encoder) throws {
try CodableEncoder(encoder).encode(self)
}
}Where CodableDecoder and CodableEncoder are provided by SwiftProtobuf.
They could even check for a custom userInfo key in the provided decoder/encoder to decide whether to use a single container (from 1st snippet) or a keyed container - so their use case is more flexible.
Would any route be of interest to implement?