Problem with Encoder.singleValueContainer

I think the following is correct:

public extension LosslessStringConvertible where Self: Encodable {
    func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        try container.encode("\(self)")
    }
}
public extension LosslessStringConvertible where Self: Decodable {
    init(from decoder: Decoder) throws {
        let stringRep = try decoder.singleValueContainer().decode(String.self)
        self.init(stringRep)!
    }
}

// Opt in.
extension Float80: Codable {}

// Test.
import Foundation

let f80 = Float80(3.142)
let encodedData = try JSONEncoder().encode(f80)
print(String(data: encodedData, encoding: .utf8)!)

let decodedF80 = try JSONDecoder().decode(Float80.self, from: encodedData)
print(decodedF80 == f80)

Unfortunately the encoding fails at runtime with the error:

Thread 1: Fatal error: Error raised at top level: Swift.EncodingError.invalidValue(3.141999999999999904, Swift.EncodingError.Context(codingPath: [], debugDescription: "Top-level Float80 encoded as string JSON fragment.", underlyingError: nil))

Is this a bug?

The issue is that JSONEncoder does not currently allow top-level fragments — you would be able to encode [f80] or {“...”: f80} but not f80 directly, unfortunately.

This is something we’d like to address at some point soon — please see Top-level \(T.self) encoded as number JSON fragment and associated threads/bugs (SR-6163) for more info.

Thanks