gonzalezreal / swift-any-value

A Swift Codable type that serves as a placeholder for any JSON value
MIT License
3 stars 0 forks source link

Clever way for unpacking? #1

Open mickeyl opened 3 years ago

mickeyl commented 3 years ago

Thanks for this great package. Lets assume I have received a [String: AnyValue] from JSON and I know that the value is, say, a [[UInt8]] matrix. Is there a clever way (perhaps, through the use of generics?) to unpack those rather than explicitly looping over the contents, inspecting the type, recursing into, and constructing the desired output?

Basically what I'm after would be a (compiler-generated or at least -assisted) version that lets me write something like

let matrix: [[UInt8]] = try anyValue.value
mickeyl commented 3 years ago

This way it somewhat works, but requires that you know all type combinations upfront:

extension AnyValue {
        enum Error: Swift.Error {
            case typeMismatch(info: String)
        }

        func value<T>() throws -> T {
            switch T.self {
                case is String.Type:
                    guard case let .string(string) = self else { throw Error.typeMismatch(info: "Expected \(T.self), got \(self) instead") }
                    return string as! T
                case is Int.Type:
                    guard case let .int(int) = self else { throw Error.typeMismatch(info: "Expected \(T.self), got \(self) instead") }
                    return int as! T
                case is Array<Int>.Type:
                    guard case let .array(array) = self else { throw Error.typeMismatch(info: "Expected \(T.self), got \(self) instead") }
                    return try (array.map { try $0.value() as Int }) as! T
                case is Array<Array<Int>>.Type:
                    guard case let .array(array) = self else { throw Error.typeMismatch(info: "Expected \(T.self), got \(self) instead") }
                    return try (array.map { try $0.value() as [Int] }) as! T
                default:
                    throw Error.typeMismatch(info: "No idea how to deal with \(T.self), while I'm \(self)")

                }
        }
}

I'd like to simplify this, but I don't know how to, e.g., get to the 'inner' type of an encapsulated array.