Enum cases as protocol witnesses

This is something I've wanted for a long time. Here's an example from something I've been working on recently that could greatly benefit from this:

Before:

enum CommonErrorReasonCode: Int {
    // Common
    case unknown = -1
    case networkError = 17020
    case tooManyRequests = 17010
}

enum AuthErrorReasonCode: Int {
    // Common
    case unknown = -1
    case networkError = 17020
    case tooManyRequests = 17010

    // Auth-related
    case invalidCredential = 17004
    case invalidEmail = 17008
    case userDisabled = 17005
}

struct CommonError: Error {
    var reasonCode: CommonErrorReasonCode
    var localizedDescription: String
}

struct AuthError: Error {
    var reasonCode: AuthErrorReasonCode
    var localizedDescription: String
}

After:

protocol CommonErrorReasonCode {
    static var unknown: Self { get }
    static var networkError: Self { get }
    static var tooManyRequests: Self { get }
}

protocol AuthErrorReasonCode {
    static var invalidCredential: Self { get }
    static var invalidEmail: Self { get }
    static var userDisabled: Self { get }
}

enum ErrorReasonCode: Int, CommonErrorReasonCode, AuthErrorReasonCode {
    // Common
    case unknown = -1
    case networkError = 17020
    case tooManyRequests = 17010

    // Auth-related
    case invalidCredential = 17004
    case invalidEmail = 17008
    case userDisabled = 17005
}

struct Error<T>: Swift.Error {
    var reasonCode: T
    var localizedDescription: String
}

typealias CommonError = Error<CommonErrorReasonCode>
typealias AuthError = Error<CommonErrorReasonCode & AuthErrorReasonCode>

A lot easier to maintain, safer, and efficient IMO.

8 Likes