How to encode objects of unknown type?

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.

7 Likes