Indeed, the problem is that protocols don't always conform to themselves – AnyFoo
cannot satisfy a generic placeholder T : Encodable
as AnyFoo
doesn't (currently) conform to Encodable
.
One rather sneaky workaround in your case would be to use a protocol extension on Encodable
:
extension Encodable {
fileprivate func encode(to container: inout SingleValueEncodingContainer) throws {
try container.encode(self)
}
}
struct AnyEncodable : Encodable {
var value: Encodable
init(_ value: Encodable) {
self.value = value
}
func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
try value.encode(to: &container)
}
}
let a: AnyFoo = Foo()
do {
let data = try JSONEncoder().encode(AnyEncodable(a))
print(String(decoding: data, as: UTF8.self))
} catch {
print(error)
}
// {"foo":0}
This exploits the fact that existentials (protocol-typed values) are "opened" when you call a method on them, which gives the extension implementation access to the underlying concrete type, which can then be used to satisfy the T : Encodable
placeholder for the single value container's encode(_:)
method.