From 3c1c32d10f680cda2a23bb1d9dd3ccfb94bd3e8e Mon Sep 17 00:00:00 2001 From: Devin Coughlin Date: Thu, 12 Apr 2018 20:49:57 -0700 Subject: [PATCH] Fix exclusivity warnings in JSONEncoder Bring in changes from the Swift overlays to avoid exclusivity warnings. These changes come from: https://github.com/apple/swift/pull/10821 --- Foundation/JSONEncoder.swift | 624 +++++++++++++++++------------------ 1 file changed, 305 insertions(+), 319 deletions(-) diff --git a/Foundation/JSONEncoder.swift b/Foundation/JSONEncoder.swift index 3de03ea6db..bdcd479091 100644 --- a/Foundation/JSONEncoder.swift +++ b/Foundation/JSONEncoder.swift @@ -179,19 +179,6 @@ fileprivate class _JSONEncoder : Encoder { self.codingPath = codingPath } - // MARK: - Coding Path Operations - - /// Performs the given closure with the given key pushed onto the end of the current coding path. - /// - /// - parameter key: The key to push. May be nil for unkeyed containers. - /// - parameter work: The work to perform with the key in the path. - fileprivate func with(pushedKey key: CodingKey, _ work: () throws -> T) rethrows -> T { - self.codingPath.append(key) - let ret: T = try work() - self.codingPath.removeLast() - return ret - } - /// Returns whether a new element can be encoded at this coding path. /// /// `true` if an element has not yet been encoded at this coding path; `false` otherwise. @@ -313,19 +300,6 @@ fileprivate struct _JSONKeyedEncodingContainer : KeyedEncodingCon self.container = container } - // MARK: - Coding Path Operations - - /// Performs the given closure with the given key pushed onto the end of the current coding path. - /// - /// - parameter key: The key to push. May be nil for unkeyed containers. - /// - parameter work: The work to perform with the key in the path. - fileprivate mutating func with(pushedKey key: CodingKey, _ work: () throws -> T) rethrows -> T { - self.codingPath.append(key) - let ret: T = try work() - self.codingPath.removeLast() - return ret - } - // MARK: - KeyedEncodingContainerProtocol Methods public mutating func encodeNil(forKey key: Key) throws { self.container[key.stringValue._bridgeToObjectiveC()] = NSNull() } @@ -344,41 +318,42 @@ fileprivate struct _JSONKeyedEncodingContainer : KeyedEncodingCon public mutating func encode(_ value: Float, forKey key: Key) throws { // Since the float may be invalid and throw, the coding path needs to contain this key. - try self.encoder.with(pushedKey: key) { - self.container[key.stringValue._bridgeToObjectiveC()] = try self.encoder.box(value) - } + self.encoder.codingPath.append(key) + defer { self.encoder.codingPath.removeLast() } + self.container[key.stringValue._bridgeToObjectiveC()] = try self.encoder.box(value) } public mutating func encode(_ value: Double, forKey key: Key) throws { // Since the double may be invalid and throw, the coding path needs to contain this key. - try self.encoder.with(pushedKey: key) { - self.container[key.stringValue._bridgeToObjectiveC()] = try self.encoder.box(value) - } + self.encoder.codingPath.append(key) + defer { self.encoder.codingPath.removeLast() } + self.container[key.stringValue._bridgeToObjectiveC()] = try self.encoder.box(value) } public mutating func encode(_ value: T, forKey key: Key) throws { - try self.encoder.with(pushedKey: key) { - self.container[key.stringValue._bridgeToObjectiveC()] = try self.encoder.box(value) - } + self.encoder.codingPath.append(key) + defer { self.encoder.codingPath.removeLast() } + self.container[key.stringValue._bridgeToObjectiveC()] = try self.encoder.box(value) } public mutating func nestedContainer(keyedBy keyType: NestedKey.Type, forKey key: Key) -> KeyedEncodingContainer { let dictionary = NSMutableDictionary() self.container[key.stringValue._bridgeToObjectiveC()] = dictionary - return self.with(pushedKey: key) { - let container = _JSONKeyedEncodingContainer(referencing: self.encoder, codingPath: self.codingPath, wrapping: dictionary) - return KeyedEncodingContainer(container) - } + self.codingPath.append(key) + defer { self.codingPath.removeLast() } + + let container = _JSONKeyedEncodingContainer(referencing: self.encoder, codingPath: self.codingPath, wrapping: dictionary) + return KeyedEncodingContainer(container) } public mutating func nestedUnkeyedContainer(forKey key: Key) -> UnkeyedEncodingContainer { let array = NSMutableArray() self.container[key.stringValue._bridgeToObjectiveC()] = array - return self.with(pushedKey: key) { - return _JSONUnkeyedEncodingContainer(referencing: self.encoder, codingPath: self.codingPath, wrapping: array) - } + self.codingPath.append(key) + defer { self.codingPath.removeLast() } + return _JSONUnkeyedEncodingContainer(referencing: self.encoder, codingPath: self.codingPath, wrapping: array) } public mutating func superEncoder() -> Encoder { @@ -416,19 +391,6 @@ fileprivate struct _JSONUnkeyedEncodingContainer : UnkeyedEncodingContainer { self.container = container } - // MARK: - Coding Path Operations - - /// Performs the given closure with the given key pushed onto the end of the current coding path. - /// - /// - parameter key: The key to push. May be nil for unkeyed containers. - /// - parameter work: The work to perform with the key in the path. - fileprivate mutating func with(pushedKey key: CodingKey, _ work: () throws -> T) rethrows -> T { - self.codingPath.append(key) - let ret: T = try work() - self.codingPath.removeLast() - return ret - } - // MARK: - UnkeyedEncodingContainer Methods public mutating func encodeNil() throws { self.container.add(NSNull()) } @@ -447,22 +409,22 @@ fileprivate struct _JSONUnkeyedEncodingContainer : UnkeyedEncodingContainer { public mutating func encode(_ value: Float) throws { // Since the float may be invalid and throw, the coding path needs to contain this key. - try self.encoder.with(pushedKey: _JSONKey(index: self.count)) { - self.container.add(try self.encoder.box(value)) - } + self.encoder.codingPath.append(_JSONKey(index: self.count)) + defer { self.encoder.codingPath.removeLast() } + self.container.add(try self.encoder.box(value)) } public mutating func encode(_ value: Double) throws { // Since the double may be invalid and throw, the coding path needs to contain this key. - try self.encoder.with(pushedKey: _JSONKey(index: self.count)) { - self.container.add(try self.encoder.box(value)) - } + self.encoder.codingPath.append(_JSONKey(index: self.count)) + defer { self.encoder.codingPath.removeLast() } + self.container.add(try self.encoder.box(value)) } public mutating func encode(_ value: T) throws { - try self.encoder.with(pushedKey: _JSONKey(index: self.count)) { - self.container.add(try self.encoder.box(value)) - } + self.encoder.codingPath.append(_JSONKey(index: self.count)) + defer { self.encoder.codingPath.removeLast() } + self.container.add(try self.encoder.box(value)) } public mutating func nestedContainer(keyedBy keyType: NestedKey.Type) -> KeyedEncodingContainer { @@ -470,10 +432,10 @@ fileprivate struct _JSONUnkeyedEncodingContainer : UnkeyedEncodingContainer { self.container.add(dictionary) // self.count - 1 to accommodate the fact that we just pushed a container. - return self.with(pushedKey: _JSONKey(index: self.count - 1)) { - let container = _JSONKeyedEncodingContainer(referencing: self.encoder, codingPath: self.codingPath, wrapping: dictionary) - return KeyedEncodingContainer(container) - } + self.codingPath.append(_JSONKey(index: self.count - 1)) + defer { self.codingPath.removeLast() } + let container = _JSONKeyedEncodingContainer(referencing: self.encoder, codingPath: self.codingPath, wrapping: dictionary) + return KeyedEncodingContainer(container) } public mutating func nestedUnkeyedContainer() -> UnkeyedEncodingContainer { @@ -481,9 +443,10 @@ fileprivate struct _JSONUnkeyedEncodingContainer : UnkeyedEncodingContainer { self.container.add(array) // self.count - 1 to accommodate the fact that we just pushed a container. - return self.with(pushedKey: _JSONKey(index: self.count - 1)) { - return _JSONUnkeyedEncodingContainer(referencing: self.encoder, codingPath: self.codingPath, wrapping: array) - } + self.codingPath.append(_JSONKey(index: self.count - 1)) + defer { self.codingPath.removeLast() } + + return _JSONUnkeyedEncodingContainer(referencing: self.encoder, codingPath: self.codingPath, wrapping: array) } public mutating func superEncoder() -> Encoder { @@ -914,7 +877,7 @@ fileprivate class _JSONDecoder : Decoder { fileprivate let options: JSONDecoder._Options /// The path to the current point in encoding. - private(set) public var codingPath: [CodingKey] + fileprivate(set) public var codingPath: [CodingKey] /// Contextual user-provided information for use during encoding. public var userInfo: [CodingUserInfoKey : Any] { @@ -931,19 +894,6 @@ fileprivate class _JSONDecoder : Decoder { self.options = options } - // MARK: - Coding Path Operations - - /// Performs the given closure with the given key pushed onto the end of the current coding path. - /// - /// - parameter key: The key to push. May be nil for unkeyed containers. - /// - parameter work: The work to perform with the key in the path. - fileprivate func with(pushedKey key: CodingKey, _ work: () throws -> T) rethrows -> T { - self.codingPath.append(key) - let ret: T = try work() - self.codingPath.removeLast() - return ret - } - // MARK: - Decoder Methods public func container(keyedBy type: Key.Type) throws -> KeyedDecodingContainer { @@ -1063,13 +1013,14 @@ fileprivate struct _JSONKeyedDecodingContainer : KeyedDecodingCon throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(key) (\"\(key.stringValue)\").")) } - return try self.decoder.with(pushedKey: key) { - guard let value = try self.decoder.unbox(entry, as: Bool.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) - } + self.decoder.codingPath.append(key) + defer { self.decoder.codingPath.removeLast() } - return value + guard let value = try self.decoder.unbox(entry, as: Bool.self) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) } + + return value } public func decode(_ type: Int.Type, forKey key: Key) throws -> Int { @@ -1077,13 +1028,14 @@ fileprivate struct _JSONKeyedDecodingContainer : KeyedDecodingCon throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(key) (\"\(key.stringValue)\").")) } - return try self.decoder.with(pushedKey: key) { - guard let value = try self.decoder.unbox(entry, as: Int.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) - } + self.decoder.codingPath.append(key) + defer { self.decoder.codingPath.removeLast() } - return value + guard let value = try self.decoder.unbox(entry, as: Int.self) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) } + + return value } public func decode(_ type: Int8.Type, forKey key: Key) throws -> Int8 { @@ -1091,13 +1043,14 @@ fileprivate struct _JSONKeyedDecodingContainer : KeyedDecodingCon throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(key) (\"\(key.stringValue)\").")) } - return try self.decoder.with(pushedKey: key) { - guard let value = try self.decoder.unbox(entry, as: Int8.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) - } + self.decoder.codingPath.append(key) + defer { self.decoder.codingPath.removeLast() } - return value + guard let value = try self.decoder.unbox(entry, as: Int8.self) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) } + + return value } public func decode(_ type: Int16.Type, forKey key: Key) throws -> Int16 { @@ -1105,13 +1058,14 @@ fileprivate struct _JSONKeyedDecodingContainer : KeyedDecodingCon throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(key) (\"\(key.stringValue)\").")) } - return try self.decoder.with(pushedKey: key) { - guard let value = try self.decoder.unbox(entry, as: Int16.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) - } + self.decoder.codingPath.append(key) + defer { self.decoder.codingPath.removeLast() } - return value + guard let value = try self.decoder.unbox(entry, as: Int16.self) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) } + + return value } public func decode(_ type: Int32.Type, forKey key: Key) throws -> Int32 { @@ -1119,13 +1073,14 @@ fileprivate struct _JSONKeyedDecodingContainer : KeyedDecodingCon throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(key) (\"\(key.stringValue)\").")) } - return try self.decoder.with(pushedKey: key) { - guard let value = try self.decoder.unbox(entry, as: Int32.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) - } + self.decoder.codingPath.append(key) + defer { self.decoder.codingPath.removeLast() } - return value + guard let value = try self.decoder.unbox(entry, as: Int32.self) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) } + + return value } public func decode(_ type: Int64.Type, forKey key: Key) throws -> Int64 { @@ -1133,13 +1088,14 @@ fileprivate struct _JSONKeyedDecodingContainer : KeyedDecodingCon throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(key) (\"\(key.stringValue)\").")) } - return try self.decoder.with(pushedKey: key) { - guard let value = try self.decoder.unbox(entry, as: Int64.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) - } + self.decoder.codingPath.append(key) + defer { self.decoder.codingPath.removeLast() } - return value + guard let value = try self.decoder.unbox(entry, as: Int64.self) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) } + + return value } public func decode(_ type: UInt.Type, forKey key: Key) throws -> UInt { @@ -1147,13 +1103,14 @@ fileprivate struct _JSONKeyedDecodingContainer : KeyedDecodingCon throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(key) (\"\(key.stringValue)\").")) } - return try self.decoder.with(pushedKey: key) { - guard let value = try self.decoder.unbox(entry, as: UInt.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) - } + self.decoder.codingPath.append(key) + defer { self.decoder.codingPath.removeLast() } - return value + guard let value = try self.decoder.unbox(entry, as: UInt.self) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) } + + return value } public func decode(_ type: UInt8.Type, forKey key: Key) throws -> UInt8 { @@ -1161,13 +1118,14 @@ fileprivate struct _JSONKeyedDecodingContainer : KeyedDecodingCon throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(key) (\"\(key.stringValue)\").")) } - return try self.decoder.with(pushedKey: key) { - guard let value = try self.decoder.unbox(entry, as: UInt8.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) - } + self.decoder.codingPath.append(key) + defer { self.decoder.codingPath.removeLast() } - return value + guard let value = try self.decoder.unbox(entry, as: UInt8.self) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) } + + return value } public func decode(_ type: UInt16.Type, forKey key: Key) throws -> UInt16 { @@ -1175,13 +1133,14 @@ fileprivate struct _JSONKeyedDecodingContainer : KeyedDecodingCon throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(key) (\"\(key.stringValue)\").")) } - return try self.decoder.with(pushedKey: key) { - guard let value = try self.decoder.unbox(entry, as: UInt16.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) - } + self.decoder.codingPath.append(key) + defer { self.decoder.codingPath.removeLast() } - return value + guard let value = try self.decoder.unbox(entry, as: UInt16.self) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) } + + return value } public func decode(_ type: UInt32.Type, forKey key: Key) throws -> UInt32 { @@ -1189,13 +1148,14 @@ fileprivate struct _JSONKeyedDecodingContainer : KeyedDecodingCon throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(key) (\"\(key.stringValue)\").")) } - return try self.decoder.with(pushedKey: key) { - guard let value = try self.decoder.unbox(entry, as: UInt32.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) - } + self.decoder.codingPath.append(key) + defer { self.decoder.codingPath.removeLast() } - return value + guard let value = try self.decoder.unbox(entry, as: UInt32.self) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) } + + return value } public func decode(_ type: UInt64.Type, forKey key: Key) throws -> UInt64 { @@ -1203,13 +1163,14 @@ fileprivate struct _JSONKeyedDecodingContainer : KeyedDecodingCon throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(key) (\"\(key.stringValue)\").")) } - return try self.decoder.with(pushedKey: key) { - guard let value = try self.decoder.unbox(entry, as: UInt64.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) - } + self.decoder.codingPath.append(key) + defer { self.decoder.codingPath.removeLast() } - return value + guard let value = try self.decoder.unbox(entry, as: UInt64.self) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) } + + return value } public func decode(_ type: Float.Type, forKey key: Key) throws -> Float { @@ -1217,13 +1178,14 @@ fileprivate struct _JSONKeyedDecodingContainer : KeyedDecodingCon throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(key) (\"\(key.stringValue)\").")) } - return try self.decoder.with(pushedKey: key) { - guard let value = try self.decoder.unbox(entry, as: Float.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) - } + self.decoder.codingPath.append(key) + defer { self.decoder.codingPath.removeLast() } - return value + guard let value = try self.decoder.unbox(entry, as: Float.self) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) } + + return value } public func decode(_ type: Double.Type, forKey key: Key) throws -> Double { @@ -1231,13 +1193,14 @@ fileprivate struct _JSONKeyedDecodingContainer : KeyedDecodingCon throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(key) (\"\(key.stringValue)\").")) } - return try self.decoder.with(pushedKey: key) { - guard let value = try self.decoder.unbox(entry, as: Double.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) - } + self.decoder.codingPath.append(key) + defer { self.decoder.codingPath.removeLast() } - return value + guard let value = try self.decoder.unbox(entry, as: Double.self) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) } + + return value } public func decode(_ type: String.Type, forKey key: Key) throws -> String { @@ -1245,13 +1208,14 @@ fileprivate struct _JSONKeyedDecodingContainer : KeyedDecodingCon throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(key) (\"\(key.stringValue)\").")) } - return try self.decoder.with(pushedKey: key) { - guard let value = try self.decoder.unbox(entry, as: String.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) - } + self.decoder.codingPath.append(key) + defer { self.decoder.codingPath.removeLast() } - return value + guard let value = try self.decoder.unbox(entry, as: String.self) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) } + + return value } public func decode(_ type: T.Type, forKey key: Key) throws -> T { @@ -1259,53 +1223,57 @@ fileprivate struct _JSONKeyedDecodingContainer : KeyedDecodingCon throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(key) (\"\(key.stringValue)\").")) } - return try self.decoder.with(pushedKey: key) { - guard let value = try self.decoder.unbox(entry, as: T.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) - } + self.decoder.codingPath.append(key) + defer { self.decoder.codingPath.removeLast() } - return value + guard let value = try self.decoder.unbox(entry, as: T.self) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) } + + return value } public func nestedContainer(keyedBy type: NestedKey.Type, forKey key: Key) throws -> KeyedDecodingContainer { - return try self.decoder.with(pushedKey: key) { - guard let value = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, - DecodingError.Context(codingPath: self.codingPath, - debugDescription: "Cannot get \(KeyedDecodingContainer.self) -- no value found for key \"\(key.stringValue)\"")) - } + self.decoder.codingPath.append(key) + defer { self.decoder.codingPath.removeLast() } - guard let dictionary = value as? [String : Any] else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: [String : Any].self, reality: value) - } + guard let value = self.container[key.stringValue] else { + throw DecodingError.keyNotFound(key, + DecodingError.Context(codingPath: self.codingPath, + debugDescription: "Cannot get \(KeyedDecodingContainer.self) -- no value found for key \"\(key.stringValue)\"")) + } - let container = _JSONKeyedDecodingContainer(referencing: self.decoder, wrapping: dictionary) - return KeyedDecodingContainer(container) + guard let dictionary = value as? [String : Any] else { + throw DecodingError._typeMismatch(at: self.codingPath, expectation: [String : Any].self, reality: value) } + + let container = _JSONKeyedDecodingContainer(referencing: self.decoder, wrapping: dictionary) + return KeyedDecodingContainer(container) } public func nestedUnkeyedContainer(forKey key: Key) throws -> UnkeyedDecodingContainer { - return try self.decoder.with(pushedKey: key) { - guard let value = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, - DecodingError.Context(codingPath: self.codingPath, - debugDescription: "Cannot get UnkeyedDecodingContainer -- no value found for key \"\(key.stringValue)\"")) - } + self.decoder.codingPath.append(key) + defer { self.decoder.codingPath.removeLast() } - guard let array = value as? [Any] else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: [Any].self, reality: value) - } + guard let value = self.container[key.stringValue] else { + throw DecodingError.keyNotFound(key, + DecodingError.Context(codingPath: self.codingPath, + debugDescription: "Cannot get UnkeyedDecodingContainer -- no value found for key \"\(key.stringValue)\"")) + } - return _JSONUnkeyedDecodingContainer(referencing: self.decoder, wrapping: array) + guard let array = value as? [Any] else { + throw DecodingError._typeMismatch(at: self.codingPath, expectation: [Any].self, reality: value) } + + return _JSONUnkeyedDecodingContainer(referencing: self.decoder, wrapping: array) } private func _superDecoder(forKey key: CodingKey) throws -> Decoder { - return self.decoder.with(pushedKey: key) { - let value: Any = self.container[key.stringValue] ?? NSNull() - return _JSONDecoder(referencing: value, at: self.decoder.codingPath, options: self.decoder.options) - } + self.decoder.codingPath.append(key) + defer { self.decoder.codingPath.removeLast() } + + let value: Any = self.container[key.stringValue] ?? NSNull() + return _JSONDecoder(referencing: value, at: self.decoder.codingPath, options: self.decoder.options) } public func superDecoder() throws -> Decoder { @@ -1370,14 +1338,15 @@ fileprivate struct _JSONUnkeyedDecodingContainer : UnkeyedDecodingContainer { throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) } - return try self.decoder.with(pushedKey: _JSONKey(index: self.currentIndex)) { - guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Bool.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) - } + self.decoder.codingPath.append(_JSONKey(index: self.currentIndex)) + defer { self.decoder.codingPath.removeLast() } - self.currentIndex += 1 - return decoded + guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Bool.self) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) } + + self.currentIndex += 1 + return decoded } public mutating func decode(_ type: Int.Type) throws -> Int { @@ -1385,14 +1354,15 @@ fileprivate struct _JSONUnkeyedDecodingContainer : UnkeyedDecodingContainer { throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) } - return try self.decoder.with(pushedKey: _JSONKey(index: self.currentIndex)) { - guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Int.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) - } + self.decoder.codingPath.append(_JSONKey(index: self.currentIndex)) + defer { self.decoder.codingPath.removeLast() } - self.currentIndex += 1 - return decoded + guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Int.self) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) } + + self.currentIndex += 1 + return decoded } public mutating func decode(_ type: Int8.Type) throws -> Int8 { @@ -1400,14 +1370,15 @@ fileprivate struct _JSONUnkeyedDecodingContainer : UnkeyedDecodingContainer { throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) } - return try self.decoder.with(pushedKey: _JSONKey(index: self.currentIndex)) { - guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Int8.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) - } + self.decoder.codingPath.append(_JSONKey(index: self.currentIndex)) + defer { self.decoder.codingPath.removeLast() } - self.currentIndex += 1 - return decoded + guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Int8.self) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) } + + self.currentIndex += 1 + return decoded } public mutating func decode(_ type: Int16.Type) throws -> Int16 { @@ -1415,14 +1386,15 @@ fileprivate struct _JSONUnkeyedDecodingContainer : UnkeyedDecodingContainer { throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) } - return try self.decoder.with(pushedKey: _JSONKey(index: self.currentIndex)) { - guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Int16.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) - } + self.decoder.codingPath.append(_JSONKey(index: self.currentIndex)) + defer { self.decoder.codingPath.removeLast() } - self.currentIndex += 1 - return decoded + guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Int16.self) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) } + + self.currentIndex += 1 + return decoded } public mutating func decode(_ type: Int32.Type) throws -> Int32 { @@ -1430,14 +1402,15 @@ fileprivate struct _JSONUnkeyedDecodingContainer : UnkeyedDecodingContainer { throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) } - return try self.decoder.with(pushedKey: _JSONKey(index: self.currentIndex)) { - guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Int32.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) - } + self.decoder.codingPath.append(_JSONKey(index: self.currentIndex)) + defer { self.decoder.codingPath.removeLast() } - self.currentIndex += 1 - return decoded + guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Int32.self) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) } + + self.currentIndex += 1 + return decoded } public mutating func decode(_ type: Int64.Type) throws -> Int64 { @@ -1445,14 +1418,15 @@ fileprivate struct _JSONUnkeyedDecodingContainer : UnkeyedDecodingContainer { throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) } - return try self.decoder.with(pushedKey: _JSONKey(index: self.currentIndex)) { - guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Int64.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) - } + self.decoder.codingPath.append(_JSONKey(index: self.currentIndex)) + defer { self.decoder.codingPath.removeLast() } - self.currentIndex += 1 - return decoded + guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Int64.self) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) } + + self.currentIndex += 1 + return decoded } public mutating func decode(_ type: UInt.Type) throws -> UInt { @@ -1460,14 +1434,15 @@ fileprivate struct _JSONUnkeyedDecodingContainer : UnkeyedDecodingContainer { throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) } - return try self.decoder.with(pushedKey: _JSONKey(index: self.currentIndex)) { - guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: UInt.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) - } + self.decoder.codingPath.append(_JSONKey(index: self.currentIndex)) + defer { self.decoder.codingPath.removeLast() } - self.currentIndex += 1 - return decoded + guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: UInt.self) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) } + + self.currentIndex += 1 + return decoded } public mutating func decode(_ type: UInt8.Type) throws -> UInt8 { @@ -1475,14 +1450,15 @@ fileprivate struct _JSONUnkeyedDecodingContainer : UnkeyedDecodingContainer { throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) } - return try self.decoder.with(pushedKey: _JSONKey(index: self.currentIndex)) { - guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: UInt8.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) - } + self.decoder.codingPath.append(_JSONKey(index: self.currentIndex)) + defer { self.decoder.codingPath.removeLast() } - self.currentIndex += 1 - return decoded + guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: UInt8.self) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) } + + self.currentIndex += 1 + return decoded } public mutating func decode(_ type: UInt16.Type) throws -> UInt16 { @@ -1490,14 +1466,15 @@ fileprivate struct _JSONUnkeyedDecodingContainer : UnkeyedDecodingContainer { throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) } - return try self.decoder.with(pushedKey: _JSONKey(index: self.currentIndex)) { - guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: UInt16.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) - } + self.decoder.codingPath.append(_JSONKey(index: self.currentIndex)) + defer { self.decoder.codingPath.removeLast() } - self.currentIndex += 1 - return decoded + guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: UInt16.self) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) } + + self.currentIndex += 1 + return decoded } public mutating func decode(_ type: UInt32.Type) throws -> UInt32 { @@ -1505,14 +1482,15 @@ fileprivate struct _JSONUnkeyedDecodingContainer : UnkeyedDecodingContainer { throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) } - return try self.decoder.with(pushedKey: _JSONKey(index: self.currentIndex)) { - guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: UInt32.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) - } + self.decoder.codingPath.append(_JSONKey(index: self.currentIndex)) + defer { self.decoder.codingPath.removeLast() } - self.currentIndex += 1 - return decoded + guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: UInt32.self) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) } + + self.currentIndex += 1 + return decoded } public mutating func decode(_ type: UInt64.Type) throws -> UInt64 { @@ -1520,14 +1498,15 @@ fileprivate struct _JSONUnkeyedDecodingContainer : UnkeyedDecodingContainer { throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) } - return try self.decoder.with(pushedKey: _JSONKey(index: self.currentIndex)) { - guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: UInt64.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) - } + self.decoder.codingPath.append(_JSONKey(index: self.currentIndex)) + defer { self.decoder.codingPath.removeLast() } - self.currentIndex += 1 - return decoded + guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: UInt64.self) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) } + + self.currentIndex += 1 + return decoded } public mutating func decode(_ type: Float.Type) throws -> Float { @@ -1535,14 +1514,15 @@ fileprivate struct _JSONUnkeyedDecodingContainer : UnkeyedDecodingContainer { throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) } - return try self.decoder.with(pushedKey: _JSONKey(index: self.currentIndex)) { - guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Float.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) - } + self.decoder.codingPath.append(_JSONKey(index: self.currentIndex)) + defer { self.decoder.codingPath.removeLast() } - self.currentIndex += 1 - return decoded + guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Float.self) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) } + + self.currentIndex += 1 + return decoded } public mutating func decode(_ type: Double.Type) throws -> Double { @@ -1550,14 +1530,15 @@ fileprivate struct _JSONUnkeyedDecodingContainer : UnkeyedDecodingContainer { throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) } - return try self.decoder.with(pushedKey: _JSONKey(index: self.currentIndex)) { - guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Double.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) - } + self.decoder.codingPath.append(_JSONKey(index: self.currentIndex)) + defer { self.decoder.codingPath.removeLast() } - self.currentIndex += 1 - return decoded + guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Double.self) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) } + + self.currentIndex += 1 + return decoded } public mutating func decode(_ type: String.Type) throws -> String { @@ -1565,14 +1546,15 @@ fileprivate struct _JSONUnkeyedDecodingContainer : UnkeyedDecodingContainer { throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) } - return try self.decoder.with(pushedKey: _JSONKey(index: self.currentIndex)) { - guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: String.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) - } + self.decoder.codingPath.append(_JSONKey(index: self.currentIndex)) + defer { self.decoder.codingPath.removeLast() } - self.currentIndex += 1 - return decoded + guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: String.self) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) } + + self.currentIndex += 1 + return decoded } public mutating func decode(_ type: T.Type) throws -> T { @@ -1580,77 +1562,81 @@ fileprivate struct _JSONUnkeyedDecodingContainer : UnkeyedDecodingContainer { throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) } - return try self.decoder.with(pushedKey: _JSONKey(index: self.currentIndex)) { - guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: T.self) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) - } + self.decoder.codingPath.append(_JSONKey(index: self.currentIndex)) + defer { self.decoder.codingPath.removeLast() } - self.currentIndex += 1 - return decoded + guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: T.self) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) } + + self.currentIndex += 1 + return decoded } public mutating func nestedContainer(keyedBy type: NestedKey.Type) throws -> KeyedDecodingContainer { - return try self.decoder.with(pushedKey: _JSONKey(index: self.currentIndex)) { - guard !self.isAtEnd else { - throw DecodingError.valueNotFound(KeyedDecodingContainer.self, - DecodingError.Context(codingPath: self.codingPath, - debugDescription: "Cannot get nested keyed container -- unkeyed container is at end.")) - } + self.decoder.codingPath.append(_JSONKey(index: self.currentIndex)) + defer { self.decoder.codingPath.removeLast() } - let value = self.container[self.currentIndex] - guard !(value is NSNull) else { - throw DecodingError.valueNotFound(KeyedDecodingContainer.self, - DecodingError.Context(codingPath: self.codingPath, - debugDescription: "Cannot get keyed decoding container -- found null value instead.")) - } + guard !self.isAtEnd else { + throw DecodingError.valueNotFound(KeyedDecodingContainer.self, + DecodingError.Context(codingPath: self.codingPath, + debugDescription: "Cannot get nested keyed container -- unkeyed container is at end.")) + } - guard let dictionary = value as? [String : Any] else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: [String : Any].self, reality: value) - } + let value = self.container[self.currentIndex] + guard !(value is NSNull) else { + throw DecodingError.valueNotFound(KeyedDecodingContainer.self, + DecodingError.Context(codingPath: self.codingPath, + debugDescription: "Cannot get keyed decoding container -- found null value instead.")) + } - self.currentIndex += 1 - let container = _JSONKeyedDecodingContainer(referencing: self.decoder, wrapping: dictionary) - return KeyedDecodingContainer(container) + guard let dictionary = value as? [String : Any] else { + throw DecodingError._typeMismatch(at: self.codingPath, expectation: [String : Any].self, reality: value) } + + self.currentIndex += 1 + let container = _JSONKeyedDecodingContainer(referencing: self.decoder, wrapping: dictionary) + return KeyedDecodingContainer(container) } public mutating func nestedUnkeyedContainer() throws -> UnkeyedDecodingContainer { - return try self.decoder.with(pushedKey: _JSONKey(index: self.currentIndex)) { - guard !self.isAtEnd else { - throw DecodingError.valueNotFound(UnkeyedDecodingContainer.self, - DecodingError.Context(codingPath: self.codingPath, - debugDescription: "Cannot get nested keyed container -- unkeyed container is at end.")) - } + self.decoder.codingPath.append(_JSONKey(index: self.currentIndex)) + defer { self.decoder.codingPath.removeLast() } - let value = self.container[self.currentIndex] - guard !(value is NSNull) else { - throw DecodingError.valueNotFound(UnkeyedDecodingContainer.self, - DecodingError.Context(codingPath: self.codingPath, - debugDescription: "Cannot get keyed decoding container -- found null value instead.")) - } + guard !self.isAtEnd else { + throw DecodingError.valueNotFound(UnkeyedDecodingContainer.self, + DecodingError.Context(codingPath: self.codingPath, + debugDescription: "Cannot get nested keyed container -- unkeyed container is at end.")) + } - guard let array = value as? [Any] else { - throw DecodingError._typeMismatch(at: self.codingPath, expectation: [Any].self, reality: value) - } + let value = self.container[self.currentIndex] + guard !(value is NSNull) else { + throw DecodingError.valueNotFound(UnkeyedDecodingContainer.self, + DecodingError.Context(codingPath: self.codingPath, + debugDescription: "Cannot get keyed decoding container -- found null value instead.")) + } - self.currentIndex += 1 - return _JSONUnkeyedDecodingContainer(referencing: self.decoder, wrapping: array) + guard let array = value as? [Any] else { + throw DecodingError._typeMismatch(at: self.codingPath, expectation: [Any].self, reality: value) } + + self.currentIndex += 1 + return _JSONUnkeyedDecodingContainer(referencing: self.decoder, wrapping: array) } public mutating func superDecoder() throws -> Decoder { - return try self.decoder.with(pushedKey: _JSONKey(index: self.currentIndex)) { - guard !self.isAtEnd else { - throw DecodingError.valueNotFound(Decoder.self, - DecodingError.Context(codingPath: self.codingPath, - debugDescription: "Cannot get superDecoder() -- unkeyed container is at end.")) - } + self.decoder.codingPath.append(_JSONKey(index: self.currentIndex)) + defer { self.decoder.codingPath.removeLast() } - let value = self.container[self.currentIndex] - self.currentIndex += 1 - return _JSONDecoder(referencing: value, at: self.decoder.codingPath, options: self.decoder.options) + guard !self.isAtEnd else { + throw DecodingError.valueNotFound(Decoder.self, + DecodingError.Context(codingPath: self.codingPath, + debugDescription: "Cannot get superDecoder() -- unkeyed container is at end.")) } + + let value = self.container[self.currentIndex] + self.currentIndex += 1 + return _JSONDecoder(referencing: value, at: self.decoder.codingPath, options: self.decoder.options) } }