@@ -1,12 +1,7 @@
//
//
// 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 {
import Foundation
private struct JSONCodingKeys : CodingKey {
var stringValue : String
init ( stringValue: String ) {
@@ -23,12 +18,12 @@ struct JSONCodingKeys: CodingKey {
extension KeyedDecodingContainer {
func decode( _ type: [ String : Any ] . Type, forKey key: K ) throws -> [ String : Any ] {
let container = try self . nestedContainer ( keyedBy: JSONCodingKeys . self, forKey: key)
let container = try 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)
var container = try nestedUnkeyedContainer ( forKey: key)
return try container. decode ( type)
}
@@ -38,16 +33,20 @@ extension KeyedDecodingContainer {
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 stringValue = try ? decode ( String . self, forKey: key) {
dictionary [ key. stringValue] = stringValue
} 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
} else if let isValueNil = try ? decodeNil ( forKey: key) , isValueNil == true {
dictionary [ key. stringValue] = nil
} else {
throw DecodingError . dataCorrupted ( DecodingError . Context ( codingPath: codingPath + [ key] , debugDescription: " Unable to decode value " ) )
}
}
return dictionary
@@ -59,37 +58,42 @@ extension UnkeyedDecodingContainer {
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 value = try ? decode ( Double . self) {
array. append ( value)
} else if let nestedDictionary = try ? decode ( [ String : Any ] . self) {
array. append ( nestedDictionary)
} else if let nestedArray = try ? decode ( [ Any ] . self) {
} else if let nestedArray = try ? decodeNestedArray ( [ Any ] . self) {
array. append ( nestedArray)
} else if let isValueNil = try ? decodeNil ( ) , isValueNil == true {
array. append ( Optional < Any > . none as Any )
} else {
throw DecodingError . dataCorrupted ( DecodingError . Context ( codingPath: codingPath, debugDescription: " Unable to decode value " ) )
}
}
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)
let container = try nestedContainer ( keyedBy: JSONCodingKeys . self)
return try container. decode ( type)
}
mutating func decodeNestedArray( _ type: [ Any ] . Type) throws -> [ Any ] {
var container = try nestedUnkeyedContainer ( )
return try container. decode ( type)
}
}
extension KeyedEncodingContainerProtocol where Key == JSONCodingKeys {
mutating func encode( _ value: [ String : Any ] ) throws {
try value . forEach ( { ( key, value) in
for ( key, value) in value {
let key = JSONCodingKeys ( stringValue: key)
switch value {
case let value as Bool :
@@ -100,8 +104,6 @@ extension KeyedEncodingContainerProtocol where Key == JSONCodingKeys {
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 ] :
@@ -111,29 +113,29 @@ extension KeyedEncodingContainerProtocol where Key == JSONCodingKeys {
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! )
}
guard let value = value else { return }
var container = 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! )
}
guard let value = value else { return }
var container = nestedUnkeyedContainer ( forKey : key )
try container . encode ( value )
}
}
extension UnkeyedEncodingContainer {
mutating func encode( _ value: [ Any ] ) throws {
try value . enumerated ( ) . forEach ( { ( index, value) in
for ( index, value) in value . enumerated ( ) {
switch value {
case let value as Bool :
try encode ( value)
@@ -143,23 +145,26 @@ extension UnkeyedEncodingContainer {
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)
try encodeNestedArray ( 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)
var container = nestedContainer ( keyedBy: JSONCodingKeys . self)
try container . encode ( value)
}
}
mutating func encodeNestedArray( _ value: [ Any ] ) throws {
var container = nestedUnkeyedContainer ( )
try container. encode ( value)
}
}