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
Decoder and Visitor) to traverse each field and decode/encode into a keyed container, so folks wishing to opt into Codable can easily do this with just an extension 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?
To use SwiftProtobuf types in
SwiftDatamodels, they must conform toCodable.Suppose you have:
where
Baris a protobuf message type.We cannot simply do:
because it will crash at runtime as
SwiftDataexpects things to use a keyed container, and not a single-value one.Ofc one can implement a custom
init(from:)andencode(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:
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)
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: CodableSomething like:
Where
CodableDecoderandCodableEncoderare provided by SwiftProtobuf.They could even check for a custom
userInfokey in the provideddecoder/encoderto 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?