diff --git a/Sources/XMLCoder/Auxiliaries/XMLElement.swift b/Sources/XMLCoder/Auxiliaries/XMLElement.swift index 4fcbd1b4..ec18f72e 100644 --- a/Sources/XMLCoder/Auxiliaries/XMLElement.swift +++ b/Sources/XMLCoder/Auxiliaries/XMLElement.swift @@ -23,7 +23,7 @@ internal class _XMLElement { self.children = children } - static func createRootElement(rootKey: String, object: ArrayBox) -> _XMLElement? { + static func createRootElement(rootKey: String, object: UnkeyedBox) -> _XMLElement? { let element = _XMLElement(key: rootKey) _XMLElement.createElement(parentElement: element, key: rootKey, object: object) @@ -31,7 +31,7 @@ internal class _XMLElement { return element } - static func createRootElement(rootKey: String, object: DictionaryBox) -> _XMLElement? { + static func createRootElement(rootKey: String, object: KeyedBox) -> _XMLElement? { let element = _XMLElement(key: rootKey) _XMLElement.modifyElement(element: element, parentElement: nil, key: nil, object: object) @@ -39,8 +39,8 @@ internal class _XMLElement { return element } - fileprivate static func modifyElement(element: _XMLElement, parentElement: _XMLElement?, key: String?, object: DictionaryBox) { - let attributesBox = object[_XMLElement.attributesKey] as? DictionaryBox + fileprivate static func modifyElement(element: _XMLElement, parentElement: _XMLElement?, key: String?, object: KeyedBox) { + let attributesBox = object[_XMLElement.attributesKey] as? KeyedBox let uniqueAttributes: [(String, String)]? = attributesBox?.unbox().compactMap { key, box in return box.xmlString().map { (key, $0) } } @@ -59,11 +59,11 @@ internal class _XMLElement { fileprivate static func createElement(parentElement: _XMLElement, key: String, object: Box) { switch object { - case let box as ArrayBox: + case let box as UnkeyedBox: for box in box.unbox() { _XMLElement.createElement(parentElement: parentElement, key: key, object: box) } - case let box as DictionaryBox: + case let box as KeyedBox: modifyElement(element: _XMLElement(key: key), parentElement: parentElement, key: key, object: box) case _: let element = _XMLElement(key: key, value: object.xmlString()) @@ -84,12 +84,12 @@ internal class _XMLElement { for childElement in children { for child in childElement.value { if let content = child.value { - if let oldContent = node[childElement.key] as? ArrayBox { + if let oldContent = node[childElement.key] as? UnkeyedBox { oldContent.append(StringBox(content)) // FIXME: Box is a reference type, so this shouldn't be necessary: node[childElement.key] = oldContent } else if let oldContent = node[childElement.key] { - node[childElement.key] = ArrayBox([oldContent, StringBox(content)]) + node[childElement.key] = UnkeyedBox([oldContent, StringBox(content)]) } else { node[childElement.key] = StringBox(content) } @@ -97,15 +97,15 @@ internal class _XMLElement { let newValue = child.flatten() if let existingValue = node[childElement.key] { - if let array = existingValue as? ArrayBox { - array.append(DictionaryBox(newValue)) + if let unkeyed = existingValue as? UnkeyedBox { + unkeyed.append(KeyedBox(newValue)) // FIXME: Box is a reference type, so this shouldn't be necessary: - node[childElement.key] = array + node[childElement.key] = unkeyed } else { - node[childElement.key] = ArrayBox([existingValue, DictionaryBox(newValue)]) + node[childElement.key] = UnkeyedBox([existingValue, KeyedBox(newValue)]) } } else { - node[childElement.key] = DictionaryBox(newValue) + node[childElement.key] = KeyedBox(newValue) } } } diff --git a/Sources/XMLCoder/Box/BoolBox.swift b/Sources/XMLCoder/Box/BoolBox.swift index 46674bd6..e2dca810 100644 --- a/Sources/XMLCoder/Box/BoolBox.swift +++ b/Sources/XMLCoder/Box/BoolBox.swift @@ -34,10 +34,6 @@ extension BoolBox: Box { return false } - var isFragment: Bool { - return true - } - /// # Lexical representation /// Boolean has a lexical representation consisting of the following /// legal literals {`true`, `false`, `1`, `0`}. @@ -53,6 +49,10 @@ extension BoolBox: Box { } } +extension BoolBox: SimpleBox { + +} + extension BoolBox: CustomStringConvertible { var description: String { return self.unboxed.description diff --git a/Sources/XMLCoder/Box/Box.swift b/Sources/XMLCoder/Box/Box.swift index 6c0b8c34..d4643318 100644 --- a/Sources/XMLCoder/Box/Box.swift +++ b/Sources/XMLCoder/Box/Box.swift @@ -9,7 +9,10 @@ import Foundation protocol Box { var isNull: Bool { get } - var isFragment: Bool { get } - func xmlString() -> String? } + +/// A box that only describes a single atomic value. +protocol SimpleBox: Box { + +} diff --git a/Sources/XMLCoder/Box/DataBox.swift b/Sources/XMLCoder/Box/DataBox.swift index 117ef23a..884dec7c 100644 --- a/Sources/XMLCoder/Box/DataBox.swift +++ b/Sources/XMLCoder/Box/DataBox.swift @@ -46,15 +46,15 @@ extension DataBox: Box { return false } - var isFragment: Bool { - return true - } - func xmlString() -> String? { return self.xmlString(format: self.format) } } +extension DataBox: SimpleBox { + +} + extension DataBox: CustomStringConvertible { var description: String { return self.unboxed.description diff --git a/Sources/XMLCoder/Box/DateBox.swift b/Sources/XMLCoder/Box/DateBox.swift index 5ce3f0d6..0c2f6756 100644 --- a/Sources/XMLCoder/Box/DateBox.swift +++ b/Sources/XMLCoder/Box/DateBox.swift @@ -88,15 +88,15 @@ extension DateBox: Box { return false } - var isFragment: Bool { - return true - } - func xmlString() -> String? { return self.xmlString(format: self.format) } } +extension DateBox: SimpleBox { + +} + extension DateBox: CustomStringConvertible { var description: String { return self.unboxed.description diff --git a/Sources/XMLCoder/Box/DecimalBox.swift b/Sources/XMLCoder/Box/DecimalBox.swift index 8a65e933..ce414270 100644 --- a/Sources/XMLCoder/Box/DecimalBox.swift +++ b/Sources/XMLCoder/Box/DecimalBox.swift @@ -33,10 +33,6 @@ extension DecimalBox: Box { return false } - var isFragment: Bool { - return true - } - /// # Lexical representation /// Decimal has a lexical representation consisting of a finite-length sequence of /// decimal digits separated by a period as a decimal indicator. @@ -60,6 +56,10 @@ extension DecimalBox: Box { } } +extension DecimalBox: SimpleBox { + +} + extension DecimalBox: CustomStringConvertible { var description: String { return self.unboxed.description diff --git a/Sources/XMLCoder/Box/FloatBox.swift b/Sources/XMLCoder/Box/FloatBox.swift index 1968d00c..ed55b560 100644 --- a/Sources/XMLCoder/Box/FloatBox.swift +++ b/Sources/XMLCoder/Box/FloatBox.swift @@ -33,10 +33,6 @@ extension FloatBox: Box { return false } - var isFragment: Bool { - return true - } - /// # Lexical representation /// float values have a lexical representation consisting of a mantissa followed, optionally, /// by the character `"E"` or `"e"`, followed by an exponent. The exponent **must** be an integer. @@ -78,6 +74,10 @@ extension FloatBox: Box { } } +extension FloatBox: SimpleBox { + +} + extension FloatBox: CustomStringConvertible { var description: String { return self.unboxed.description diff --git a/Sources/XMLCoder/Box/IntBox.swift b/Sources/XMLCoder/Box/IntBox.swift index f43ba986..2bedb312 100644 --- a/Sources/XMLCoder/Box/IntBox.swift +++ b/Sources/XMLCoder/Box/IntBox.swift @@ -33,10 +33,6 @@ extension IntBox: Box { return false } - var isFragment: Bool { - return true - } - /// # Lexical representation /// Integer has a lexical representation consisting of a finite-length sequence of /// decimal digits with an optional leading sign. If the sign is omitted, `"+"` is assumed. @@ -55,6 +51,10 @@ extension IntBox: Box { } } +extension IntBox: SimpleBox { + +} + extension IntBox: CustomStringConvertible { var description: String { return self.unboxed.description diff --git a/Sources/XMLCoder/Box/DictionaryBox.swift b/Sources/XMLCoder/Box/KeyedBox.swift similarity index 83% rename from Sources/XMLCoder/Box/DictionaryBox.swift rename to Sources/XMLCoder/Box/KeyedBox.swift index 0d75d548..ffe88790 100644 --- a/Sources/XMLCoder/Box/DictionaryBox.swift +++ b/Sources/XMLCoder/Box/KeyedBox.swift @@ -1,5 +1,5 @@ // -// DictionaryBox.swift +// KeyedBox.swift // XMLCoderPackageDescription // // Created by Vincent Esche on 11/19/18. @@ -8,7 +8,7 @@ import Foundation // Minimalist implementation of an order-preserving keyed box: -class DictionaryBox { +class KeyedBox { typealias Key = String typealias Value = Box @@ -58,27 +58,30 @@ class DictionaryBox { return try self.unboxed.compactMap(transform) } - func mapValues(_ transform: (Value) throws -> Value) rethrows -> DictionaryBox { - return DictionaryBox(try self.unboxed.mapValues(transform)) + func mapValues(_ transform: (Value) throws -> Value) rethrows -> KeyedBox { + return KeyedBox(try self.unboxed.mapValues(transform)) } } -extension DictionaryBox: Box { +extension KeyedBox: Box { var isNull: Bool { return false } - var isFragment: Bool { - return false - } - func xmlString() -> String? { return nil } } +extension KeyedBox: Sequence { + typealias Iterator = Unboxed.Iterator + + func makeIterator() -> Iterator { + return self.unboxed.makeIterator() + } +} -extension DictionaryBox: CustomStringConvertible { +extension KeyedBox: CustomStringConvertible { var description: String { return self.unboxed.description } diff --git a/Sources/XMLCoder/Box/NullBox.swift b/Sources/XMLCoder/Box/NullBox.swift index e3078960..be04bf5e 100644 --- a/Sources/XMLCoder/Box/NullBox.swift +++ b/Sources/XMLCoder/Box/NullBox.swift @@ -16,15 +16,15 @@ extension NullBox: Box { return true } - var isFragment: Bool { - return true - } - func xmlString() -> String? { return nil } } +extension NullBox: SimpleBox { + +} + extension NullBox: Equatable { static func == (lhs: NullBox, rhs: NullBox) -> Bool { return true diff --git a/Sources/XMLCoder/Box/StringBox.swift b/Sources/XMLCoder/Box/StringBox.swift index 93dd9327..39cb88ad 100644 --- a/Sources/XMLCoder/Box/StringBox.swift +++ b/Sources/XMLCoder/Box/StringBox.swift @@ -30,15 +30,15 @@ extension StringBox: Box { return false } - var isFragment: Bool { - return true - } - func xmlString() -> String? { return self.unboxed.description } } +extension StringBox: SimpleBox { + +} + extension StringBox: CustomStringConvertible { var description: String { return self.unboxed.description diff --git a/Sources/XMLCoder/Box/UIntBox.swift b/Sources/XMLCoder/Box/UIntBox.swift index 753aacce..63f76121 100644 --- a/Sources/XMLCoder/Box/UIntBox.swift +++ b/Sources/XMLCoder/Box/UIntBox.swift @@ -33,10 +33,6 @@ extension UIntBox: Box { return false } - var isFragment: Bool { - return true - } - /// # Lexical representation /// Unsigned integer has a lexical representation consisting of an optional /// sign followed by a finite-length sequence of decimal digits. @@ -58,6 +54,10 @@ extension UIntBox: Box { } } +extension UIntBox: SimpleBox { + +} + extension UIntBox: CustomStringConvertible { var description: String { return self.unboxed.description diff --git a/Sources/XMLCoder/Box/ArrayBox.swift b/Sources/XMLCoder/Box/UnkeyedBox.swift similarity index 84% rename from Sources/XMLCoder/Box/ArrayBox.swift rename to Sources/XMLCoder/Box/UnkeyedBox.swift index 24c8314f..83013757 100644 --- a/Sources/XMLCoder/Box/ArrayBox.swift +++ b/Sources/XMLCoder/Box/UnkeyedBox.swift @@ -1,5 +1,5 @@ // -// ArrayBox.swift +// UnkeyedBox.swift // XMLCoderPackageDescription // // Created by Vincent Esche on 11/20/18. @@ -8,7 +8,7 @@ import Foundation // Minimalist implementation of an order-preserving unkeyed box: -class ArrayBox { +class UnkeyedBox { typealias Element = Box typealias Unboxed = [Element] @@ -56,21 +56,25 @@ class ArrayBox { } } -extension ArrayBox: Box { +extension UnkeyedBox: Box { var isNull: Bool { return false } - var isFragment: Bool { - return false - } - func xmlString() -> String? { return nil } } -extension ArrayBox: CustomStringConvertible { +extension UnkeyedBox: Sequence { + typealias Iterator = Unboxed.Iterator + + func makeIterator() -> Iterator { + return self.unboxed.makeIterator() + } +} + +extension UnkeyedBox: CustomStringConvertible { var description: String { return self.unboxed.description } diff --git a/Sources/XMLCoder/Decoder/DecodingErrorExtension.swift b/Sources/XMLCoder/Decoder/DecodingErrorExtension.swift index 9b8b4146..61a61824 100644 --- a/Sources/XMLCoder/Decoder/DecodingErrorExtension.swift +++ b/Sources/XMLCoder/Decoder/DecodingErrorExtension.swift @@ -43,9 +43,9 @@ internal extension DecodingError { return "an unsigned integer value" case is FloatBox: return "a floating-point value" - case is ArrayBox: + case is UnkeyedBox: return "a array value" - case is DictionaryBox: + case is KeyedBox: return "a dictionary value" case _: return "\(type(of: box))" diff --git a/Sources/XMLCoder/Decoder/XMLDecoder.swift b/Sources/XMLCoder/Decoder/XMLDecoder.swift index 309a78e5..86cedb6a 100644 --- a/Sources/XMLCoder/Decoder/XMLDecoder.swift +++ b/Sources/XMLCoder/Decoder/XMLDecoder.swift @@ -245,7 +245,7 @@ open class XMLDecoder { open func decode(_ type: T.Type, from data: Data) throws -> T { let topLevel: Box do { - topLevel = DictionaryBox(try _XMLStackParser.parse(with: data)) + topLevel = KeyedBox(try _XMLStackParser.parse(with: data)) } catch { throw DecodingError.dataCorrupted(DecodingError.Context( codingPath: [], @@ -305,11 +305,11 @@ internal class _XMLDecoder: Decoder { )) } - guard let dictionary = storage.topContainer as? DictionaryBox else { + guard let keyed = storage.topContainer as? KeyedBox else { throw DecodingError._typeMismatch(at: codingPath, expectation: [String: Any].self, reality: storage.topContainer) } - let container = _XMLKeyedDecodingContainer(referencing: self, wrapping: dictionary) + let container = _XMLKeyedDecodingContainer(referencing: self, wrapping: keyed) return KeyedDecodingContainer(container) } @@ -321,15 +321,9 @@ internal class _XMLDecoder: Decoder { )) } - let array: ArrayBox + let unkeyed = (storage.topContainer as? UnkeyedBox) ?? UnkeyedBox([storage.topContainer]) - if let container = storage.topContainer as? ArrayBox { - array = container - } else { - array = ArrayBox([storage.topContainer]) - } - - return _XMLUnkeyedDecodingContainer(referencing: self, wrapping: array) + return _XMLUnkeyedDecodingContainer(referencing: self, wrapping: unkeyed) } public func singleValueContainer() throws -> SingleValueDecodingContainer { diff --git a/Sources/XMLCoder/Decoder/XMLDecodingStorage.swift b/Sources/XMLCoder/Decoder/XMLDecodingStorage.swift index 3593b817..1057cd1d 100644 --- a/Sources/XMLCoder/Decoder/XMLDecodingStorage.swift +++ b/Sources/XMLCoder/Decoder/XMLDecodingStorage.swift @@ -14,7 +14,7 @@ internal struct _XMLDecodingStorage { // MARK: Properties /// The container stack. - /// Elements may be any one of the XML types (String, [String : Any]). + /// Elements may be any one of the XML types (StringBox, KeyedBox). private var containers: [Box] = [] // MARK: - Initialization diff --git a/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift b/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift index 72161851..2ae70132 100644 --- a/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift +++ b/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift @@ -28,7 +28,7 @@ internal struct _XMLKeyedDecodingContainer: KeyedDecodingContainer private let decoder: _XMLDecoder /// A reference to the container we're reading from. - private let container: DictionaryBox + private let container: KeyedBox /// The path of coding keys taken to get to this point in decoding. public private(set) var codingPath: [CodingKey] @@ -36,7 +36,7 @@ internal struct _XMLKeyedDecodingContainer: KeyedDecodingContainer // MARK: - Initialization /// Initializes `self` by referencing the given decoder and container. - internal init(referencing decoder: _XMLDecoder, wrapping container: DictionaryBox) { + internal init(referencing decoder: _XMLDecoder, wrapping container: KeyedBox) { self.decoder = decoder switch decoder.options.keyDecodingStrategy { case .useDefaultKeys: @@ -44,15 +44,15 @@ internal struct _XMLKeyedDecodingContainer: KeyedDecodingContainer case .convertFromSnakeCase: // Convert the snake case keys in the container to camel case. // If we hit a duplicate key after conversion, then we'll use the first one we saw. Effectively an undefined behavior with dictionaries. - self.container = DictionaryBox(container.map { + self.container = KeyedBox(container.map { key, value in (XMLDecoder.KeyDecodingStrategy._convertFromSnakeCase(key), value) }, uniquingKeysWith: { first, _ in first }) case .convertFromCapitalized: - self.container = DictionaryBox(container.map { + self.container = KeyedBox(container.map { key, value in (XMLDecoder.KeyDecodingStrategy._convertFromCapitalized(key), value) }, uniquingKeysWith: { first, _ in first }) case let .custom(converter): - self.container = DictionaryBox(container.map { + self.container = KeyedBox(container.map { key, value in (converter(decoder.codingPath + [_XMLKey(stringValue: key, intValue: nil)]).stringValue, value) }, uniquingKeysWith: { first, _ in first }) } @@ -95,229 +95,131 @@ internal struct _XMLKeyedDecodingContainer: KeyedDecodingContainer } public func decode(_ type: Bool.Type, forKey key: Key) throws -> Bool { - guard let entry = container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + return try self.decode(type, forKey: key) { decoder, box in + return try decoder.unbox(box) } + } - decoder.codingPath.append(key) - defer { self.decoder.codingPath.removeLast() } - - guard let value: Bool = try self.decoder.unbox(entry) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + public func decode(_ type: Decimal.Type, forKey key: Key) throws -> Decimal { + return try self.decode(type, forKey: key) { decoder, box in + return try decoder.unbox(box) } - - return value } public func decode(_ type: Int.Type, forKey key: Key) throws -> Int { - guard let entry = container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) - } - - decoder.codingPath.append(key) - defer { self.decoder.codingPath.removeLast() } - - guard let value: Int = try self.decoder.unbox(entry) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) - } - - return value + return try self.decodeSignedInteger(type, forKey: key) } public func decode(_ type: Int8.Type, forKey key: Key) throws -> Int8 { - guard let entry = container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) - } - - decoder.codingPath.append(key) - defer { self.decoder.codingPath.removeLast() } - - guard let value: Int8 = try self.decoder.unbox(entry) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) - } - - return value + return try self.decodeSignedInteger(type, forKey: key) } public func decode(_ type: Int16.Type, forKey key: Key) throws -> Int16 { - guard let entry = container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) - } - - decoder.codingPath.append(key) - defer { self.decoder.codingPath.removeLast() } - - guard let value: Int16 = try self.decoder.unbox(entry) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) - } - - return value + return try self.decodeSignedInteger(type, forKey: key) } public func decode(_ type: Int32.Type, forKey key: Key) throws -> Int32 { - guard let entry = container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) - } - - decoder.codingPath.append(key) - defer { self.decoder.codingPath.removeLast() } - - guard let value: Int32 = try self.decoder.unbox(entry) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) - } - - return value + return try self.decodeSignedInteger(type, forKey: key) } public func decode(_ type: Int64.Type, forKey key: Key) throws -> Int64 { - guard let entry = container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) - } - - decoder.codingPath.append(key) - defer { self.decoder.codingPath.removeLast() } - - guard let value: Int64 = try self.decoder.unbox(entry) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) - } - - return value + return try self.decodeSignedInteger(type, forKey: key) } public func decode(_ type: UInt.Type, forKey key: Key) throws -> UInt { - guard let entry = container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) - } - - decoder.codingPath.append(key) - defer { self.decoder.codingPath.removeLast() } - - guard let value: UInt = try self.decoder.unbox(entry) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) - } - - return value + return try self.decodeUnsignedInteger(type, forKey: key) } public func decode(_ type: UInt8.Type, forKey key: Key) throws -> UInt8 { - guard let entry = container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) - } - - decoder.codingPath.append(key) - defer { self.decoder.codingPath.removeLast() } - - guard let value: UInt8 = try self.decoder.unbox(entry) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) - } - - return value + return try self.decodeUnsignedInteger(type, forKey: key) } public func decode(_ type: UInt16.Type, forKey key: Key) throws -> UInt16 { - guard let entry = container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) - } - - decoder.codingPath.append(key) - defer { self.decoder.codingPath.removeLast() } - - guard let value: UInt16 = try self.decoder.unbox(entry) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) - } - - return value + return try self.decodeUnsignedInteger(type, forKey: key) } public func decode(_ type: UInt32.Type, forKey key: Key) throws -> UInt32 { - guard let entry = container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) - } - - decoder.codingPath.append(key) - defer { self.decoder.codingPath.removeLast() } - - guard let value: UInt32 = try decoder.unbox(entry) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) - } - - return value + return try self.decodeUnsignedInteger(type, forKey: key) } public func decode(_ type: UInt64.Type, forKey key: Key) throws -> UInt64 { - guard let entry = container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) - } - - decoder.codingPath.append(key) - defer { self.decoder.codingPath.removeLast() } - - guard let value: UInt64 = try self.decoder.unbox(entry) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) - } - - return value + return try self.decodeUnsignedInteger(type, forKey: key) } public func decode(_ type: Float.Type, forKey key: Key) throws -> Float { - guard let entry = container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) - } + return try self.decodeFloatingPoint(type, forKey: key) + } - decoder.codingPath.append(key) - defer { self.decoder.codingPath.removeLast() } + public func decode(_ type: Double.Type, forKey key: Key) throws -> Double { + return try self.decodeFloatingPoint(type, forKey: key) + } - guard let value: Float = try decoder.unbox(entry) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + public func decode(_ type: String.Type, forKey key: Key) throws -> String { + return try self.decode(type, forKey: key) { decoder, box in + return try decoder.unbox(box) } - - return value } - public func decode(_ type: Double.Type, forKey key: Key) throws -> Double { - guard let entry = container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + public func decode(_ type: Date.Type, forKey key: Key) throws -> Date { + return try self.decode(type, forKey: key) { decoder, box in + return try decoder.unbox(box) } + } - decoder.codingPath.append(key) - defer { self.decoder.codingPath.removeLast() } - - guard let value: Double = try self.decoder.unbox(entry) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + public func decode(_ type: Data.Type, forKey key: Key) throws -> Data { + return try self.decode(type, forKey: key) { decoder, box in + return try decoder.unbox(box) } - - return value } - public func decode(_ type: String.Type, forKey key: Key) throws -> String { - guard let entry = container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + public func decode(_ type: T.Type, forKey key: Key) throws -> T { + if type is AnyEmptySequence.Type && container[key.stringValue] == nil { + return (type as! AnyEmptySequence.Type).init() as! T } - decoder.codingPath.append(key) - defer { self.decoder.codingPath.removeLast() } + return try self.decode(type, forKey: key) { decoder, box in + return try decoder.unbox(box) + } + } - guard let value: String = try decoder.unbox(entry) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + private func decodeSignedInteger(_ type: T.Type, forKey key: Key) throws -> T { + return try self.decode(type, forKey: key) { decoder, box in + return try decoder.unbox(box) } + } - return value + private func decodeUnsignedInteger(_ type: T.Type, forKey key: Key) throws -> T { + return try self.decode(type, forKey: key) { decoder, box in + return try decoder.unbox(box) + } } - public func decode(_ type: T.Type, forKey key: Key) throws -> T { - if type is AnyEmptySequence.Type && container[key.stringValue] == nil { - return (type as! AnyEmptySequence.Type).init() as! T + private func decodeFloatingPoint(_ type: T.Type, forKey key: Key) throws -> T { + return try self.decode(type, forKey: key) { decoder, box in + return try decoder.unbox(box) } + } + private func decode( + _ type: T.Type, + forKey key: Key, + decode: (_XMLDecoder, Box) throws -> T? + ) throws -> T { guard let entry = container[key.stringValue] else { - throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + throw DecodingError.keyNotFound(key, DecodingError.Context( + codingPath: decoder.codingPath, + debugDescription: "No value associated with key \(_errorDescription(of: key))." + )) } decoder.codingPath.append(key) defer { decoder.codingPath.removeLast() } guard let value: T = try decoder.unbox(entry) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + throw DecodingError.valueNotFound(type, DecodingError.Context( + codingPath: decoder.codingPath, + debugDescription: "Expected \(type) value but found null instead." + )) } return value @@ -328,16 +230,17 @@ internal struct _XMLKeyedDecodingContainer: KeyedDecodingContainer defer { decoder.codingPath.removeLast() } guard let value = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, - DecodingError.Context(codingPath: codingPath, - debugDescription: "Cannot get \(KeyedDecodingContainer.self) -- no value found for key \"\(key.stringValue)\"")) + throw DecodingError.keyNotFound(key, DecodingError.Context( + codingPath: codingPath, + debugDescription: "Cannot get \(KeyedDecodingContainer.self) -- no value found for key \"\(key.stringValue)\"" + )) } - guard let dictionary = value as? DictionaryBox else { + guard let keyed = value as? KeyedBox else { throw DecodingError._typeMismatch(at: codingPath, expectation: [String: Any].self, reality: value) } - let container = _XMLKeyedDecodingContainer(referencing: decoder, wrapping: dictionary) + let container = _XMLKeyedDecodingContainer(referencing: decoder, wrapping: keyed) return KeyedDecodingContainer(container) } @@ -346,16 +249,17 @@ internal struct _XMLKeyedDecodingContainer: KeyedDecodingContainer defer { decoder.codingPath.removeLast() } guard let value = self.container[key.stringValue] else { - throw DecodingError.keyNotFound(key, - DecodingError.Context(codingPath: codingPath, - debugDescription: "Cannot get UnkeyedDecodingContainer -- no value found for key \"\(key.stringValue)\"")) + throw DecodingError.keyNotFound(key, DecodingError.Context( + codingPath: codingPath, + debugDescription: "Cannot get UnkeyedDecodingContainer -- no value found for key \"\(key.stringValue)\"" + )) } - guard let array = value as? ArrayBox else { + guard let unkeyed = value as? UnkeyedBox else { throw DecodingError._typeMismatch(at: codingPath, expectation: [Any].self, reality: value) } - return _XMLUnkeyedDecodingContainer(referencing: decoder, wrapping: array) + return _XMLUnkeyedDecodingContainer(referencing: decoder, wrapping: unkeyed) } private func _superDecoder(forKey key: CodingKey) throws -> Decoder { diff --git a/Sources/XMLCoder/Decoder/XMLUnkeyedDecodingContainer.swift b/Sources/XMLCoder/Decoder/XMLUnkeyedDecodingContainer.swift index d4c8fe48..b7650bcb 100644 --- a/Sources/XMLCoder/Decoder/XMLUnkeyedDecodingContainer.swift +++ b/Sources/XMLCoder/Decoder/XMLUnkeyedDecodingContainer.swift @@ -15,7 +15,7 @@ internal struct _XMLUnkeyedDecodingContainer: UnkeyedDecodingContainer { private let decoder: _XMLDecoder /// A reference to the container we're reading from. - private let container: ArrayBox + private let container: UnkeyedBox /// The path of coding keys taken to get to this point in decoding. public private(set) var codingPath: [CodingKey] @@ -26,7 +26,7 @@ internal struct _XMLUnkeyedDecodingContainer: UnkeyedDecodingContainer { // MARK: - Initialization /// Initializes `self` by referencing the given decoder and container. - internal init(referencing decoder: _XMLDecoder, wrapping container: ArrayBox) { + internal init(referencing decoder: _XMLDecoder, wrapping container: UnkeyedBox) { self.decoder = decoder self.container = container codingPath = decoder.codingPath @@ -45,7 +45,10 @@ internal struct _XMLUnkeyedDecodingContainer: UnkeyedDecodingContainer { public mutating func decodeNil() throws -> Bool { guard !isAtEnd else { - throw DecodingError.valueNotFound(Any?.self, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + throw DecodingError.valueNotFound(Any?.self, DecodingError.Context( + codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], + debugDescription: "Unkeyed container is at end." + )) } if container[self.currentIndex].isNull { @@ -57,241 +60,112 @@ internal struct _XMLUnkeyedDecodingContainer: UnkeyedDecodingContainer { } public mutating func decode(_ type: Bool.Type) throws -> Bool { - guard !isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) - } - - decoder.codingPath.append(_XMLKey(index: currentIndex)) - defer { self.decoder.codingPath.removeLast() } - - guard let decoded: Bool = try self.decoder.unbox(self.container[self.currentIndex]) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + return try self.decode(type) { decoder, box in + return try decoder.unbox(box) } - - currentIndex += 1 - return decoded } public mutating func decode(_ type: Int.Type) throws -> Int { - guard !isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) - } - - decoder.codingPath.append(_XMLKey(index: currentIndex)) - defer { self.decoder.codingPath.removeLast() } - - guard let decoded: Int = try self.decoder.unbox(self.container[self.currentIndex]) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) - } - - currentIndex += 1 - return decoded + return try self.decodeSignedInteger(type) } public mutating func decode(_ type: Int8.Type) throws -> Int8 { - guard !isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) - } - - decoder.codingPath.append(_XMLKey(index: currentIndex)) - defer { self.decoder.codingPath.removeLast() } - - guard let decoded: Int8 = try self.decoder.unbox(self.container[self.currentIndex]) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) - } - - currentIndex += 1 - return decoded + return try self.decodeSignedInteger(type) } public mutating func decode(_ type: Int16.Type) throws -> Int16 { - guard !isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) - } - - decoder.codingPath.append(_XMLKey(index: currentIndex)) - defer { self.decoder.codingPath.removeLast() } - - guard let decoded: Int16 = try self.decoder.unbox(self.container[self.currentIndex]) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) - } - - currentIndex += 1 - return decoded + return try self.decodeSignedInteger(type) } public mutating func decode(_ type: Int32.Type) throws -> Int32 { - guard !isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) - } - - decoder.codingPath.append(_XMLKey(index: currentIndex)) - defer { self.decoder.codingPath.removeLast() } - - guard let decoded: Int32 = try self.decoder.unbox(self.container[self.currentIndex]) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) - } - - currentIndex += 1 - return decoded + return try self.decodeSignedInteger(type) } public mutating func decode(_ type: Int64.Type) throws -> Int64 { - guard !isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) - } - - decoder.codingPath.append(_XMLKey(index: currentIndex)) - defer { self.decoder.codingPath.removeLast() } - - guard let decoded: Int64 = try self.decoder.unbox(self.container[self.currentIndex]) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) - } - - currentIndex += 1 - return decoded + return try self.decodeSignedInteger(type) } - + public mutating func decode(_ type: UInt.Type) throws -> UInt { - guard !isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) - } - - decoder.codingPath.append(_XMLKey(index: currentIndex)) - defer { self.decoder.codingPath.removeLast() } - - guard let decoded: UInt = try self.decoder.unbox(self.container[self.currentIndex]) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) - } - - currentIndex += 1 - return decoded + return try self.decodeUnsignedInteger(type) } public mutating func decode(_ type: UInt8.Type) throws -> UInt8 { - guard !isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) - } - - decoder.codingPath.append(_XMLKey(index: currentIndex)) - defer { self.decoder.codingPath.removeLast() } - - guard let decoded: UInt8 = try self.decoder.unbox(self.container[self.currentIndex]) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) - } - - currentIndex += 1 - return decoded + return try self.decodeUnsignedInteger(type) } public mutating func decode(_ type: UInt16.Type) throws -> UInt16 { - guard !isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) - } - - decoder.codingPath.append(_XMLKey(index: currentIndex)) - defer { self.decoder.codingPath.removeLast() } - - guard let decoded: UInt16 = try self.decoder.unbox(self.container[self.currentIndex]) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) - } - - currentIndex += 1 - return decoded + return try self.decodeUnsignedInteger(type) } public mutating func decode(_ type: UInt32.Type) throws -> UInt32 { - guard !isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) - } - - decoder.codingPath.append(_XMLKey(index: currentIndex)) - defer { self.decoder.codingPath.removeLast() } - - guard let decoded: UInt32 = try self.decoder.unbox(self.container[self.currentIndex]) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) - } - - currentIndex += 1 - return decoded + return try self.decodeUnsignedInteger(type) } public mutating func decode(_ type: UInt64.Type) throws -> UInt64 { - guard !isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) - } - - decoder.codingPath.append(_XMLKey(index: currentIndex)) - defer { self.decoder.codingPath.removeLast() } - - guard let decoded: UInt64 = try self.decoder.unbox(self.container[self.currentIndex]) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) - } - - currentIndex += 1 - return decoded + return try self.decodeUnsignedInteger(type) } - + public mutating func decode(_ type: Float.Type) throws -> Float { - guard !isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) - } + return try self.decodeFloatingPoint(type) + } - decoder.codingPath.append(_XMLKey(index: currentIndex)) - defer { self.decoder.codingPath.removeLast() } + public mutating func decode(_ type: Double.Type) throws -> Double { + return try self.decodeFloatingPoint(type) + } - guard let decoded: Float = try self.decoder.unbox(self.container[self.currentIndex]) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + public mutating func decode(_ type: String.Type) throws -> String { + return try self.decode(type) { decoder, box in + return try decoder.unbox(box) } - - currentIndex += 1 - return decoded } - public mutating func decode(_ type: Double.Type) throws -> Double { - guard !isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + public mutating func decode(_ type: T.Type) throws -> T { + return try self.decode(type) { decoder, box in + return try decoder.unbox(box) } - - decoder.codingPath.append(_XMLKey(index: currentIndex)) - defer { self.decoder.codingPath.removeLast() } - - guard let decoded: Double = try self.decoder.unbox(self.container[self.currentIndex]) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + } + + private mutating func decodeSignedInteger(_ type: T.Type) throws -> T { + return try self.decode(type) { decoder, box in + return try decoder.unbox(box) } - - currentIndex += 1 - return decoded } - - public mutating func decode(_ type: String.Type) throws -> String { - guard !isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + + private mutating func decodeUnsignedInteger(_ type: T.Type) throws -> T { + return try self.decode(type) { decoder, box in + return try decoder.unbox(box) } - - decoder.codingPath.append(_XMLKey(index: currentIndex)) - defer { self.decoder.codingPath.removeLast() } - - guard let decoded: String = try self.decoder.unbox(self.container[self.currentIndex]) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + } + + private mutating func decodeFloatingPoint(_ type: T.Type) throws -> T { + return try self.decode(type) { decoder, box in + return try decoder.unbox(box) } - - currentIndex += 1 - return decoded } - - public mutating func decode(_ type: T.Type) throws -> T { + + private mutating func decode( + _ type: T.Type, + decode: (_XMLDecoder, Box) throws -> T? + ) throws -> T { guard !isAtEnd else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + throw DecodingError.valueNotFound(type, DecodingError.Context( + codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], + debugDescription: "Unkeyed container is at end." + )) } - + decoder.codingPath.append(_XMLKey(index: currentIndex)) defer { self.decoder.codingPath.removeLast() } - - guard let decoded: T = try self.decoder.unbox(self.container[self.currentIndex]) else { - throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + + let box = self.container[self.currentIndex] + let value = try decode(decoder, box) + guard let decoded: T = value else { + throw DecodingError.valueNotFound(type, DecodingError.Context( + codingPath: decoder.codingPath + [_XMLKey(index: self.currentIndex)], + debugDescription: "Expected \(type) but found null instead." + )) } - + currentIndex += 1 return decoded } @@ -301,24 +175,26 @@ internal struct _XMLUnkeyedDecodingContainer: UnkeyedDecodingContainer { defer { self.decoder.codingPath.removeLast() } guard !isAtEnd else { - throw DecodingError.valueNotFound(KeyedDecodingContainer.self, - DecodingError.Context(codingPath: codingPath, - debugDescription: "Cannot get nested keyed container -- unkeyed container is at end.")) + throw DecodingError.valueNotFound(KeyedDecodingContainer.self, DecodingError.Context( + codingPath: codingPath, + debugDescription: "Cannot get nested keyed container -- unkeyed container is at end." + )) } let value = self.container[self.currentIndex] guard !value.isNull else { - throw DecodingError.valueNotFound(KeyedDecodingContainer.self, - DecodingError.Context(codingPath: codingPath, - debugDescription: "Cannot get keyed decoding container -- found null value instead.")) + throw DecodingError.valueNotFound(KeyedDecodingContainer.self, DecodingError.Context( + codingPath: codingPath, + debugDescription: "Cannot get keyed decoding container -- found null value instead." + )) } - guard let dictionary = value as? DictionaryBox else { + guard let keyed = value as? KeyedBox else { throw DecodingError._typeMismatch(at: codingPath, expectation: [String: Any].self, reality: value) } currentIndex += 1 - let container = _XMLKeyedDecodingContainer(referencing: decoder, wrapping: dictionary) + let container = _XMLKeyedDecodingContainer(referencing: decoder, wrapping: keyed) return KeyedDecodingContainer(container) } @@ -327,24 +203,26 @@ internal struct _XMLUnkeyedDecodingContainer: UnkeyedDecodingContainer { defer { self.decoder.codingPath.removeLast() } guard !isAtEnd else { - throw DecodingError.valueNotFound(UnkeyedDecodingContainer.self, - DecodingError.Context(codingPath: codingPath, - debugDescription: "Cannot get nested keyed container -- unkeyed container is at end.")) + throw DecodingError.valueNotFound(UnkeyedDecodingContainer.self, DecodingError.Context( + codingPath: codingPath, + debugDescription: "Cannot get nested keyed container -- unkeyed container is at end." + )) } let value = container[self.currentIndex] guard !value.isNull else { - throw DecodingError.valueNotFound(UnkeyedDecodingContainer.self, - DecodingError.Context(codingPath: codingPath, - debugDescription: "Cannot get keyed decoding container -- found null value instead.")) + throw DecodingError.valueNotFound(UnkeyedDecodingContainer.self, DecodingError.Context( + codingPath: codingPath, + debugDescription: "Cannot get keyed decoding container -- found null value instead." + )) } - guard let array = value as? ArrayBox else { - throw DecodingError._typeMismatch(at: codingPath, expectation: ArrayBox.self, reality: value) + guard let unkeyed = value as? UnkeyedBox else { + throw DecodingError._typeMismatch(at: codingPath, expectation: UnkeyedBox.self, reality: value) } currentIndex += 1 - return _XMLUnkeyedDecodingContainer(referencing: decoder, wrapping: array) + return _XMLUnkeyedDecodingContainer(referencing: decoder, wrapping: unkeyed) } public mutating func superDecoder() throws -> Decoder { @@ -352,9 +230,10 @@ internal struct _XMLUnkeyedDecodingContainer: UnkeyedDecodingContainer { defer { self.decoder.codingPath.removeLast() } guard !isAtEnd else { - throw DecodingError.valueNotFound(Decoder.self, - DecodingError.Context(codingPath: codingPath, - debugDescription: "Cannot get superDecoder() -- unkeyed container is at end.")) + throw DecodingError.valueNotFound(Decoder.self, DecodingError.Context( + codingPath: codingPath, + debugDescription: "Cannot get superDecoder() -- unkeyed container is at end." + )) } let value = container[self.currentIndex] diff --git a/Sources/XMLCoder/Encoder/XMLEncoder.swift b/Sources/XMLCoder/Encoder/XMLEncoder.swift index 5efa3f98..e783ddba 100644 --- a/Sources/XMLCoder/Encoder/XMLEncoder.swift +++ b/Sources/XMLCoder/Encoder/XMLEncoder.swift @@ -29,7 +29,7 @@ open class XMLEncoder { /// Produce human-readable XML with indented output. public static let prettyPrinted = OutputFormatting(rawValue: 1 << 0) - /// Produce XML with dictionary keys sorted in lexicographic order. + /// Produce XML with keys sorted in lexicographic order. @available(macOS 10.13, iOS 11.0, watchOS 4.0, tvOS 11.0, *) public static let sortedKeys = OutputFormatting(rawValue: 1 << 1) } @@ -274,10 +274,10 @@ open class XMLEncoder { let elementOrNone: _XMLElement? - if let dictionary = topLevel as? DictionaryBox { - elementOrNone = _XMLElement.createRootElement(rootKey: rootKey, object: dictionary) - } else if let array = topLevel as? ArrayBox { - elementOrNone = _XMLElement.createRootElement(rootKey: rootKey, object: array) + if let keyed = topLevel as? KeyedBox { + elementOrNone = _XMLElement.createRootElement(rootKey: rootKey, object: keyed) + } else if let unkeyed = topLevel as? UnkeyedBox { + elementOrNone = _XMLElement.createRootElement(rootKey: rootKey, object: unkeyed) } else { fatalError("Unrecognized top-level element.") } @@ -344,12 +344,12 @@ internal class _XMLEncoder: Encoder { public func container(keyedBy _: Key.Type) -> KeyedEncodingContainer { // If an existing keyed container was already requested, return that one. - let topContainer: DictionaryBox + let topContainer: KeyedBox if canEncodeNewValue { // We haven't yet pushed a container at this level; do so here. topContainer = storage.pushKeyedContainer() } else { - guard let container = storage.lastContainer as? DictionaryBox else { + guard let container = storage.lastContainer as? KeyedBox else { preconditionFailure("Attempt to push new keyed encoding container when already previously encoded at this path.") } @@ -362,12 +362,12 @@ internal class _XMLEncoder: Encoder { public func unkeyedContainer() -> UnkeyedEncodingContainer { // If an existing unkeyed container was already requested, return that one. - let topContainer: ArrayBox + let topContainer: UnkeyedBox if canEncodeNewValue { // We haven't yet pushed a container at this level; do so here. topContainer = storage.pushUnkeyedContainer() } else { - guard let container = storage.lastContainer as? ArrayBox else { + guard let container = storage.lastContainer as? UnkeyedBox else { preconditionFailure("Attempt to push new unkeyed encoding container when already previously encoded at this path.") } @@ -472,31 +472,27 @@ extension _XMLEncoder: SingleValueEncodingContainer { extension _XMLEncoder { /// Returns the given value boxed in a container appropriate for pushing onto the container stack. - internal func box() -> Box { + internal func box() -> SimpleBox { return NullBox() } - internal func box(_ value: Bool) -> Box { + internal func box(_ value: Bool) -> SimpleBox { return BoolBox(value) } - internal func box(_ value: Decimal) -> Box { + internal func box(_ value: Decimal) -> SimpleBox { return DecimalBox(value) } - internal func box(_ value: T) -> Box { + internal func box(_ value: T) -> SimpleBox { return IntBox(value) } - internal func box(_ value: T) -> Box { + internal func box(_ value: T) -> SimpleBox { return UIntBox(value) } - internal func box(_ value: String) -> Box { - return StringBox(value) - } - - internal func box(_ value: T) throws -> Box { + internal func box(_ value: T) throws -> SimpleBox { guard value.isInfinite || value.isNaN else { return FloatBox(value) } @@ -512,6 +508,10 @@ extension _XMLEncoder { } } + internal func box(_ value: String) -> SimpleBox { + return StringBox(value) + } + internal func box(_ value: Date) throws -> Box { switch options.dateEncodingStrategy { case .deferredToDate: @@ -529,7 +529,7 @@ extension _XMLEncoder { let depth = storage.count try closure(value, self) - guard storage.count > depth else { return DictionaryBox() } + guard storage.count > depth else { return KeyedBox() } return storage.popContainer() } @@ -546,22 +546,18 @@ extension _XMLEncoder { let depth = storage.count try closure(value, self) - guard storage.count > depth else { return DictionaryBox() } + guard storage.count > depth else { return KeyedBox() } return storage.popContainer() } } - internal func boxOrNil(_ value: T) throws -> Box? { - return try self.box(value) - } - internal func box(_ value: T) throws -> Box { - return try self.box_(value) ?? DictionaryBox() + return try self.boxOrNil(value) ?? KeyedBox() } // This method is called "box_" instead of "box" to disambiguate it from the overloads. Because the return type here is different from all of the "box" overloads (and is more general), any "box" calls in here would call back into "box" recursively instead of calling the appropriate overload, which is not what we want. - private func box_(_ value: T) throws -> Box? { + internal func boxOrNil(_ value: T) throws -> Box? { if T.self == Date.self || T.self == NSDate.self { return try box(value as! Date) } diff --git a/Sources/XMLCoder/Encoder/XMLEncodingStorage.swift b/Sources/XMLCoder/Encoder/XMLEncodingStorage.swift index e324b502..566b989d 100644 --- a/Sources/XMLCoder/Encoder/XMLEncodingStorage.swift +++ b/Sources/XMLCoder/Encoder/XMLEncodingStorage.swift @@ -32,16 +32,16 @@ internal struct _XMLEncodingStorage { return containers.last } - mutating func pushKeyedContainer() -> DictionaryBox { - let dictionary = DictionaryBox() - containers.append(dictionary) - return dictionary + mutating func pushKeyedContainer() -> KeyedBox { + let keyed = KeyedBox() + containers.append(keyed) + return keyed } - mutating func pushUnkeyedContainer() -> ArrayBox { - let array = ArrayBox() - containers.append(array) - return array + mutating func pushUnkeyedContainer() -> UnkeyedBox { + let unkeyed = UnkeyedBox() + containers.append(unkeyed) + return unkeyed } mutating func push(container: Box) { diff --git a/Sources/XMLCoder/Encoder/XMLKeyedEncodingContainer.swift b/Sources/XMLCoder/Encoder/XMLKeyedEncodingContainer.swift index 58696367..f91c2e57 100644 --- a/Sources/XMLCoder/Encoder/XMLKeyedEncodingContainer.swift +++ b/Sources/XMLCoder/Encoder/XMLKeyedEncodingContainer.swift @@ -16,7 +16,7 @@ internal struct _XMLKeyedEncodingContainer : KeyedEncodingContain private let encoder: _XMLEncoder /// A reference to the container we're writing to. - private let container: DictionaryBox + private let container: KeyedBox /// The path of coding keys taken to get to this point in encoding. private(set) public var codingPath: [CodingKey] @@ -24,7 +24,7 @@ internal struct _XMLKeyedEncodingContainer : KeyedEncodingContain // MARK: - Initialization /// Initializes `self` with the given references. - internal init(referencing encoder: _XMLEncoder, codingPath: [CodingKey], wrapping container: DictionaryBox) { + internal init(referencing encoder: _XMLEncoder, codingPath: [CodingKey], wrapping container: KeyedBox) { self.encoder = encoder self.codingPath = codingPath self.container = container @@ -51,108 +51,116 @@ internal struct _XMLKeyedEncodingContainer : KeyedEncodingContain } public mutating func encode(_ value: Bool, forKey key: Key) throws { - self.encoder.codingPath.append(key) - defer { self.encoder.codingPath.removeLast() } - guard let strategy = self.encoder.nodeEncodings.last else { - preconditionFailure("Attempt to access node encoding strategy from empty stack.") - } - switch strategy(key) { - case .attribute: - if let attributesContainer = self.container[_XMLElement.attributesKey] as? DictionaryBox { - attributesContainer[_converted(key).stringValue] = self.encoder.box(value) - } else { - let attributesContainer = DictionaryBox() - attributesContainer[_converted(key).stringValue] = self.encoder.box(value) - self.container[_XMLElement.attributesKey] = attributesContainer - } - case .element: - self.container[_converted(key).stringValue] = self.encoder.box(value) + return try self.encode(value, forKey: key) { encoder, value in + return encoder.box(value) } } - public mutating func encode(_ value: T, forKey key: Key) throws { - self.encoder.codingPath.append(key) - defer { self.encoder.codingPath.removeLast() } - guard let strategy = self.encoder.nodeEncodings.last else { - preconditionFailure("Attempt to access node encoding strategy from empty stack.") - } - switch strategy(key) { - case .attribute: - if let attributesContainer = self.container[_XMLElement.attributesKey] as? DictionaryBox { - attributesContainer[_converted(key).stringValue] = try self.encoder.box(value) - } else { - let attributesContainer = DictionaryBox() - attributesContainer[_converted(key).stringValue] = try self.encoder.box(value) - self.container[_XMLElement.attributesKey] = attributesContainer - } - case .element: - self.container[_converted(key).stringValue] = try self.encoder.box(value) + public mutating func encode(_ value: Decimal, forKey key: Key) throws { + return try self.encode(value, forKey: key) { encoder, value in + return encoder.box(value) } } + public mutating func encode(_ value: Int, forKey key: Key) throws { + return try self.encodeSignedInteger(value, forKey: key) + } + + public mutating func encode(_ value: Int8, forKey key: Key) throws { + return try self.encodeSignedInteger(value, forKey: key) + } + + public mutating func encode(_ value: Int16, forKey key: Key) throws { + return try self.encodeSignedInteger(value, forKey: key) + } + + public mutating func encode(_ value: Int32, forKey key: Key) throws { + return try self.encodeSignedInteger(value, forKey: key) + } + + public mutating func encode(_ value: Int64, forKey key: Key) throws { + return try self.encodeSignedInteger(value, forKey: key) + } + + public mutating func encode(_ value: UInt, forKey key: Key) throws { + return try self.encodeUnsignedInteger(value, forKey: key) + } + + public mutating func encode(_ value: UInt8, forKey key: Key) throws { + return try self.encodeUnsignedInteger(value, forKey: key) + } + + public mutating func encode(_ value: UInt16, forKey key: Key) throws { + return try self.encodeUnsignedInteger(value, forKey: key) + } + + public mutating func encode(_ value: UInt32, forKey key: Key) throws { + return try self.encodeUnsignedInteger(value, forKey: key) + } + + public mutating func encode(_ value: UInt64, forKey key: Key) throws { + return try self.encodeUnsignedInteger(value, forKey: key) + } + + public mutating func encode(_ value: Float, forKey key: Key) throws { + return try self.encodeFloatingPoint(value, forKey: key) + } + + public mutating func encode(_ value: Double, forKey key: Key) throws { + return try self.encodeFloatingPoint(value, forKey: key) + } + public mutating func encode(_ value: String, forKey key: Key) throws { - self.encoder.codingPath.append(key) - defer { self.encoder.codingPath.removeLast() } - guard let strategy = self.encoder.nodeEncodings.last else { - preconditionFailure("Attempt to access node encoding strategy from empty stack.") + return try self.encode(value, forKey: key) { encoder, value in + return encoder.box(value) } - switch strategy(key) { - case .attribute: - if let attributesContainer = self.container[_XMLElement.attributesKey] as? DictionaryBox { - attributesContainer[_converted(key).stringValue] = self.encoder.box(value) - } else { - let attributesContainer = DictionaryBox() - attributesContainer[_converted(key).stringValue] = self.encoder.box(value) - self.container[_XMLElement.attributesKey] = attributesContainer - } - case .element: - self.container[_converted(key).stringValue] = self.encoder.box(value) + } + + public mutating func encode(_ value: Date, forKey key: Key) throws { + return try self.encode(value, forKey: key) { encoder, value in + return try encoder.box(value) } } - 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. - self.encoder.codingPath.append(key) - defer { self.encoder.codingPath.removeLast() } - guard let strategy = self.encoder.nodeEncodings.last else { - preconditionFailure("Attempt to access node encoding strategy from empty stack.") + public mutating func encode(_ value: Data, forKey key: Key) throws { + return try self.encode(value, forKey: key) { encoder, value in + return try encoder.box(value) } - switch strategy(key) { - case .attribute: - if let attributesContainer = self.container[_XMLElement.attributesKey] as? DictionaryBox { - attributesContainer[_converted(key).stringValue] = try self.encoder.box(value) - } else { - let attributesContainer = DictionaryBox() - attributesContainer[_converted(key).stringValue] = try self.encoder.box(value) - self.container[_XMLElement.attributesKey] = attributesContainer - } - case .element: - self.container[_converted(key).stringValue] = try self.encoder.box(value) + } + + public mutating func encode(_ value: T, forKey key: Key) throws { + return try self.encode(value, forKey: key) { encoder, value in + return try 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. - self.encoder.codingPath.append(key) - defer { self.encoder.codingPath.removeLast() } - guard let strategy = self.encoder.nodeEncodings.last else { - preconditionFailure("Attempt to access node encoding strategy from empty stack.") + private mutating func encodeSignedInteger(_ value: T, forKey key: Key) throws { + return try self.encode(value, forKey: key) { encoder, value in + return encoder.box(value) } - switch strategy(key) { - case .attribute: - if let attributesContainer = self.container[_XMLElement.attributesKey] as? DictionaryBox { - attributesContainer[_converted(key).stringValue] = try self.encoder.box(value) - } else { - let attributesContainer = DictionaryBox() - attributesContainer[_converted(key).stringValue] = try self.encoder.box(value) - self.container[_XMLElement.attributesKey] = attributesContainer - } - case .element: - self.container[_converted(key).stringValue] = try self.encoder.box(value) + } + + private mutating func encodeUnsignedInteger(_ value: T, forKey key: Key) throws { + return try self.encode(value, forKey: key) { encoder, value in + return encoder.box(value) } } - public mutating func encode(_ value: T, forKey key: Key) throws { + private mutating func encodeFloatingPoint(_ value: T, forKey key: Key) throws { + return try self.encode(value, forKey: key) { encoder, value in + return try encoder.box(value) + } + } + + private mutating func encode( + _ value: T, + forKey key: Key, + encode: (_XMLEncoder, T) throws -> Box + ) throws { + defer { + let _ = self.encoder.nodeEncodings.removeLast() + self.encoder.codingPath.removeLast() + } guard let strategy = self.encoder.nodeEncodings.last else { preconditionFailure("Attempt to access node encoding strategy from empty stack.") } @@ -162,42 +170,45 @@ internal struct _XMLKeyedEncodingContainer : KeyedEncodingContain with: self.encoder ) self.encoder.nodeEncodings.append(nodeEncodings) - defer { - let _ = self.encoder.nodeEncodings.removeLast() - self.encoder.codingPath.removeLast() - } + let box = try encode(self.encoder, value) switch strategy(key) { case .attribute: - if let attributesContainer = self.container[_XMLElement.attributesKey] as? DictionaryBox { - attributesContainer[_converted(key).stringValue] = try self.encoder.box(value) + guard box is SimpleBox else { + throw EncodingError.invalidValue(value, EncodingError.Context( + codingPath: [], + debugDescription: "Complex values cannot be encoded as attributes." + )) + } + if let attributesContainer = self.container[_XMLElement.attributesKey] as? KeyedBox { + attributesContainer[_converted(key).stringValue] = box } else { - let attributesContainer = DictionaryBox() - attributesContainer[_converted(key).stringValue] = try self.encoder.box(value) + let attributesContainer = KeyedBox() + attributesContainer[_converted(key).stringValue] = box self.container[_XMLElement.attributesKey] = attributesContainer } case .element: - self.container[_converted(key).stringValue] = try self.encoder.box(value) + self.container[_converted(key).stringValue] = box } } public mutating func nestedContainer(keyedBy keyType: NestedKey.Type, forKey key: Key) -> KeyedEncodingContainer { - let dictionary = DictionaryBox() - self.container[_converted(key).stringValue] = dictionary + let keyed = KeyedBox() + self.container[_converted(key).stringValue] = keyed self.codingPath.append(key) defer { self.codingPath.removeLast() } - let container = _XMLKeyedEncodingContainer(referencing: self.encoder, codingPath: self.codingPath, wrapping: dictionary) + let container = _XMLKeyedEncodingContainer(referencing: self.encoder, codingPath: self.codingPath, wrapping: keyed) return KeyedEncodingContainer(container) } public mutating func nestedUnkeyedContainer(forKey key: Key) -> UnkeyedEncodingContainer { - let array = ArrayBox() - self.container[_converted(key).stringValue] = array + let unkeyed = UnkeyedBox() + self.container[_converted(key).stringValue] = unkeyed self.codingPath.append(key) defer { self.codingPath.removeLast() } - return _XMLUnkeyedEncodingContainer(referencing: self.encoder, codingPath: self.codingPath, wrapping: array) + return _XMLUnkeyedEncodingContainer(referencing: self.encoder, codingPath: self.codingPath, wrapping: unkeyed) } public mutating func superEncoder() -> Encoder { diff --git a/Sources/XMLCoder/Encoder/XMLReferencingEncoder.swift b/Sources/XMLCoder/Encoder/XMLReferencingEncoder.swift index 622e44e6..32e7847d 100644 --- a/Sources/XMLCoder/Encoder/XMLReferencingEncoder.swift +++ b/Sources/XMLCoder/Encoder/XMLReferencingEncoder.swift @@ -17,11 +17,11 @@ internal class _XMLReferencingEncoder: _XMLEncoder { /// The type of container we're referencing. private enum Reference { - /// Referencing a specific index in an array container. - case array(ArrayBox, Int) + /// Referencing a specific index in an unkeyed container. + case unkeyed(UnkeyedBox, Int) - /// Referencing a specific key in a dictionary container. - case dictionary(DictionaryBox, String) + /// Referencing a specific key in a keyed container. + case keyed(KeyedBox, String) } // MARK: - Properties @@ -38,10 +38,10 @@ internal class _XMLReferencingEncoder: _XMLEncoder { internal init( referencing encoder: _XMLEncoder, at index: Int, - wrapping array: ArrayBox + wrapping unkeyed: UnkeyedBox ) { self.encoder = encoder - reference = .array(array, index) + reference = .unkeyed(unkeyed, index) super.init( options: encoder.options, nodeEncodings: encoder.nodeEncodings, @@ -56,10 +56,10 @@ internal class _XMLReferencingEncoder: _XMLEncoder { referencing encoder: _XMLEncoder, key: CodingKey, convertedKey: CodingKey, - wrapping dictionary: DictionaryBox + wrapping keyed: KeyedBox ) { self.encoder = encoder - reference = .dictionary(dictionary, convertedKey.stringValue) + reference = .keyed(keyed, convertedKey.stringValue) super.init( options: encoder.options, nodeEncodings: encoder.nodeEncodings, @@ -84,16 +84,16 @@ internal class _XMLReferencingEncoder: _XMLEncoder { deinit { let box: Box switch self.storage.count { - case 0: box = DictionaryBox() + case 0: box = KeyedBox() case 1: box = self.storage.popContainer() default: fatalError("Referencing encoder deallocated with multiple containers on stack.") } switch self.reference { - case let .array(array, index): - array.insert(box, at: index) - case let .dictionary(dictionary, key): - dictionary[key] = box + case let .unkeyed(unkeyed, index): + unkeyed.insert(box, at: index) + case let .keyed(keyed, key): + keyed[key] = box } } } diff --git a/Sources/XMLCoder/Encoder/XMLUnkeyedEncodingContainer.swift b/Sources/XMLCoder/Encoder/XMLUnkeyedEncodingContainer.swift index 398e7957..67e140ef 100644 --- a/Sources/XMLCoder/Encoder/XMLUnkeyedEncodingContainer.swift +++ b/Sources/XMLCoder/Encoder/XMLUnkeyedEncodingContainer.swift @@ -14,7 +14,7 @@ internal struct _XMLUnkeyedEncodingContainer : UnkeyedEncodingContainer { private let encoder: _XMLEncoder /// A reference to the container we're writing to. - private let container: ArrayBox + private let container: UnkeyedBox /// The path of coding keys taken to get to this point in encoding. private(set) public var codingPath: [CodingKey] @@ -27,7 +27,7 @@ internal struct _XMLUnkeyedEncodingContainer : UnkeyedEncodingContainer { // MARK: - Initialization /// Initializes `self` with the given references. - internal init(referencing encoder: _XMLEncoder, codingPath: [CodingKey], wrapping container: ArrayBox) { + internal init(referencing encoder: _XMLEncoder, codingPath: [CodingKey], wrapping container: UnkeyedBox) { self.encoder = encoder self.codingPath = codingPath self.container = container @@ -40,54 +40,124 @@ internal struct _XMLUnkeyedEncodingContainer : UnkeyedEncodingContainer { } public mutating func encode(_ value: Bool) throws { - self.container.append(self.encoder.box(value)) + self.encode(value) { encoder, value in + return encoder.box(value) + } } public mutating func encode(_ value: Decimal) throws { - self.container.append(self.encoder.box(value)) + self.encode(value) { encoder, value in + return encoder.box(value) + } } - - public mutating func encode(_ value: T) throws { - self.container.append(self.encoder.box(value)) + + public mutating func encode(_ value: Int) throws { + try self.encodeSignedInteger(value) + } + + public mutating func encode(_ value: Int8) throws { + try self.encodeSignedInteger(value) + } + + public mutating func encode(_ value: Int16) throws { + try self.encodeSignedInteger(value) + } + + public mutating func encode(_ value: Int32) throws { + try self.encodeSignedInteger(value) } - public mutating func encode(_ value: T) throws { - self.container.append(self.encoder.box(value)) + public mutating func encode(_ value: Int64) throws { + try self.encodeSignedInteger(value) } - public mutating func encode(_ value: T) throws { - // Since the float/double may be invalid and throw, the coding path needs to contain this key. - self.encoder.codingPath.append(_XMLKey(index: self.count)) - defer { self.encoder.codingPath.removeLast() } - self.container.append(try self.encoder.box(value)) + public mutating func encode(_ value: UInt) throws { + try self.encodeUnsignedInteger(value) + } + + public mutating func encode(_ value: UInt8) throws { + try self.encodeUnsignedInteger(value) + } + + public mutating func encode(_ value: UInt16) throws { + try self.encodeUnsignedInteger(value) + } + + public mutating func encode(_ value: UInt32) throws { + try self.encodeUnsignedInteger(value) + } + + public mutating func encode(_ value: UInt64) throws { + try self.encodeUnsignedInteger(value) + } + + public mutating func encode(_ value: Float) throws { + try self.encodeFloatingPoint(value) + } + + public mutating func encode(_ value: Double) throws { + try self.encodeFloatingPoint(value) + } + + public mutating func encode(_ value: String) throws { + self.encode(value) { encoder, value in + return encoder.box(value) + } } public mutating func encode(_ value: Date) throws { - self.container.append(try self.encoder.box(value)) + try self.encode(value) { encoder, value in + return try encoder.box(value) + } } public mutating func encode(_ value: Data) throws { - self.container.append(try self.encoder.box(value)) + try self.encode(value) { encoder, value in + return try encoder.box(value) + } } - public mutating func encode(_ value: String) throws { - self.container.append(self.encoder.box(value)) + private mutating func encodeSignedInteger(_ value: T) throws { + self.encode(value) { encoder, value in + return encoder.box(value) + } + } + + private mutating func encodeUnsignedInteger(_ value: T) throws { + self.encode(value) { encoder, value in + return encoder.box(value) + } + } + + private mutating func encodeFloatingPoint(_ value: T) throws { + try self.encode(value) { encoder, value in + return try encoder.box(value) + } } public mutating func encode(_ value: T) throws { + try self.encode(value) { encoder, value in + return try encoder.box(value) + } + } + + private mutating func encode( + _ value: T, + encode: (_XMLEncoder, T) throws -> (Box) + ) rethrows { self.encoder.codingPath.append(_XMLKey(index: self.count)) defer { self.encoder.codingPath.removeLast() } - self.container.append(try self.encoder.box(value)) + self.container.append(try encode(self.encoder, value)) } public mutating func nestedContainer(keyedBy keyType: NestedKey.Type) -> KeyedEncodingContainer { self.codingPath.append(_XMLKey(index: self.count)) defer { self.codingPath.removeLast() } - let dictionary = DictionaryBox() - self.container.append(dictionary) + let keyed = KeyedBox() + self.container.append(keyed) - let container = _XMLKeyedEncodingContainer(referencing: self.encoder, codingPath: self.codingPath, wrapping: dictionary) + let container = _XMLKeyedEncodingContainer(referencing: self.encoder, codingPath: self.codingPath, wrapping: keyed) return KeyedEncodingContainer(container) } @@ -95,10 +165,10 @@ internal struct _XMLUnkeyedEncodingContainer : UnkeyedEncodingContainer { self.codingPath.append(_XMLKey(index: self.count)) defer { self.codingPath.removeLast() } - let array = ArrayBox() - self.container.append(array) + let unkeyed = UnkeyedBox() + self.container.append(unkeyed) - return _XMLUnkeyedEncodingContainer(referencing: self.encoder, codingPath: self.codingPath, wrapping: array) + return _XMLUnkeyedEncodingContainer(referencing: self.encoder, codingPath: self.codingPath, wrapping: unkeyed) } public mutating func superEncoder() -> Encoder { diff --git a/Tests/XMLCoderTests/Box/DictionaryBoxTests.swift b/Tests/XMLCoderTests/Box/KeyedBoxTests.swift similarity index 85% rename from Tests/XMLCoderTests/Box/DictionaryBoxTests.swift rename to Tests/XMLCoderTests/Box/KeyedBoxTests.swift index f208b5aa..9a0e3089 100644 --- a/Tests/XMLCoderTests/Box/DictionaryBoxTests.swift +++ b/Tests/XMLCoderTests/Box/KeyedBoxTests.swift @@ -1,5 +1,5 @@ // -// ArrayBoxTests.swift +// UnkeyedBoxTests.swift // XMLCoderTests // // Created by Vincent Esche on 12/18/18. @@ -8,8 +8,8 @@ import XCTest @testable import XMLCoder -class DictionaryBoxTests: XCTestCase { - lazy var box = DictionaryBox(["foo": StringBox("bar"), "baz": IntBox(42)]) +class KeyedBoxTests: XCTestCase { + lazy var box = KeyedBox(["foo": StringBox("bar"), "baz": IntBox(42)]) func testUnbox() { let unboxed = box.unbox() diff --git a/Tests/XMLCoderTests/Box/ArrayBoxTests.swift b/Tests/XMLCoderTests/Box/UnkeyedBoxTests.swift similarity index 80% rename from Tests/XMLCoderTests/Box/ArrayBoxTests.swift rename to Tests/XMLCoderTests/Box/UnkeyedBoxTests.swift index 2f215e00..30fb4361 100644 --- a/Tests/XMLCoderTests/Box/ArrayBoxTests.swift +++ b/Tests/XMLCoderTests/Box/UnkeyedBoxTests.swift @@ -1,5 +1,5 @@ // -// ArrayBoxTests.swift +// UnkeyedBoxTests.swift // XMLCoderTests // // Created by Vincent Esche on 12/18/18. @@ -8,8 +8,8 @@ import XCTest @testable import XMLCoder -class ArrayBoxTests: XCTestCase { - lazy var box = ArrayBox([StringBox("foo"), IntBox(42)]) +class UnkeyedBoxTests: XCTestCase { + lazy var box = UnkeyedBox([StringBox("foo"), IntBox(42)]) func testUnbox() { let unboxed = box.unbox() diff --git a/Tests/XMLCoderTests/Minimal/DictionaryTests.swift b/Tests/XMLCoderTests/Minimal/KeyedTests.swift similarity index 80% rename from Tests/XMLCoderTests/Minimal/DictionaryTests.swift rename to Tests/XMLCoderTests/Minimal/KeyedTests.swift index 2910764d..ed3b10c8 100644 --- a/Tests/XMLCoderTests/Minimal/DictionaryTests.swift +++ b/Tests/XMLCoderTests/Minimal/KeyedTests.swift @@ -1,5 +1,5 @@ // -// DictionaryTests.swift +// KeyedTests.swift // XMLCoderTests // // Created by Max Desiatov on 19/11/2018. @@ -8,7 +8,7 @@ import XCTest @testable import XMLCoder -class DictionaryTests: XCTestCase { +class KeyedTests: XCTestCase { struct Container: Codable, Equatable { let value: [String: Int] } @@ -77,9 +77,24 @@ class DictionaryTests: XCTestCase { } } + func testAttribute() { + let encoder = XMLEncoder() + + encoder.nodeEncodingStrategy = .custom { codableType, _ in + return { _ in .attribute } + } + + let container = Container(value: ["foo": 12, "bar": 34]) + + XCTAssertThrowsError( + try encoder.encode(container, withRootKey: "container") + ) + } + static var allTests = [ ("testEmpty", testEmpty), ("testSingleElement", testSingleElement), ("testMultiElement", testMultiElement), + ("testAttribute", testAttribute), ] } diff --git a/Tests/XMLCoderTests/Minimal/ArrayTests.swift b/Tests/XMLCoderTests/Minimal/UnkeyedTests.swift similarity index 79% rename from Tests/XMLCoderTests/Minimal/ArrayTests.swift rename to Tests/XMLCoderTests/Minimal/UnkeyedTests.swift index a1d8c00f..265f6688 100644 --- a/Tests/XMLCoderTests/Minimal/ArrayTests.swift +++ b/Tests/XMLCoderTests/Minimal/UnkeyedTests.swift @@ -1,5 +1,5 @@ // -// ArrayTests.swift +// UnkeyedTests.swift // XMLCoderTests // // Created by Max Desiatov on 19/11/2018. @@ -8,7 +8,7 @@ import XCTest @testable import XMLCoder -class ArrayTests: XCTestCase { +class UnkeyedTests: XCTestCase { struct Container: Codable, Equatable { let value: [String] } @@ -73,9 +73,24 @@ class ArrayTests: XCTestCase { } } + func testAttribute() { + let encoder = XMLEncoder() + + encoder.nodeEncodingStrategy = .custom { codableType, _ in + return { _ in .attribute } + } + + let container = Container(value: ["foo", "bar"]) + + XCTAssertThrowsError( + try encoder.encode(container, withRootKey: "container") + ) + } + static var allTests = [ ("testEmpty", testEmpty), ("testSingleElement", testSingleElement), ("testMultiElement", testMultiElement), + ("testAttribute", testAttribute), ] } diff --git a/XMLCoder.xcodeproj/project.pbxproj b/XMLCoder.xcodeproj/project.pbxproj index 88d15b58..86127444 100644 --- a/XMLCoder.xcodeproj/project.pbxproj +++ b/XMLCoder.xcodeproj/project.pbxproj @@ -23,8 +23,8 @@ /* Begin PBXBuildFile section */ BF63EF0021CCDED2001D38C5 /* XMLStackParserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF63EEFF21CCDED2001D38C5 /* XMLStackParserTests.swift */; }; BF9457A821CBB498005ACFDE /* NullBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF94579E21CBB497005ACFDE /* NullBox.swift */; }; - BF9457A921CBB498005ACFDE /* DictionaryBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF94579F21CBB497005ACFDE /* DictionaryBox.swift */; }; - BF9457AA21CBB498005ACFDE /* ArrayBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF9457A021CBB497005ACFDE /* ArrayBox.swift */; }; + BF9457A921CBB498005ACFDE /* KeyedBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF94579F21CBB497005ACFDE /* KeyedBox.swift */; }; + BF9457AA21CBB498005ACFDE /* UnkeyedBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF9457A021CBB497005ACFDE /* UnkeyedBox.swift */; }; BF9457AB21CBB498005ACFDE /* DecimalBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF9457A121CBB497005ACFDE /* DecimalBox.swift */; }; BF9457AD21CBB498005ACFDE /* BoolBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF9457A321CBB497005ACFDE /* BoolBox.swift */; }; BF9457AE21CBB498005ACFDE /* Box.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF9457A421CBB497005ACFDE /* Box.swift */; }; @@ -36,14 +36,14 @@ BF9457BB21CBB4DB005ACFDE /* XMLKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF9457B521CBB4DB005ACFDE /* XMLKey.swift */; }; BF9457BC21CBB4DB005ACFDE /* XMLElement.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF9457B621CBB4DB005ACFDE /* XMLElement.swift */; }; BF9457C821CBB516005ACFDE /* BoolBoxTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF9457BE21CBB516005ACFDE /* BoolBoxTests.swift */; }; - BF9457C921CBB516005ACFDE /* DictionaryBoxTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF9457BF21CBB516005ACFDE /* DictionaryBoxTests.swift */; }; + BF9457C921CBB516005ACFDE /* KeyedBoxTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF9457BF21CBB516005ACFDE /* KeyedBoxTests.swift */; }; BF9457CB21CBB516005ACFDE /* DecimalBoxTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF9457C121CBB516005ACFDE /* DecimalBoxTests.swift */; }; BF9457CC21CBB516005ACFDE /* NullBoxTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF9457C221CBB516005ACFDE /* NullBoxTests.swift */; }; BF9457CD21CBB516005ACFDE /* FloatBoxTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF9457C321CBB516005ACFDE /* FloatBoxTests.swift */; }; BF9457CE21CBB516005ACFDE /* StringBoxTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF9457C421CBB516005ACFDE /* StringBoxTests.swift */; }; BF9457CF21CBB516005ACFDE /* IntBoxTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF9457C521CBB516005ACFDE /* IntBoxTests.swift */; }; BF9457D021CBB516005ACFDE /* UIntBoxTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF9457C621CBB516005ACFDE /* UIntBoxTests.swift */; }; - BF9457D121CBB516005ACFDE /* ArrayBoxTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF9457C721CBB516005ACFDE /* ArrayBoxTests.swift */; }; + BF9457D121CBB516005ACFDE /* UnkeyedBoxTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF9457C721CBB516005ACFDE /* UnkeyedBoxTests.swift */; }; BF9457D521CBB59E005ACFDE /* UIntBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF9457D221CBB59D005ACFDE /* UIntBox.swift */; }; BF9457D621CBB59E005ACFDE /* FloatBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF9457D321CBB59D005ACFDE /* FloatBox.swift */; }; BF9457D721CBB59E005ACFDE /* IntBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF9457D421CBB59D005ACFDE /* IntBox.swift */; }; @@ -56,11 +56,11 @@ BF9457EF21CBB6BC005ACFDE /* NullTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF9457E421CBB6BC005ACFDE /* NullTests.swift */; }; BF9457F021CBB6BC005ACFDE /* StringTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF9457E521CBB6BC005ACFDE /* StringTests.swift */; }; BF9457F121CBB6BC005ACFDE /* FloatTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF9457E621CBB6BC005ACFDE /* FloatTests.swift */; }; - BF9457F221CBB6BC005ACFDE /* ArrayTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF9457E721CBB6BC005ACFDE /* ArrayTests.swift */; }; + BF9457F221CBB6BC005ACFDE /* UnkeyedTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF9457E721CBB6BC005ACFDE /* UnkeyedTests.swift */; }; BF9457F321CBB6BC005ACFDE /* DateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF9457E821CBB6BC005ACFDE /* DateTests.swift */; }; BF9457F421CBB6BC005ACFDE /* UIntTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF9457E921CBB6BC005ACFDE /* UIntTests.swift */; }; BF9457F521CBB6BC005ACFDE /* DecimalTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF9457EA21CBB6BC005ACFDE /* DecimalTests.swift */; }; - BF9457F621CBB6BC005ACFDE /* DictionaryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF9457EB21CBB6BC005ACFDE /* DictionaryTests.swift */; }; + BF9457F621CBB6BC005ACFDE /* KeyedTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF9457EB21CBB6BC005ACFDE /* KeyedTests.swift */; }; BF9457F721CBB6BC005ACFDE /* DataTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF9457EC21CBB6BC005ACFDE /* DataTests.swift */; }; D1FC040521C7EF8200065B43 /* RJISample.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1FC040421C7EF8200065B43 /* RJISample.swift */; }; OBJ_48 /* DecodingErrorExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_10 /* DecodingErrorExtension.swift */; }; @@ -108,8 +108,8 @@ /* Begin PBXFileReference section */ BF63EEFF21CCDED2001D38C5 /* XMLStackParserTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XMLStackParserTests.swift; sourceTree = ""; }; BF94579E21CBB497005ACFDE /* NullBox.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NullBox.swift; sourceTree = ""; }; - BF94579F21CBB497005ACFDE /* DictionaryBox.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DictionaryBox.swift; sourceTree = ""; }; - BF9457A021CBB497005ACFDE /* ArrayBox.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ArrayBox.swift; sourceTree = ""; }; + BF94579F21CBB497005ACFDE /* KeyedBox.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyedBox.swift; sourceTree = ""; }; + BF9457A021CBB497005ACFDE /* UnkeyedBox.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UnkeyedBox.swift; sourceTree = ""; }; BF9457A121CBB497005ACFDE /* DecimalBox.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DecimalBox.swift; sourceTree = ""; }; BF9457A321CBB497005ACFDE /* BoolBox.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoolBox.swift; sourceTree = ""; }; BF9457A421CBB497005ACFDE /* Box.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Box.swift; sourceTree = ""; }; @@ -121,14 +121,14 @@ BF9457B521CBB4DB005ACFDE /* XMLKey.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = XMLKey.swift; sourceTree = ""; }; BF9457B621CBB4DB005ACFDE /* XMLElement.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = XMLElement.swift; sourceTree = ""; }; BF9457BE21CBB516005ACFDE /* BoolBoxTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoolBoxTests.swift; sourceTree = ""; }; - BF9457BF21CBB516005ACFDE /* DictionaryBoxTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DictionaryBoxTests.swift; sourceTree = ""; }; + BF9457BF21CBB516005ACFDE /* KeyedBoxTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyedBoxTests.swift; sourceTree = ""; }; BF9457C121CBB516005ACFDE /* DecimalBoxTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DecimalBoxTests.swift; sourceTree = ""; }; BF9457C221CBB516005ACFDE /* NullBoxTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NullBoxTests.swift; sourceTree = ""; }; BF9457C321CBB516005ACFDE /* FloatBoxTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FloatBoxTests.swift; sourceTree = ""; }; BF9457C421CBB516005ACFDE /* StringBoxTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StringBoxTests.swift; sourceTree = ""; }; BF9457C521CBB516005ACFDE /* IntBoxTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IntBoxTests.swift; sourceTree = ""; }; BF9457C621CBB516005ACFDE /* UIntBoxTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIntBoxTests.swift; sourceTree = ""; }; - BF9457C721CBB516005ACFDE /* ArrayBoxTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ArrayBoxTests.swift; sourceTree = ""; }; + BF9457C721CBB516005ACFDE /* UnkeyedBoxTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UnkeyedBoxTests.swift; sourceTree = ""; }; BF9457D221CBB59D005ACFDE /* UIntBox.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIntBox.swift; sourceTree = ""; }; BF9457D321CBB59D005ACFDE /* FloatBox.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FloatBox.swift; sourceTree = ""; }; BF9457D421CBB59D005ACFDE /* IntBox.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IntBox.swift; sourceTree = ""; }; @@ -141,11 +141,11 @@ BF9457E421CBB6BC005ACFDE /* NullTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NullTests.swift; sourceTree = ""; }; BF9457E521CBB6BC005ACFDE /* StringTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StringTests.swift; sourceTree = ""; }; BF9457E621CBB6BC005ACFDE /* FloatTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FloatTests.swift; sourceTree = ""; }; - BF9457E721CBB6BC005ACFDE /* ArrayTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ArrayTests.swift; sourceTree = ""; }; + BF9457E721CBB6BC005ACFDE /* UnkeyedTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UnkeyedTests.swift; sourceTree = ""; }; BF9457E821CBB6BC005ACFDE /* DateTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DateTests.swift; sourceTree = ""; }; BF9457E921CBB6BC005ACFDE /* UIntTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIntTests.swift; sourceTree = ""; }; BF9457EA21CBB6BC005ACFDE /* DecimalTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DecimalTests.swift; sourceTree = ""; }; - BF9457EB21CBB6BC005ACFDE /* DictionaryTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DictionaryTests.swift; sourceTree = ""; }; + BF9457EB21CBB6BC005ACFDE /* KeyedTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyedTests.swift; sourceTree = ""; }; BF9457EC21CBB6BC005ACFDE /* DataTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DataTests.swift; sourceTree = ""; }; D1FC040421C7EF8200065B43 /* RJISample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RJISample.swift; sourceTree = ""; }; OBJ_10 /* DecodingErrorExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DecodingErrorExtension.swift; sourceTree = ""; }; @@ -215,8 +215,8 @@ BF9457A521CBB498005ACFDE /* StringBox.swift */, BF9457D821CBB5D2005ACFDE /* DataBox.swift */, BF9457D921CBB5D2005ACFDE /* DateBox.swift */, - BF9457A021CBB497005ACFDE /* ArrayBox.swift */, - BF94579F21CBB497005ACFDE /* DictionaryBox.swift */, + BF9457A021CBB497005ACFDE /* UnkeyedBox.swift */, + BF94579F21CBB497005ACFDE /* KeyedBox.swift */, ); path = Box; sourceTree = ""; @@ -246,8 +246,8 @@ BF9457C421CBB516005ACFDE /* StringBoxTests.swift */, BF9457DE21CBB683005ACFDE /* DataBoxTests.swift */, BF9457DC21CBB62C005ACFDE /* DateBoxTests.swift */, - BF9457C721CBB516005ACFDE /* ArrayBoxTests.swift */, - BF9457BF21CBB516005ACFDE /* DictionaryBoxTests.swift */, + BF9457C721CBB516005ACFDE /* UnkeyedBoxTests.swift */, + BF9457BF21CBB516005ACFDE /* KeyedBoxTests.swift */, ); path = Box; sourceTree = ""; @@ -260,11 +260,11 @@ BF9457E421CBB6BC005ACFDE /* NullTests.swift */, BF9457E521CBB6BC005ACFDE /* StringTests.swift */, BF9457E621CBB6BC005ACFDE /* FloatTests.swift */, - BF9457E721CBB6BC005ACFDE /* ArrayTests.swift */, + BF9457E721CBB6BC005ACFDE /* UnkeyedTests.swift */, BF9457E821CBB6BC005ACFDE /* DateTests.swift */, BF9457E921CBB6BC005ACFDE /* UIntTests.swift */, BF9457EA21CBB6BC005ACFDE /* DecimalTests.swift */, - BF9457EB21CBB6BC005ACFDE /* DictionaryTests.swift */, + BF9457EB21CBB6BC005ACFDE /* KeyedTests.swift */, BF9457EC21CBB6BC005ACFDE /* DataTests.swift */, ); path = Minimal; @@ -463,7 +463,7 @@ OBJ_54 /* XMLEncoder.swift in Sources */, BF9457BA21CBB4DB005ACFDE /* ISO8601DateFormatter.swift in Sources */, OBJ_55 /* XMLEncodingStorage.swift in Sources */, - BF9457A921CBB498005ACFDE /* DictionaryBox.swift in Sources */, + BF9457A921CBB498005ACFDE /* KeyedBox.swift in Sources */, BF9457D721CBB59E005ACFDE /* IntBox.swift in Sources */, BF9457AD21CBB498005ACFDE /* BoolBox.swift in Sources */, BF9457B821CBB4DB005ACFDE /* String+Extensions.swift in Sources */, @@ -473,7 +473,7 @@ OBJ_56 /* XMLKeyedEncodingContainer.swift in Sources */, OBJ_57 /* XMLReferencingEncoder.swift in Sources */, BF9457BC21CBB4DB005ACFDE /* XMLElement.swift in Sources */, - BF9457AA21CBB498005ACFDE /* ArrayBox.swift in Sources */, + BF9457AA21CBB498005ACFDE /* UnkeyedBox.swift in Sources */, BF9457AF21CBB498005ACFDE /* StringBox.swift in Sources */, OBJ_58 /* XMLUnkeyedEncodingContainer.swift in Sources */, BF9457A821CBB498005ACFDE /* NullBox.swift in Sources */, @@ -493,9 +493,9 @@ buildActionMask = 0; files = ( BF9457CB21CBB516005ACFDE /* DecimalBoxTests.swift in Sources */, - BF9457F221CBB6BC005ACFDE /* ArrayTests.swift in Sources */, + BF9457F221CBB6BC005ACFDE /* UnkeyedTests.swift in Sources */, BF9457F321CBB6BC005ACFDE /* DateTests.swift in Sources */, - BF9457D121CBB516005ACFDE /* ArrayBoxTests.swift in Sources */, + BF9457D121CBB516005ACFDE /* UnkeyedBoxTests.swift in Sources */, BF9457F021CBB6BC005ACFDE /* StringTests.swift in Sources */, BF9457ED21CBB6BC005ACFDE /* BoolTests.swift in Sources */, D1FC040521C7EF8200065B43 /* RJISample.swift in Sources */, @@ -515,11 +515,11 @@ BF9457F721CBB6BC005ACFDE /* DataTests.swift in Sources */, BF9457EE21CBB6BC005ACFDE /* IntTests.swift in Sources */, OBJ_87 /* PlantCatalog.swift in Sources */, - BF9457C921CBB516005ACFDE /* DictionaryBoxTests.swift in Sources */, + BF9457C921CBB516005ACFDE /* KeyedBoxTests.swift in Sources */, OBJ_88 /* PlantTest.swift in Sources */, BF9457DD21CBB62C005ACFDE /* DateBoxTests.swift in Sources */, BF9457CD21CBB516005ACFDE /* FloatBoxTests.swift in Sources */, - BF9457F621CBB6BC005ACFDE /* DictionaryTests.swift in Sources */, + BF9457F621CBB6BC005ACFDE /* KeyedTests.swift in Sources */, BF9457C821CBB516005ACFDE /* BoolBoxTests.swift in Sources */, BF9457F421CBB6BC005ACFDE /* UIntTests.swift in Sources */, OBJ_89 /* RJITest.swift in Sources */,