Merge pull request #10729 from itaiferber/4.0-non-optional-coding-paths
[4.0] Make coding paths non-optional [DO NOT MERGE]
diff --git a/stdlib/public/SDK/Foundation/Codable.swift b/stdlib/public/SDK/Foundation/Codable.swift
index 200cbb1..f12afa8 100644
--- a/stdlib/public/SDK/Foundation/Codable.swift
+++ b/stdlib/public/SDK/Foundation/Codable.swift
@@ -29,7 +29,7 @@
/// - parameter expectation: The type expected to be encountered.
/// - parameter reality: The value that was encountered instead of the expected type.
/// - returns: A `DecodingError` with the appropriate path and debug description.
- internal static func _typeMismatch(at path: [CodingKey?], expectation: Any.Type, reality: Any) -> DecodingError {
+ internal static func _typeMismatch(at path: [CodingKey], expectation: Any.Type, reality: Any) -> DecodingError {
let description = "Expected to decode \(expectation) but found \(_typeDescription(of: reality)) instead."
return .typeMismatch(expectation, Context(codingPath: path, debugDescription: description))
}
diff --git a/stdlib/public/SDK/Foundation/JSONEncoder.swift b/stdlib/public/SDK/Foundation/JSONEncoder.swift
index 65a5e54..2d6fa50 100644
--- a/stdlib/public/SDK/Foundation/JSONEncoder.swift
+++ b/stdlib/public/SDK/Foundation/JSONEncoder.swift
@@ -165,7 +165,7 @@
fileprivate let options: JSONEncoder._Options
/// The path to the current point in encoding.
- public var codingPath: [CodingKey?]
+ public var codingPath: [CodingKey]
/// Contextual user-provided information for use during encoding.
public var userInfo: [CodingUserInfoKey : Any] {
@@ -175,7 +175,7 @@
// MARK: - Initialization
/// Initializes `self` with the given top-level encoder options.
- fileprivate init(options: JSONEncoder._Options, codingPath: [CodingKey?] = []) {
+ fileprivate init(options: JSONEncoder._Options, codingPath: [CodingKey] = []) {
self.options = options
self.storage = _JSONEncodingStorage()
self.codingPath = codingPath
@@ -187,7 +187,7 @@
///
/// - 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<T>(pushedKey key: CodingKey?, _ work: () throws -> T) rethrows -> T {
+ fileprivate func with<T>(pushedKey key: CodingKey, _ work: () throws -> T) rethrows -> T {
self.codingPath.append(key)
let ret: T = try work()
self.codingPath.removeLast()
@@ -304,12 +304,12 @@
private let container: NSMutableDictionary
/// The path of coding keys taken to get to this point in encoding.
- private(set) public var codingPath: [CodingKey?]
+ private(set) public var codingPath: [CodingKey]
// MARK: - Initialization
/// Initializes `self` with the given references.
- fileprivate init(referencing encoder: _JSONEncoder, codingPath: [CodingKey?], wrapping container: NSMutableDictionary) {
+ fileprivate init(referencing encoder: _JSONEncoder, codingPath: [CodingKey], wrapping container: NSMutableDictionary) {
self.encoder = encoder
self.codingPath = codingPath
self.container = container
@@ -321,7 +321,7 @@
///
/// - 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<T>(pushedKey key: CodingKey?, _ work: () throws -> T) rethrows -> T {
+ fileprivate mutating func with<T>(pushedKey key: CodingKey, _ work: () throws -> T) rethrows -> T {
self.codingPath.append(key)
let ret: T = try work()
self.codingPath.removeLast()
@@ -384,7 +384,7 @@
}
public mutating func superEncoder() -> Encoder {
- return _JSONReferencingEncoder(referencing: self.encoder, at: _JSONSuperKey.super, wrapping: self.container)
+ return _JSONReferencingEncoder(referencing: self.encoder, at: _JSONKey.super, wrapping: self.container)
}
public mutating func superEncoder(forKey key: Key) -> Encoder {
@@ -402,12 +402,17 @@
private let container: NSMutableArray
/// The path of coding keys taken to get to this point in encoding.
- private(set) public var codingPath: [CodingKey?]
+ private(set) public var codingPath: [CodingKey]
+
+ /// The number of elements encoded into the container.
+ public var count: Int {
+ return self.container.count
+ }
// MARK: - Initialization
/// Initializes `self` with the given references.
- fileprivate init(referencing encoder: _JSONEncoder, codingPath: [CodingKey?], wrapping container: NSMutableArray) {
+ fileprivate init(referencing encoder: _JSONEncoder, codingPath: [CodingKey], wrapping container: NSMutableArray) {
self.encoder = encoder
self.codingPath = codingPath
self.container = container
@@ -419,7 +424,7 @@
///
/// - 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<T>(pushedKey key: CodingKey?, _ work: () throws -> T) rethrows -> T {
+ fileprivate mutating func with<T>(pushedKey key: CodingKey, _ work: () throws -> T) rethrows -> T {
self.codingPath.append(key)
let ret: T = try work()
self.codingPath.removeLast()
@@ -444,39 +449,39 @@
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: nil) {
+ try self.encoder.with(pushedKey: _JSONKey(index: self.count)) {
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: nil) {
+ try self.encoder.with(pushedKey: _JSONKey(index: self.count)) {
self.container.add(try self.encoder.box(value))
}
}
public mutating func encode<T : Encodable>(_ value: T) throws {
- try self.encoder.with(pushedKey: nil) {
+ try self.encoder.with(pushedKey: _JSONKey(index: self.count)) {
self.container.add(try self.encoder.box(value))
}
}
public mutating func nestedContainer<NestedKey>(keyedBy keyType: NestedKey.Type) -> KeyedEncodingContainer<NestedKey> {
- let dictionary = NSMutableDictionary()
- self.container.add(dictionary)
+ return self.with(pushedKey: _JSONKey(index: self.count)) {
+ let dictionary = NSMutableDictionary()
+ self.container.add(dictionary)
- return self.with(pushedKey: nil) {
let container = _JSONKeyedEncodingContainer<NestedKey>(referencing: self.encoder, codingPath: self.codingPath, wrapping: dictionary)
return KeyedEncodingContainer(container)
}
}
public mutating func nestedUnkeyedContainer() -> UnkeyedEncodingContainer {
- let array = NSMutableArray()
- self.container.add(array)
+ return self.with(pushedKey: _JSONKey(index: self.count)) {
+ let array = NSMutableArray()
+ self.container.add(array)
- return self.with(pushedKey: nil) {
return _JSONUnkeyedEncodingContainer(referencing: self.encoder, codingPath: self.codingPath, wrapping: array)
}
}
@@ -753,7 +758,7 @@
self.reference = .array(array, index)
super.init(options: encoder.options, codingPath: encoder.codingPath)
- self.codingPath.append(nil)
+ self.codingPath.append(_JSONKey(index: index))
}
/// Initializes `self` by referencing the given dictionary container in the given encoder.
@@ -913,7 +918,7 @@
fileprivate let options: JSONDecoder._Options
/// The path to the current point in encoding.
- private(set) public var codingPath: [CodingKey?]
+ private(set) public var codingPath: [CodingKey]
/// Contextual user-provided information for use during encoding.
public var userInfo: [CodingUserInfoKey : Any] {
@@ -923,7 +928,7 @@
// MARK: - Initialization
/// Initializes `self` with the given top-level container and options.
- fileprivate init(referencing container: Any, at codingPath: [CodingKey?] = [], options: JSONDecoder._Options) {
+ fileprivate init(referencing container: Any, at codingPath: [CodingKey] = [], options: JSONDecoder._Options) {
self.storage = _JSONDecodingStorage()
self.storage.push(container: container)
self.codingPath = codingPath
@@ -936,7 +941,7 @@
///
/// - 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<T>(pushedKey key: CodingKey?, _ work: () throws -> T) rethrows -> T {
+ fileprivate func with<T>(pushedKey key: CodingKey, _ work: () throws -> T) rethrows -> T {
self.codingPath.append(key)
let ret: T = try work()
self.codingPath.removeLast()
@@ -1028,7 +1033,7 @@
private let container: [String : Any]
/// The path of coding keys taken to get to this point in decoding.
- private(set) public var codingPath: [CodingKey?]
+ private(set) public var codingPath: [CodingKey]
// MARK: - Initialization
@@ -1308,7 +1313,7 @@
}
public func superDecoder() throws -> Decoder {
- return try _superDecoder(forKey: _JSONSuperKey.super)
+ return try _superDecoder(forKey: _JSONKey.super)
}
public func superDecoder(forKey key: Key) throws -> Decoder {
@@ -1326,10 +1331,10 @@
private let container: [Any]
/// The path of coding keys taken to get to this point in decoding.
- private(set) public var codingPath: [CodingKey?]
+ private(set) public var codingPath: [CodingKey]
/// The index of the element we're about to decode.
- private var currentIndex: Int
+ private(set) public var currentIndex: Int
// MARK: - Initialization
@@ -1353,7 +1358,7 @@
public mutating func decodeNil() throws -> Bool {
guard !self.isAtEnd else {
- throw DecodingError.valueNotFound(Any?.self, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ throw DecodingError.valueNotFound(Any?.self, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end."))
}
if self.container[self.currentIndex] is NSNull {
@@ -1366,12 +1371,12 @@
public mutating func decode(_ type: Bool.Type) throws -> Bool {
guard !self.isAtEnd else {
- throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ 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: nil) {
+ 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 + [nil], debugDescription: "Expected \(type) but found null instead."))
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead."))
}
self.currentIndex += 1
@@ -1381,12 +1386,12 @@
public mutating func decode(_ type: Int.Type) throws -> Int {
guard !self.isAtEnd else {
- throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ 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: nil) {
+ 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 + [nil], debugDescription: "Expected \(type) but found null instead."))
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead."))
}
self.currentIndex += 1
@@ -1396,12 +1401,12 @@
public mutating func decode(_ type: Int8.Type) throws -> Int8 {
guard !self.isAtEnd else {
- throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ 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: nil) {
+ 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 + [nil], debugDescription: "Expected \(type) but found null instead."))
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead."))
}
self.currentIndex += 1
@@ -1411,12 +1416,12 @@
public mutating func decode(_ type: Int16.Type) throws -> Int16 {
guard !self.isAtEnd else {
- throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ 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: nil) {
+ 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 + [nil], debugDescription: "Expected \(type) but found null instead."))
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead."))
}
self.currentIndex += 1
@@ -1426,12 +1431,12 @@
public mutating func decode(_ type: Int32.Type) throws -> Int32 {
guard !self.isAtEnd else {
- throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ 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: nil) {
+ 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 + [nil], debugDescription: "Expected \(type) but found null instead."))
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead."))
}
self.currentIndex += 1
@@ -1441,12 +1446,12 @@
public mutating func decode(_ type: Int64.Type) throws -> Int64 {
guard !self.isAtEnd else {
- throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ 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: nil) {
+ 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 + [nil], debugDescription: "Expected \(type) but found null instead."))
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead."))
}
self.currentIndex += 1
@@ -1456,12 +1461,12 @@
public mutating func decode(_ type: UInt.Type) throws -> UInt {
guard !self.isAtEnd else {
- throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ 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: nil) {
+ 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 + [nil], debugDescription: "Expected \(type) but found null instead."))
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead."))
}
self.currentIndex += 1
@@ -1471,12 +1476,12 @@
public mutating func decode(_ type: UInt8.Type) throws -> UInt8 {
guard !self.isAtEnd else {
- throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ 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: nil) {
+ 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 + [nil], debugDescription: "Expected \(type) but found null instead."))
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead."))
}
self.currentIndex += 1
@@ -1486,12 +1491,12 @@
public mutating func decode(_ type: UInt16.Type) throws -> UInt16 {
guard !self.isAtEnd else {
- throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ 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: nil) {
+ 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 + [nil], debugDescription: "Expected \(type) but found null instead."))
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead."))
}
self.currentIndex += 1
@@ -1501,12 +1506,12 @@
public mutating func decode(_ type: UInt32.Type) throws -> UInt32 {
guard !self.isAtEnd else {
- throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ 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: nil) {
+ 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 + [nil], debugDescription: "Expected \(type) but found null instead."))
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead."))
}
self.currentIndex += 1
@@ -1516,12 +1521,12 @@
public mutating func decode(_ type: UInt64.Type) throws -> UInt64 {
guard !self.isAtEnd else {
- throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ 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: nil) {
+ 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 + [nil], debugDescription: "Expected \(type) but found null instead."))
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead."))
}
self.currentIndex += 1
@@ -1531,12 +1536,12 @@
public mutating func decode(_ type: Float.Type) throws -> Float {
guard !self.isAtEnd else {
- throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ 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: nil) {
+ 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 + [nil], debugDescription: "Expected \(type) but found null instead."))
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead."))
}
self.currentIndex += 1
@@ -1546,12 +1551,12 @@
public mutating func decode(_ type: Double.Type) throws -> Double {
guard !self.isAtEnd else {
- throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ 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: nil) {
+ 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 + [nil], debugDescription: "Expected \(type) but found null instead."))
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead."))
}
self.currentIndex += 1
@@ -1561,12 +1566,12 @@
public mutating func decode(_ type: String.Type) throws -> String {
guard !self.isAtEnd else {
- throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ 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: nil) {
+ 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 + [nil], debugDescription: "Expected \(type) but found null instead."))
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead."))
}
self.currentIndex += 1
@@ -1576,12 +1581,12 @@
public mutating func decode<T : Decodable>(_ type: T.Type) throws -> T {
guard !self.isAtEnd else {
- throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ 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: nil) {
+ 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 + [nil], debugDescription: "Expected \(type) but found null instead."))
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead."))
}
self.currentIndex += 1
@@ -1590,7 +1595,7 @@
}
public mutating func nestedContainer<NestedKey>(keyedBy type: NestedKey.Type) throws -> KeyedDecodingContainer<NestedKey> {
- return try self.decoder.with(pushedKey: nil) {
+ return try self.decoder.with(pushedKey: _JSONKey(index: self.currentIndex)) {
guard !self.isAtEnd else {
throw DecodingError.valueNotFound(KeyedDecodingContainer<NestedKey>.self,
DecodingError.Context(codingPath: self.codingPath,
@@ -1615,7 +1620,7 @@
}
public mutating func nestedUnkeyedContainer() throws -> UnkeyedDecodingContainer {
- return try self.decoder.with(pushedKey: nil) {
+ return try self.decoder.with(pushedKey: _JSONKey(index: self.currentIndex)) {
guard !self.isAtEnd else {
throw DecodingError.valueNotFound(UnkeyedDecodingContainer.self,
DecodingError.Context(codingPath: self.codingPath,
@@ -1639,7 +1644,7 @@
}
public mutating func superDecoder() throws -> Decoder {
- return try self.decoder.with(pushedKey: nil) {
+ return try self.decoder.with(pushedKey: _JSONKey(index: self.currentIndex)) {
guard !self.isAtEnd else {
throw DecodingError.valueNotFound(Decoder.self,
DecodingError.Context(codingPath: self.codingPath,
@@ -2128,11 +2133,29 @@
}
//===----------------------------------------------------------------------===//
-// Shared Super Key
+// Shared Key Types
//===----------------------------------------------------------------------===//
-fileprivate enum _JSONSuperKey : String, CodingKey {
- case `super`
+fileprivate struct _JSONKey : CodingKey {
+ public var stringValue: String
+ public var intValue: Int?
+
+ public init?(stringValue: String) {
+ self.stringValue = stringValue
+ self.intValue = nil
+ }
+
+ public init?(intValue: Int) {
+ self.stringValue = "\(intValue)"
+ self.intValue = intValue
+ }
+
+ fileprivate init(index: Int) {
+ self.stringValue = "Index \(index)"
+ self.intValue = index
+ }
+
+ fileprivate static let `super` = _JSONKey(stringValue: "super")!
}
//===----------------------------------------------------------------------===//
@@ -2158,7 +2181,7 @@
/// - parameter value: The value that was invalid to encode.
/// - parameter path: The path of `CodingKey`s taken to encode this value.
/// - returns: An `EncodingError` with the appropriate path and debug description.
- fileprivate static func _invalidFloatingPointValue<T : FloatingPoint>(_ value: T, at codingPath: [CodingKey?]) -> EncodingError {
+ fileprivate static func _invalidFloatingPointValue<T : FloatingPoint>(_ value: T, at codingPath: [CodingKey]) -> EncodingError {
let valueDescription: String
if value == T.infinity {
valueDescription = "\(T.self).infinity"
diff --git a/stdlib/public/SDK/Foundation/PlistEncoder.swift b/stdlib/public/SDK/Foundation/PlistEncoder.swift
index b7e4d2f..cc8db11 100644
--- a/stdlib/public/SDK/Foundation/PlistEncoder.swift
+++ b/stdlib/public/SDK/Foundation/PlistEncoder.swift
@@ -94,7 +94,7 @@
fileprivate let options: PropertyListEncoder._Options
/// The path to the current point in encoding.
- fileprivate(set) public var codingPath: [CodingKey?]
+ fileprivate(set) public var codingPath: [CodingKey]
/// Contextual user-provided information for use during encoding.
public var userInfo: [CodingUserInfoKey : Any] {
@@ -104,7 +104,7 @@
// MARK: - Initialization
/// Initializes `self` with the given top-level encoder options.
- fileprivate init(options: PropertyListEncoder._Options, codingPath: [CodingKey?] = []) {
+ fileprivate init(options: PropertyListEncoder._Options, codingPath: [CodingKey] = []) {
self.options = options
self.storage = _PlistEncodingStorage()
self.codingPath = codingPath
@@ -116,7 +116,7 @@
///
/// - 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<T>(pushedKey key: CodingKey?, _ work: () throws -> T) rethrows -> T {
+ fileprivate func with<T>(pushedKey key: CodingKey, _ work: () throws -> T) rethrows -> T {
self.codingPath.append(key)
let ret: T = try work()
self.codingPath.removeLast()
@@ -233,12 +233,12 @@
private let container: NSMutableDictionary
/// The path of coding keys taken to get to this point in encoding.
- private(set) public var codingPath: [CodingKey?]
+ private(set) public var codingPath: [CodingKey]
// MARK: - Initialization
/// Initializes `self` with the given references.
- fileprivate init(referencing encoder: _PlistEncoder, codingPath: [CodingKey?], wrapping container: NSMutableDictionary) {
+ fileprivate init(referencing encoder: _PlistEncoder, codingPath: [CodingKey], wrapping container: NSMutableDictionary) {
self.encoder = encoder
self.codingPath = codingPath
self.container = container
@@ -250,7 +250,7 @@
///
/// - 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<T>(pushedKey key: CodingKey?, _ work: () throws -> T) rethrows -> T {
+ fileprivate mutating func with<T>(pushedKey key: CodingKey, _ work: () throws -> T) rethrows -> T {
self.codingPath.append(key)
let ret: T = try work()
self.codingPath.removeLast()
@@ -301,7 +301,7 @@
}
public mutating func superEncoder() -> Encoder {
- return _PlistReferencingEncoder(referencing: self.encoder, at: _PlistSuperKey.super, wrapping: self.container)
+ return _PlistReferencingEncoder(referencing: self.encoder, at: _PlistKey.super, wrapping: self.container)
}
public mutating func superEncoder(forKey key: Key) -> Encoder {
@@ -319,12 +319,17 @@
private let container: NSMutableArray
/// The path of coding keys taken to get to this point in encoding.
- private(set) public var codingPath: [CodingKey?]
+ private(set) public var codingPath: [CodingKey]
+
+ /// The number of elements encoded into the container.
+ public var count: Int {
+ return self.container.count
+ }
// MARK: - Initialization
/// Initializes `self` with the given references.
- fileprivate init(referencing encoder: _PlistEncoder, codingPath: [CodingKey?], wrapping container: NSMutableArray) {
+ fileprivate init(referencing encoder: _PlistEncoder, codingPath: [CodingKey], wrapping container: NSMutableArray) {
self.encoder = encoder
self.codingPath = codingPath
self.container = container
@@ -336,7 +341,7 @@
///
/// - 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<T>(pushedKey key: CodingKey?, _ work: () throws -> T) rethrows -> T {
+ fileprivate mutating func with<T>(pushedKey key: CodingKey, _ work: () throws -> T) rethrows -> T {
self.codingPath.append(key)
let ret: T = try work()
self.codingPath.removeLast()
@@ -362,26 +367,26 @@
public mutating func encode(_ value: String) throws { self.container.add(self.encoder.box(value)) }
public mutating func encode<T : Encodable>(_ value: T) throws {
- try self.encoder.with(pushedKey: nil) {
+ try self.encoder.with(pushedKey: _PlistKey(index: self.count)) {
self.container.add(try self.encoder.box(value))
}
}
public mutating func nestedContainer<NestedKey>(keyedBy keyType: NestedKey.Type) -> KeyedEncodingContainer<NestedKey> {
- let dictionary = NSMutableDictionary()
- self.container.add(dictionary)
+ return self.with(pushedKey: _PlistKey(index: self.count)) {
+ let dictionary = NSMutableDictionary()
+ self.container.add(dictionary)
- return self.with(pushedKey: nil) {
let container = _PlistKeyedEncodingContainer<NestedKey>(referencing: self.encoder, codingPath: self.codingPath, wrapping: dictionary)
return KeyedEncodingContainer(container)
}
}
public mutating func nestedUnkeyedContainer() -> UnkeyedEncodingContainer {
- let array = NSMutableArray()
- self.container.add(array)
+ return self.with(pushedKey: _PlistKey(index: self.count)) {
+ let array = NSMutableArray()
+ self.container.add(array)
- return self.with(pushedKey: nil) {
return _PlistUnkeyedEncodingContainer(referencing: self.encoder, codingPath: self.codingPath, wrapping: array)
}
}
@@ -555,7 +560,7 @@
self.reference = .array(array, index)
super.init(options: encoder.options, codingPath: encoder.codingPath)
- self.codingPath.append(nil)
+ self.codingPath.append(_PlistKey(index: index))
}
/// Initializes `self` by referencing the given dictionary container in the given encoder.
@@ -669,7 +674,7 @@
fileprivate let options: PropertyListDecoder._Options
/// The path to the current point in encoding.
- fileprivate(set) public var codingPath: [CodingKey?]
+ fileprivate(set) public var codingPath: [CodingKey]
/// Contextual user-provided information for use during encoding.
public var userInfo: [CodingUserInfoKey : Any] {
@@ -679,7 +684,7 @@
// MARK: - Initialization
/// Initializes `self` with the given top-level container and options.
- fileprivate init(referencing container: Any, at codingPath: [CodingKey?] = [], options: PropertyListDecoder._Options) {
+ fileprivate init(referencing container: Any, at codingPath: [CodingKey] = [], options: PropertyListDecoder._Options) {
self.storage = _PlistDecodingStorage()
self.storage.push(container: container)
self.codingPath = codingPath
@@ -692,7 +697,7 @@
///
/// - 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<T>(pushedKey key: CodingKey?, _ work: () throws -> T) rethrows -> T {
+ fileprivate func with<T>(pushedKey key: CodingKey, _ work: () throws -> T) rethrows -> T {
self.codingPath.append(key)
let ret: T = try work()
self.codingPath.removeLast()
@@ -784,7 +789,7 @@
private let container: [String : Any]
/// The path of coding keys taken to get to this point in decoding.
- private(set) public var codingPath: [CodingKey?]
+ private(set) public var codingPath: [CodingKey]
// MARK: - Initialization
@@ -1068,7 +1073,7 @@
}
public func superDecoder() throws -> Decoder {
- return try _superDecoder(forKey: _PlistSuperKey.super)
+ return try _superDecoder(forKey: _PlistKey.super)
}
public func superDecoder(forKey key: Key) throws -> Decoder {
@@ -1086,10 +1091,10 @@
private let container: [Any]
/// The path of coding keys taken to get to this point in decoding.
- private(set) public var codingPath: [CodingKey?]
+ private(set) public var codingPath: [CodingKey]
/// The index of the element we're about to decode.
- private var currentIndex: Int
+ private(set) public var currentIndex: Int
// MARK: - Initialization
@@ -1113,7 +1118,7 @@
public mutating func decodeNil() throws -> Bool {
guard !self.isAtEnd else {
- throw DecodingError.valueNotFound(Any?.self, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ throw DecodingError.valueNotFound(Any?.self, DecodingError.Context(codingPath: self.decoder.codingPath + [_PlistKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end."))
}
if self.container[self.currentIndex] is NSNull {
@@ -1126,12 +1131,12 @@
public mutating func decode(_ type: Bool.Type) throws -> Bool {
guard !self.isAtEnd else {
- throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_PlistKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end."))
}
- return try self.decoder.with(pushedKey: nil) {
+ return try self.decoder.with(pushedKey: _PlistKey(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 + [nil], debugDescription: "Expected \(type) but found null instead."))
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_PlistKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead."))
}
self.currentIndex += 1
@@ -1141,12 +1146,12 @@
public mutating func decode(_ type: Int.Type) throws -> Int {
guard !self.isAtEnd else {
- throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_PlistKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end."))
}
- return try self.decoder.with(pushedKey: nil) {
+ return try self.decoder.with(pushedKey: _PlistKey(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 + [nil], debugDescription: "Expected \(type) but found null instead."))
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_PlistKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead."))
}
self.currentIndex += 1
@@ -1156,12 +1161,12 @@
public mutating func decode(_ type: Int8.Type) throws -> Int8 {
guard !self.isAtEnd else {
- throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_PlistKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end."))
}
- return try self.decoder.with(pushedKey: nil) {
+ return try self.decoder.with(pushedKey: _PlistKey(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 + [nil], debugDescription: "Expected \(type) but found null instead."))
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_PlistKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead."))
}
self.currentIndex += 1
@@ -1171,12 +1176,12 @@
public mutating func decode(_ type: Int16.Type) throws -> Int16 {
guard !self.isAtEnd else {
- throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_PlistKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end."))
}
- return try self.decoder.with(pushedKey: nil) {
+ return try self.decoder.with(pushedKey: _PlistKey(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 + [nil], debugDescription: "Expected \(type) but found null instead."))
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_PlistKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead."))
}
self.currentIndex += 1
@@ -1186,12 +1191,12 @@
public mutating func decode(_ type: Int32.Type) throws -> Int32 {
guard !self.isAtEnd else {
- throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_PlistKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end."))
}
- return try self.decoder.with(pushedKey: nil) {
+ return try self.decoder.with(pushedKey: _PlistKey(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 + [nil], debugDescription: "Expected \(type) but found null instead."))
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_PlistKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead."))
}
self.currentIndex += 1
@@ -1201,12 +1206,12 @@
public mutating func decode(_ type: Int64.Type) throws -> Int64 {
guard !self.isAtEnd else {
- throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_PlistKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end."))
}
- return try self.decoder.with(pushedKey: nil) {
+ return try self.decoder.with(pushedKey: _PlistKey(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 + [nil], debugDescription: "Expected \(type) but found null instead."))
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_PlistKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead."))
}
self.currentIndex += 1
@@ -1216,12 +1221,12 @@
public mutating func decode(_ type: UInt.Type) throws -> UInt {
guard !self.isAtEnd else {
- throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_PlistKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end."))
}
- return try self.decoder.with(pushedKey: nil) {
+ return try self.decoder.with(pushedKey: _PlistKey(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 + [nil], debugDescription: "Expected \(type) but found null instead."))
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_PlistKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead."))
}
self.currentIndex += 1
@@ -1231,12 +1236,12 @@
public mutating func decode(_ type: UInt8.Type) throws -> UInt8 {
guard !self.isAtEnd else {
- throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_PlistKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end."))
}
- return try self.decoder.with(pushedKey: nil) {
+ return try self.decoder.with(pushedKey: _PlistKey(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 + [nil], debugDescription: "Expected \(type) but found null instead."))
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_PlistKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead."))
}
self.currentIndex += 1
@@ -1246,12 +1251,12 @@
public mutating func decode(_ type: UInt16.Type) throws -> UInt16 {
guard !self.isAtEnd else {
- throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_PlistKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end."))
}
- return try self.decoder.with(pushedKey: nil) {
+ return try self.decoder.with(pushedKey: _PlistKey(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 + [nil], debugDescription: "Expected \(type) but found null instead."))
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_PlistKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead."))
}
self.currentIndex += 1
@@ -1261,12 +1266,12 @@
public mutating func decode(_ type: UInt32.Type) throws -> UInt32 {
guard !self.isAtEnd else {
- throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_PlistKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end."))
}
- return try self.decoder.with(pushedKey: nil) {
+ return try self.decoder.with(pushedKey: _PlistKey(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 + [nil], debugDescription: "Expected \(type) but found null instead."))
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_PlistKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead."))
}
self.currentIndex += 1
@@ -1276,12 +1281,12 @@
public mutating func decode(_ type: UInt64.Type) throws -> UInt64 {
guard !self.isAtEnd else {
- throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_PlistKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end."))
}
- return try self.decoder.with(pushedKey: nil) {
+ return try self.decoder.with(pushedKey: _PlistKey(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 + [nil], debugDescription: "Expected \(type) but found null instead."))
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_PlistKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead."))
}
self.currentIndex += 1
@@ -1291,12 +1296,12 @@
public mutating func decode(_ type: Float.Type) throws -> Float {
guard !self.isAtEnd else {
- throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_PlistKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end."))
}
- return try self.decoder.with(pushedKey: nil) {
+ return try self.decoder.with(pushedKey: _PlistKey(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 + [nil], debugDescription: "Expected \(type) but found null instead."))
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_PlistKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead."))
}
self.currentIndex += 1
@@ -1306,12 +1311,12 @@
public mutating func decode(_ type: Double.Type) throws -> Double {
guard !self.isAtEnd else {
- throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_PlistKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end."))
}
- return try self.decoder.with(pushedKey: nil) {
+ return try self.decoder.with(pushedKey: _PlistKey(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 + [nil], debugDescription: "Expected \(type) but found null instead."))
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_PlistKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead."))
}
self.currentIndex += 1
@@ -1321,12 +1326,12 @@
public mutating func decode(_ type: String.Type) throws -> String {
guard !self.isAtEnd else {
- throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_PlistKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end."))
}
- return try self.decoder.with(pushedKey: nil) {
+ return try self.decoder.with(pushedKey: _PlistKey(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 + [nil], debugDescription: "Expected \(type) but found null instead."))
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_PlistKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead."))
}
self.currentIndex += 1
@@ -1336,12 +1341,12 @@
public mutating func decode<T : Decodable>(_ type: T.Type) throws -> T {
guard !self.isAtEnd else {
- throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [nil], debugDescription: "Unkeyed container is at end."))
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_PlistKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end."))
}
- return try self.decoder.with(pushedKey: nil) {
+ return try self.decoder.with(pushedKey: _PlistKey(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 + [nil], debugDescription: "Expected \(type) but found null instead."))
+ throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_PlistKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead."))
}
self.currentIndex += 1
@@ -1350,7 +1355,7 @@
}
public mutating func nestedContainer<NestedKey>(keyedBy type: NestedKey.Type) throws -> KeyedDecodingContainer<NestedKey> {
- return try self.decoder.with(pushedKey: nil) {
+ return try self.decoder.with(pushedKey: _PlistKey(index: self.currentIndex)) {
guard !self.isAtEnd else {
throw DecodingError.valueNotFound(KeyedDecodingContainer<NestedKey>.self,
DecodingError.Context(codingPath: self.codingPath,
@@ -1375,7 +1380,7 @@
}
public mutating func nestedUnkeyedContainer() throws -> UnkeyedDecodingContainer {
- return try self.decoder.with(pushedKey: nil) {
+ return try self.decoder.with(pushedKey: _PlistKey(index: self.currentIndex)) {
guard !self.isAtEnd else {
throw DecodingError.valueNotFound(UnkeyedDecodingContainer.self,
DecodingError.Context(codingPath: self.codingPath,
@@ -1399,7 +1404,7 @@
}
public mutating func superDecoder() throws -> Decoder {
- return try self.decoder.with(pushedKey: nil) {
+ return try self.decoder.with(pushedKey: _PlistKey(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."))
@@ -1765,9 +1770,27 @@
fileprivate let _plistNullNSString = NSString(string: _plistNull)
//===----------------------------------------------------------------------===//
-// Shared Super Key
+// Shared Key Types
//===----------------------------------------------------------------------===//
-fileprivate enum _PlistSuperKey : String, CodingKey {
- case `super`
+fileprivate struct _PlistKey : CodingKey {
+ public var stringValue: String
+ public var intValue: Int?
+
+ public init?(stringValue: String) {
+ self.stringValue = stringValue
+ self.intValue = nil
+ }
+
+ public init?(intValue: Int) {
+ self.stringValue = "\(intValue)"
+ self.intValue = intValue
+ }
+
+ fileprivate init(index: Int) {
+ self.stringValue = "Index \(index)"
+ self.intValue = index
+ }
+
+ fileprivate static let `super` = _PlistKey(stringValue: "super")!
}
diff --git a/stdlib/public/core/Codable.swift b/stdlib/public/core/Codable.swift
index 1cd4209..74f7c13 100644
--- a/stdlib/public/core/Codable.swift
+++ b/stdlib/public/core/Codable.swift
@@ -75,7 +75,7 @@
public protocol Encoder {
/// The path of coding keys taken to get to this point in encoding.
/// A `nil` value indicates an unkeyed container.
- var codingPath: [CodingKey?] { get }
+ var codingPath: [CodingKey] { get }
/// Any contextual information set by the user for encoding.
var userInfo: [CodingUserInfoKey : Any] { get }
@@ -108,7 +108,7 @@
public protocol Decoder {
/// The path of coding keys taken to get to this point in decoding.
/// A `nil` value indicates an unkeyed container.
- var codingPath: [CodingKey?] { get }
+ var codingPath: [CodingKey] { get }
/// Any contextual information set by the user for decoding.
var userInfo: [CodingUserInfoKey : Any] { get }
@@ -147,7 +147,7 @@
/// The path of coding keys taken to get to this point in encoding.
/// A `nil` value indicates an unkeyed container.
- var codingPath: [CodingKey?] { get }
+ var codingPath: [CodingKey] { get }
/// Encodes a null value for the given key.
///
@@ -423,7 +423,7 @@
/// The path of coding keys taken to get to this point in encoding.
/// A `nil` value indicates an unkeyed container.
- public var codingPath: [CodingKey?] {
+ public var codingPath: [CodingKey] {
return _box.codingPath
}
@@ -761,7 +761,7 @@
/// The path of coding keys taken to get to this point in decoding.
/// A `nil` value indicates an unkeyed container.
- var codingPath: [CodingKey?] { get }
+ var codingPath: [CodingKey] { get }
/// All the keys the `Decoder` has for this container.
///
@@ -1136,7 +1136,7 @@
/// The path of coding keys taken to get to this point in decoding.
/// A `nil` value indicates an unkeyed container.
- public var codingPath: [CodingKey?] {
+ public var codingPath: [CodingKey] {
return _box.codingPath
}
@@ -1578,7 +1578,10 @@
public protocol UnkeyedEncodingContainer {
/// The path of coding keys taken to get to this point in encoding.
/// A `nil` value indicates an unkeyed container.
- var codingPath: [CodingKey?] { get }
+ var codingPath: [CodingKey] { get }
+
+ /// The number of elements encoded into the container.
+ var count: Int { get }
/// Encodes a null value.
///
@@ -1800,7 +1803,7 @@
public protocol UnkeyedDecodingContainer {
/// The path of coding keys taken to get to this point in decoding.
/// A `nil` value indicates an unkeyed container.
- var codingPath: [CodingKey?] { get }
+ var codingPath: [CodingKey] { get }
/// Returns the number of elements (if known) contained within this container.
var count: Int? { get }
@@ -1808,8 +1811,14 @@
/// Returns whether there are no more elements left to be decoded in the container.
var isAtEnd: Bool { get }
+ /// The current decoding index of the container (i.e. the index of the next element to be decoded.)
+ /// Incremented after every successful decode call.
+ var currentIndex: Int { get }
+
/// Decodes a null value.
///
+ /// If the value is not null, does not increment currentIndex.
+ ///
/// - returns: Whether the encountered value was null.
/// - throws: `DecodingError.valueNotFound` if there are no more values to decode.
mutating func decodeNil() throws -> Bool
@@ -2098,7 +2107,7 @@
public protocol SingleValueEncodingContainer {
/// The path of coding keys taken to get to this point in encoding.
/// A `nil` value indicates an unkeyed container.
- var codingPath: [CodingKey?] { get }
+ var codingPath: [CodingKey] { get }
/// Encodes a null value.
///
@@ -2216,7 +2225,7 @@
public protocol SingleValueDecodingContainer {
/// The path of coding keys taken to get to this point in encoding.
/// A `nil` value indicates an unkeyed container.
- var codingPath: [CodingKey?] { get }
+ var codingPath: [CodingKey] { get }
/// Decodes a null value.
///
@@ -2385,7 +2394,7 @@
/// The context in which the error occurred.
public struct Context {
/// The path of `CodingKey`s taken to get to the point of the failing encode call.
- public let codingPath: [CodingKey?]
+ public let codingPath: [CodingKey]
/// A description of what went wrong, for debugging purposes.
public let debugDescription: String
@@ -2398,7 +2407,7 @@
/// - parameter codingPath: The path of `CodingKey`s taken to get to the point of the failing encode call.
/// - parameter debugDescription: A description of what went wrong, for debugging purposes.
/// - parameter underlyingError: The underlying error which caused this error, if any.
- public init(codingPath: [CodingKey?], debugDescription: String, underlyingError: Error? = nil) {
+ public init(codingPath: [CodingKey], debugDescription: String, underlyingError: Error? = nil) {
self.codingPath = codingPath
self.debugDescription = debugDescription
self.underlyingError = underlyingError
@@ -2454,7 +2463,7 @@
/// The context in which the error occurred.
public struct Context {
/// The path of `CodingKey`s taken to get to the point of the failing decode call.
- public let codingPath: [CodingKey?]
+ public let codingPath: [CodingKey]
/// A description of what went wrong, for debugging purposes.
public let debugDescription: String
@@ -2467,7 +2476,7 @@
/// - parameter codingPath: The path of `CodingKey`s taken to get to the point of the failing decode call.
/// - parameter debugDescription: A description of what went wrong, for debugging purposes.
/// - parameter underlyingError: The underlying error which caused this error, if any.
- public init(codingPath: [CodingKey?], debugDescription: String, underlyingError: Error? = nil) {
+ public init(codingPath: [CodingKey], debugDescription: String, underlyingError: Error? = nil) {
self.codingPath = codingPath
self.debugDescription = debugDescription
self.underlyingError = underlyingError
@@ -2541,6 +2550,20 @@
// The following extensions allow for easier error construction.
+internal struct _GenericIndexKey : CodingKey {
+ var stringValue: String
+ var intValue: Int?
+
+ init?(stringValue: String) {
+ return nil
+ }
+
+ init?(intValue: Int) {
+ self.stringValue = "Index \(intValue)"
+ self.intValue = intValue
+ }
+}
+
public extension DecodingError {
/// A convenience method which creates a new .dataCorrupted error using a constructed coding path and the given debug description.
///
@@ -2562,7 +2585,7 @@
/// - param container: The container in which the corrupted data was accessed.
/// - param debugDescription: A description of the error to aid in debugging.
static func dataCorruptedError(in container: UnkeyedDecodingContainer, debugDescription: String) -> DecodingError {
- let context = DecodingError.Context(codingPath: container.codingPath + [nil],
+ let context = DecodingError.Context(codingPath: container.codingPath + [_GenericIndexKey(intValue: container.currentIndex)!],
debugDescription: debugDescription)
return .dataCorrupted(context)
}
@@ -2590,7 +2613,7 @@
// These must all be given a concrete implementation in _*Box.
@_inlineable
@_versioned
- internal var codingPath: [CodingKey?] {
+ internal var codingPath: [CodingKey] {
fatalError("_KeyedEncodingContainerBase cannot be used directly.")
}
@@ -2827,7 +2850,7 @@
@_inlineable
@_versioned
- override internal var codingPath: [CodingKey?] {
+ override internal var codingPath: [CodingKey] {
return concrete.codingPath
}
@@ -3053,7 +3076,7 @@
internal class _KeyedDecodingContainerBase<Key : CodingKey> {
@_inlineable
@_versioned
- internal var codingPath: [CodingKey?] {
+ internal var codingPath: [CodingKey] {
fatalError("_KeyedDecodingContainerBase cannot be used directly.")
}
@@ -3296,7 +3319,7 @@
@_inlineable
@_versioned
- override var codingPath: [CodingKey?] {
+ override var codingPath: [CodingKey] {
return concrete.codingPath
}
diff --git a/test/stdlib/TestJSONEncoder.swift b/test/stdlib/TestJSONEncoder.swift
index 9362421..c1f318f 100644
--- a/test/stdlib/TestJSONEncoder.swift
+++ b/test/stdlib/TestJSONEncoder.swift
@@ -408,27 +408,13 @@
}
// MARK: - Helper Global Functions
-func expectEqualPaths(_ lhs: [CodingKey?], _ rhs: [CodingKey?], _ prefix: String) {
+func expectEqualPaths(_ lhs: [CodingKey], _ rhs: [CodingKey], _ prefix: String) {
if lhs.count != rhs.count {
- expectUnreachable("\(prefix) [CodingKey?].count mismatch: \(lhs.count) != \(rhs.count)")
+ expectUnreachable("\(prefix) [CodingKey].count mismatch: \(lhs.count) != \(rhs.count)")
return
}
- for (k1, k2) in zip(lhs, rhs) {
- switch (k1, k2) {
- case (.none, .none): continue
- case (.some(let _k1), .none):
- expectUnreachable("\(prefix) CodingKey mismatch: \(type(of: _k1)) != nil")
- return
- case (.none, .some(let _k2)):
- expectUnreachable("\(prefix) CodingKey mismatch: nil != \(type(of: _k2))")
- return
- default: break
- }
-
- let key1 = k1!
- let key2 = k2!
-
+ for (key1, key2) in zip(lhs, rhs) {
switch (key1.intValue, key2.intValue) {
case (.none, .none): break
case (.some(let i1), .none):
@@ -788,7 +774,7 @@
}
}
- func _testNestedContainers(in encoder: Encoder, baseCodingPath: [CodingKey?]) {
+ func _testNestedContainers(in encoder: Encoder, baseCodingPath: [CodingKey]) {
expectEqualPaths(encoder.codingPath, baseCodingPath, "New encoder has non-empty codingPath.")
// codingPath should not change upon fetching a non-nested container.
@@ -822,30 +808,52 @@
// Nested Unkeyed Container
do {
// Nested container for key should have a new key pushed on.
- var secondLevelContainer = firstLevelContainer.nestedUnkeyedContainer(forKey: .a)
+ var secondLevelContainer = firstLevelContainer.nestedUnkeyedContainer(forKey: .b)
expectEqualPaths(encoder.codingPath, baseCodingPath, "Top-level Encoder's codingPath changed.")
expectEqualPaths(firstLevelContainer.codingPath, baseCodingPath, "First-level keyed container's codingPath changed.")
- expectEqualPaths(secondLevelContainer.codingPath, baseCodingPath + [TopLevelCodingKeys.a], "New second-level keyed container had unexpected codingPath.")
+ expectEqualPaths(secondLevelContainer.codingPath, baseCodingPath + [TopLevelCodingKeys.b], "New second-level keyed container had unexpected codingPath.")
// Appending a keyed container should not change existing coding paths.
let thirdLevelContainerKeyed = secondLevelContainer.nestedContainer(keyedBy: IntermediateCodingKeys.self)
expectEqualPaths(encoder.codingPath, baseCodingPath, "Top-level Encoder's codingPath changed.")
expectEqualPaths(firstLevelContainer.codingPath, baseCodingPath, "First-level keyed container's codingPath changed.")
- expectEqualPaths(secondLevelContainer.codingPath, baseCodingPath + [TopLevelCodingKeys.a], "Second-level unkeyed container's codingPath changed.")
- expectEqualPaths(thirdLevelContainerKeyed.codingPath, baseCodingPath + [TopLevelCodingKeys.a, nil], "New third-level keyed container had unexpected codingPath.")
+ expectEqualPaths(secondLevelContainer.codingPath, baseCodingPath + [TopLevelCodingKeys.b], "Second-level unkeyed container's codingPath changed.")
+ expectEqualPaths(thirdLevelContainerKeyed.codingPath, baseCodingPath + [TopLevelCodingKeys.b, _TestKey(index: 0)], "New third-level keyed container had unexpected codingPath.")
// Appending an unkeyed container should not change existing coding paths.
let thirdLevelContainerUnkeyed = secondLevelContainer.nestedUnkeyedContainer()
expectEqualPaths(encoder.codingPath, baseCodingPath, "Top-level Encoder's codingPath changed.")
expectEqualPaths(firstLevelContainer.codingPath, baseCodingPath, "First-level keyed container's codingPath changed.")
- expectEqualPaths(secondLevelContainer.codingPath, baseCodingPath + [TopLevelCodingKeys.a], "Second-level unkeyed container's codingPath changed.")
- expectEqualPaths(thirdLevelContainerUnkeyed.codingPath, baseCodingPath + [TopLevelCodingKeys.a, nil], "New third-level unkeyed container had unexpected codingPath.")
+ expectEqualPaths(secondLevelContainer.codingPath, baseCodingPath + [TopLevelCodingKeys.b], "Second-level unkeyed container's codingPath changed.")
+ expectEqualPaths(thirdLevelContainerUnkeyed.codingPath, baseCodingPath + [TopLevelCodingKeys.b, _TestKey(index: 1)], "New third-level unkeyed container had unexpected codingPath.")
}
}
}
// MARK: - Helper Types
+/// A key type which can take on any string or integer value.
+/// This needs to mirror _JSONKey.
+fileprivate struct _TestKey : CodingKey {
+ var stringValue: String
+ var intValue: Int?
+
+ init?(stringValue: String) {
+ self.stringValue = stringValue
+ self.intValue = nil
+ }
+
+ init?(intValue: Int) {
+ self.stringValue = "\(intValue)"
+ self.intValue = intValue
+ }
+
+ init(index: Int) {
+ self.stringValue = "Index \(index)"
+ self.intValue = index
+ }
+}
+
/// Wraps a type T so that it can be encoded at the top level of a payload.
fileprivate struct TopLevelWrapper<T> : Codable, Equatable where T : Codable, T : Equatable {
let value: T
diff --git a/test/stdlib/TestPlistEncoder.swift b/test/stdlib/TestPlistEncoder.swift
index 9f55f38..f20b200 100644
--- a/test/stdlib/TestPlistEncoder.swift
+++ b/test/stdlib/TestPlistEncoder.swift
@@ -192,27 +192,13 @@
}
// MARK: - Helper Global Functions
-func expectEqualPaths(_ lhs: [CodingKey?], _ rhs: [CodingKey?], _ prefix: String) {
+func expectEqualPaths(_ lhs: [CodingKey], _ rhs: [CodingKey], _ prefix: String) {
if lhs.count != rhs.count {
- expectUnreachable("\(prefix) [CodingKey?].count mismatch: \(lhs.count) != \(rhs.count)")
+ expectUnreachable("\(prefix) [CodingKey].count mismatch: \(lhs.count) != \(rhs.count)")
return
}
- for (k1, k2) in zip(lhs, rhs) {
- switch (k1, k2) {
- case (.none, .none): continue
- case (.some(let _k1), .none):
- expectUnreachable("\(prefix) CodingKey mismatch: \(type(of: _k1)) != nil")
- return
- case (.none, .some(let _k2)):
- expectUnreachable("\(prefix) CodingKey mismatch: nil != \(type(of: _k2))")
- return
- default: break
- }
-
- let key1 = k1!
- let key2 = k2!
-
+ for (key1, key2) in zip(lhs, rhs) {
switch (key1.intValue, key2.intValue) {
case (.none, .none): break
case (.some(let i1), .none):
@@ -572,7 +558,7 @@
}
}
- func _testNestedContainers(in encoder: Encoder, baseCodingPath: [CodingKey?]) {
+ func _testNestedContainers(in encoder: Encoder, baseCodingPath: [CodingKey]) {
expectEqualPaths(encoder.codingPath, baseCodingPath, "New encoder has non-empty codingPath.")
// codingPath should not change upon fetching a non-nested container.
@@ -606,30 +592,52 @@
// Nested Unkeyed Container
do {
// Nested container for key should have a new key pushed on.
- var secondLevelContainer = firstLevelContainer.nestedUnkeyedContainer(forKey: .a)
+ var secondLevelContainer = firstLevelContainer.nestedUnkeyedContainer(forKey: .b)
expectEqualPaths(encoder.codingPath, baseCodingPath, "Top-level Encoder's codingPath changed.")
expectEqualPaths(firstLevelContainer.codingPath, baseCodingPath, "First-level keyed container's codingPath changed.")
- expectEqualPaths(secondLevelContainer.codingPath, baseCodingPath + [TopLevelCodingKeys.a], "New second-level keyed container had unexpected codingPath.")
+ expectEqualPaths(secondLevelContainer.codingPath, baseCodingPath + [TopLevelCodingKeys.b], "New second-level keyed container had unexpected codingPath.")
// Appending a keyed container should not change existing coding paths.
let thirdLevelContainerKeyed = secondLevelContainer.nestedContainer(keyedBy: IntermediateCodingKeys.self)
expectEqualPaths(encoder.codingPath, baseCodingPath, "Top-level Encoder's codingPath changed.")
expectEqualPaths(firstLevelContainer.codingPath, baseCodingPath, "First-level keyed container's codingPath changed.")
- expectEqualPaths(secondLevelContainer.codingPath, baseCodingPath + [TopLevelCodingKeys.a], "Second-level unkeyed container's codingPath changed.")
- expectEqualPaths(thirdLevelContainerKeyed.codingPath, baseCodingPath + [TopLevelCodingKeys.a, nil], "New third-level keyed container had unexpected codingPath.")
+ expectEqualPaths(secondLevelContainer.codingPath, baseCodingPath + [TopLevelCodingKeys.b], "Second-level unkeyed container's codingPath changed.")
+ expectEqualPaths(thirdLevelContainerKeyed.codingPath, baseCodingPath + [TopLevelCodingKeys.b, _TestKey(index: 0)], "New third-level keyed container had unexpected codingPath.")
// Appending an unkeyed container should not change existing coding paths.
let thirdLevelContainerUnkeyed = secondLevelContainer.nestedUnkeyedContainer()
expectEqualPaths(encoder.codingPath, baseCodingPath, "Top-level Encoder's codingPath changed.")
expectEqualPaths(firstLevelContainer.codingPath, baseCodingPath, "First-level keyed container's codingPath changed.")
- expectEqualPaths(secondLevelContainer.codingPath, baseCodingPath + [TopLevelCodingKeys.a], "Second-level unkeyed container's codingPath changed.")
- expectEqualPaths(thirdLevelContainerUnkeyed.codingPath, baseCodingPath + [TopLevelCodingKeys.a, nil], "New third-level unkeyed container had unexpected codingPath.")
+ expectEqualPaths(secondLevelContainer.codingPath, baseCodingPath + [TopLevelCodingKeys.b], "Second-level unkeyed container's codingPath changed.")
+ expectEqualPaths(thirdLevelContainerUnkeyed.codingPath, baseCodingPath + [TopLevelCodingKeys.b, _TestKey(index: 1)], "New third-level unkeyed container had unexpected codingPath.")
}
}
}
// MARK: - Helper Types
+/// A key type which can take on any string or integer value.
+/// This needs to mirror _PlistKey.
+fileprivate struct _TestKey : CodingKey {
+ var stringValue: String
+ var intValue: Int?
+
+ init?(stringValue: String) {
+ self.stringValue = stringValue
+ self.intValue = nil
+ }
+
+ init?(intValue: Int) {
+ self.stringValue = "\(intValue)"
+ self.intValue = intValue
+ }
+
+ init(index: Int) {
+ self.stringValue = "Index \(index)"
+ self.intValue = index
+ }
+}
+
/// Wraps a type T so that it can be encoded at the top level of a payload.
fileprivate struct TopLevelWrapper<T> : Codable, Equatable where T : Codable, T : Equatable {
let value: T