-
Notifications
You must be signed in to change notification settings - Fork 112
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Moved
_XML…EncodingContainer
into their own files, matching decoder (…
…#4) The `XMLEncoder.swift` is far too large as it is right now. I thus moved `_XMLUnkeyedEncodingContainer` and `_XMLKeyedEncodingContainer` into their own respective files. Note: The `Decoder` directory already does the same. * Moved `_XML(Unk|K)eyedEncodingContainer` into their own files, matching decoder * Fix `testUnkeyedContainer` in NodeEncodingStrategy * Add Int key to NodeEncodingStrategyTests * Increase XMLKeyedEncodingContainer test coverage * Cleanup integers in XMLKeyedEncodingContainer * Cleanup integers in XMLUnkeyedEncodingContainer
- Loading branch information
1 parent
0f07759
commit 7e13f4b
Showing
9 changed files
with
411 additions
and
556 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
196 changes: 196 additions & 0 deletions
196
Sources/XMLCoder/Encoder/XMLKeyedEncodingContainer.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,196 @@ | ||
// | ||
// XMLKeyedEncodingContainer.swift | ||
// XMLCoder | ||
// | ||
// Created by Vincent Esche on 11/20/18. | ||
// | ||
|
||
import Foundation | ||
|
||
internal struct _XMLKeyedEncodingContainer<K : CodingKey> : KeyedEncodingContainerProtocol { | ||
typealias Key = K | ||
|
||
// MARK: Properties | ||
|
||
/// A reference to the encoder we're writing to. | ||
private let encoder: _XMLEncoder | ||
|
||
/// A reference to the container we're writing to. | ||
private let container: NSMutableDictionary | ||
|
||
/// The path of coding keys taken to get to this point in encoding. | ||
private(set) public var codingPath: [CodingKey] | ||
|
||
// MARK: - Initialization | ||
|
||
/// Initializes `self` with the given references. | ||
internal init(referencing encoder: _XMLEncoder, codingPath: [CodingKey], wrapping container: NSMutableDictionary) { | ||
self.encoder = encoder | ||
self.codingPath = codingPath | ||
self.container = container | ||
} | ||
|
||
// MARK: - Coding Path Operations | ||
|
||
private func _converted(_ key: CodingKey) -> CodingKey { | ||
switch encoder.options.keyEncodingStrategy { | ||
case .useDefaultKeys: | ||
return key | ||
case .convertToSnakeCase: | ||
let newKeyString = XMLEncoder.KeyEncodingStrategy._convertToSnakeCase(key.stringValue) | ||
return _XMLKey(stringValue: newKeyString, intValue: key.intValue) | ||
case .custom(let converter): | ||
return converter(codingPath + [key]) | ||
} | ||
} | ||
|
||
// MARK: - KeyedEncodingContainerProtocol Methods | ||
|
||
public mutating func encodeNil(forKey key: Key) throws { | ||
self.container[_converted(key).stringValue] = NSNull() | ||
} | ||
|
||
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? NSMutableDictionary { | ||
attributesContainer[_converted(key).stringValue] = self.encoder.box(value) | ||
} else { | ||
let attributesContainer = NSMutableDictionary() | ||
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<T: FixedWidthInteger & Encodable>(_ 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? NSMutableDictionary { | ||
attributesContainer[_converted(key).stringValue] = try self.encoder.box(value) | ||
} else { | ||
let attributesContainer = NSMutableDictionary() | ||
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: 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.") | ||
} | ||
switch strategy(key) { | ||
case .attribute: | ||
if let attributesContainer = self.container[_XMLElement.attributesKey] as? NSMutableDictionary { | ||
attributesContainer[_converted(key).stringValue] = self.encoder.box(value) | ||
} else { | ||
let attributesContainer = NSMutableDictionary() | ||
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: 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() } | ||
self.container[_converted(key).stringValue] = try self.encoder.box(value) | ||
} | ||
|
||
public mutating func encode(_ value: Double, forKey key: Key) throws { | ||
// Since the double may be invalid and throw, the coding path needs to contain this key. | ||
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? NSMutableDictionary { | ||
attributesContainer[_converted(key).stringValue] = try self.encoder.box(value) | ||
} else { | ||
let attributesContainer = NSMutableDictionary() | ||
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<T : Encodable>(_ value: T, forKey key: Key) throws { | ||
guard let strategy = self.encoder.nodeEncodings.last else { | ||
preconditionFailure("Attempt to access node encoding strategy from empty stack.") | ||
} | ||
self.encoder.codingPath.append(key) | ||
let nodeEncodings = self.encoder.options.nodeEncodingStrategy.nodeEncodings( | ||
forType: T.self, | ||
with: self.encoder | ||
) | ||
self.encoder.nodeEncodings.append(nodeEncodings) | ||
defer { | ||
let _ = self.encoder.nodeEncodings.removeLast() | ||
self.encoder.codingPath.removeLast() | ||
} | ||
switch strategy(key) { | ||
case .attribute: | ||
if let attributesContainer = self.container[_XMLElement.attributesKey] as? NSMutableDictionary { | ||
attributesContainer[_converted(key).stringValue] = try self.encoder.box(value) | ||
} else { | ||
let attributesContainer = NSMutableDictionary() | ||
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 nestedContainer<NestedKey>(keyedBy keyType: NestedKey.Type, forKey key: Key) -> KeyedEncodingContainer<NestedKey> { | ||
let dictionary = NSMutableDictionary() | ||
self.container[_converted(key).stringValue] = dictionary | ||
|
||
self.codingPath.append(key) | ||
defer { self.codingPath.removeLast() } | ||
|
||
let container = _XMLKeyedEncodingContainer<NestedKey>(referencing: self.encoder, codingPath: self.codingPath, wrapping: dictionary) | ||
return KeyedEncodingContainer(container) | ||
} | ||
|
||
public mutating func nestedUnkeyedContainer(forKey key: Key) -> UnkeyedEncodingContainer { | ||
let array = NSMutableArray() | ||
self.container[_converted(key).stringValue] = array | ||
|
||
self.codingPath.append(key) | ||
defer { self.codingPath.removeLast() } | ||
return _XMLUnkeyedEncodingContainer(referencing: self.encoder, codingPath: self.codingPath, wrapping: array) | ||
} | ||
|
||
public mutating func superEncoder() -> Encoder { | ||
return _XMLReferencingEncoder(referencing: self.encoder, key: _XMLKey.super, convertedKey: _converted(_XMLKey.super), wrapping: self.container) | ||
} | ||
|
||
public mutating func superEncoder(forKey key: Key) -> Encoder { | ||
return _XMLReferencingEncoder(referencing: self.encoder, key: key, convertedKey: _converted(key), wrapping: self.container) | ||
} | ||
} |
90 changes: 90 additions & 0 deletions
90
Sources/XMLCoder/Encoder/XMLUnkeyedEncodingContainer.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
// | ||
// XMLUnkeyedEncodingContainer.swift | ||
// XMLCoder | ||
// | ||
// Created by Vincent Esche on 11/20/18. | ||
// | ||
|
||
import Foundation | ||
|
||
internal struct _XMLUnkeyedEncodingContainer : UnkeyedEncodingContainer { | ||
// MARK: Properties | ||
|
||
/// A reference to the encoder we're writing to. | ||
private let encoder: _XMLEncoder | ||
|
||
/// A reference to the container we're writing to. | ||
private let container: NSMutableArray | ||
|
||
/// The path of coding keys taken to get to this point in encoding. | ||
private(set) public var codingPath: [CodingKey] | ||
|
||
/// The number of elements encoded into the container. | ||
public var count: Int { | ||
return self.container.count | ||
} | ||
|
||
// MARK: - Initialization | ||
|
||
/// Initializes `self` with the given references. | ||
internal init(referencing encoder: _XMLEncoder, codingPath: [CodingKey], wrapping container: NSMutableArray) { | ||
self.encoder = encoder | ||
self.codingPath = codingPath | ||
self.container = container | ||
} | ||
|
||
// MARK: - UnkeyedEncodingContainer Methods | ||
|
||
public mutating func encodeNil() throws { self.container.add(NSNull()) } | ||
public mutating func encode(_ value: Bool) throws { self.container.add(self.encoder.box(value)) } | ||
|
||
public mutating func encode<T: FixedWidthInteger & Encodable>(_ value: T) throws { | ||
try self.container.add(self.encoder.box(value)) | ||
} | ||
|
||
public mutating func encode(_ value: String) throws { self.container.add(self.encoder.box(value)) } | ||
|
||
public mutating func encode(_ value: Float) throws { | ||
// Since the float 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.add(try self.encoder.box(value)) | ||
} | ||
|
||
public mutating func encode(_ value: Double) throws { | ||
// Since the double may be invalid and throw, the coding path needs to contain this key. | ||
self.encoder.codingPath.append(_XMLKey(index: self.count)) | ||
defer { self.encoder.codingPath.removeLast() } | ||
self.container.add(try self.encoder.box(value)) | ||
} | ||
|
||
public mutating func encode<T : Encodable>(_ value: T) throws { | ||
self.encoder.codingPath.append(_XMLKey(index: self.count)) | ||
defer { self.encoder.codingPath.removeLast() } | ||
self.container.add(try self.encoder.box(value)) | ||
} | ||
|
||
public mutating func nestedContainer<NestedKey>(keyedBy keyType: NestedKey.Type) -> KeyedEncodingContainer<NestedKey> { | ||
self.codingPath.append(_XMLKey(index: self.count)) | ||
defer { self.codingPath.removeLast() } | ||
|
||
let dictionary = NSMutableDictionary() | ||
self.container.add(dictionary) | ||
|
||
let container = _XMLKeyedEncodingContainer<NestedKey>(referencing: self.encoder, codingPath: self.codingPath, wrapping: dictionary) | ||
return KeyedEncodingContainer(container) | ||
} | ||
|
||
public mutating func nestedUnkeyedContainer() -> UnkeyedEncodingContainer { | ||
self.codingPath.append(_XMLKey(index: self.count)) | ||
defer { self.codingPath.removeLast() } | ||
|
||
let array = NSMutableArray() | ||
self.container.add(array) | ||
return _XMLUnkeyedEncodingContainer(referencing: self.encoder, codingPath: self.codingPath, wrapping: array) | ||
} | ||
|
||
public mutating func superEncoder() -> Encoder { | ||
return _XMLReferencingEncoder(referencing: self.encoder, at: self.container.count, wrapping: self.container) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.