Skip to content

ErrorEnvelope: Codable, make it possible to encode and carry a Codable error #512

@ktoso

Description

@ktoso

Complete this basically:

public struct ErrorEnvelope: Error, ActorMessage {
    public let error: Error

    public init<Failure: Error>(_ error: Failure) {
        if let codableError = error as? (Error & Codable) {
            self.error = codableError
        } else {
            // we we can at least carry the error type (not the whole string repr, since it may have information we'd rather not share though)
            self.error = BestEffortStringError(representation: String(reflecting: Failure.self))
        }
    }

    // this is a cop out if we want to send back a message or just type name etc
    public init(description: String) {
        self.error = BestEffortStringError(representation: description)
    }

    enum CodingKeys: CodingKey {
        case manifest
        case error
    }

    public init(from decoder: Decoder) throws {
        guard let context = decoder.actorSerializationContext else {
            throw SerializationError.missingSerializationContext(ErrorEnvelope.self, details: "While decoding [\(ErrorEnvelope.self)], using [\(decoder)]")
        }

        let container = try decoder.container(keyedBy: CodingKeys.self)
        let manifest = try container.decode(Serialization.Manifest.self, forKey: .manifest)

        // FIXME: implement being able to encode and carry Codable errors
//        // FIXME: serialization should offer to more easily perform manifest deserialization of a Codable inside another one
//        if let ErrorType = try context.summonType(from: manifest) as? Codable.Type {
//            ErrorType._decode(from: &bytes, using: JSONDecoder())
//
//            self.error = error
//        } else {
//            throw SerializationError.unableToDeserialize(hint: "Unable to summon Codable type for \(manifest)")
//        }
        let error = try container.decode(BestEffortStringError.self, forKey: .error)
        self.error = error
    }

    // FIXME: this likely fails in some cases
    public func encode(to encoder: Encoder) throws {
        guard let context: Serialization.Context = encoder.actorSerializationContext else {
            throw SerializationError.missingSerializationContext(ErrorEnvelope.self, details: "While encoding [\(ErrorEnvelope.self)], using [\(encoder)]")
        }

        var container = encoder.container(keyedBy: CodingKeys.self)

        // FIXME: implement being able to encode and carry Codable errors (!)
//        if let codableError = self.error as? Codable {
//            try container.encode(context.outboundManifest(type(of: self.error as Any)), forKey: .manifest)
//            try container.encode(codableError, forKey: .error)
//        } else {
        try container.encode(context.outboundManifest(BestEffortStringError.self), forKey: .manifest)
        try container.encode(BestEffortStringError(representation: "\(type(of: self.error as Any))"), forKey: .error)
//        }

    }
}

May need more API on Serialization to work with Data.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions