Last active
December 22, 2022 19:26
-
-
Save ApoorvKhatreja/5b7fba5689db7958652fd3d3fc7b5109 to your computer and use it in GitHub Desktop.
A Swift enum that represents a valid JSON value, that is equatable and supports implicit type conversion. Instead of parsing to [String: Any], parse to [String: JSONValue], and enjoy type safety.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
enum JSONValue: Equatable, | |
ExpressibleByStringLiteral, | |
ExpressibleByFloatLiteral, | |
ExpressibleByIntegerLiteral, | |
ExpressibleByDictionaryLiteral, | |
ExpressibleByArrayLiteral, | |
ExpressibleByBooleanLiteral, | |
ExpressibleByNilLiteral, | |
RawRepresentable { | |
typealias RawValue = Any | |
case string(String) | |
case number(Float) | |
case object([String: JSONValue]) | |
case array([JSONValue]) | |
case boolean(Bool) | |
case null(NSNull) | |
init(stringLiteral value: String) { | |
self = .string(value) | |
} | |
init(floatLiteral value: Float) { | |
self = .number(value) | |
} | |
init(integerLiteral value: Int) { | |
self = .number(Float(value)) | |
} | |
init(dictionaryLiteral elements: (String, JSONValue)...) { | |
self = .object(Dictionary(uniqueKeysWithValues: elements)) | |
} | |
init(arrayLiteral elements: JSONValue...) { | |
self = .array(elements) | |
} | |
init(booleanLiteral value: Bool) { | |
self = .boolean(value) | |
} | |
init(nilLiteral: ()) { | |
self = .null(NSNull()) | |
} | |
init?(rawValue: RawValue) { | |
switch rawValue { | |
case let string as String: | |
self = .string(string) | |
case let number as Float: | |
self = .number(number) | |
case let number as Int: | |
self = .number(Float(number)) | |
case let object as [String: JSONValue]: | |
self = .object(object) | |
case let array as [JSONValue]: | |
self = .array(array) | |
case let boolean as Bool: | |
self = .boolean(boolean) | |
case let null as NSNull: | |
self = .null(null) | |
default: | |
return nil | |
} | |
} | |
var rawValue: Any { | |
switch self { | |
case .string(let string): | |
return string | |
case .number(let number): | |
return number | |
case .object(let object): | |
return rawValue(for: object) | |
case .array(let array): | |
return rawValue(for: array) | |
case .boolean(let boolean): | |
return boolean | |
case .null(let null): | |
return null | |
} | |
} | |
private func rawValue(for object: [String: JSONValue]) -> [String: Any] { | |
var terminalRawValue: [String: Any] = [:] | |
for (key, jsonValue) in object { | |
terminalRawValue[key] = jsonValue.rawValue | |
} | |
return terminalRawValue | |
} | |
private func rawValue(for array: [JSONValue]) -> [Any] { | |
var terminalRawValue: [Any] = [] | |
for jsonValue in array { | |
terminalRawValue.append(jsonValue.rawValue) | |
} | |
return terminalRawValue | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Sample usage: