Created
January 25, 2019 21:46
-
-
Save mikebuss/17142624da4baf9cdcc337861e256533 to your computer and use it in GitHub Desktop.
Revisions
-
mikebuss created this gist
Jan 25, 2019 .There are no files selected for viewing
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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,165 @@ // // // Adapted from: // // Original: https://gist.github.com/loudmouth/332e8d89d8de2c1eaf81875cfcd22e24 // Adds encoding: https://github.com/3D4Medical/glTFSceneKit/blob/master/Sources/glTFSceneKit/GLTF/JSONCodingKeys.swift // Adds fix for null inside arrays causing infinite loop: https://gist.github.com/loudmouth/332e8d89d8de2c1eaf81875cfcd22e24#gistcomment-2807855 // struct JSONCodingKeys: CodingKey { var stringValue: String init(stringValue: String) { self.stringValue = stringValue } var intValue: Int? init?(intValue: Int) { self.init(stringValue: "\(intValue)") self.intValue = intValue } } extension KeyedDecodingContainer { func decode(_ type: [String: Any].Type, forKey key: K) throws -> [String: Any] { let container = try self.nestedContainer(keyedBy: JSONCodingKeys.self, forKey: key) return try container.decode(type) } func decode(_ type: [Any].Type, forKey key: K) throws -> [Any] { var container = try self.nestedUnkeyedContainer(forKey: key) return try container.decode(type) } func decode(_ type: [String: Any].Type) throws -> [String: Any] { var dictionary = [String: Any]() for key in allKeys { if let boolValue = try? decode(Bool.self, forKey: key) { dictionary[key.stringValue] = boolValue } else if let stringValue = try? decode(String.self, forKey: key) { dictionary[key.stringValue] = stringValue } else if let intValue = try? decode(Int.self, forKey: key) { dictionary[key.stringValue] = intValue } else if let doubleValue = try? decode(Double.self, forKey: key) { dictionary[key.stringValue] = doubleValue } else if let nestedDictionary = try? decode([String: Any].self, forKey: key) { dictionary[key.stringValue] = nestedDictionary } else if let nestedArray = try? decode([Any].self, forKey: key) { dictionary[key.stringValue] = nestedArray } } return dictionary } } extension UnkeyedDecodingContainer { mutating func decode(_ type: [Any].Type) throws -> [Any] { var array: [Any] = [] while isAtEnd == false { let value: String? = try decode(String?.self) if value == nil { continue } if let value = try? decode(Bool.self) { array.append(value) } else if let value = try? decode(Int.self) { array.append(value) } else if let value = try? decode(Double.self) { array.append(value) } else if let value = try? decode(String.self) { array.append(value) } else if let nestedDictionary = try? decode([String: Any].self) { array.append(nestedDictionary) } else if let nestedArray = try? decode([Any].self) { array.append(nestedArray) } } return array } mutating func decode(_ type: [String: Any].Type) throws -> [String: Any] { let nestedContainer = try self.nestedContainer(keyedBy: JSONCodingKeys.self) return try nestedContainer.decode(type) } } extension KeyedEncodingContainerProtocol where Key == JSONCodingKeys { mutating func encode(_ value: [String: Any]) throws { try value.forEach({ (key, value) in let key = JSONCodingKeys(stringValue: key) switch value { case let value as Bool: try encode(value, forKey: key) case let value as Int: try encode(value, forKey: key) case let value as String: try encode(value, forKey: key) case let value as Double: try encode(value, forKey: key) case let value as CGFloat: try encode(value, forKey: key) case let value as [String: Any]: try encode(value, forKey: key) case let value as [Any]: try encode(value, forKey: key) case Optional<Any>.none: try encodeNil(forKey: key) default: throw EncodingError.invalidValue(value, EncodingError.Context(codingPath: codingPath + [key], debugDescription: "Invalid JSON value")) } }) } } extension KeyedEncodingContainerProtocol { mutating func encode(_ value: [String: Any]?, forKey key: Key) throws { if value != nil { var container = self.nestedContainer(keyedBy: JSONCodingKeys.self, forKey: key) try container.encode(value!) } } mutating func encode(_ value: [Any]?, forKey key: Key) throws { if value != nil { var container = self.nestedUnkeyedContainer(forKey: key) try container.encode(value!) } } } extension UnkeyedEncodingContainer { mutating func encode(_ value: [Any]) throws { try value.enumerated().forEach({ (index, value) in switch value { case let value as Bool: try encode(value) case let value as Int: try encode(value) case let value as String: try encode(value) case let value as Double: try encode(value) case let value as CGFloat: try encode(value) case let value as [String: Any]: try encode(value) case let value as [Any]: try encode(value) case Optional<Any>.none: try encodeNil() default: let keys = JSONCodingKeys(intValue: index).map({ [ $0 ] }) ?? [] throw EncodingError.invalidValue(value, EncodingError.Context(codingPath: codingPath + keys, debugDescription: "Invalid JSON value")) } }) } mutating func encode(_ value: [String: Any]) throws { var nestedContainer = self.nestedContainer(keyedBy: JSONCodingKeys.self) try nestedContainer.encode(value) } }