From 285622fcf41c84cabe3fa7ca4667f1931fc01f0d Mon Sep 17 00:00:00 2001 From: Vincent Esche Date: Thu, 20 Dec 2018 21:38:47 +0100 Subject: [PATCH 1/7] Made `ArrayBox` and `DictionaryBox` conform to `Sequence` --- Sources/XMLCoder/Box/ArrayBox.swift | 8 ++++++++ Sources/XMLCoder/Box/DictionaryBox.swift | 7 +++++++ 2 files changed, 15 insertions(+) diff --git a/Sources/XMLCoder/Box/ArrayBox.swift b/Sources/XMLCoder/Box/ArrayBox.swift index 24c8314f..20e9f051 100644 --- a/Sources/XMLCoder/Box/ArrayBox.swift +++ b/Sources/XMLCoder/Box/ArrayBox.swift @@ -70,6 +70,14 @@ extension ArrayBox: Box { } } +extension ArrayBox: Sequence { + typealias Iterator = Unboxed.Iterator + + func makeIterator() -> Iterator { + return self.unboxed.makeIterator() + } +} + extension ArrayBox: CustomStringConvertible { var description: String { return self.unboxed.description diff --git a/Sources/XMLCoder/Box/DictionaryBox.swift b/Sources/XMLCoder/Box/DictionaryBox.swift index 0d75d548..2f657c90 100644 --- a/Sources/XMLCoder/Box/DictionaryBox.swift +++ b/Sources/XMLCoder/Box/DictionaryBox.swift @@ -77,6 +77,13 @@ extension DictionaryBox: Box { } } +extension DictionaryBox: Sequence { + typealias Iterator = Unboxed.Iterator + + func makeIterator() -> Iterator { + return self.unboxed.makeIterator() + } +} extension DictionaryBox: CustomStringConvertible { var description: String { From 9420d18263d6025817345f1e3eee3146738ebb5f Mon Sep 17 00:00:00 2001 From: Vincent Esche Date: Thu, 20 Dec 2018 21:43:58 +0100 Subject: [PATCH 2/7] Renamed `ArrayBox` to `UnkeyedBox`. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit What’s interesting about `ArrayBox` is its unkeyed semantics, not the fact it’s currently using an `Array` as storage, which is an implementation detail after all. --- Sources/XMLCoder/Auxiliaries/XMLElement.swift | 16 ++++++++-------- .../Box/{ArrayBox.swift => UnkeyedBox.swift} | 10 +++++----- .../Decoder/DecodingErrorExtension.swift | 2 +- Sources/XMLCoder/Decoder/XMLDecoder.swift | 10 +++++----- .../Decoder/XMLKeyedDecodingContainer.swift | 4 ++-- .../Decoder/XMLUnkeyedDecodingContainer.swift | 10 +++++----- Sources/XMLCoder/Encoder/XMLEncoder.swift | 8 ++++---- .../XMLCoder/Encoder/XMLEncodingStorage.swift | 8 ++++---- .../Encoder/XMLKeyedEncodingContainer.swift | 6 +++--- .../XMLCoder/Encoder/XMLReferencingEncoder.swift | 12 ++++++------ .../Encoder/XMLUnkeyedEncodingContainer.swift | 10 +++++----- Tests/XMLCoderTests/Box/ArrayBoxTests.swift | 6 +++--- Tests/XMLCoderTests/Box/DictionaryBoxTests.swift | 2 +- XMLCoder.xcodeproj/project.pbxproj | 8 ++++---- 14 files changed, 56 insertions(+), 56 deletions(-) rename Sources/XMLCoder/Box/{ArrayBox.swift => UnkeyedBox.swift} (91%) diff --git a/Sources/XMLCoder/Auxiliaries/XMLElement.swift b/Sources/XMLCoder/Auxiliaries/XMLElement.swift index 4fcbd1b4..aa266af1 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) @@ -59,7 +59,7 @@ 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) } @@ -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,12 +97,12 @@ 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(DictionaryBox(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, DictionaryBox(newValue)]) } } else { node[childElement.key] = DictionaryBox(newValue) diff --git a/Sources/XMLCoder/Box/ArrayBox.swift b/Sources/XMLCoder/Box/UnkeyedBox.swift similarity index 91% rename from Sources/XMLCoder/Box/ArrayBox.swift rename to Sources/XMLCoder/Box/UnkeyedBox.swift index 20e9f051..9fb15e3c 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,7 +56,7 @@ class ArrayBox { } } -extension ArrayBox: Box { +extension UnkeyedBox: Box { var isNull: Bool { return false } @@ -70,7 +70,7 @@ extension ArrayBox: Box { } } -extension ArrayBox: Sequence { +extension UnkeyedBox: Sequence { typealias Iterator = Unboxed.Iterator func makeIterator() -> Iterator { @@ -78,7 +78,7 @@ extension ArrayBox: Sequence { } } -extension ArrayBox: CustomStringConvertible { +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..cc7df70d 100644 --- a/Sources/XMLCoder/Decoder/DecodingErrorExtension.swift +++ b/Sources/XMLCoder/Decoder/DecodingErrorExtension.swift @@ -43,7 +43,7 @@ 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: return "a dictionary value" diff --git a/Sources/XMLCoder/Decoder/XMLDecoder.swift b/Sources/XMLCoder/Decoder/XMLDecoder.swift index 309a78e5..17a38b73 100644 --- a/Sources/XMLCoder/Decoder/XMLDecoder.swift +++ b/Sources/XMLCoder/Decoder/XMLDecoder.swift @@ -321,15 +321,15 @@ internal class _XMLDecoder: Decoder { )) } - let array: ArrayBox + let unkeyed: UnkeyedBox - if let container = storage.topContainer as? ArrayBox { - array = container + if let container = storage.topContainer as? UnkeyedBox { + unkeyed = container } else { - array = ArrayBox([storage.topContainer]) + unkeyed = UnkeyedBox([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/XMLKeyedDecodingContainer.swift b/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift index 72161851..05445080 100644 --- a/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift +++ b/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift @@ -351,11 +351,11 @@ internal struct _XMLKeyedDecodingContainer: KeyedDecodingContainer 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..a1191d5f 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 @@ -339,12 +339,12 @@ internal struct _XMLUnkeyedDecodingContainer: UnkeyedDecodingContainer { 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 { diff --git a/Sources/XMLCoder/Encoder/XMLEncoder.swift b/Sources/XMLCoder/Encoder/XMLEncoder.swift index 5efa3f98..cc235e33 100644 --- a/Sources/XMLCoder/Encoder/XMLEncoder.swift +++ b/Sources/XMLCoder/Encoder/XMLEncoder.swift @@ -276,8 +276,8 @@ open class XMLEncoder { 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) + } else if let unkeyed = topLevel as? UnkeyedBox { + elementOrNone = _XMLElement.createRootElement(rootKey: rootKey, object: unkeyed) } else { fatalError("Unrecognized top-level element.") } @@ -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.") } diff --git a/Sources/XMLCoder/Encoder/XMLEncodingStorage.swift b/Sources/XMLCoder/Encoder/XMLEncodingStorage.swift index e324b502..bf54a4ab 100644 --- a/Sources/XMLCoder/Encoder/XMLEncodingStorage.swift +++ b/Sources/XMLCoder/Encoder/XMLEncodingStorage.swift @@ -38,10 +38,10 @@ internal struct _XMLEncodingStorage { return dictionary } - 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..d2c1210c 100644 --- a/Sources/XMLCoder/Encoder/XMLKeyedEncodingContainer.swift +++ b/Sources/XMLCoder/Encoder/XMLKeyedEncodingContainer.swift @@ -192,12 +192,12 @@ internal struct _XMLKeyedEncodingContainer : KeyedEncodingContain } 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..752e6ee4 100644 --- a/Sources/XMLCoder/Encoder/XMLReferencingEncoder.swift +++ b/Sources/XMLCoder/Encoder/XMLReferencingEncoder.swift @@ -17,8 +17,8 @@ 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) @@ -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, @@ -90,8 +90,8 @@ internal class _XMLReferencingEncoder: _XMLEncoder { } switch self.reference { - case let .array(array, index): - array.insert(box, at: index) + case let .unkeyed(unkeyed, index): + unkeyed.insert(box, at: index) case let .dictionary(dictionary, key): dictionary[key] = box } diff --git a/Sources/XMLCoder/Encoder/XMLUnkeyedEncodingContainer.swift b/Sources/XMLCoder/Encoder/XMLUnkeyedEncodingContainer.swift index 398e7957..61d96d7b 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 @@ -95,10 +95,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/ArrayBoxTests.swift b/Tests/XMLCoderTests/Box/ArrayBoxTests.swift index 2f215e00..30fb4361 100644 --- a/Tests/XMLCoderTests/Box/ArrayBoxTests.swift +++ b/Tests/XMLCoderTests/Box/ArrayBoxTests.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/Box/DictionaryBoxTests.swift b/Tests/XMLCoderTests/Box/DictionaryBoxTests.swift index f208b5aa..9cb11ec4 100644 --- a/Tests/XMLCoderTests/Box/DictionaryBoxTests.swift +++ b/Tests/XMLCoderTests/Box/DictionaryBoxTests.swift @@ -1,5 +1,5 @@ // -// ArrayBoxTests.swift +// UnkeyedBoxTests.swift // XMLCoderTests // // Created by Vincent Esche on 12/18/18. diff --git a/XMLCoder.xcodeproj/project.pbxproj b/XMLCoder.xcodeproj/project.pbxproj index 88d15b58..dea6128a 100644 --- a/XMLCoder.xcodeproj/project.pbxproj +++ b/XMLCoder.xcodeproj/project.pbxproj @@ -24,7 +24,7 @@ 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 */; }; + 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 */; }; @@ -109,7 +109,7 @@ 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 = ""; }; + 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 = ""; }; @@ -215,7 +215,7 @@ BF9457A521CBB498005ACFDE /* StringBox.swift */, BF9457D821CBB5D2005ACFDE /* DataBox.swift */, BF9457D921CBB5D2005ACFDE /* DateBox.swift */, - BF9457A021CBB497005ACFDE /* ArrayBox.swift */, + BF9457A021CBB497005ACFDE /* UnkeyedBox.swift */, BF94579F21CBB497005ACFDE /* DictionaryBox.swift */, ); path = Box; @@ -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 */, From c189513b49332d8198097ad4a148f96be72276ed Mon Sep 17 00:00:00 2001 From: Vincent Esche Date: Thu, 20 Dec 2018 21:49:42 +0100 Subject: [PATCH 3/7] Renamed `DictionaryBox` to `KeyedBox`. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit What’s interesting about `DictionaryBox` is its keyed semantics, not the fact it’s currently using an `Dictionary` as storage, which is an implementation detail after all, and expected to be changed soon, even (to preserve element order). --- Sources/XMLCoder/Auxiliaries/XMLElement.swift | 14 ++++---- .../{DictionaryBox.swift => KeyedBox.swift} | 14 ++++---- .../Decoder/DecodingErrorExtension.swift | 2 +- Sources/XMLCoder/Decoder/XMLDecoder.swift | 14 +++----- .../Decoder/XMLKeyedDecodingContainer.swift | 14 ++++---- .../Decoder/XMLUnkeyedDecodingContainer.swift | 4 +-- Sources/XMLCoder/Encoder/XMLEncoder.swift | 16 ++++----- .../XMLCoder/Encoder/XMLEncodingStorage.swift | 8 ++--- .../Encoder/XMLKeyedEncodingContainer.swift | 34 +++++++++---------- .../Encoder/XMLReferencingEncoder.swift | 14 ++++---- .../Encoder/XMLUnkeyedEncodingContainer.swift | 6 ++-- .../Box/DictionaryBoxTests.swift | 4 +-- XMLCoder.xcodeproj/project.pbxproj | 8 ++--- 13 files changed, 73 insertions(+), 79 deletions(-) rename Sources/XMLCoder/Box/{DictionaryBox.swift => KeyedBox.swift} (88%) diff --git a/Sources/XMLCoder/Auxiliaries/XMLElement.swift b/Sources/XMLCoder/Auxiliaries/XMLElement.swift index aa266af1..ec18f72e 100644 --- a/Sources/XMLCoder/Auxiliaries/XMLElement.swift +++ b/Sources/XMLCoder/Auxiliaries/XMLElement.swift @@ -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) } } @@ -63,7 +63,7 @@ internal class _XMLElement { 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()) @@ -98,14 +98,14 @@ internal class _XMLElement { if let existingValue = node[childElement.key] { if let unkeyed = existingValue as? UnkeyedBox { - unkeyed.append(DictionaryBox(newValue)) + unkeyed.append(KeyedBox(newValue)) // FIXME: Box is a reference type, so this shouldn't be necessary: node[childElement.key] = unkeyed } else { - node[childElement.key] = UnkeyedBox([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/DictionaryBox.swift b/Sources/XMLCoder/Box/KeyedBox.swift similarity index 88% rename from Sources/XMLCoder/Box/DictionaryBox.swift rename to Sources/XMLCoder/Box/KeyedBox.swift index 2f657c90..ae9aacc7 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,12 +58,12 @@ 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 } @@ -77,7 +77,7 @@ extension DictionaryBox: Box { } } -extension DictionaryBox: Sequence { +extension KeyedBox: Sequence { typealias Iterator = Unboxed.Iterator func makeIterator() -> Iterator { @@ -85,7 +85,7 @@ extension DictionaryBox: Sequence { } } -extension DictionaryBox: CustomStringConvertible { +extension KeyedBox: CustomStringConvertible { var description: String { return self.unboxed.description } diff --git a/Sources/XMLCoder/Decoder/DecodingErrorExtension.swift b/Sources/XMLCoder/Decoder/DecodingErrorExtension.swift index cc7df70d..61a61824 100644 --- a/Sources/XMLCoder/Decoder/DecodingErrorExtension.swift +++ b/Sources/XMLCoder/Decoder/DecodingErrorExtension.swift @@ -45,7 +45,7 @@ internal extension DecodingError { return "a floating-point value" 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 17a38b73..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,13 +321,7 @@ internal class _XMLDecoder: Decoder { )) } - let unkeyed: UnkeyedBox - - if let container = storage.topContainer as? UnkeyedBox { - unkeyed = container - } else { - unkeyed = UnkeyedBox([storage.topContainer]) - } + let unkeyed = (storage.topContainer as? UnkeyedBox) ?? UnkeyedBox([storage.topContainer]) return _XMLUnkeyedDecodingContainer(referencing: self, wrapping: unkeyed) } diff --git a/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift b/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift index 05445080..746aa963 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 }) } @@ -333,11 +333,11 @@ internal struct _XMLKeyedDecodingContainer: KeyedDecodingContainer 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) } diff --git a/Sources/XMLCoder/Decoder/XMLUnkeyedDecodingContainer.swift b/Sources/XMLCoder/Decoder/XMLUnkeyedDecodingContainer.swift index a1191d5f..ff13cd82 100644 --- a/Sources/XMLCoder/Decoder/XMLUnkeyedDecodingContainer.swift +++ b/Sources/XMLCoder/Decoder/XMLUnkeyedDecodingContainer.swift @@ -313,12 +313,12 @@ internal struct _XMLUnkeyedDecodingContainer: UnkeyedDecodingContainer { 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) } diff --git a/Sources/XMLCoder/Encoder/XMLEncoder.swift b/Sources/XMLCoder/Encoder/XMLEncoder.swift index cc235e33..e439e040 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,8 +274,8 @@ open class XMLEncoder { let elementOrNone: _XMLElement? - if let dictionary = topLevel as? DictionaryBox { - elementOrNone = _XMLElement.createRootElement(rootKey: rootKey, object: dictionary) + 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 { @@ -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.") } @@ -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,7 +546,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() } @@ -557,7 +557,7 @@ extension _XMLEncoder { } internal func box(_ value: T) throws -> Box { - return try self.box_(value) ?? DictionaryBox() + return try self.box_(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. diff --git a/Sources/XMLCoder/Encoder/XMLEncodingStorage.swift b/Sources/XMLCoder/Encoder/XMLEncodingStorage.swift index bf54a4ab..566b989d 100644 --- a/Sources/XMLCoder/Encoder/XMLEncodingStorage.swift +++ b/Sources/XMLCoder/Encoder/XMLEncodingStorage.swift @@ -32,10 +32,10 @@ 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() -> UnkeyedBox { diff --git a/Sources/XMLCoder/Encoder/XMLKeyedEncodingContainer.swift b/Sources/XMLCoder/Encoder/XMLKeyedEncodingContainer.swift index d2c1210c..11afbcd0 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 @@ -58,10 +58,10 @@ internal struct _XMLKeyedEncodingContainer : KeyedEncodingContain } switch strategy(key) { case .attribute: - if let attributesContainer = self.container[_XMLElement.attributesKey] as? DictionaryBox { + if let attributesContainer = self.container[_XMLElement.attributesKey] as? KeyedBox { attributesContainer[_converted(key).stringValue] = self.encoder.box(value) } else { - let attributesContainer = DictionaryBox() + let attributesContainer = KeyedBox() attributesContainer[_converted(key).stringValue] = self.encoder.box(value) self.container[_XMLElement.attributesKey] = attributesContainer } @@ -78,10 +78,10 @@ internal struct _XMLKeyedEncodingContainer : KeyedEncodingContain } switch strategy(key) { case .attribute: - if let attributesContainer = self.container[_XMLElement.attributesKey] as? DictionaryBox { + if let attributesContainer = self.container[_XMLElement.attributesKey] as? KeyedBox { attributesContainer[_converted(key).stringValue] = try self.encoder.box(value) } else { - let attributesContainer = DictionaryBox() + let attributesContainer = KeyedBox() attributesContainer[_converted(key).stringValue] = try self.encoder.box(value) self.container[_XMLElement.attributesKey] = attributesContainer } @@ -98,10 +98,10 @@ internal struct _XMLKeyedEncodingContainer : KeyedEncodingContain } switch strategy(key) { case .attribute: - if let attributesContainer = self.container[_XMLElement.attributesKey] as? DictionaryBox { + if let attributesContainer = self.container[_XMLElement.attributesKey] as? KeyedBox { attributesContainer[_converted(key).stringValue] = self.encoder.box(value) } else { - let attributesContainer = DictionaryBox() + let attributesContainer = KeyedBox() attributesContainer[_converted(key).stringValue] = self.encoder.box(value) self.container[_XMLElement.attributesKey] = attributesContainer } @@ -119,10 +119,10 @@ internal struct _XMLKeyedEncodingContainer : KeyedEncodingContain } switch strategy(key) { case .attribute: - if let attributesContainer = self.container[_XMLElement.attributesKey] as? DictionaryBox { + if let attributesContainer = self.container[_XMLElement.attributesKey] as? KeyedBox { attributesContainer[_converted(key).stringValue] = try self.encoder.box(value) } else { - let attributesContainer = DictionaryBox() + let attributesContainer = KeyedBox() attributesContainer[_converted(key).stringValue] = try self.encoder.box(value) self.container[_XMLElement.attributesKey] = attributesContainer } @@ -140,10 +140,10 @@ internal struct _XMLKeyedEncodingContainer : KeyedEncodingContain } switch strategy(key) { case .attribute: - if let attributesContainer = self.container[_XMLElement.attributesKey] as? DictionaryBox { + if let attributesContainer = self.container[_XMLElement.attributesKey] as? KeyedBox { attributesContainer[_converted(key).stringValue] = try self.encoder.box(value) } else { - let attributesContainer = DictionaryBox() + let attributesContainer = KeyedBox() attributesContainer[_converted(key).stringValue] = try self.encoder.box(value) self.container[_XMLElement.attributesKey] = attributesContainer } @@ -168,10 +168,10 @@ internal struct _XMLKeyedEncodingContainer : KeyedEncodingContain } switch strategy(key) { case .attribute: - if let attributesContainer = self.container[_XMLElement.attributesKey] as? DictionaryBox { + if let attributesContainer = self.container[_XMLElement.attributesKey] as? KeyedBox { attributesContainer[_converted(key).stringValue] = try self.encoder.box(value) } else { - let attributesContainer = DictionaryBox() + let attributesContainer = KeyedBox() attributesContainer[_converted(key).stringValue] = try self.encoder.box(value) self.container[_XMLElement.attributesKey] = attributesContainer } @@ -181,13 +181,13 @@ internal struct _XMLKeyedEncodingContainer : KeyedEncodingContain } 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) } diff --git a/Sources/XMLCoder/Encoder/XMLReferencingEncoder.swift b/Sources/XMLCoder/Encoder/XMLReferencingEncoder.swift index 752e6ee4..32e7847d 100644 --- a/Sources/XMLCoder/Encoder/XMLReferencingEncoder.swift +++ b/Sources/XMLCoder/Encoder/XMLReferencingEncoder.swift @@ -20,8 +20,8 @@ internal class _XMLReferencingEncoder: _XMLEncoder { /// 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 @@ -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,7 +84,7 @@ 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.") } @@ -92,8 +92,8 @@ internal class _XMLReferencingEncoder: _XMLEncoder { switch self.reference { case let .unkeyed(unkeyed, index): unkeyed.insert(box, at: index) - case let .dictionary(dictionary, key): - dictionary[key] = box + case let .keyed(keyed, key): + keyed[key] = box } } } diff --git a/Sources/XMLCoder/Encoder/XMLUnkeyedEncodingContainer.swift b/Sources/XMLCoder/Encoder/XMLUnkeyedEncodingContainer.swift index 61d96d7b..36071831 100644 --- a/Sources/XMLCoder/Encoder/XMLUnkeyedEncodingContainer.swift +++ b/Sources/XMLCoder/Encoder/XMLUnkeyedEncodingContainer.swift @@ -84,10 +84,10 @@ internal struct _XMLUnkeyedEncodingContainer : UnkeyedEncodingContainer { 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) } diff --git a/Tests/XMLCoderTests/Box/DictionaryBoxTests.swift b/Tests/XMLCoderTests/Box/DictionaryBoxTests.swift index 9cb11ec4..9a0e3089 100644 --- a/Tests/XMLCoderTests/Box/DictionaryBoxTests.swift +++ b/Tests/XMLCoderTests/Box/DictionaryBoxTests.swift @@ -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/XMLCoder.xcodeproj/project.pbxproj b/XMLCoder.xcodeproj/project.pbxproj index dea6128a..ed238f6c 100644 --- a/XMLCoder.xcodeproj/project.pbxproj +++ b/XMLCoder.xcodeproj/project.pbxproj @@ -23,7 +23,7 @@ /* 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 */; }; + 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 */; }; @@ -108,7 +108,7 @@ /* 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 = ""; }; + 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 = ""; }; @@ -216,7 +216,7 @@ BF9457D821CBB5D2005ACFDE /* DataBox.swift */, BF9457D921CBB5D2005ACFDE /* DateBox.swift */, BF9457A021CBB497005ACFDE /* UnkeyedBox.swift */, - BF94579F21CBB497005ACFDE /* DictionaryBox.swift */, + BF94579F21CBB497005ACFDE /* KeyedBox.swift */, ); path = Box; sourceTree = ""; @@ -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 */, From b2618608e7a54366eb6760aad05627b973a423a0 Mon Sep 17 00:00:00 2001 From: Vincent Esche Date: Thu, 20 Dec 2018 21:59:11 +0100 Subject: [PATCH 4/7] Turned `var isFragment` into `protocol SimpleBox: Box` --- Sources/XMLCoder/Box/BoolBox.swift | 8 ++++---- Sources/XMLCoder/Box/Box.swift | 7 +++++-- Sources/XMLCoder/Box/DataBox.swift | 8 ++++---- Sources/XMLCoder/Box/DateBox.swift | 8 ++++---- Sources/XMLCoder/Box/DecimalBox.swift | 8 ++++---- Sources/XMLCoder/Box/FloatBox.swift | 8 ++++---- Sources/XMLCoder/Box/IntBox.swift | 8 ++++---- Sources/XMLCoder/Box/KeyedBox.swift | 4 ---- Sources/XMLCoder/Box/NullBox.swift | 8 ++++---- Sources/XMLCoder/Box/StringBox.swift | 8 ++++---- Sources/XMLCoder/Box/UIntBox.swift | 8 ++++---- Sources/XMLCoder/Box/UnkeyedBox.swift | 4 ---- 12 files changed, 41 insertions(+), 46 deletions(-) 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/KeyedBox.swift b/Sources/XMLCoder/Box/KeyedBox.swift index ae9aacc7..ffe88790 100644 --- a/Sources/XMLCoder/Box/KeyedBox.swift +++ b/Sources/XMLCoder/Box/KeyedBox.swift @@ -68,10 +68,6 @@ extension KeyedBox: Box { return false } - var isFragment: Bool { - return false - } - func xmlString() -> String? { return nil } 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/UnkeyedBox.swift b/Sources/XMLCoder/Box/UnkeyedBox.swift index 9fb15e3c..83013757 100644 --- a/Sources/XMLCoder/Box/UnkeyedBox.swift +++ b/Sources/XMLCoder/Box/UnkeyedBox.swift @@ -61,10 +61,6 @@ extension UnkeyedBox: Box { return false } - var isFragment: Bool { - return false - } - func xmlString() -> String? { return nil } From 48a851997ee852ff4414db4467f92f41f6501cce Mon Sep 17 00:00:00 2001 From: Vincent Esche Date: Fri, 21 Dec 2018 01:47:51 +0100 Subject: [PATCH 5/7] Renamed unit test files related to `KeyedBox`/`UnkeyedBox` --- ...naryBoxTests.swift => KeyedBoxTests.swift} | 0 ...ayBoxTests.swift => UnkeyedBoxTests.swift} | 0 ...DictionaryTests.swift => KeyedTests.swift} | 19 +++++++++-- .../{ArrayTests.swift => UnkeyedTests.swift} | 19 +++++++++-- XMLCoder.xcodeproj/project.pbxproj | 32 +++++++++---------- 5 files changed, 50 insertions(+), 20 deletions(-) rename Tests/XMLCoderTests/Box/{DictionaryBoxTests.swift => KeyedBoxTests.swift} (100%) rename Tests/XMLCoderTests/Box/{ArrayBoxTests.swift => UnkeyedBoxTests.swift} (100%) rename Tests/XMLCoderTests/Minimal/{DictionaryTests.swift => KeyedTests.swift} (80%) rename Tests/XMLCoderTests/Minimal/{ArrayTests.swift => UnkeyedTests.swift} (79%) diff --git a/Tests/XMLCoderTests/Box/DictionaryBoxTests.swift b/Tests/XMLCoderTests/Box/KeyedBoxTests.swift similarity index 100% rename from Tests/XMLCoderTests/Box/DictionaryBoxTests.swift rename to Tests/XMLCoderTests/Box/KeyedBoxTests.swift diff --git a/Tests/XMLCoderTests/Box/ArrayBoxTests.swift b/Tests/XMLCoderTests/Box/UnkeyedBoxTests.swift similarity index 100% rename from Tests/XMLCoderTests/Box/ArrayBoxTests.swift rename to Tests/XMLCoderTests/Box/UnkeyedBoxTests.swift 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 ed238f6c..86127444 100644 --- a/XMLCoder.xcodeproj/project.pbxproj +++ b/XMLCoder.xcodeproj/project.pbxproj @@ -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 */; }; @@ -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 = ""; }; @@ -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; @@ -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 */, From fe9f4e40bc8887477882f2a8d355ac26d7deab38 Mon Sep 17 00:00:00 2001 From: Vincent Esche Date: Fri, 21 Dec 2018 01:55:20 +0100 Subject: [PATCH 6/7] Greatly reduced redundancy of coding logic, simplifying maintenance --- .../XMLCoder/Decoder/XMLDecodingStorage.swift | 2 +- .../Decoder/XMLKeyedDecodingContainer.swift | 274 ++++++----------- .../Decoder/XMLUnkeyedDecodingContainer.swift | 285 +++++------------- Sources/XMLCoder/Encoder/XMLEncoder.swift | 28 +- .../Encoder/XMLKeyedEncodingContainer.swift | 191 ++++++------ .../Encoder/XMLUnkeyedEncodingContainer.swift | 104 +++++-- 6 files changed, 372 insertions(+), 512 deletions(-) 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 746aa963..c34c7982 100644 --- a/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift +++ b/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift @@ -95,213 +95,81 @@ 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)).")) - } - - decoder.codingPath.append(key) - defer { self.decoder.codingPath.removeLast() } - - 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.")) - } - - return value + return try self.decodeFloatingPoint(type, forKey: key) } - + 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)).")) - } - - 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.")) - } - - return value + return try self.decodeFloatingPoint(type, forKey: key) } 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)).")) + 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: String = 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: Date.Type, forKey key: Key) throws -> Date { + return try self.decode(type, forKey: key) { decoder, box in + return try decoder.unbox(box) + } + } + + 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: T.Type, forKey key: Key) throws -> T { @@ -309,17 +177,51 @@ internal struct _XMLKeyedDecodingContainer: KeyedDecodingContainer return (type as! AnyEmptySequence.Type).init() as! T } + return try self.decode(type, forKey: key) { decoder, box in + return try decoder.unbox(box) + } + } + + 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) + } + } + + 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) + } + } + + 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,9 +230,10 @@ 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 keyed = value as? KeyedBox else { @@ -346,9 +249,10 @@ 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 unkeyed = value as? UnkeyedBox else { diff --git a/Sources/XMLCoder/Decoder/XMLUnkeyedDecodingContainer.swift b/Sources/XMLCoder/Decoder/XMLUnkeyedDecodingContainer.swift index ff13cd82..b7650bcb 100644 --- a/Sources/XMLCoder/Decoder/XMLUnkeyedDecodingContainer.swift +++ b/Sources/XMLCoder/Decoder/XMLUnkeyedDecodingContainer.swift @@ -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,16 +175,18 @@ 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 keyed = value as? KeyedBox else { @@ -327,16 +203,18 @@ 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 unkeyed = value as? UnkeyedBox else { @@ -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 e439e040..e783ddba 100644 --- a/Sources/XMLCoder/Encoder/XMLEncoder.swift +++ b/Sources/XMLCoder/Encoder/XMLEncoder.swift @@ -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: @@ -552,16 +552,12 @@ extension _XMLEncoder { } } - internal func boxOrNil(_ value: T) throws -> Box? { - return try self.box(value) - } - internal func box(_ value: T) throws -> Box { - return try self.box_(value) ?? KeyedBox() + 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/XMLKeyedEncodingContainer.swift b/Sources/XMLCoder/Encoder/XMLKeyedEncodingContainer.swift index 11afbcd0..f91c2e57 100644 --- a/Sources/XMLCoder/Encoder/XMLKeyedEncodingContainer.swift +++ b/Sources/XMLCoder/Encoder/XMLKeyedEncodingContainer.swift @@ -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? KeyedBox { - attributesContainer[_converted(key).stringValue] = self.encoder.box(value) - } else { - let attributesContainer = KeyedBox() - 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? KeyedBox { - attributesContainer[_converted(key).stringValue] = try self.encoder.box(value) - } else { - let attributesContainer = KeyedBox() - 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? KeyedBox { - attributesContainer[_converted(key).stringValue] = self.encoder.box(value) - } else { - let attributesContainer = KeyedBox() - 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? KeyedBox { - attributesContainer[_converted(key).stringValue] = try self.encoder.box(value) - } else { - let attributesContainer = KeyedBox() - 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? KeyedBox { - attributesContainer[_converted(key).stringValue] = try self.encoder.box(value) - } else { - let attributesContainer = KeyedBox() - 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,21 +170,24 @@ 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: + 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] = try self.encoder.box(value) + attributesContainer[_converted(key).stringValue] = box } else { let attributesContainer = KeyedBox() - attributesContainer[_converted(key).stringValue] = try self.encoder.box(value) + 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 } } diff --git a/Sources/XMLCoder/Encoder/XMLUnkeyedEncodingContainer.swift b/Sources/XMLCoder/Encoder/XMLUnkeyedEncodingContainer.swift index 36071831..67e140ef 100644 --- a/Sources/XMLCoder/Encoder/XMLUnkeyedEncodingContainer.swift +++ b/Sources/XMLCoder/Encoder/XMLUnkeyedEncodingContainer.swift @@ -40,44 +40,114 @@ 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 { From cd0cdc7408baa87d15abafefacecc4b29ef4297e Mon Sep 17 00:00:00 2001 From: Vincent Esche Date: Fri, 21 Dec 2018 11:39:28 +0100 Subject: [PATCH 7/7] Removed trailing whitespace --- .../Decoder/XMLKeyedDecodingContainer.swift | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift b/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift index c34c7982..2ae70132 100644 --- a/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift +++ b/Sources/XMLCoder/Decoder/XMLKeyedDecodingContainer.swift @@ -99,7 +99,7 @@ internal struct _XMLKeyedDecodingContainer: KeyedDecodingContainer return try decoder.unbox(box) } } - + 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) @@ -109,39 +109,39 @@ internal struct _XMLKeyedDecodingContainer: KeyedDecodingContainer public func decode(_ type: Int.Type, forKey key: Key) throws -> Int { return try self.decodeSignedInteger(type, forKey: key) } - + public func decode(_ type: Int8.Type, forKey key: Key) throws -> Int8 { return try self.decodeSignedInteger(type, forKey: key) } - + public func decode(_ type: Int16.Type, forKey key: Key) throws -> Int16 { return try self.decodeSignedInteger(type, forKey: key) } - + public func decode(_ type: Int32.Type, forKey key: Key) throws -> Int32 { return try self.decodeSignedInteger(type, forKey: key) } - + public func decode(_ type: Int64.Type, forKey key: Key) throws -> Int64 { return try self.decodeSignedInteger(type, forKey: key) } - + public func decode(_ type: UInt.Type, forKey key: Key) throws -> UInt { return try self.decodeUnsignedInteger(type, forKey: key) } - + public func decode(_ type: UInt8.Type, forKey key: Key) throws -> UInt8 { return try self.decodeUnsignedInteger(type, forKey: key) } - + public func decode(_ type: UInt16.Type, forKey key: Key) throws -> UInt16 { return try self.decodeUnsignedInteger(type, forKey: key) } - + public func decode(_ type: UInt32.Type, forKey key: Key) throws -> UInt32 { return try self.decodeUnsignedInteger(type, forKey: key) } - + public func decode(_ type: UInt64.Type, forKey key: Key) throws -> UInt64 { return try self.decodeUnsignedInteger(type, forKey: key) } @@ -149,7 +149,7 @@ internal struct _XMLKeyedDecodingContainer: KeyedDecodingContainer public func decode(_ type: Float.Type, forKey key: Key) throws -> Float { return try self.decodeFloatingPoint(type, forKey: key) } - + public func decode(_ type: Double.Type, forKey key: Key) throws -> Double { return try self.decodeFloatingPoint(type, forKey: key) } @@ -159,13 +159,13 @@ internal struct _XMLKeyedDecodingContainer: KeyedDecodingContainer return try decoder.unbox(box) } } - + 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) } } - + 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) @@ -181,25 +181,25 @@ internal struct _XMLKeyedDecodingContainer: KeyedDecodingContainer return try decoder.unbox(box) } } - + 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) } } - + 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) } } - + 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, @@ -211,17 +211,17 @@ internal struct _XMLKeyedDecodingContainer: KeyedDecodingContainer 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." )) } - + return value }