swiftgenericsswift-protocols

if-let Any to RawRepresentable<String>


Let's assume this:

enum MyEnum: String { case value }
let possibleEnum: Any = MyEnum.value
if let str = stringFromPossibleEnum(possibleEnum: possibleEnum)

What's my best bet of implementing stringFromPossibleEnum without knowing enum type name?

func stringFromPossibleEnum(possibleEnum: Any) -> String? {
//    how should this be implemented without knowing enum type name?
}

UPD: ok, it's getting better, with this I can tell if possibleEnum is an enum:

if Mirror(reflecting: possibleEnum).displayStyle == .enum { print("yes!") }

But how to tell if that's a String-based enum?

UPD: this tweet suggests that you can get rawValue as Any from Enum. You can probably then check if that rawValue is String. But how to get rawValue from Mirror?


Solution

  • Ok, so this is basically not doable currently out of the box, as you can't as?-cast to RawRepresentable, and Mirror does not provide rawValue for enums.

    I'd say the best bet is to make own protocol, provide default implementation for String-based RawRepresentable and conform all enums manually like so:

    Assuming these are the enums:

    enum E1: String { case one }
    enum E2: String { case two }
    enum E3: String { case three }
    

    StringRawRepresentable protocol and default implementation:

    protocol StringRawRepresentable {
        var stringRawValue: String { get }
    }
    
    extension StringRawRepresentable 
    where Self: RawRepresentable, Self.RawValue == String {
        var stringRawValue: String { return rawValue }
    }
    

    Conform all needed existing enums to the protocol:

    extension E1: StringRawRepresentable {}
    extension E2: StringRawRepresentable {}
    extension E3: StringRawRepresentable {}
    

    And now we can cast to StringRawRepresentable:

    func stringFromPossibleEnum(possibleEnum: Any) -> String? {
        if let e = possibleEnum as? StringRawRepresentable { return e.stringRawValue }
        return nil
    }
    
    stringFromPossibleEnum(possibleEnum: E2.two as Any)