From 869b58e962273d03250fe18ca6af3e426725e046 Mon Sep 17 00:00:00 2001 From: Ben Wetherfield Date: Sat, 23 Nov 2019 13:24:46 -0800 Subject: [PATCH 01/15] Add breaking case --- Tests/XMLCoderTests/SimpleChoiceTests.swift | 22 +++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/Tests/XMLCoderTests/SimpleChoiceTests.swift b/Tests/XMLCoderTests/SimpleChoiceTests.swift index e22ce864..361c2428 100644 --- a/Tests/XMLCoderTests/SimpleChoiceTests.swift +++ b/Tests/XMLCoderTests/SimpleChoiceTests.swift @@ -13,6 +13,23 @@ private enum IntOrString: Equatable { case string(String) } +private struct Mixed: Equatable { + let intOrString: IntOrString + let otherValue: String +} + +extension Mixed: Encodable { + enum CodingKeys: String, CodingKey { + case otherValue = "other-value" + } + + func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(otherValue, forKey: .otherValue) + try intOrString.encode(to: encoder) + } +} + extension IntOrString: Codable { enum CodingKeys: String, XMLChoiceCodingKey { case int @@ -115,4 +132,9 @@ class SimpleChoiceTests: XCTestCase { let decoded = try XMLDecoder().decode([[IntOrString]].self, from: encoded) XCTAssertEqual(original, decoded) } + + func testMixedEncode() throws { + let original = Mixed(intOrString: .int(4), otherValue: "other") + print(try XMLEncoder().encode(original, withRootKey: "container")) + } } From afdc1967d99fe11d32e286a8c6cfc53ed500090f Mon Sep 17 00:00:00 2001 From: Ben Wetherfield Date: Sun, 24 Nov 2019 15:18:25 -0800 Subject: [PATCH 02/15] Add choice and keyed merging encode functionality --- .../SingleValueEncodingContainer.swift | 14 ++-- .../Encoder/XMLEncoderImplementation.swift | 76 +++++++++++-------- .../XMLCoder/Encoder/XMLEncodingStorage.swift | 4 +- Tests/XMLCoderTests/SimpleChoiceTests.swift | 62 +++++++++++++-- Tests/XMLCoderTests/XCTestManifests.swift | 1 + 5 files changed, 112 insertions(+), 45 deletions(-) diff --git a/Sources/XMLCoder/Encoder/SingleValueEncodingContainer.swift b/Sources/XMLCoder/Encoder/SingleValueEncodingContainer.swift index f693b027..0cca88e5 100644 --- a/Sources/XMLCoder/Encoder/SingleValueEncodingContainer.swift +++ b/Sources/XMLCoder/Encoder/SingleValueEncodingContainer.swift @@ -12,13 +12,13 @@ extension XMLEncoderImplementation: SingleValueEncodingContainer { // MARK: - SingleValueEncodingContainer Methods func assertCanEncodeNewValue() { - precondition( - canEncodeNewValue, - """ - Attempt to encode value through single value container when \ - previously value already encoded. - """ - ) +// precondition( +// canEncodeNewValue, +// """ +// Attempt to encode value through single value container when \ +// previously value already encoded. +// """ +// ) } public func encodeNil() throws { diff --git a/Sources/XMLCoder/Encoder/XMLEncoderImplementation.swift b/Sources/XMLCoder/Encoder/XMLEncoderImplementation.swift index d16c3210..00ee2073 100644 --- a/Sources/XMLCoder/Encoder/XMLEncoderImplementation.swift +++ b/Sources/XMLCoder/Encoder/XMLEncoderImplementation.swift @@ -73,47 +73,63 @@ class XMLEncoderImplementation: Encoder { public func keyedContainer(keyedBy _: Key.Type) -> KeyedEncodingContainer { // If an existing keyed container was already requested, return that one. - let topContainer: SharedBox if canEncodeNewValue { // We haven't yet pushed a container at this level; do so here. - topContainer = storage.pushKeyedContainer() + let container = XMLKeyedEncodingContainer( + referencing: self, + codingPath: codingPath, + wrapping: storage.pushKeyedContainer() + ) + return KeyedEncodingContainer(container) + } else if let keyed = storage.lastContainer as? SharedBox { + let container = XMLKeyedEncodingContainer( + referencing: self, + codingPath: codingPath, + wrapping: keyed + ) + return KeyedEncodingContainer(container) + } else if let choice = storage.lastContainer as? SharedBox { + let keyed = KeyedBox(elements: .init([choice.withShared { ($0.key, $0.element) }])) + let container = XMLKeyedEncodingContainer( + referencing: self, + codingPath: codingPath, + wrapping: storage.pushKeyedContainer(keyed) + ) + return KeyedEncodingContainer(container) } else { - guard let container = storage.lastContainer as? SharedBox else { - preconditionFailure( - """ - Attempt to push new keyed encoding container when already previously encoded \ - at this path. - """ - ) - } - - topContainer = container + preconditionFailure( + """ + Attempt to push new keyed encoding container when already previously encoded \ + at this path. + """ + ) } - - let container = XMLKeyedEncodingContainer(referencing: self, codingPath: codingPath, wrapping: topContainer) - return KeyedEncodingContainer(container) } public func choiceContainer(keyedBy _: Key.Type) -> KeyedEncodingContainer { - let topContainer: SharedBox if canEncodeNewValue { // We haven't yet pushed a container at this level; do so here. - topContainer = storage.pushChoiceContainer() + let container = XMLChoiceEncodingContainer( + referencing: self, + codingPath: codingPath, + wrapping: storage.pushChoiceContainer() + ) + return KeyedEncodingContainer(container) + } else if let keyed = storage.lastContainer as? SharedBox { + let container = XMLKeyedEncodingContainer( + referencing: self, + codingPath: codingPath, + wrapping: keyed + ) + return KeyedEncodingContainer(container) } else { - guard let container = storage.lastContainer as? SharedBox else { - preconditionFailure( - """ - Attempt to push new (single element) keyed encoding container when already \ - previously encoded at this path. - """ - ) - } - - topContainer = container + preconditionFailure( + """ + Attempt to push new keyed encoding container when already previously encoded \ + at this path. + """ + ) } - - let container = XMLChoiceEncodingContainer(referencing: self, codingPath: codingPath, wrapping: topContainer) - return KeyedEncodingContainer(container) } public func unkeyedContainer() -> UnkeyedEncodingContainer { diff --git a/Sources/XMLCoder/Encoder/XMLEncodingStorage.swift b/Sources/XMLCoder/Encoder/XMLEncodingStorage.swift index eecba789..669accf8 100644 --- a/Sources/XMLCoder/Encoder/XMLEncodingStorage.swift +++ b/Sources/XMLCoder/Encoder/XMLEncodingStorage.swift @@ -31,8 +31,8 @@ struct XMLEncodingStorage { return containers.last } - mutating func pushKeyedContainer() -> SharedBox { - let container = SharedBox(KeyedBox()) + mutating func pushKeyedContainer(_ keyedBox: KeyedBox = KeyedBox()) -> SharedBox { + let container = SharedBox(keyedBox) containers.append(container) return container } diff --git a/Tests/XMLCoderTests/SimpleChoiceTests.swift b/Tests/XMLCoderTests/SimpleChoiceTests.swift index 361c2428..f1e154e1 100644 --- a/Tests/XMLCoderTests/SimpleChoiceTests.swift +++ b/Tests/XMLCoderTests/SimpleChoiceTests.swift @@ -13,16 +13,33 @@ private enum IntOrString: Equatable { case string(String) } -private struct Mixed: Equatable { +private struct MixedIntOrStringFirst: Equatable { let intOrString: IntOrString let otherValue: String } -extension Mixed: Encodable { +extension MixedIntOrStringFirst: Encodable { enum CodingKeys: String, CodingKey { case otherValue = "other-value" } - + + func encode(to encoder: Encoder) throws { + try intOrString.encode(to: encoder) + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(otherValue, forKey: .otherValue) + } +} + +private struct MixedOtherFirst: Equatable { + let intOrString: IntOrString + let otherValue: String +} + +extension MixedOtherFirst: Encodable { + enum CodingKeys: String, CodingKey { + case otherValue = "other-value" + } + func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(otherValue, forKey: .otherValue) @@ -30,6 +47,26 @@ extension Mixed: Encodable { } } +private struct MixedEitherSide { + let leading: String + let intOrString: IntOrString + let trailing: String +} + +extension MixedEitherSide: Encodable { + enum CodingKeys: String, CodingKey { + case leading + case trailing + } + + func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(leading, forKey: .leading) + try intOrString.encode(to: encoder) + try container.encode(trailing, forKey: .trailing) + } +} + extension IntOrString: Codable { enum CodingKeys: String, XMLChoiceCodingKey { case int @@ -132,9 +169,22 @@ class SimpleChoiceTests: XCTestCase { let decoded = try XMLDecoder().decode([[IntOrString]].self, from: encoded) XCTAssertEqual(original, decoded) } - + func testMixedEncode() throws { - let original = Mixed(intOrString: .int(4), otherValue: "other") - print(try XMLEncoder().encode(original, withRootKey: "container")) + let first = MixedIntOrStringFirst(intOrString: .int(4), otherValue: "other") + let second = MixedOtherFirst(intOrString: .int(4), otherValue: "other") + let flanked = MixedEitherSide(leading: "first", intOrString: .string("then"), trailing: "second") + + let firstEncoded = try XMLEncoder().encode(first, withRootKey: "container") + let secondEncoded = try XMLEncoder().encode(second, withRootKey: "container") + let flankedEncoded = try XMLEncoder().encode(flanked, withRootKey: "container") + + let firstExpectedXML = "4other" + let secondExpectedXML = "other4" + let flankedExpectedXML = "firstthensecond" + + XCTAssertEqual(String(data: firstEncoded, encoding: .utf8), firstExpectedXML) + XCTAssertEqual(String(data: secondEncoded, encoding: .utf8), secondExpectedXML) + XCTAssertEqual(String(data: flankedEncoded, encoding: .utf8), flankedExpectedXML) } } diff --git a/Tests/XMLCoderTests/XCTestManifests.swift b/Tests/XMLCoderTests/XCTestManifests.swift index 26fd2943..1cd6785f 100644 --- a/Tests/XMLCoderTests/XCTestManifests.swift +++ b/Tests/XMLCoderTests/XCTestManifests.swift @@ -610,6 +610,7 @@ extension SimpleChoiceTests { ("testIntOrStringIntDecoding", testIntOrStringIntDecoding), ("testIntOrStringRoundTrip", testIntOrStringRoundTrip), ("testIntOrStringStringDecoding", testIntOrStringStringDecoding), + ("testMixedEncode", testMixedEncode), ] } From 2e2b843ae25b8ddb3b4a6c842b613758de979e4a Mon Sep 17 00:00:00 2001 From: Ben Wetherfield Date: Sun, 24 Nov 2019 15:29:32 -0800 Subject: [PATCH 03/15] Refactor --- Tests/XMLCoderTests/IntOrString.swift | 39 +++++++ .../MixedChoiceAndNonChocieTests.swift | 88 +++++++++++++++ Tests/XMLCoderTests/SimpleChoiceTests.swift | 103 ------------------ Tests/XMLCoderTests/XCTestManifests.swift | 13 ++- XMLCoder.xcodeproj/project.pbxproj | 15 ++- 5 files changed, 149 insertions(+), 109 deletions(-) create mode 100644 Tests/XMLCoderTests/IntOrString.swift create mode 100644 Tests/XMLCoderTests/MixedChoiceAndNonChocieTests.swift diff --git a/Tests/XMLCoderTests/IntOrString.swift b/Tests/XMLCoderTests/IntOrString.swift new file mode 100644 index 00000000..af90069c --- /dev/null +++ b/Tests/XMLCoderTests/IntOrString.swift @@ -0,0 +1,39 @@ +// +// IntOrString.swift +// XMLCoderTests +// +// Created by Benjamin Wetherfield on 11/24/19. +// + +import XMLCoder + +internal enum IntOrString: Equatable { + case int(Int) + case string(String) +} + +extension IntOrString: Codable { + enum CodingKeys: String, XMLChoiceCodingKey { + case int + case string + } + + func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + switch self { + case let .int(value): + try container.encode(value, forKey: .int) + case let .string(value): + try container.encode(value, forKey: .string) + } + } + + init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + do { + self = .int(try container.decode(Int.self, forKey: .int)) + } catch { + self = .string(try container.decode(String.self, forKey: .string)) + } + } +} diff --git a/Tests/XMLCoderTests/MixedChoiceAndNonChocieTests.swift b/Tests/XMLCoderTests/MixedChoiceAndNonChocieTests.swift new file mode 100644 index 00000000..fb640e1c --- /dev/null +++ b/Tests/XMLCoderTests/MixedChoiceAndNonChocieTests.swift @@ -0,0 +1,88 @@ +// +// MixedChoiceAndNonChoiceTests.swift +// XMLCoderTests +// +// Created by Benjamin Wetherfield on 11/24/19. +// + +import XCTest +import XMLCoder + +private struct MixedIntOrStringFirst: Equatable { + let intOrString: IntOrString + let otherValue: String +} + +extension MixedIntOrStringFirst: Encodable { + enum CodingKeys: String, CodingKey { + case otherValue = "other-value" + } + + func encode(to encoder: Encoder) throws { + try intOrString.encode(to: encoder) + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(otherValue, forKey: .otherValue) + } +} + +private struct MixedOtherFirst: Equatable { + let intOrString: IntOrString + let otherValue: String +} + +extension MixedOtherFirst: Encodable { + enum CodingKeys: String, CodingKey { + case otherValue = "other-value" + } + + func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(otherValue, forKey: .otherValue) + try intOrString.encode(to: encoder) + } +} + +private struct MixedEitherSide { + let leading: String + let intOrString: IntOrString + let trailing: String +} + +extension MixedEitherSide: Encodable { + enum CodingKeys: String, CodingKey { + case leading + case trailing + } + + func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(leading, forKey: .leading) + try intOrString.encode(to: encoder) + try container.encode(trailing, forKey: .trailing) + } +} + +class MixedChoiceAndNonChoiceTests: XCTestCase { + func testMixedChoiceFirstEncode() throws { + let first = MixedIntOrStringFirst(intOrString: .int(4), otherValue: "other") + let firstEncoded = try XMLEncoder().encode(first, withRootKey: "container") + let firstExpectedXML = "4other" + XCTAssertEqual(String(data: firstEncoded, encoding: .utf8), firstExpectedXML) + } + + func testMixedChoiceSecondEncode() throws { + let second = MixedOtherFirst(intOrString: .int(4), otherValue: "other") + let secondEncoded = try XMLEncoder().encode(second, withRootKey: "container") + let secondExpectedXML = "other4" + XCTAssertEqual(String(data: secondEncoded, encoding: .utf8), secondExpectedXML) + } + + func testMixedChoiceFlankedEncode() throws { + let flanked = MixedEitherSide(leading: "first", intOrString: .string("then"), trailing: "second") + let flankedEncoded = try XMLEncoder().encode(flanked, withRootKey: "container") + let flankedExpectedXML = """ + firstthensecond + """ + XCTAssertEqual(String(data: flankedEncoded, encoding: .utf8), flankedExpectedXML) + } +} diff --git a/Tests/XMLCoderTests/SimpleChoiceTests.swift b/Tests/XMLCoderTests/SimpleChoiceTests.swift index f1e154e1..86834caa 100644 --- a/Tests/XMLCoderTests/SimpleChoiceTests.swift +++ b/Tests/XMLCoderTests/SimpleChoiceTests.swift @@ -8,91 +8,6 @@ import XCTest import XMLCoder -private enum IntOrString: Equatable { - case int(Int) - case string(String) -} - -private struct MixedIntOrStringFirst: Equatable { - let intOrString: IntOrString - let otherValue: String -} - -extension MixedIntOrStringFirst: Encodable { - enum CodingKeys: String, CodingKey { - case otherValue = "other-value" - } - - func encode(to encoder: Encoder) throws { - try intOrString.encode(to: encoder) - var container = encoder.container(keyedBy: CodingKeys.self) - try container.encode(otherValue, forKey: .otherValue) - } -} - -private struct MixedOtherFirst: Equatable { - let intOrString: IntOrString - let otherValue: String -} - -extension MixedOtherFirst: Encodable { - enum CodingKeys: String, CodingKey { - case otherValue = "other-value" - } - - func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - try container.encode(otherValue, forKey: .otherValue) - try intOrString.encode(to: encoder) - } -} - -private struct MixedEitherSide { - let leading: String - let intOrString: IntOrString - let trailing: String -} - -extension MixedEitherSide: Encodable { - enum CodingKeys: String, CodingKey { - case leading - case trailing - } - - func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - try container.encode(leading, forKey: .leading) - try intOrString.encode(to: encoder) - try container.encode(trailing, forKey: .trailing) - } -} - -extension IntOrString: Codable { - enum CodingKeys: String, XMLChoiceCodingKey { - case int - case string - } - - func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - switch self { - case let .int(value): - try container.encode(value, forKey: .int) - case let .string(value): - try container.encode(value, forKey: .string) - } - } - - init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - do { - self = .int(try container.decode(Int.self, forKey: .int)) - } catch { - self = .string(try container.decode(String.self, forKey: .string)) - } - } -} - class SimpleChoiceTests: XCTestCase { func testIntOrStringIntDecoding() throws { let xml = """ @@ -169,22 +84,4 @@ class SimpleChoiceTests: XCTestCase { let decoded = try XMLDecoder().decode([[IntOrString]].self, from: encoded) XCTAssertEqual(original, decoded) } - - func testMixedEncode() throws { - let first = MixedIntOrStringFirst(intOrString: .int(4), otherValue: "other") - let second = MixedOtherFirst(intOrString: .int(4), otherValue: "other") - let flanked = MixedEitherSide(leading: "first", intOrString: .string("then"), trailing: "second") - - let firstEncoded = try XMLEncoder().encode(first, withRootKey: "container") - let secondEncoded = try XMLEncoder().encode(second, withRootKey: "container") - let flankedEncoded = try XMLEncoder().encode(flanked, withRootKey: "container") - - let firstExpectedXML = "4other" - let secondExpectedXML = "other4" - let flankedExpectedXML = "firstthensecond" - - XCTAssertEqual(String(data: firstEncoded, encoding: .utf8), firstExpectedXML) - XCTAssertEqual(String(data: secondEncoded, encoding: .utf8), secondExpectedXML) - XCTAssertEqual(String(data: flankedEncoded, encoding: .utf8), flankedExpectedXML) - } } diff --git a/Tests/XMLCoderTests/XCTestManifests.swift b/Tests/XMLCoderTests/XCTestManifests.swift index 1cd6785f..28d53c65 100644 --- a/Tests/XMLCoderTests/XCTestManifests.swift +++ b/Tests/XMLCoderTests/XCTestManifests.swift @@ -414,6 +414,17 @@ extension KeyedTests { ] } +extension MixedChoiceAndNonChoiceTests { + // DO NOT MODIFY: This is autogenerated, use: + // `swift test --generate-linuxmain` + // to regenerate. + static let __allTests__MixedChoiceAndNonChoiceTests = [ + ("testMixedChoiceFirstEncode", testMixedChoiceFirstEncode), + ("testMixedChoiceFlankedEncode", testMixedChoiceFlankedEncode), + ("testMixedChoiceSecondEncode", testMixedChoiceSecondEncode), + ] +} + extension MixedContainerTest { // DO NOT MODIFY: This is autogenerated, use: // `swift test --generate-linuxmain` @@ -610,7 +621,6 @@ extension SimpleChoiceTests { ("testIntOrStringIntDecoding", testIntOrStringIntDecoding), ("testIntOrStringRoundTrip", testIntOrStringRoundTrip), ("testIntOrStringStringDecoding", testIntOrStringStringDecoding), - ("testMixedEncode", testMixedEncode), ] } @@ -841,6 +851,7 @@ public func __allTests() -> [XCTestCaseEntry] { testCase(KeyedBoxTests.__allTests__KeyedBoxTests), testCase(KeyedIntTests.__allTests__KeyedIntTests), testCase(KeyedTests.__allTests__KeyedTests), + testCase(MixedChoiceAndNonChoiceTests.__allTests__MixedChoiceAndNonChoiceTests), testCase(MixedContainerTest.__allTests__MixedContainerTest), testCase(NameSpaceTest.__allTests__NameSpaceTest), testCase(NestedAttributeChoiceTests.__allTests__NestedAttributeChoiceTests), diff --git a/XMLCoder.xcodeproj/project.pbxproj b/XMLCoder.xcodeproj/project.pbxproj index 322538b5..31045234 100644 --- a/XMLCoder.xcodeproj/project.pbxproj +++ b/XMLCoder.xcodeproj/project.pbxproj @@ -22,9 +22,10 @@ /* Begin PBXBuildFile section */ 07E441BA2340F14B00890F46 /* EmptyElementEmptyStringTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 07E441B92340F14B00890F46 /* EmptyElementEmptyStringTests.swift */; }; - B54555BC2343F5C1000D4128 /* EmptyArrayTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = B54555BB2343F5C1000D4128 /* EmptyArrayTest.swift */; }; - B5EA3BB6230F237800D8D69B /* NestedChoiceArrayTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5EA3BB4230F235C00D8D69B /* NestedChoiceArrayTest.swift */; }; 4A062D4F2341924E009BCAC1 /* CombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A062D4E2341924E009BCAC1 /* CombineTests.swift */; }; + B54555BC2343F5C1000D4128 /* EmptyArrayTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = B54555BB2343F5C1000D4128 /* EmptyArrayTest.swift */; }; + B5E67533238B47E5006C8548 /* MixedChoiceAndNonChocieTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E67532238B47E5006C8548 /* MixedChoiceAndNonChocieTests.swift */; }; + B5E67535238B4960006C8548 /* IntOrString.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E67534238B4960006C8548 /* IntOrString.swift */; }; B5EA3BB6230F237800D8D69B /* NestedChoiceArrayTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5EA3BB4230F235C00D8D69B /* NestedChoiceArrayTest.swift */; }; B5F74472233F74E400BBDB15 /* RootLevelAttributeTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5F74471233F74E400BBDB15 /* RootLevelAttributeTest.swift */; }; D11E094623491BCE00C24DCB /* DoubleBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = D11E094523491BCE00C24DCB /* DoubleBox.swift */; }; @@ -162,9 +163,10 @@ /* Begin PBXFileReference section */ 07E441B92340F14B00890F46 /* EmptyElementEmptyStringTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyElementEmptyStringTests.swift; sourceTree = ""; }; - B54555BB2343F5C1000D4128 /* EmptyArrayTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyArrayTest.swift; sourceTree = ""; }; - B5EA3BB4230F235C00D8D69B /* NestedChoiceArrayTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NestedChoiceArrayTest.swift; sourceTree = ""; }; 4A062D4E2341924E009BCAC1 /* CombineTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CombineTests.swift; sourceTree = ""; }; + B54555BB2343F5C1000D4128 /* EmptyArrayTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyArrayTest.swift; sourceTree = ""; }; + B5E67532238B47E5006C8548 /* MixedChoiceAndNonChocieTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MixedChoiceAndNonChocieTests.swift; sourceTree = ""; }; + B5E67534238B4960006C8548 /* IntOrString.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntOrString.swift; sourceTree = ""; }; B5EA3BB4230F235C00D8D69B /* NestedChoiceArrayTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NestedChoiceArrayTest.swift; sourceTree = ""; }; B5F74471233F74E400BBDB15 /* RootLevelAttributeTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootLevelAttributeTest.swift; sourceTree = ""; }; D11E094523491BCE00C24DCB /* DoubleBox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DoubleBox.swift; sourceTree = ""; }; @@ -455,7 +457,6 @@ OBJ_113 /* MixedContainerTest.swift */, OBJ_114 /* NamespaceTest.swift */, OBJ_115 /* NestedAttributeChoiceTests.swift */, - B5EA3BB4230F235C00D8D69B /* NestedChoiceArrayTest.swift */, OBJ_116 /* NestedChoiceTests.swift */, OBJ_117 /* NestingTests.swift */, OBJ_118 /* NodeEncodingStrategyTests.swift */, @@ -473,6 +474,8 @@ OBJ_127 /* SpacePreserveTest.swift */, B5EA3BB4230F235C00D8D69B /* NestedChoiceArrayTest.swift */, B54555BB2343F5C1000D4128 /* EmptyArrayTest.swift */, + B5E67532238B47E5006C8548 /* MixedChoiceAndNonChocieTests.swift */, + B5E67534238B4960006C8548 /* IntOrString.swift */, ); name = XMLCoderTests; path = Tests/XMLCoderTests; @@ -723,6 +726,7 @@ OBJ_227 /* SharedBoxTests.swift in Sources */, OBJ_228 /* StringBoxTests.swift in Sources */, OBJ_229 /* UIntBoxTests.swift in Sources */, + B5E67533238B47E5006C8548 /* MixedChoiceAndNonChocieTests.swift in Sources */, OBJ_230 /* URLBoxTests.swift in Sources */, OBJ_231 /* UnkeyedBoxTests.swift in Sources */, OBJ_232 /* BreakfastTest.swift in Sources */, @@ -765,6 +769,7 @@ OBJ_266 /* PlantCatalog.swift in Sources */, OBJ_267 /* PlantTest.swift in Sources */, OBJ_268 /* RJISample.swift in Sources */, + B5E67535238B4960006C8548 /* IntOrString.swift in Sources */, OBJ_269 /* RJITest.swift in Sources */, OBJ_270 /* RelationshipsTest.swift in Sources */, OBJ_271 /* SimpleChoiceTests.swift in Sources */, From 40f9f4208c0145ea5fd998001cd05b4b02936d0c Mon Sep 17 00:00:00 2001 From: Ben Wetherfield Date: Sun, 24 Nov 2019 15:33:20 -0800 Subject: [PATCH 04/15] Fix commented code --- .../Encoder/SingleValueEncodingContainer.swift | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Sources/XMLCoder/Encoder/SingleValueEncodingContainer.swift b/Sources/XMLCoder/Encoder/SingleValueEncodingContainer.swift index 0cca88e5..f693b027 100644 --- a/Sources/XMLCoder/Encoder/SingleValueEncodingContainer.swift +++ b/Sources/XMLCoder/Encoder/SingleValueEncodingContainer.swift @@ -12,13 +12,13 @@ extension XMLEncoderImplementation: SingleValueEncodingContainer { // MARK: - SingleValueEncodingContainer Methods func assertCanEncodeNewValue() { -// precondition( -// canEncodeNewValue, -// """ -// Attempt to encode value through single value container when \ -// previously value already encoded. -// """ -// ) + precondition( + canEncodeNewValue, + """ + Attempt to encode value through single value container when \ + previously value already encoded. + """ + ) } public func encodeNil() throws { From c335791d2878b5e8d773dfd2f343e465c76cf1db Mon Sep 17 00:00:00 2001 From: Ben Wetherfield Date: Sun, 24 Nov 2019 15:34:13 -0800 Subject: [PATCH 05/15] Fix misnamed file --- ...AndNonChocieTests.swift => MixedChoiceAndNonChoiceTests.swift} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Tests/XMLCoderTests/{MixedChoiceAndNonChocieTests.swift => MixedChoiceAndNonChoiceTests.swift} (100%) diff --git a/Tests/XMLCoderTests/MixedChoiceAndNonChocieTests.swift b/Tests/XMLCoderTests/MixedChoiceAndNonChoiceTests.swift similarity index 100% rename from Tests/XMLCoderTests/MixedChoiceAndNonChocieTests.swift rename to Tests/XMLCoderTests/MixedChoiceAndNonChoiceTests.swift From 5d2aeb0bb98d9a8c876d477523927da955ef48e4 Mon Sep 17 00:00:00 2001 From: Ben Wetherfield Date: Sun, 24 Nov 2019 15:34:33 -0800 Subject: [PATCH 06/15] Fix xcode project --- XMLCoder.xcodeproj/project.pbxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/XMLCoder.xcodeproj/project.pbxproj b/XMLCoder.xcodeproj/project.pbxproj index 31045234..82099ba9 100644 --- a/XMLCoder.xcodeproj/project.pbxproj +++ b/XMLCoder.xcodeproj/project.pbxproj @@ -24,7 +24,7 @@ 07E441BA2340F14B00890F46 /* EmptyElementEmptyStringTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 07E441B92340F14B00890F46 /* EmptyElementEmptyStringTests.swift */; }; 4A062D4F2341924E009BCAC1 /* CombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A062D4E2341924E009BCAC1 /* CombineTests.swift */; }; B54555BC2343F5C1000D4128 /* EmptyArrayTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = B54555BB2343F5C1000D4128 /* EmptyArrayTest.swift */; }; - B5E67533238B47E5006C8548 /* MixedChoiceAndNonChocieTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E67532238B47E5006C8548 /* MixedChoiceAndNonChocieTests.swift */; }; + B5E67533238B47E5006C8548 /* MixedChoiceAndNonChoiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E67532238B47E5006C8548 /* MixedChoiceAndNonChoiceTests.swift */; }; B5E67535238B4960006C8548 /* IntOrString.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E67534238B4960006C8548 /* IntOrString.swift */; }; B5EA3BB6230F237800D8D69B /* NestedChoiceArrayTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5EA3BB4230F235C00D8D69B /* NestedChoiceArrayTest.swift */; }; B5F74472233F74E400BBDB15 /* RootLevelAttributeTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5F74471233F74E400BBDB15 /* RootLevelAttributeTest.swift */; }; @@ -165,7 +165,7 @@ 07E441B92340F14B00890F46 /* EmptyElementEmptyStringTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyElementEmptyStringTests.swift; sourceTree = ""; }; 4A062D4E2341924E009BCAC1 /* CombineTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CombineTests.swift; sourceTree = ""; }; B54555BB2343F5C1000D4128 /* EmptyArrayTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyArrayTest.swift; sourceTree = ""; }; - B5E67532238B47E5006C8548 /* MixedChoiceAndNonChocieTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MixedChoiceAndNonChocieTests.swift; sourceTree = ""; }; + B5E67532238B47E5006C8548 /* MixedChoiceAndNonChoiceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MixedChoiceAndNonChoiceTests.swift; sourceTree = ""; }; B5E67534238B4960006C8548 /* IntOrString.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntOrString.swift; sourceTree = ""; }; B5EA3BB4230F235C00D8D69B /* NestedChoiceArrayTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NestedChoiceArrayTest.swift; sourceTree = ""; }; B5F74471233F74E400BBDB15 /* RootLevelAttributeTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootLevelAttributeTest.swift; sourceTree = ""; }; @@ -474,7 +474,7 @@ OBJ_127 /* SpacePreserveTest.swift */, B5EA3BB4230F235C00D8D69B /* NestedChoiceArrayTest.swift */, B54555BB2343F5C1000D4128 /* EmptyArrayTest.swift */, - B5E67532238B47E5006C8548 /* MixedChoiceAndNonChocieTests.swift */, + B5E67532238B47E5006C8548 /* MixedChoiceAndNonChoiceTests.swift */, B5E67534238B4960006C8548 /* IntOrString.swift */, ); name = XMLCoderTests; @@ -726,7 +726,7 @@ OBJ_227 /* SharedBoxTests.swift in Sources */, OBJ_228 /* StringBoxTests.swift in Sources */, OBJ_229 /* UIntBoxTests.swift in Sources */, - B5E67533238B47E5006C8548 /* MixedChoiceAndNonChocieTests.swift in Sources */, + B5E67533238B47E5006C8548 /* MixedChoiceAndNonChoiceTests.swift in Sources */, OBJ_230 /* URLBoxTests.swift in Sources */, OBJ_231 /* UnkeyedBoxTests.swift in Sources */, OBJ_232 /* BreakfastTest.swift in Sources */, From 8712a67a5225db9741dd2cfbbb23a05f30b0c10e Mon Sep 17 00:00:00 2001 From: Ben Wetherfield Date: Sun, 24 Nov 2019 15:44:27 -0800 Subject: [PATCH 07/15] Fix precondition catch --- Sources/XMLCoder/Encoder/XMLEncoderImplementation.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Sources/XMLCoder/Encoder/XMLEncoderImplementation.swift b/Sources/XMLCoder/Encoder/XMLEncoderImplementation.swift index 00ee2073..38730283 100644 --- a/Sources/XMLCoder/Encoder/XMLEncoderImplementation.swift +++ b/Sources/XMLCoder/Encoder/XMLEncoderImplementation.swift @@ -89,6 +89,7 @@ class XMLEncoderImplementation: Encoder { ) return KeyedEncodingContainer(container) } else if let choice = storage.lastContainer as? SharedBox { + _ = storage.popContainer() let keyed = KeyedBox(elements: .init([choice.withShared { ($0.key, $0.element) }])) let container = XMLKeyedEncodingContainer( referencing: self, From 8ac394451a4862bfe6038138d74723e4d10d7200 Mon Sep 17 00:00:00 2001 From: Ben Wetherfield Date: Sun, 24 Nov 2019 15:46:59 -0800 Subject: [PATCH 08/15] Use switch syntax --- .../Encoder/XMLEncoderImplementation.swift | 47 ++++++++++--------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/Sources/XMLCoder/Encoder/XMLEncoderImplementation.swift b/Sources/XMLCoder/Encoder/XMLEncoderImplementation.swift index 38730283..5089bf81 100644 --- a/Sources/XMLCoder/Encoder/XMLEncoderImplementation.swift +++ b/Sources/XMLCoder/Encoder/XMLEncoderImplementation.swift @@ -81,29 +81,32 @@ class XMLEncoderImplementation: Encoder { wrapping: storage.pushKeyedContainer() ) return KeyedEncodingContainer(container) - } else if let keyed = storage.lastContainer as? SharedBox { - let container = XMLKeyedEncodingContainer( - referencing: self, - codingPath: codingPath, - wrapping: keyed - ) - return KeyedEncodingContainer(container) - } else if let choice = storage.lastContainer as? SharedBox { - _ = storage.popContainer() - let keyed = KeyedBox(elements: .init([choice.withShared { ($0.key, $0.element) }])) - let container = XMLKeyedEncodingContainer( - referencing: self, - codingPath: codingPath, - wrapping: storage.pushKeyedContainer(keyed) - ) - return KeyedEncodingContainer(container) } else { - preconditionFailure( - """ - Attempt to push new keyed encoding container when already previously encoded \ - at this path. - """ - ) + switch storage.lastContainer { + case let keyed as SharedBox: + let container = XMLKeyedEncodingContainer( + referencing: self, + codingPath: codingPath, + wrapping: keyed + ) + return KeyedEncodingContainer(container) + case let choice as SharedBox: + _ = storage.popContainer() + let keyed = KeyedBox(elements: .init([choice.withShared { ($0.key, $0.element) }])) + let container = XMLKeyedEncodingContainer( + referencing: self, + codingPath: codingPath, + wrapping: storage.pushKeyedContainer(keyed) + ) + return KeyedEncodingContainer(container) + default: + preconditionFailure( + """ + Attempt to push new keyed encoding container when already previously encoded \ + at this path. + """ + ) + } } } From fd6ec429b081555719fdc8f3d45f2a1f65902116 Mon Sep 17 00:00:00 2001 From: Ben Wetherfield Date: Sun, 24 Nov 2019 16:17:04 -0800 Subject: [PATCH 09/15] Add multiple choice element case --- .../Encoder/XMLEncoderImplementation.swift | 9 +++++++++ Tests/XMLCoderTests/IntOrString.swift | 4 +++- .../MixedChoiceAndNonChoiceTests.swift | 19 +++++++++++++++++++ Tests/XMLCoderTests/XCTestManifests.swift | 1 + 4 files changed, 32 insertions(+), 1 deletion(-) diff --git a/Sources/XMLCoder/Encoder/XMLEncoderImplementation.swift b/Sources/XMLCoder/Encoder/XMLEncoderImplementation.swift index 5089bf81..0e63e386 100644 --- a/Sources/XMLCoder/Encoder/XMLEncoderImplementation.swift +++ b/Sources/XMLCoder/Encoder/XMLEncoderImplementation.swift @@ -126,6 +126,15 @@ class XMLEncoderImplementation: Encoder { wrapping: keyed ) return KeyedEncodingContainer(container) + } else if let choice = storage.lastContainer as? SharedBox { + _ = storage.popContainer() + let keyed = KeyedBox(elements: .init([choice.withShared { ($0.key, $0.element) }])) + let container = XMLKeyedEncodingContainer( + referencing: self, + codingPath: codingPath, + wrapping: storage.pushKeyedContainer(keyed) + ) + return KeyedEncodingContainer(container) } else { preconditionFailure( """ diff --git a/Tests/XMLCoderTests/IntOrString.swift b/Tests/XMLCoderTests/IntOrString.swift index af90069c..2fba2adb 100644 --- a/Tests/XMLCoderTests/IntOrString.swift +++ b/Tests/XMLCoderTests/IntOrString.swift @@ -13,7 +13,7 @@ internal enum IntOrString: Equatable { } extension IntOrString: Codable { - enum CodingKeys: String, XMLChoiceCodingKey { + enum CodingKeys: String, CodingKey { case int case string } @@ -37,3 +37,5 @@ extension IntOrString: Codable { } } } + +extension IntOrString.CodingKeys: XMLChoiceCodingKey {} diff --git a/Tests/XMLCoderTests/MixedChoiceAndNonChoiceTests.swift b/Tests/XMLCoderTests/MixedChoiceAndNonChoiceTests.swift index fb640e1c..e1e16638 100644 --- a/Tests/XMLCoderTests/MixedChoiceAndNonChoiceTests.swift +++ b/Tests/XMLCoderTests/MixedChoiceAndNonChoiceTests.swift @@ -62,6 +62,18 @@ extension MixedEitherSide: Encodable { } } +private struct TwoChoiceElements { + let first: IntOrString + let second: IntOrString +} + +extension TwoChoiceElements: Encodable { + func encode(to encoder: Encoder) throws { + try first.encode(to: encoder) + try second.encode(to: encoder) + } +} + class MixedChoiceAndNonChoiceTests: XCTestCase { func testMixedChoiceFirstEncode() throws { let first = MixedIntOrStringFirst(intOrString: .int(4), otherValue: "other") @@ -85,4 +97,11 @@ class MixedChoiceAndNonChoiceTests: XCTestCase { """ XCTAssertEqual(String(data: flankedEncoded, encoding: .utf8), flankedExpectedXML) } + + func testTwoChoiceElementsEncode() throws { + let twoChoiceElements = TwoChoiceElements(first: .int(1), second: .string("one")) + let encoded = try XMLEncoder().encode(twoChoiceElements, withRootKey: "container") + let expectedXML = "1one" + XCTAssertEqual(String(data: encoded, encoding: .utf8), expectedXML) + } } diff --git a/Tests/XMLCoderTests/XCTestManifests.swift b/Tests/XMLCoderTests/XCTestManifests.swift index 28d53c65..075c0cbc 100644 --- a/Tests/XMLCoderTests/XCTestManifests.swift +++ b/Tests/XMLCoderTests/XCTestManifests.swift @@ -422,6 +422,7 @@ extension MixedChoiceAndNonChoiceTests { ("testMixedChoiceFirstEncode", testMixedChoiceFirstEncode), ("testMixedChoiceFlankedEncode", testMixedChoiceFlankedEncode), ("testMixedChoiceSecondEncode", testMixedChoiceSecondEncode), + ("testTwoChoiceElementsEncode", testTwoChoiceElementsEncode), ] } From 63f02cd70ad854e9dc6213d65ea4fbaf9db954d9 Mon Sep 17 00:00:00 2001 From: Ben Wetherfield Date: Mon, 25 Nov 2019 16:23:20 -0800 Subject: [PATCH 10/15] Add explicit types in KeyedBox initialization --- .../XMLCoder/Encoder/XMLEncoderImplementation.swift | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Sources/XMLCoder/Encoder/XMLEncoderImplementation.swift b/Sources/XMLCoder/Encoder/XMLEncoderImplementation.swift index 0e63e386..24f82555 100644 --- a/Sources/XMLCoder/Encoder/XMLEncoderImplementation.swift +++ b/Sources/XMLCoder/Encoder/XMLEncoderImplementation.swift @@ -92,7 +92,11 @@ class XMLEncoderImplementation: Encoder { return KeyedEncodingContainer(container) case let choice as SharedBox: _ = storage.popContainer() - let keyed = KeyedBox(elements: .init([choice.withShared { ($0.key, $0.element) }])) + let keyed = KeyedBox( + elements: KeyedBox.Elements([choice.withShared { (contents: inout ChoiceBox) -> (String, Box) in + (contents.key, contents.element) + }]) + ) let container = XMLKeyedEncodingContainer( referencing: self, codingPath: codingPath, @@ -128,7 +132,11 @@ class XMLEncoderImplementation: Encoder { return KeyedEncodingContainer(container) } else if let choice = storage.lastContainer as? SharedBox { _ = storage.popContainer() - let keyed = KeyedBox(elements: .init([choice.withShared { ($0.key, $0.element) }])) + let keyed = KeyedBox( + elements: KeyedBox.Elements([choice.withShared { (contents: inout ChoiceBox) -> (String, Box) in + (contents.key, contents.element) + }]) + ) let container = XMLKeyedEncodingContainer( referencing: self, codingPath: codingPath, From a847719735ca92bcf1f3b10a36a71024dec51254 Mon Sep 17 00:00:00 2001 From: Ben Wetherfield Date: Mon, 25 Nov 2019 18:19:38 -0800 Subject: [PATCH 11/15] Add explicitly empty parameter to KeyedBox initializer --- Sources/XMLCoder/Encoder/XMLEncoderImplementation.swift | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Sources/XMLCoder/Encoder/XMLEncoderImplementation.swift b/Sources/XMLCoder/Encoder/XMLEncoderImplementation.swift index 24f82555..36dac24a 100644 --- a/Sources/XMLCoder/Encoder/XMLEncoderImplementation.swift +++ b/Sources/XMLCoder/Encoder/XMLEncoderImplementation.swift @@ -95,7 +95,8 @@ class XMLEncoderImplementation: Encoder { let keyed = KeyedBox( elements: KeyedBox.Elements([choice.withShared { (contents: inout ChoiceBox) -> (String, Box) in (contents.key, contents.element) - }]) + }]), + attributes: [] ) let container = XMLKeyedEncodingContainer( referencing: self, @@ -135,7 +136,8 @@ class XMLEncoderImplementation: Encoder { let keyed = KeyedBox( elements: KeyedBox.Elements([choice.withShared { (contents: inout ChoiceBox) -> (String, Box) in (contents.key, contents.element) - }]) + }]), + attributes: [] ) let container = XMLKeyedEncodingContainer( referencing: self, From d27e7569b6973b859981d35c67b3adab19a5b83d Mon Sep 17 00:00:00 2001 From: Ben Wetherfield Date: Mon, 25 Nov 2019 18:46:03 -0800 Subject: [PATCH 12/15] Use more concise type inference --- Sources/XMLCoder/Encoder/XMLEncoderImplementation.swift | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/Sources/XMLCoder/Encoder/XMLEncoderImplementation.swift b/Sources/XMLCoder/Encoder/XMLEncoderImplementation.swift index 36dac24a..1ebf4549 100644 --- a/Sources/XMLCoder/Encoder/XMLEncoderImplementation.swift +++ b/Sources/XMLCoder/Encoder/XMLEncoderImplementation.swift @@ -93,9 +93,7 @@ class XMLEncoderImplementation: Encoder { case let choice as SharedBox: _ = storage.popContainer() let keyed = KeyedBox( - elements: KeyedBox.Elements([choice.withShared { (contents: inout ChoiceBox) -> (String, Box) in - (contents.key, contents.element) - }]), + elements: KeyedBox.Elements([choice.withShared { ($0.key, $0.element) }]), attributes: [] ) let container = XMLKeyedEncodingContainer( @@ -134,9 +132,7 @@ class XMLEncoderImplementation: Encoder { } else if let choice = storage.lastContainer as? SharedBox { _ = storage.popContainer() let keyed = KeyedBox( - elements: KeyedBox.Elements([choice.withShared { (contents: inout ChoiceBox) -> (String, Box) in - (contents.key, contents.element) - }]), + elements: KeyedBox.Elements([choice.withShared { ($0.key, $0.element) }]), attributes: [] ) let container = XMLKeyedEncodingContainer( From 900a530971b07fd5cfba2e0844c57810bf08cbdc Mon Sep 17 00:00:00 2001 From: Ben Wetherfield Date: Mon, 25 Nov 2019 18:51:15 -0800 Subject: [PATCH 13/15] Unify switch syntax --- .../Encoder/XMLEncoderImplementation.swift | 53 ++++++++++--------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/Sources/XMLCoder/Encoder/XMLEncoderImplementation.swift b/Sources/XMLCoder/Encoder/XMLEncoderImplementation.swift index 1ebf4549..83494ca9 100644 --- a/Sources/XMLCoder/Encoder/XMLEncoderImplementation.swift +++ b/Sources/XMLCoder/Encoder/XMLEncoderImplementation.swift @@ -122,32 +122,35 @@ class XMLEncoderImplementation: Encoder { wrapping: storage.pushChoiceContainer() ) return KeyedEncodingContainer(container) - } else if let keyed = storage.lastContainer as? SharedBox { - let container = XMLKeyedEncodingContainer( - referencing: self, - codingPath: codingPath, - wrapping: keyed - ) - return KeyedEncodingContainer(container) - } else if let choice = storage.lastContainer as? SharedBox { - _ = storage.popContainer() - let keyed = KeyedBox( - elements: KeyedBox.Elements([choice.withShared { ($0.key, $0.element) }]), - attributes: [] - ) - let container = XMLKeyedEncodingContainer( - referencing: self, - codingPath: codingPath, - wrapping: storage.pushKeyedContainer(keyed) - ) - return KeyedEncodingContainer(container) } else { - preconditionFailure( - """ - Attempt to push new keyed encoding container when already previously encoded \ - at this path. - """ - ) + switch storage.lastContainer { + case let keyed as SharedBox: + let container = XMLKeyedEncodingContainer( + referencing: self, + codingPath: codingPath, + wrapping: keyed + ) + return KeyedEncodingContainer(container) + case let choice as SharedBox: + _ = storage.popContainer() + let keyed = KeyedBox( + elements: KeyedBox.Elements([choice.withShared { ($0.key, $0.element) }]), + attributes: [] + ) + let container = XMLKeyedEncodingContainer( + referencing: self, + codingPath: codingPath, + wrapping: storage.pushKeyedContainer(keyed) + ) + return KeyedEncodingContainer(container) + default: + preconditionFailure( + """ + Attempt to push new keyed encoding container when already previously encoded \ + at this path. + """ + ) + } } } From f5c63ba3ec82d335c315d2fedd76554615b907f4 Mon Sep 17 00:00:00 2001 From: Ben Wetherfield Date: Tue, 26 Nov 2019 08:36:14 -0800 Subject: [PATCH 14/15] Cut down code duplication --- .../Encoder/XMLEncoderImplementation.swift | 134 +++++++----------- 1 file changed, 51 insertions(+), 83 deletions(-) diff --git a/Sources/XMLCoder/Encoder/XMLEncoderImplementation.swift b/Sources/XMLCoder/Encoder/XMLEncoderImplementation.swift index 83494ca9..8f1077e9 100644 --- a/Sources/XMLCoder/Encoder/XMLEncoderImplementation.swift +++ b/Sources/XMLCoder/Encoder/XMLEncoderImplementation.swift @@ -64,6 +64,9 @@ class XMLEncoderImplementation: Encoder { // MARK: - Encoder Methods public func container(keyedBy _: Key.Type) -> KeyedEncodingContainer { + guard canEncodeNewValue else { + return mergeWithExistingKeyedContainer(keyedBy: Key.self) + } if Key.self is XMLChoiceCodingKey.Type { return choiceContainer(keyedBy: Key.self) } else { @@ -71,89 +74,6 @@ class XMLEncoderImplementation: Encoder { } } - public func keyedContainer(keyedBy _: Key.Type) -> KeyedEncodingContainer { - // If an existing keyed container was already requested, return that one. - if canEncodeNewValue { - // We haven't yet pushed a container at this level; do so here. - let container = XMLKeyedEncodingContainer( - referencing: self, - codingPath: codingPath, - wrapping: storage.pushKeyedContainer() - ) - return KeyedEncodingContainer(container) - } else { - switch storage.lastContainer { - case let keyed as SharedBox: - let container = XMLKeyedEncodingContainer( - referencing: self, - codingPath: codingPath, - wrapping: keyed - ) - return KeyedEncodingContainer(container) - case let choice as SharedBox: - _ = storage.popContainer() - let keyed = KeyedBox( - elements: KeyedBox.Elements([choice.withShared { ($0.key, $0.element) }]), - attributes: [] - ) - let container = XMLKeyedEncodingContainer( - referencing: self, - codingPath: codingPath, - wrapping: storage.pushKeyedContainer(keyed) - ) - return KeyedEncodingContainer(container) - default: - preconditionFailure( - """ - Attempt to push new keyed encoding container when already previously encoded \ - at this path. - """ - ) - } - } - } - - public func choiceContainer(keyedBy _: Key.Type) -> KeyedEncodingContainer { - if canEncodeNewValue { - // We haven't yet pushed a container at this level; do so here. - let container = XMLChoiceEncodingContainer( - referencing: self, - codingPath: codingPath, - wrapping: storage.pushChoiceContainer() - ) - return KeyedEncodingContainer(container) - } else { - switch storage.lastContainer { - case let keyed as SharedBox: - let container = XMLKeyedEncodingContainer( - referencing: self, - codingPath: codingPath, - wrapping: keyed - ) - return KeyedEncodingContainer(container) - case let choice as SharedBox: - _ = storage.popContainer() - let keyed = KeyedBox( - elements: KeyedBox.Elements([choice.withShared { ($0.key, $0.element) }]), - attributes: [] - ) - let container = XMLKeyedEncodingContainer( - referencing: self, - codingPath: codingPath, - wrapping: storage.pushKeyedContainer(keyed) - ) - return KeyedEncodingContainer(container) - default: - preconditionFailure( - """ - Attempt to push new keyed encoding container when already previously encoded \ - at this path. - """ - ) - } - } - } - public func unkeyedContainer() -> UnkeyedEncodingContainer { // If an existing unkeyed container was already requested, return that one. let topContainer: SharedBox @@ -179,6 +99,54 @@ class XMLEncoderImplementation: Encoder { public func singleValueContainer() -> SingleValueEncodingContainer { return self } + + private func keyedContainer(keyedBy _: Key.Type) -> KeyedEncodingContainer { + let container = XMLKeyedEncodingContainer( + referencing: self, + codingPath: codingPath, + wrapping: storage.pushKeyedContainer() + ) + return KeyedEncodingContainer(container) + } + + private func choiceContainer(keyedBy _: Key.Type) -> KeyedEncodingContainer { + let container = XMLChoiceEncodingContainer( + referencing: self, + codingPath: codingPath, + wrapping: storage.pushChoiceContainer() + ) + return KeyedEncodingContainer(container) + } + + private func mergeWithExistingKeyedContainer(keyedBy _: Key.Type) -> KeyedEncodingContainer { + switch storage.lastContainer { + case let keyed as SharedBox: + let container = XMLKeyedEncodingContainer( + referencing: self, + codingPath: codingPath, + wrapping: keyed + ) + return KeyedEncodingContainer(container) + case let choice as SharedBox: + _ = storage.popContainer() + let keyed = KeyedBox( + elements: KeyedBox.Elements([choice.withShared { ($0.key, $0.element) }]), + attributes: [] + ) + let container = XMLKeyedEncodingContainer( + referencing: self, + codingPath: codingPath, + wrapping: storage.pushKeyedContainer(keyed) + ) + return KeyedEncodingContainer(container) + default: + preconditionFailure( + """ + No existing keyed encoding container to merge with. + """ + ) + } + } } extension XMLEncoderImplementation { From 0a9681eedd8d151adf9028d0b67582396d8c6e8f Mon Sep 17 00:00:00 2001 From: Ben Wetherfield Date: Tue, 26 Nov 2019 08:37:33 -0800 Subject: [PATCH 15/15] Fix formatting --- Sources/XMLCoder/Encoder/XMLEncoderImplementation.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/XMLCoder/Encoder/XMLEncoderImplementation.swift b/Sources/XMLCoder/Encoder/XMLEncoderImplementation.swift index 8f1077e9..e18b8fd4 100644 --- a/Sources/XMLCoder/Encoder/XMLEncoderImplementation.swift +++ b/Sources/XMLCoder/Encoder/XMLEncoderImplementation.swift @@ -99,7 +99,7 @@ class XMLEncoderImplementation: Encoder { public func singleValueContainer() -> SingleValueEncodingContainer { return self } - + private func keyedContainer(keyedBy _: Key.Type) -> KeyedEncodingContainer { let container = XMLKeyedEncodingContainer( referencing: self, @@ -117,7 +117,7 @@ class XMLEncoderImplementation: Encoder { ) return KeyedEncodingContainer(container) } - + private func mergeWithExistingKeyedContainer(keyedBy _: Key.Type) -> KeyedEncodingContainer { switch storage.lastContainer { case let keyed as SharedBox: