Commit 479ba0f2 by Demid Merzlyakov

Add XMLCoder pod.

parent 6ea6fb52
...@@ -9,4 +9,5 @@ target '1Weather' do ...@@ -9,4 +9,5 @@ target '1Weather' do
pod 'SnapKit' pod 'SnapKit'
pod 'BezierKit' pod 'BezierKit'
pod 'Localize-Swift' pod 'Localize-Swift'
pod 'XMLCoder', '~> 0.12.0'
end end
...@@ -7,23 +7,27 @@ PODS: ...@@ -7,23 +7,27 @@ PODS:
- Localize-Swift/UIKit (3.2.0): - Localize-Swift/UIKit (3.2.0):
- Localize-Swift/LocalizeSwiftCore - Localize-Swift/LocalizeSwiftCore
- SnapKit (5.0.1) - SnapKit (5.0.1)
- XMLCoder (0.12.0)
DEPENDENCIES: DEPENDENCIES:
- BezierKit - BezierKit
- Localize-Swift - Localize-Swift
- SnapKit - SnapKit
- XMLCoder (~> 0.12.0)
SPEC REPOS: SPEC REPOS:
trunk: trunk:
- BezierKit - BezierKit
- Localize-Swift - Localize-Swift
- SnapKit - SnapKit
- XMLCoder
SPEC CHECKSUMS: SPEC CHECKSUMS:
BezierKit: 1828aca1675d68f0659c5353bc5b0d3399a3910c BezierKit: 1828aca1675d68f0659c5353bc5b0d3399a3910c
Localize-Swift: 6f4475136bdb0d7b2882ea3d4ea919d70142b232 Localize-Swift: 6f4475136bdb0d7b2882ea3d4ea919d70142b232
SnapKit: 97b92857e3df3a0c71833cce143274bf6ef8e5eb SnapKit: 97b92857e3df3a0c71833cce143274bf6ef8e5eb
XMLCoder: f884dfa894a6f8b7dce465e4f6c02963bf17e028
PODFILE CHECKSUM: 06893793de13524c28b9afdc6dca649b77af3601 PODFILE CHECKSUM: 1f2e35e8ddbf05711e7cbbc0504177213177b924
COCOAPODS: 1.10.1 COCOAPODS: 1.10.1
...@@ -7,23 +7,27 @@ PODS: ...@@ -7,23 +7,27 @@ PODS:
- Localize-Swift/UIKit (3.2.0): - Localize-Swift/UIKit (3.2.0):
- Localize-Swift/LocalizeSwiftCore - Localize-Swift/LocalizeSwiftCore
- SnapKit (5.0.1) - SnapKit (5.0.1)
- XMLCoder (0.12.0)
DEPENDENCIES: DEPENDENCIES:
- BezierKit - BezierKit
- Localize-Swift - Localize-Swift
- SnapKit - SnapKit
- XMLCoder (~> 0.12.0)
SPEC REPOS: SPEC REPOS:
trunk: trunk:
- BezierKit - BezierKit
- Localize-Swift - Localize-Swift
- SnapKit - SnapKit
- XMLCoder
SPEC CHECKSUMS: SPEC CHECKSUMS:
BezierKit: 1828aca1675d68f0659c5353bc5b0d3399a3910c BezierKit: 1828aca1675d68f0659c5353bc5b0d3399a3910c
Localize-Swift: 6f4475136bdb0d7b2882ea3d4ea919d70142b232 Localize-Swift: 6f4475136bdb0d7b2882ea3d4ea919d70142b232
SnapKit: 97b92857e3df3a0c71833cce143274bf6ef8e5eb SnapKit: 97b92857e3df3a0c71833cce143274bf6ef8e5eb
XMLCoder: f884dfa894a6f8b7dce465e4f6c02963bf17e028
PODFILE CHECKSUM: 06893793de13524c28b9afdc6dca649b77af3601 PODFILE CHECKSUM: 1f2e35e8ddbf05711e7cbbc0504177213177b924
COCOAPODS: 1.10.1 COCOAPODS: 1.10.1
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -70,4 +70,29 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ...@@ -70,4 +70,29 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. THE SOFTWARE.
## XMLCoder
MIT License
Copyright (c) 2018-2019 Shawn Moore and XMLCoder contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Generated by CocoaPods - https://cocoapods.org Generated by CocoaPods - https://cocoapods.org
...@@ -102,6 +102,37 @@ THE SOFTWARE. ...@@ -102,6 +102,37 @@ THE SOFTWARE.
</dict> </dict>
<dict> <dict>
<key>FooterText</key> <key>FooterText</key>
<string>MIT License
Copyright (c) 2018-2019 Shawn Moore and XMLCoder contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
</string>
<key>License</key>
<string>MIT</string>
<key>Title</key>
<string>XMLCoder</string>
<key>Type</key>
<string>PSGroupSpecifier</string>
</dict>
<dict>
<key>FooterText</key>
<string>Generated by CocoaPods - https://cocoapods.org</string> <string>Generated by CocoaPods - https://cocoapods.org</string>
<key>Title</key> <key>Title</key>
<string></string> <string></string>
......
${PODS_ROOT}/Target Support Files/Pods-1Weather/Pods-1Weather-frameworks.sh ${PODS_ROOT}/Target Support Files/Pods-1Weather/Pods-1Weather-frameworks.sh
${BUILT_PRODUCTS_DIR}/BezierKit/BezierKit.framework ${BUILT_PRODUCTS_DIR}/BezierKit/BezierKit.framework
${BUILT_PRODUCTS_DIR}/Localize-Swift/Localize_Swift.framework ${BUILT_PRODUCTS_DIR}/Localize-Swift/Localize_Swift.framework
${BUILT_PRODUCTS_DIR}/SnapKit/SnapKit.framework ${BUILT_PRODUCTS_DIR}/SnapKit/SnapKit.framework
\ No newline at end of file ${BUILT_PRODUCTS_DIR}/XMLCoder/XMLCoder.framework
\ No newline at end of file
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/BezierKit.framework ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/BezierKit.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Localize_Swift.framework ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Localize_Swift.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SnapKit.framework ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SnapKit.framework
\ No newline at end of file ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/XMLCoder.framework
\ No newline at end of file
${PODS_ROOT}/Target Support Files/Pods-1Weather/Pods-1Weather-frameworks.sh ${PODS_ROOT}/Target Support Files/Pods-1Weather/Pods-1Weather-frameworks.sh
${BUILT_PRODUCTS_DIR}/BezierKit/BezierKit.framework ${BUILT_PRODUCTS_DIR}/BezierKit/BezierKit.framework
${BUILT_PRODUCTS_DIR}/Localize-Swift/Localize_Swift.framework ${BUILT_PRODUCTS_DIR}/Localize-Swift/Localize_Swift.framework
${BUILT_PRODUCTS_DIR}/SnapKit/SnapKit.framework ${BUILT_PRODUCTS_DIR}/SnapKit/SnapKit.framework
\ No newline at end of file ${BUILT_PRODUCTS_DIR}/XMLCoder/XMLCoder.framework
\ No newline at end of file
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/BezierKit.framework ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/BezierKit.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Localize_Swift.framework ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Localize_Swift.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SnapKit.framework ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SnapKit.framework
\ No newline at end of file ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/XMLCoder.framework
\ No newline at end of file
...@@ -178,11 +178,13 @@ if [[ "$CONFIGURATION" == "Debug" ]]; then ...@@ -178,11 +178,13 @@ if [[ "$CONFIGURATION" == "Debug" ]]; then
install_framework "${BUILT_PRODUCTS_DIR}/BezierKit/BezierKit.framework" install_framework "${BUILT_PRODUCTS_DIR}/BezierKit/BezierKit.framework"
install_framework "${BUILT_PRODUCTS_DIR}/Localize-Swift/Localize_Swift.framework" install_framework "${BUILT_PRODUCTS_DIR}/Localize-Swift/Localize_Swift.framework"
install_framework "${BUILT_PRODUCTS_DIR}/SnapKit/SnapKit.framework" install_framework "${BUILT_PRODUCTS_DIR}/SnapKit/SnapKit.framework"
install_framework "${BUILT_PRODUCTS_DIR}/XMLCoder/XMLCoder.framework"
fi fi
if [[ "$CONFIGURATION" == "Release" ]]; then if [[ "$CONFIGURATION" == "Release" ]]; then
install_framework "${BUILT_PRODUCTS_DIR}/BezierKit/BezierKit.framework" install_framework "${BUILT_PRODUCTS_DIR}/BezierKit/BezierKit.framework"
install_framework "${BUILT_PRODUCTS_DIR}/Localize-Swift/Localize_Swift.framework" install_framework "${BUILT_PRODUCTS_DIR}/Localize-Swift/Localize_Swift.framework"
install_framework "${BUILT_PRODUCTS_DIR}/SnapKit/SnapKit.framework" install_framework "${BUILT_PRODUCTS_DIR}/SnapKit/SnapKit.framework"
install_framework "${BUILT_PRODUCTS_DIR}/XMLCoder/XMLCoder.framework"
fi fi
if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
wait wait
......
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/BezierKit" "${PODS_CONFIGURATION_BUILD_DIR}/Localize-Swift" "${PODS_CONFIGURATION_BUILD_DIR}/SnapKit" FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/BezierKit" "${PODS_CONFIGURATION_BUILD_DIR}/Localize-Swift" "${PODS_CONFIGURATION_BUILD_DIR}/SnapKit" "${PODS_CONFIGURATION_BUILD_DIR}/XMLCoder"
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/BezierKit/BezierKit.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Localize-Swift/Localize_Swift.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SnapKit/SnapKit.framework/Headers" HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/BezierKit/BezierKit.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Localize-Swift/Localize_Swift.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SnapKit/SnapKit.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/XMLCoder/XMLCoder.framework/Headers"
LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
OTHER_LDFLAGS = $(inherited) -framework "BezierKit" -framework "CoreGraphics" -framework "Localize_Swift" -framework "SnapKit" -framework "UIKit" OTHER_LDFLAGS = $(inherited) -framework "BezierKit" -framework "CoreGraphics" -framework "Localize_Swift" -framework "SnapKit" -framework "UIKit" -framework "XMLCoder"
OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
PODS_BUILD_DIR = ${BUILD_DIR} PODS_BUILD_DIR = ${BUILD_DIR}
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
......
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/BezierKit" "${PODS_CONFIGURATION_BUILD_DIR}/Localize-Swift" "${PODS_CONFIGURATION_BUILD_DIR}/SnapKit" FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/BezierKit" "${PODS_CONFIGURATION_BUILD_DIR}/Localize-Swift" "${PODS_CONFIGURATION_BUILD_DIR}/SnapKit" "${PODS_CONFIGURATION_BUILD_DIR}/XMLCoder"
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/BezierKit/BezierKit.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Localize-Swift/Localize_Swift.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SnapKit/SnapKit.framework/Headers" HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/BezierKit/BezierKit.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Localize-Swift/Localize_Swift.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SnapKit/SnapKit.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/XMLCoder/XMLCoder.framework/Headers"
LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
OTHER_LDFLAGS = $(inherited) -framework "BezierKit" -framework "CoreGraphics" -framework "Localize_Swift" -framework "SnapKit" -framework "UIKit" OTHER_LDFLAGS = $(inherited) -framework "BezierKit" -framework "CoreGraphics" -framework "Localize_Swift" -framework "SnapKit" -framework "UIKit" -framework "XMLCoder"
OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
PODS_BUILD_DIR = ${BUILD_DIR} PODS_BUILD_DIR = ${BUILD_DIR}
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
......
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>0.12.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>${CURRENT_PROJECT_VERSION}</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>
#import <Foundation/Foundation.h>
@interface PodsDummy_XMLCoder : NSObject
@end
@implementation PodsDummy_XMLCoder
@end
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#else
#ifndef FOUNDATION_EXPORT
#if defined(__cplusplus)
#define FOUNDATION_EXPORT extern "C"
#else
#define FOUNDATION_EXPORT extern
#endif
#endif
#endif
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#else
#ifndef FOUNDATION_EXPORT
#if defined(__cplusplus)
#define FOUNDATION_EXPORT extern "C"
#else
#define FOUNDATION_EXPORT extern
#endif
#endif
#endif
FOUNDATION_EXPORT double XMLCoderVersionNumber;
FOUNDATION_EXPORT const unsigned char XMLCoderVersionString[];
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/XMLCoder
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
PODS_BUILD_DIR = ${BUILD_DIR}
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
PODS_ROOT = ${SRCROOT}
PODS_TARGET_SRCROOT = ${PODS_ROOT}/XMLCoder
PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
SKIP_INSTALL = YES
USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
framework module XMLCoder {
umbrella header "XMLCoder-umbrella.h"
export *
module * { export * }
}
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/XMLCoder
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
PODS_BUILD_DIR = ${BUILD_DIR}
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
PODS_ROOT = ${SRCROOT}
PODS_TARGET_SRCROOT = ${PODS_ROOT}/XMLCoder
PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
SKIP_INSTALL = YES
USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
MIT License
Copyright (c) 2018-2019 Shawn Moore and XMLCoder contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
// Copyright (c) 2018-2020 XMLCoder contributors
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
//
// Created by Vincent Esche on 12/17/18.
//
struct BoolBox: Equatable {
typealias Unboxed = Bool
let unboxed: Unboxed
init(_ unboxed: Unboxed) {
self.unboxed = unboxed
}
init?(xmlString: String) {
switch xmlString.lowercased() {
case "false", "0", "n", "no": self.init(false)
case "true", "1", "y", "yes": self.init(true)
case _: return nil
}
}
}
extension BoolBox: Box {
var isNull: Bool {
return false
}
/// # Lexical representation
/// Boolean has a lexical representation consisting of the following
/// legal literals {`true`, `false`, `1`, `0`}.
///
/// # Canonical representation
/// The canonical representation for boolean is the set of literals {`true`, `false`}.
///
/// ---
///
/// [Schema definition](https://www.w3.org/TR/xmlschema-2/#boolean)
var xmlString: String? {
return (unboxed) ? "true" : "false"
}
}
extension BoolBox: SimpleBox {}
extension BoolBox: CustomStringConvertible {
var description: String {
return unboxed.description
}
}
// Copyright (c) 2018-2020 XMLCoder contributors
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
//
// Created by Vincent Esche on 12/17/18.
//
protocol Box {
var isNull: Bool { get }
var xmlString: String? { get }
}
/// A box that only describes a single atomic value.
protocol SimpleBox: Box {
// A simple tagging protocol, for now.
}
protocol TypeErasedSharedBoxProtocol {
func typeErasedUnbox() -> Box
}
protocol SharedBoxProtocol: TypeErasedSharedBoxProtocol {
associatedtype B: Box
func unbox() -> B
}
extension SharedBoxProtocol {
func typeErasedUnbox() -> Box {
return unbox()
}
}
// Copyright (c) 2019-2020 XMLCoder contributors
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
//
// Created by James Bean on 7/18/19.
//
/// A `Box` which represents an element which is known to contain an XML choice element.
struct ChoiceBox {
var key: String = ""
var element: Box = NullBox()
}
extension ChoiceBox: Box {
var isNull: Bool {
return false
}
var xmlString: String? {
return nil
}
}
extension ChoiceBox: SimpleBox {}
extension ChoiceBox {
init?(_ keyedBox: KeyedBox) {
guard
let firstKey = keyedBox.elements.keys.first,
let firstElement = keyedBox.elements[firstKey].first
else {
return nil
}
self.init(key: firstKey, element: firstElement)
}
init(_ singleKeyedBox: SingleKeyedBox) {
self.init(key: singleKeyedBox.key, element: singleKeyedBox.element)
}
}
// Copyright (c) 2018-2020 XMLCoder contributors
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
//
// Created by Vincent Esche on 12/19/18.
//
import Foundation
struct DataBox: Equatable {
enum Format: Equatable {
case base64
}
typealias Unboxed = Data
let unboxed: Unboxed
let format: Format
init(_ unboxed: Unboxed, format: Format) {
self.unboxed = unboxed
self.format = format
}
init?(base64 string: String) {
guard let data = Data(base64Encoded: string) else {
return nil
}
self.init(data, format: .base64)
}
func xmlString(format: Format) -> String {
switch format {
case .base64:
return unboxed.base64EncodedString()
}
}
}
extension DataBox: Box {
var isNull: Bool {
return false
}
var xmlString: String? {
return xmlString(format: format)
}
}
extension DataBox: SimpleBox {}
extension DataBox: CustomStringConvertible {
var description: String {
return unboxed.description
}
}
// Copyright (c) 2018-2020 XMLCoder contributors
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
//
// Created by Vincent Esche on 12/18/18.
//
import Foundation
struct DateBox: Equatable {
enum Format: Equatable {
case secondsSince1970
case millisecondsSince1970
case iso8601
case formatter(DateFormatter)
}
typealias Unboxed = Date
let unboxed: Unboxed
let format: Format
init(_ unboxed: Unboxed, format: Format) {
self.unboxed = unboxed
self.format = format
}
init?(secondsSince1970 string: String) {
guard let seconds = TimeInterval(string) else {
return nil
}
let unboxed = Date(timeIntervalSince1970: seconds)
self.init(unboxed, format: .secondsSince1970)
}
init?(millisecondsSince1970 string: String) {
guard let milliseconds = TimeInterval(string) else {
return nil
}
let unboxed = Date(timeIntervalSince1970: milliseconds / 1000.0)
self.init(unboxed, format: .millisecondsSince1970)
}
init?(iso8601 string: String) {
if #available(macOS 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *) {
guard let unboxed = _iso8601Formatter.date(from: string) else {
return nil
}
self.init(unboxed, format: .iso8601)
} else {
fatalError("ISO8601DateFormatter is unavailable on this platform.")
}
}
init?(xmlString: String, formatter: DateFormatter) {
guard let date = formatter.date(from: xmlString) else {
return nil
}
self.init(date, format: .formatter(formatter))
}
func xmlString(format: Format) -> String {
switch format {
case .secondsSince1970:
let seconds = unboxed.timeIntervalSince1970
return seconds.description
case .millisecondsSince1970:
let milliseconds = unboxed.timeIntervalSince1970 * 1000.0
return milliseconds.description
case .iso8601:
if #available(macOS 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *) {
return _iso8601Formatter.string(from: self.unboxed)
} else {
fatalError("ISO8601DateFormatter is unavailable on this platform.")
}
case let .formatter(formatter):
return formatter.string(from: unboxed)
}
}
}
extension DateBox: Box {
var isNull: Bool {
return false
}
var xmlString: String? {
return xmlString(format: format)
}
}
extension DateBox: SimpleBox {}
extension DateBox: CustomStringConvertible {
var description: String {
return unboxed.description
}
}
// Copyright (c) 2018-2020 XMLCoder contributors
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
//
// Created by Vincent Esche on 12/17/18.
//
import Foundation
struct DecimalBox: Equatable {
typealias Unboxed = Decimal
let unboxed: Unboxed
init(_ unboxed: Unboxed) {
self.unboxed = unboxed
}
init?(xmlString: String) {
guard let unboxed = Unboxed(string: xmlString) else {
return nil
}
self.init(unboxed)
}
}
extension DecimalBox: Box {
var isNull: Bool {
return false
}
/// # Lexical representation
/// Decimal has a lexical representation consisting of a finite-length sequence of
/// decimal digits separated by a period as a decimal indicator.
/// An optional leading sign is allowed. If the sign is omitted, `"+"` is assumed.
/// Leading and trailing zeroes are optional. If the fractional part is zero,
/// the period and following zero(es) can be omitted.
/// For example: `-1.23`, `12678967.543233`, `+100000.00`, `210`.
///
/// # Canonical representation
/// The canonical representation for decimal is defined by prohibiting certain
/// options from the Lexical representation. Specifically, the preceding optional
/// `"+"` sign is prohibited. The decimal point is required. Leading and trailing
/// zeroes are prohibited subject to the following: there must be at least one
/// digit to the right and to the left of the decimal point which may be a zero.
///
/// ---
///
/// [Schema definition](https://www.w3.org/TR/xmlschema-2/#decimal)
var xmlString: String? {
return "\(unboxed)"
}
}
extension DecimalBox: SimpleBox {}
extension DecimalBox: CustomStringConvertible {
var description: String {
return unboxed.description
}
}
// Copyright (c) 2019-2020 XMLCoder contributors
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
//
// Created by Max Desiatov on 05/10/2019.
//
struct DoubleBox: Equatable, ValueBox {
typealias Unboxed = Double
let unboxed: Unboxed
init(_ value: Unboxed) {
unboxed = value
}
init?(xmlString: String) {
guard let unboxed = Double(xmlString) else { return nil }
self.init(unboxed)
}
}
extension DoubleBox: Box {
var isNull: Bool {
return false
}
var xmlString: String? {
guard !unboxed.isNaN else {
return "NaN"
}
guard !unboxed.isInfinite else {
return (unboxed > 0.0) ? "INF" : "-INF"
}
return unboxed.description
}
}
extension DoubleBox: SimpleBox {}
extension DoubleBox: CustomStringConvertible {
var description: String {
return unboxed.description
}
}
// Copyright (c) 2018-2020 XMLCoder contributors
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
//
// Created by Vincent Esche on 12/17/18.
//
struct FloatBox: Equatable, ValueBox {
typealias Unboxed = Float
let unboxed: Unboxed
init<Float: BinaryFloatingPoint>(_ unboxed: Float) {
self.unboxed = Unboxed(unboxed)
}
init?(xmlString: String) {
guard let unboxed = Unboxed(xmlString) else {
return nil
}
self.init(unboxed)
}
}
extension FloatBox: Box {
var isNull: Bool {
return false
}
/// # 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.
/// The mantissa **must** be a decimal number. The representations for exponent and mantissa **must**
/// follow the lexical rules for integer and decimal. If the `"E"` or `"e"` and the following
/// exponent are omitted, an exponent value of `0` is assumed.
///
/// The special values positive and negative infinity and not-a-number have lexical
/// representations `INF`, `-INF` and `NaN`, respectively. Lexical representations for zero
/// may take a positive or negative sign.
///
/// For example, `-1E4`, `1267.43233E12`, `12.78e-2`, `12` , `-0`, `0` and `INF` are all
/// legal literals for float.
///
/// # Canonical representation
/// The canonical representation for float is defined by prohibiting certain options from the
/// Lexical representation. Specifically, the exponent must be indicated by `"E"`.
/// Leading zeroes and the preceding optional `"+"` sign are prohibited in the exponent.
/// If the exponent is zero, it must be indicated by `"E0"`. For the mantissa, the preceding
/// optional `"+"` sign is prohibited and the decimal point is required. Leading and trailing
/// zeroes are prohibited subject to the following: number representations must be normalized
/// such that there is a single digit which is non-zero to the left of the decimal point and
/// at least a single digit to the right of the decimal point unless the value being represented
/// is zero. The canonical representation for zero is `0.0E0`.
///
/// ---
///
/// [Schema definition](https://www.w3.org/TR/xmlschema-2/#float)
var xmlString: String? {
guard !unboxed.isNaN else {
return "NaN"
}
guard !unboxed.isInfinite else {
return (unboxed > 0.0) ? "INF" : "-INF"
}
return unboxed.description
}
}
extension FloatBox: SimpleBox {}
extension FloatBox: CustomStringConvertible {
var description: String {
return unboxed.description
}
}
// Copyright (c) 2018-2020 XMLCoder contributors
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
//
// Created by Vincent Esche on 12/17/18.
//
struct IntBox: Equatable {
typealias Unboxed = Int64
let unboxed: Unboxed
init<Integer: SignedInteger>(_ unboxed: Integer) {
self.unboxed = Unboxed(unboxed)
}
init?(xmlString: String) {
guard let unboxed = Unboxed(xmlString) else {
return nil
}
self.init(unboxed)
}
func unbox<Integer: BinaryInteger>() -> Integer? {
return Integer(exactly: unboxed)
}
}
extension IntBox: Box {
var isNull: Bool {
return false
}
/// # 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.
/// For example: `-1`, `0`, `12678967543233`, `+100000`.
///
/// # Canonical representation
/// The canonical representation for integer is defined by prohibiting certain
/// options from the Lexical representation. Specifically, the preceding optional
/// `"+"` sign is prohibited and leading zeroes are prohibited.
///
/// ---
///
/// [Schema definition](https://www.w3.org/TR/xmlschema-2/#integer)
var xmlString: String? {
return unboxed.description
}
}
extension IntBox: SimpleBox {}
extension IntBox: CustomStringConvertible {
var description: String {
return unboxed.description
}
}
// Copyright (c) 2018-2020 XMLCoder contributors
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
//
// Created by Vincent Esche on 11/19/18.
//
struct KeyedBox {
typealias Key = String
typealias Attribute = SimpleBox
typealias Element = Box
typealias Attributes = KeyedStorage<Key, Attribute>
typealias Elements = KeyedStorage<Key, Element>
var elements = Elements()
var attributes = Attributes()
var unboxed: (elements: Elements, attributes: Attributes) {
return (
elements: elements,
attributes: attributes
)
}
var value: SimpleBox? {
return elements.values.first as? SimpleBox
}
}
extension KeyedBox {
init<E, A>(elements: E, attributes: A)
where E: Sequence, E.Element == (Key, Element),
A: Sequence, A.Element == (Key, Attribute)
{
let elements = Elements(elements)
let attributes = Attributes(attributes)
self.init(elements: elements, attributes: attributes)
}
}
extension KeyedBox: Box {
var isNull: Bool {
return false
}
var xmlString: String? {
return nil
}
}
extension KeyedBox: CustomStringConvertible {
var description: String {
return "{attributes: \(attributes), elements: \(elements)}"
}
}
// Copyright (c) 2018-2020 XMLCoder contributors
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
//
// Created by Vincent Esche on 12/17/18.
//
struct NullBox {}
extension NullBox: Box {
var isNull: Bool {
return true
}
var xmlString: String? {
return nil
}
}
extension NullBox: SimpleBox {}
extension NullBox: Equatable {
static func ==(_: NullBox, _: NullBox) -> Bool {
return true
}
}
extension NullBox: CustomStringConvertible {
var description: String {
return "null"
}
}
// Copyright (c) 2018-2020 XMLCoder contributors
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
//
// Created by Vincent Esche on 12/22/18.
//
class SharedBox<Unboxed: Box> {
private(set) var unboxed: Unboxed
init(_ wrapped: Unboxed) {
unboxed = wrapped
}
func withShared<T>(_ body: (inout Unboxed) throws -> T) rethrows -> T {
return try body(&unboxed)
}
}
extension SharedBox: Box {
var isNull: Bool {
return unboxed.isNull
}
var xmlString: String? {
return unboxed.xmlString
}
}
extension SharedBox: SharedBoxProtocol {
func unbox() -> Unboxed {
return unboxed
}
}
// Copyright (c) 2019-2020 XMLCoder contributors
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
//
// Created by James Bean on 7/15/19.
//
/// A `Box` which contains a single `key` and `element` pair. This is useful for disambiguating elements which could either represent
/// an element nested in a keyed or unkeyed container, or an choice between multiple known-typed values (implemented in Swift using
/// enums with associated values).
struct SingleKeyedBox: SimpleBox {
var key: String
var element: Box
}
extension SingleKeyedBox: Box {
var isNull: Bool {
return false
}
var xmlString: String? {
return nil
}
}
// Copyright (c) 2018-2020 XMLCoder contributors
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
//
// Created by Vincent Esche on 12/17/18.
//
struct StringBox: Equatable {
typealias Unboxed = String
let unboxed: Unboxed
init(_ unboxed: Unboxed) {
self.unboxed = unboxed
}
init(xmlString: Unboxed) {
self.init(xmlString)
}
}
extension StringBox: Box {
var isNull: Bool {
return false
}
var xmlString: String? {
return unboxed.description
}
}
extension StringBox: SimpleBox {}
extension StringBox: CustomStringConvertible {
var description: String {
return unboxed.description
}
}
// Copyright (c) 2018-2020 XMLCoder contributors
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
//
// Created by Vincent Esche on 12/17/18.
//
struct UIntBox: Equatable {
typealias Unboxed = UInt64
let unboxed: Unboxed
init<Integer: UnsignedInteger>(_ unboxed: Integer) {
self.unboxed = Unboxed(unboxed)
}
init?(xmlString: String) {
guard let unboxed = Unboxed(xmlString) else {
return nil
}
self.init(unboxed)
}
func unbox<Integer: BinaryInteger>() -> Integer? {
return Integer(exactly: unboxed)
}
}
extension UIntBox: Box {
var isNull: Bool {
return false
}
/// # Lexical representation
/// Unsigned integer has a lexical representation consisting of an optional
/// sign followed by a finite-length sequence of decimal digits.
/// If the sign is omitted, the positive sign (`"+"`) is assumed.
/// If the sign is present, it must be `"+"` except for lexical forms denoting zero,
/// which may be preceded by a positive (`"+"`) or a negative (`"-"`) sign.
/// For example: `1`, `0`, `12678967543233`, `+100000`.
///
/// # Canonical representation
/// The canonical representation for nonNegativeInteger is defined by prohibiting
/// certain options from the Lexical representation. Specifically,
/// the the optional `"+"` sign is prohibited and leading zeroes are prohibited.
///
/// ---
///
/// [Schema definition](https://www.w3.org/TR/xmlschema-2/#nonNegativeInteger)
var xmlString: String? {
return unboxed.description
}
}
extension UIntBox: SimpleBox {}
extension UIntBox: CustomStringConvertible {
var description: String {
return unboxed.description
}
}
// Copyright (c) 2018-2020 XMLCoder contributors
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
//
// Created by Vincent Esche on 12/21/18.
//
import Foundation
struct URLBox: Equatable {
typealias Unboxed = URL
let unboxed: Unboxed
init(_ unboxed: Unboxed) {
self.unboxed = unboxed
}
init?(xmlString: String) {
guard let unboxed = Unboxed(string: xmlString) else {
return nil
}
self.init(unboxed)
}
}
extension URLBox: Box {
var isNull: Bool {
return false
}
var xmlString: String? {
return unboxed.absoluteString
}
}
extension URLBox: SimpleBox {}
extension URLBox: CustomStringConvertible {
var description: String {
return unboxed.description
}
}
// Copyright (c) 2018-2020 XMLCoder contributors
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
//
// Created by Vincent Esche on 11/20/18.
//
typealias UnkeyedBox = [Box]
extension Array: Box {
var isNull: Bool {
return false
}
var xmlString: String? {
return nil
}
}
// Copyright (c) 2019-2020 XMLCoder contributors
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
//
// Created by Max Desiatov on 05/10/2019.
//
protocol ValueBox: SimpleBox {
associatedtype Unboxed
init(_ value: Unboxed)
}
// Copyright (c) 2017-2020 Shawn Moore and XMLCoder contributors
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
//
// Created by Shawn Moore on 11/21/17.
//
import Foundation
/// Shared ISO8601 Date Formatter
/// NOTE: This value is implicitly lazy and _must_ be lazy. We're compiled
/// against the latest SDK (w/ ISO8601DateFormatter), but linked against
/// whichever Foundation the user has. ISO8601DateFormatter might not exist, so
/// we better not hit this code path on an older OS.
@available(macOS 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *)
var _iso8601Formatter: ISO8601DateFormatter = {
let formatter = ISO8601DateFormatter()
formatter.formatOptions = .withInternetDateTime
return formatter
}()
// Copyright (c) 2019-2020 XMLCoder contributors
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
//
// Created by Max Desiatov on 07/04/2019.
//
struct KeyedStorage<Key: Hashable & Comparable, Value> {
typealias Buffer = [(Key, Value)]
typealias KeyMap = [Key: [Int]]
fileprivate var keyMap = KeyMap()
fileprivate var buffer = Buffer()
var isEmpty: Bool {
return buffer.isEmpty
}
var count: Int {
return buffer.count
}
var keys: [Key] {
return buffer.map { $0.0 }
}
var values: [Value] {
return buffer.map { $0.1 }
}
init<S>(_ sequence: S) where S: Sequence, S.Element == (Key, Value) {
buffer = Buffer()
keyMap = KeyMap()
sequence.forEach { key, value in append(value, at: key) }
}
subscript(key: Key) -> [Value] {
return keyMap[key]?.map { buffer[$0].1 } ?? []
}
mutating func append(_ value: Value, at key: Key) {
let i = buffer.count
buffer.append((key, value))
if keyMap[key] != nil {
keyMap[key]?.append(i)
} else {
keyMap[key] = [i]
}
}
func map<T>(_ transform: (Key, Value) throws -> T) rethrows -> [T] {
return try buffer.map(transform)
}
func compactMap<T>(
_ transform: ((Key, Value)) throws -> T?
) rethrows -> [T] {
return try buffer.compactMap(transform)
}
init() {}
}
extension KeyedStorage: Sequence {
func makeIterator() -> Buffer.Iterator {
return buffer.makeIterator()
}
}
extension KeyedStorage: CustomStringConvertible {
var description: String {
let result = buffer.map { "\"\($0)\": \($1)" }.joined(separator: ", ")
return "[\(result)]"
}
}
extension KeyedStorage where Key == String, Value == Box {
func merge(element: XMLCoderElement) -> KeyedStorage<String, Box> {
var result = self
let hasElements = !element.elements.isEmpty
let hasAttributes = !element.attributes.isEmpty
let hasText = element.stringValue != nil
if hasElements || hasAttributes {
result.append(element.transformToBoxTree(), at: element.key)
} else if hasText {
result.append(element.transformToBoxTree(), at: element.key)
} else {
result.append(SingleKeyedBox(key: element.key, element: NullBox()), at: element.key)
}
return result
}
}
// Copyright (c) 2018-2020 XMLCoder contributors
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
//
// Created by Max Desiatov on 30/12/2018.
//
/// Type-erased protocol helper for a metatype check in generic `decode`
/// overload.
protocol AnySequence {
init()
}
extension Array: AnySequence {}
extension Dictionary: AnySequence {}
/// Type-erased protocol helper for a metatype check in generic `decode`
/// overload.
protocol AnyOptional {
init()
}
extension Optional: AnyOptional {
init() {
self = nil
}
}
// Copyright (c) 2018-2020 XMLCoder contributors
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
//
// Created by Vincent Esche on 12/18/18.
//
import Foundation
extension StringProtocol where Self.Index == String.Index {
func escape(_ characterSet: [(character: String, escapedCharacter: String)]) -> String {
var string = String(self)
for set in characterSet {
string = string.replacingOccurrences(of: set.character, with: set.escapedCharacter, options: .literal)
}
return string
}
}
extension StringProtocol {
func capitalizingFirstLetter() -> Self {
guard !isEmpty else {
return self
}
return Self(prefix(1).uppercased() + dropFirst())!
}
mutating func capitalizeFirstLetter() {
self = capitalizingFirstLetter()
}
func lowercasingFirstLetter() -> Self {
// avoid lowercasing single letters (I), or capitalized multiples (AThing ! to aThing, leave as AThing)
guard count > 1, !(String(prefix(2)) == prefix(2).lowercased()) else {
return self
}
return Self(prefix(1).lowercased() + dropFirst())!
}
mutating func lowercaseFirstLetter() {
self = lowercasingFirstLetter()
}
}
// Copyright (c) 2019-2020 XMLCoder contributors
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
//
// Created by Benjamin Wetherfield on 7/17/19.
//
/// An empty marker protocol that can be used in place of `CodingKey`. It must be used when
/// attempting to encode and decode union-type–like enums with associated values to and from `XML`
/// choice elements.
///
/// - Important: In order for your `XML`-destined `Codable` type to be encoded and/or decoded
/// properly, you must conform your custom `CodingKey` type additionally to `XMLChoiceCodingKey`.
///
/// For example, say you have defined a type which can hold _either_ an `Int` _or_ a `String`:
///
/// enum IntOrString {
/// case int(Int)
/// case string(String)
/// }
///
/// Implementing the requirements for the `Codable` protocol like this:
///
/// 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))
/// }
/// }
/// }
///
/// Retroactively conform the `CodingKeys` enum to `XMLChoiceCodingKey` when targeting `XML` as your
/// encoded format.
///
/// extension IntOrString.CodingKeys: XMLChoiceCodingKey {}
///
/// - Note: The `XMLChoiceCodingKey` marker protocol allows the `XMLEncoder` / `XMLDecoder` to
/// resolve ambiguities particular to the `XML` format between nested unkeyed container elements and
/// choice elements.
public protocol XMLChoiceCodingKey: CodingKey {}
// Copyright (c) 2018-2020 XMLCoder contributors
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
//
// Created by Vincent Esche on 12/18/18.
//
import Foundation
public struct XMLHeader {
/// The XML standard that the produced document conforms to.
public let version: Double?
/// The encoding standard used to represent the characters in the produced document.
public let encoding: String?
/// Indicates whether a document relies on information from an external source.
public let standalone: String?
public init(version: Double? = nil, encoding: String? = nil, standalone: String? = nil) {
self.version = version
self.encoding = encoding
self.standalone = standalone
}
func isEmpty() -> Bool {
return version == nil && encoding == nil && standalone == nil
}
func toXML() -> String? {
guard !isEmpty() else {
return nil
}
var string = "<?xml"
if let version = version {
string += " version=\"\(version)\""
}
if let encoding = encoding {
string += " encoding=\"\(encoding)\""
}
if let standalone = standalone {
string += " standalone=\"\(standalone)\""
}
string += "?>\n"
return string
}
}
// Copyright (c) 2017-2020 Shawn Moore and XMLCoder contributors
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
//
// Created by Shawn Moore on 11/21/17.
//
import Foundation
/// Shared Key Types
struct XMLKey: CodingKey {
public let stringValue: String
public let intValue: Int?
public init?(stringValue: String) {
self.init(key: stringValue)
}
public init?(intValue: Int) {
self.init(index: intValue)
}
public init(stringValue: String, intValue: Int?) {
self.stringValue = stringValue
self.intValue = intValue
}
init(key: String) {
self.init(stringValue: key, intValue: nil)
}
init(index: Int) {
self.init(stringValue: "\(index)", intValue: index)
}
static let `super` = XMLKey(stringValue: "super")!
}
// Copyright (c) 2017-2020 Shawn Moore and XMLCoder contributors
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
//
// Created by Shawn Moore on 11/14/17.
//
import Foundation
#if canImport(FoundationXML)
import FoundationXML
#endif
class XMLStackParser: NSObject {
var root: XMLCoderElement?
private var stack: [XMLCoderElement] = []
private let trimValueWhitespaces: Bool
init(trimValueWhitespaces: Bool = true) {
self.trimValueWhitespaces = trimValueWhitespaces
super.init()
}
static func parse(
with data: Data,
errorContextLength length: UInt,
shouldProcessNamespaces: Bool,
trimValueWhitespaces: Bool
) throws -> Box {
let parser = XMLStackParser(trimValueWhitespaces: trimValueWhitespaces)
let node = try parser.parse(
with: data,
errorContextLength: length,
shouldProcessNamespaces: shouldProcessNamespaces
)
return node.transformToBoxTree()
}
func parse(
with data: Data,
errorContextLength: UInt,
shouldProcessNamespaces: Bool
) throws -> XMLCoderElement {
let xmlParser = XMLParser(data: data)
xmlParser.shouldProcessNamespaces = shouldProcessNamespaces
xmlParser.delegate = self
guard !xmlParser.parse() || root == nil else {
return root!
}
guard let error = xmlParser.parserError else {
throw DecodingError.dataCorrupted(DecodingError.Context(
codingPath: [],
debugDescription: "The given data could not be parsed into XML."
))
}
// `lineNumber` isn't 0-indexed, so 0 is an invalid value for context
guard errorContextLength > 0 && xmlParser.lineNumber > 0 else {
throw error
}
let string = String(data: data, encoding: .utf8) ?? ""
let lines = string.split(separator: "\n")
var errorPosition = 0
let offset = Int(errorContextLength / 2)
for i in 0..<xmlParser.lineNumber - 1 {
errorPosition += lines[i].count
}
errorPosition += xmlParser.columnNumber
var lowerBoundIndex = 0
if errorPosition - offset > 0 {
lowerBoundIndex = errorPosition - offset
}
var upperBoundIndex = string.count
if errorPosition + offset < string.count {
upperBoundIndex = errorPosition + offset
}
#if compiler(>=5.0)
let lowerBound = String.Index(utf16Offset: lowerBoundIndex, in: string)
let upperBound = String.Index(utf16Offset: upperBoundIndex, in: string)
#else
let lowerBound = String.Index(encodedOffset: lowerBoundIndex)
let upperBound = String.Index(encodedOffset: upperBoundIndex)
#endif
let context = string[lowerBound..<upperBound]
throw DecodingError.dataCorrupted(DecodingError.Context(
codingPath: [],
debugDescription: """
\(error.localizedDescription) \
at line \(xmlParser.lineNumber), column \(xmlParser.columnNumber):
`\(context)`
""",
underlyingError: error
))
}
func withCurrentElement(_ body: (inout XMLCoderElement) throws -> ()) rethrows {
guard !stack.isEmpty else {
return
}
try body(&stack[stack.count - 1])
}
/// Trim whitespaces for a given string if needed.
func process(string: String) -> String {
return trimValueWhitespaces
? string.trimmingCharacters(in: .whitespacesAndNewlines)
: string
}
}
extension XMLStackParser: XMLParserDelegate {
func parserDidStartDocument(_: XMLParser) {
root = nil
stack = []
}
func parser(_: XMLParser,
didStartElement elementName: String,
namespaceURI: String?,
qualifiedName: String?,
attributes attributeDict: [String: String] = [:])
{
#if os(Linux) && !compiler(>=5.1)
// For some reason, element names on linux are coming out with the namespace after the name
// https://bugs.swift.org/browse/SR-11191
let elementName = elementName.components(separatedBy: ":").reversed().joined(separator: ":")
#endif
let attributes = attributeDict.map { key, value in
Attribute(key: key, value: value)
}
let element = XMLCoderElement(key: elementName, attributes: attributes)
stack.append(element)
}
func parser(_: XMLParser,
didEndElement _: String,
namespaceURI _: String?,
qualifiedName _: String?)
{
guard let element = stack.popLast() else {
return
}
withCurrentElement { currentElement in
currentElement.append(element: element, forKey: element.key)
}
if stack.isEmpty {
root = element
}
}
func parser(_: XMLParser, foundCharacters string: String) {
let processedString = process(string: string)
guard processedString.count > 0, string.count != 0 else {
return
}
withCurrentElement { currentElement in
currentElement.append(string: processedString)
}
}
func parser(_: XMLParser, foundCDATA CDATABlock: Data) {
guard let string = String(data: CDATABlock, encoding: .utf8) else {
return
}
withCurrentElement { currentElement in
currentElement.append(cdata: string)
}
}
}
// Copyright (c) 2017-2020 Shawn Moore and XMLCoder contributors
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
//
// Created by Shawn Moore on 11/21/17.
//
import Foundation
//===----------------------------------------------------------------------===//
// Error Utilities
//===----------------------------------------------------------------------===//
extension DecodingError {
/// Returns a `.typeMismatch` error describing the expected type.
///
/// - parameter path: The path of `CodingKey`s taken to decode a value of this type.
/// - parameter expectation: The type expected to be encountered.
/// - parameter reality: The value that was encountered instead of the expected type.
/// - returns: A `DecodingError` with the appropriate path and debug description.
static func typeMismatch(at path: [CodingKey], expectation: Any.Type, reality: Box) -> DecodingError {
let description = "Expected to decode \(expectation) but found \(_typeDescription(of: reality)) instead."
return .typeMismatch(expectation, Context(codingPath: path, debugDescription: description))
}
/// Returns a description of the type of `value` appropriate for an error message.
///
/// - parameter value: The value whose type to describe.
/// - returns: A string describing `value`.
/// - precondition: `value` is one of the types below.
static func _typeDescription(of box: Box) -> String {
switch box {
case is NullBox:
return "a null value"
case is BoolBox:
return "a boolean value"
case is DecimalBox:
return "a decimal value"
case is IntBox:
return "a signed integer value"
case is UIntBox:
return "an unsigned integer value"
case is FloatBox:
return "a floating-point value"
case is DoubleBox:
return "a double floating-point value"
case is UnkeyedBox:
return "a array value"
case is KeyedBox:
return "a dictionary value"
case _:
return "\(type(of: box))"
}
}
}
// Copyright (c) 2019-2020 XMLCoder contributors
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
//
// Created by Max Desiatov on 01/03/2019.
//
public protocol DynamicNodeDecoding: Decodable {
static func nodeDecoding(for key: CodingKey) -> XMLDecoder.NodeDecoding
}
// Copyright (c) 2017-2020 Shawn Moore and XMLCoder contributors
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
//
// Created by Shawn Moore on 11/20/17.
//
import Foundation
extension XMLDecoderImplementation: SingleValueDecodingContainer {
// MARK: SingleValueDecodingContainer Methods
public func decodeNil() -> Bool {
return (try? topContainer().isNull) ?? true
}
public func decode(_: Bool.Type) throws -> Bool {
return try unbox(try topContainer())
}
public func decode(_: Decimal.Type) throws -> Decimal {
return try unbox(try topContainer())
}
public func decode<T: BinaryInteger & SignedInteger & Decodable>(_: T.Type) throws -> T {
return try unbox(try topContainer())
}
public func decode<T: BinaryInteger & UnsignedInteger & Decodable>(_: T.Type) throws -> T {
return try unbox(try topContainer())
}
public func decode(_: Float.Type) throws -> Float {
return try unbox(try topContainer())
}
public func decode(_: Double.Type) throws -> Double {
return try unbox(try topContainer())
}
public func decode(_: String.Type) throws -> String {
return try unbox(try topContainer())
}
public func decode(_: String.Type) throws -> Date {
return try unbox(try topContainer())
}
public func decode(_: String.Type) throws -> Data {
return try unbox(try topContainer())
}
public func decode<T: Decodable>(_: T.Type) throws -> T {
return try unbox(try topContainer())
}
}
// Copyright (c) 2019-2020 XMLCoder contributors
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
//
// Created by James Bean on 7/18/19.
//
/// Container specialized for decoding XML choice elements.
struct XMLChoiceDecodingContainer<K: CodingKey>: KeyedDecodingContainerProtocol {
typealias Key = K
// MARK: Properties
/// A reference to the decoder we're reading from.
private let decoder: XMLDecoderImplementation
/// A reference to the container we're reading from.
private let container: SharedBox<ChoiceBox>
/// The path of coding keys taken to get to this point in decoding.
public private(set) var codingPath: [CodingKey]
// MARK: - Initialization
/// Initializes `self` by referencing the given decoder and container.
init(referencing decoder: XMLDecoderImplementation, wrapping container: SharedBox<ChoiceBox>) {
self.decoder = decoder
container.withShared { $0.key = decoder.keyTransform($0.key) }
self.container = container
codingPath = decoder.codingPath
}
// MARK: - KeyedDecodingContainerProtocol Methods
public var allKeys: [Key] {
return container.withShared { [Key(stringValue: $0.key)!] }
}
public func contains(_ key: Key) -> Bool {
return container.withShared { $0.key == key.stringValue }
}
public func decodeNil(forKey key: Key) throws -> Bool {
return container.withShared { $0.element.isNull }
}
public func decode<T: Decodable>(_ type: T.Type, forKey key: Key) throws -> T {
guard container.withShared({ $0.key == key.stringValue }), key is XMLChoiceCodingKey else {
throw DecodingError.typeMismatch(
at: codingPath,
expectation: type,
reality: container
)
}
return try decoder.unbox(container.withShared { $0.element })
}
public func nestedContainer<NestedKey>(
keyedBy _: NestedKey.Type, forKey key: Key
) throws -> KeyedDecodingContainer<NestedKey> {
throw DecodingError.typeMismatch(
at: codingPath,
expectation: NestedKey.self,
reality: container
)
}
public func nestedUnkeyedContainer(forKey key: Key) throws -> UnkeyedDecodingContainer {
throw DecodingError.typeMismatch(
at: codingPath,
expectation: Key.self,
reality: container
)
}
public func superDecoder() throws -> Decoder {
throw DecodingError.typeMismatch(
at: codingPath,
expectation: Key.self,
reality: container
)
}
public func superDecoder(forKey key: Key) throws -> Decoder {
throw DecodingError.typeMismatch(
at: codingPath,
expectation: Key.self,
reality: container
)
}
}
// Copyright (c) 2017-2020 Shawn Moore and XMLCoder contributors
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
//
// Created by Shawn Moore on 11/20/17.
//
import Foundation
// MARK: - Decoding Storage
struct XMLDecodingStorage {
// MARK: Properties
/// The container stack.
/// Elements may be any one of the XML types (StringBox, KeyedBox).
private var containers: [Box] = []
// MARK: - Initialization
/// Initializes `self` with no containers.
init() {}
// MARK: - Modifying the Stack
var count: Int {
return containers.count
}
func topContainer() -> Box? {
return containers.last
}
mutating func push(container: Box) {
if let keyedBox = container as? KeyedBox {
containers.append(SharedBox(keyedBox))
} else if let unkeyedBox = container as? UnkeyedBox {
containers.append(SharedBox(unkeyedBox))
} else {
containers.append(container)
}
}
@discardableResult
mutating func popContainer() -> Box? {
guard !containers.isEmpty else {
return nil
}
return containers.removeLast()
}
}
// Copyright (c) 2017-2020 Shawn Moore and XMLCoder contributors
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
//
// Created by Shawn Moore on 11/21/17.
//
import Foundation
struct XMLUnkeyedDecodingContainer: UnkeyedDecodingContainer {
// MARK: Properties
/// A reference to the decoder we're reading from.
private let decoder: XMLDecoderImplementation
/// A reference to the container we're reading from.
private let container: SharedBox<UnkeyedBox>
/// The path of coding keys taken to get to this point in decoding.
public private(set) var codingPath: [CodingKey]
/// The index of the element we're about to decode.
public private(set) var currentIndex: Int
// MARK: - Initialization
/// Initializes `self` by referencing the given decoder and container.
init(referencing decoder: XMLDecoderImplementation, wrapping container: SharedBox<UnkeyedBox>) {
self.decoder = decoder
self.container = container
codingPath = decoder.codingPath
currentIndex = 0
}
// MARK: - UnkeyedDecodingContainer Methods
public var count: Int? {
return container.withShared { unkeyedBox in
unkeyedBox.count
}
}
public var isAtEnd: Bool {
return currentIndex >= count!
}
public mutating func decodeNil() throws -> Bool {
guard !isAtEnd else {
throw DecodingError.valueNotFound(Any?.self, DecodingError.Context(
codingPath: decoder.codingPath + [XMLKey(index: currentIndex)],
debugDescription: "Unkeyed container is at end."
))
}
let isNull = container.withShared { unkeyedBox in
unkeyedBox[self.currentIndex].isNull
}
if isNull {
currentIndex += 1
return true
} else {
return false
}
}
public mutating func decode<T: Decodable>(_ type: T.Type) throws -> T {
return try decode(type) { decoder, box in
try decoder.unbox(box)
}
}
private mutating func decode<T: Decodable>(
_ type: T.Type,
decode: (XMLDecoderImplementation, Box) throws -> T?
) throws -> T {
decoder.codingPath.append(XMLKey(index: currentIndex))
let nodeDecodings = decoder.options.nodeDecodingStrategy.nodeDecodings(
forType: T.self,
with: decoder
)
decoder.nodeDecodings.append(nodeDecodings)
defer {
_ = decoder.nodeDecodings.removeLast()
_ = decoder.codingPath.removeLast()
}
guard !isAtEnd else {
throw DecodingError.valueNotFound(type, DecodingError.Context(
codingPath: decoder.codingPath + [XMLKey(index: currentIndex)],
debugDescription: "Unkeyed container is at end."
))
}
decoder.codingPath.append(XMLKey(index: currentIndex))
defer { self.decoder.codingPath.removeLast() }
let box = container.withShared { unkeyedBox in
unkeyedBox[self.currentIndex]
}
var value: T?
if let singleKeyed = box as? SingleKeyedBox {
do {
value = try decode(decoder, singleKeyed)
} catch {
do {
// Drill down to the element in the case of an nested unkeyed element
value = try decode(decoder, singleKeyed.element)
} catch {
// Specialize for choice elements
value = try decode(decoder, ChoiceBox(key: singleKeyed.key, element: singleKeyed.element))
}
}
} else {
value = try decode(decoder, box)
}
defer { currentIndex += 1 }
if value == nil, let type = type as? AnyOptional.Type,
let result = type.init() as? T
{
return result
}
guard let decoded: T = value else {
throw DecodingError.valueNotFound(type, DecodingError.Context(
codingPath: decoder.codingPath + [XMLKey(index: currentIndex)],
debugDescription: "Expected \(type) but found null instead."
))
}
return decoded
}
public mutating func nestedContainer<NestedKey>(
keyedBy _: NestedKey.Type
) throws -> KeyedDecodingContainer<NestedKey> {
decoder.codingPath.append(XMLKey(index: currentIndex))
defer { self.decoder.codingPath.removeLast() }
guard !isAtEnd else {
throw DecodingError.valueNotFound(
KeyedDecodingContainer<NestedKey>.self, DecodingError.Context(
codingPath: codingPath,
debugDescription: "Cannot get nested keyed container -- unkeyed container is at end."
)
)
}
let value = self.container.withShared { unkeyedBox in
unkeyedBox[self.currentIndex]
}
guard !value.isNull else {
throw DecodingError.valueNotFound(KeyedDecodingContainer<NestedKey>.self, DecodingError.Context(
codingPath: codingPath,
debugDescription: "Cannot get keyed decoding container -- found null value instead."
))
}
guard let keyedContainer = value as? SharedBox<KeyedBox> else {
throw DecodingError.typeMismatch(at: codingPath,
expectation: [String: Any].self,
reality: value)
}
currentIndex += 1
let container = XMLKeyedDecodingContainer<NestedKey>(
referencing: decoder,
wrapping: keyedContainer
)
return KeyedDecodingContainer(container)
}
public mutating func nestedUnkeyedContainer() throws -> UnkeyedDecodingContainer {
decoder.codingPath.append(XMLKey(index: currentIndex))
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."
)
)
}
let value = container.withShared { unkeyedBox in
unkeyedBox[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."
))
}
guard let unkeyedContainer = value as? SharedBox<UnkeyedBox> else {
throw DecodingError.typeMismatch(at: codingPath,
expectation: UnkeyedBox.self,
reality: value)
}
currentIndex += 1
return XMLUnkeyedDecodingContainer(referencing: decoder, wrapping: unkeyedContainer)
}
public mutating func superDecoder() throws -> Decoder {
decoder.codingPath.append(XMLKey(index: currentIndex))
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."
))
}
let value = container.withShared { unkeyedBox in
unkeyedBox[self.currentIndex]
}
currentIndex += 1
return XMLDecoderImplementation(
referencing: value,
options: decoder.options,
nodeDecodings: decoder.nodeDecodings,
codingPath: decoder.codingPath
)
}
}
// Copyright (c) 2019-2020 XMLCoder contributors
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
//
// Created by Joseph Mattiello on 1/24/19.
//
public protocol DynamicNodeEncoding: Encodable {
static func nodeEncoding(for key: CodingKey) -> XMLEncoder.NodeEncoding
}
extension Array: DynamicNodeEncoding where Element: DynamicNodeEncoding {
public static func nodeEncoding(for key: CodingKey) -> XMLEncoder.NodeEncoding {
return Element.nodeEncoding(for: key)
}
}
public extension DynamicNodeEncoding where Self: Collection, Self.Iterator.Element: DynamicNodeEncoding {
static func nodeEncoding(for key: CodingKey) -> XMLEncoder.NodeEncoding {
return Element.nodeEncoding(for: key)
}
}
// Copyright (c) 2017-2020 Shawn Moore and XMLCoder contributors
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
//
// Created by Shawn Moore on 11/22/17.
//
import Foundation
/// Error Utilities
extension EncodingError {
/// Returns a `.invalidValue` error describing the given invalid floating-point value.
///
///
/// - parameter value: The value that was invalid to encode.
/// - parameter path: The path of `CodingKey`s taken to encode this value.
/// - returns: An `EncodingError` with the appropriate path and debug description.
static func _invalidFloatingPointValue<T: FloatingPoint>(_ value: T, at codingPath: [CodingKey]) -> EncodingError {
let valueDescription: String
if value == T.infinity {
valueDescription = "\(T.self).infinity"
} else if value == -T.infinity {
valueDescription = "-\(T.self).infinity"
} else {
valueDescription = "\(T.self).nan"
}
let debugDescription = """
Unable to encode \(valueDescription) directly in XML. \
Use XMLEncoder.NonConformingFloatEncodingStrategy.convertToString \
to specify how the value should be encoded.
"""
return .invalidValue(value, EncodingError.Context(codingPath: codingPath, debugDescription: debugDescription))
}
}
// Copyright (c) 2017-2020 Shawn Moore and XMLCoder contributors
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
//
// Created by Shawn Moore on 11/22/17.
//
import Foundation
extension XMLEncoderImplementation: SingleValueEncodingContainer {
// MARK: - SingleValueEncodingContainer Methods
func assertCanEncodeNewValue() {
precondition(
canEncodeNewValue,
"""
Attempt to encode value through single value container when \
previously value already encoded.
"""
)
}
public func encodeNil() throws {
assertCanEncodeNewValue()
storage.push(container: box())
}
public func encode(_ value: Bool) throws {
assertCanEncodeNewValue()
storage.push(container: box(value))
}
public func encode(_ value: Int) throws {
assertCanEncodeNewValue()
storage.push(container: box(value))
}
public func encode(_ value: Int8) throws {
assertCanEncodeNewValue()
storage.push(container: box(value))
}
public func encode(_ value: Int16) throws {
assertCanEncodeNewValue()
storage.push(container: box(value))
}
public func encode(_ value: Int32) throws {
assertCanEncodeNewValue()
storage.push(container: box(value))
}
public func encode(_ value: Int64) throws {
assertCanEncodeNewValue()
storage.push(container: box(value))
}
public func encode(_ value: UInt) throws {
assertCanEncodeNewValue()
storage.push(container: box(value))
}
public func encode(_ value: UInt8) throws {
assertCanEncodeNewValue()
storage.push(container: box(value))
}
public func encode(_ value: UInt16) throws {
assertCanEncodeNewValue()
storage.push(container: box(value))
}
public func encode(_ value: UInt32) throws {
assertCanEncodeNewValue()
storage.push(container: box(value))
}
public func encode(_ value: UInt64) throws {
assertCanEncodeNewValue()
storage.push(container: box(value))
}
public func encode(_ value: String) throws {
assertCanEncodeNewValue()
storage.push(container: box(value))
}
public func encode(_ value: Float) throws {
assertCanEncodeNewValue()
try storage.push(container: box(value))
}
public func encode(_ value: Double) throws {
assertCanEncodeNewValue()
try storage.push(container: box(value))
}
public func encode<T: Encodable>(_ value: T) throws {
assertCanEncodeNewValue()
try storage.push(container: box(value))
}
}
// Copyright (c) 2019-2020 XMLCoder contributors
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
//
// Created by Benjamin Wetherfield on 7/17/19.
//
struct XMLChoiceEncodingContainer<K: CodingKey>: KeyedEncodingContainerProtocol {
typealias Key = K
// MARK: Properties
/// A reference to the encoder we're writing to.
private let encoder: XMLEncoderImplementation
/// A reference to the container we're writing to.
private var container: SharedBox<ChoiceBox>
/// The path of coding keys taken to get to this point in encoding.
public private(set) var codingPath: [CodingKey]
// MARK: - Initialization
/// Initializes `self` with the given references.
init(
referencing encoder: XMLEncoderImplementation,
codingPath: [CodingKey],
wrapping container: SharedBox<ChoiceBox>
) {
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 .convertToKebabCase:
let newKeyString = XMLEncoder.KeyEncodingStrategy
._convertToKebabCase(key.stringValue)
return XMLKey(stringValue: newKeyString, intValue: key.intValue)
case let .custom(converter):
return converter(codingPath + [key])
case .capitalized:
let newKeyString = XMLEncoder.KeyEncodingStrategy
._convertToCapitalized(key.stringValue)
return XMLKey(stringValue: newKeyString, intValue: key.intValue)
case .uppercased:
let newKeyString = XMLEncoder.KeyEncodingStrategy
._convertToUppercased(key.stringValue)
return XMLKey(stringValue: newKeyString, intValue: key.intValue)
case .lowercased:
let newKeyString = XMLEncoder.KeyEncodingStrategy
._convertToLowercased(key.stringValue)
return XMLKey(stringValue: newKeyString, intValue: key.intValue)
}
}
// MARK: - KeyedEncodingContainerProtocol Methods
public mutating func encodeNil(forKey key: Key) throws {
container.withShared {
$0.key = converted(key).stringValue
$0.element = NullBox()
}
}
public mutating func encode<T: Encodable>(
_ value: T,
forKey key: Key
) throws {
return try encode(value, forKey: key) { encoder, value in
try encoder.box(value)
}
}
private mutating func encode<T: Encodable>(
_ value: T,
forKey key: Key,
encode: (XMLEncoderImplementation, T) throws -> Box
) throws {
defer {
_ = self.encoder.nodeEncodings.removeLast()
self.encoder.codingPath.removeLast()
}
encoder.codingPath.append(key)
let nodeEncodings = encoder.options.nodeEncodingStrategy.nodeEncodings(
forType: T.self,
with: encoder
)
encoder.nodeEncodings.append(nodeEncodings)
let box = try encode(encoder, value)
let oldSelf = self
let elementEncoder: (T, Key, Box) throws -> () = { _, key, box in
oldSelf.container.withShared { container in
container.element = box
container.key = oldSelf.converted(key).stringValue
}
}
defer {
self = oldSelf
}
try elementEncoder(value, key, box)
}
public mutating func nestedContainer<NestedKey>(
keyedBy _: NestedKey.Type,
forKey key: Key
) -> KeyedEncodingContainer<NestedKey> {
if NestedKey.self is XMLChoiceCodingKey.Type {
return nestedChoiceContainer(keyedBy: NestedKey.self, forKey: key)
} else {
return nestedKeyedContainer(keyedBy: NestedKey.self, forKey: key)
}
}
mutating func nestedKeyedContainer<NestedKey>(
keyedBy _: NestedKey.Type,
forKey key: Key
) -> KeyedEncodingContainer<NestedKey> {
let sharedKeyed = SharedBox(KeyedBox())
self.container.withShared { container in
container.element = sharedKeyed
container.key = converted(key).stringValue
}
codingPath.append(key)
defer { self.codingPath.removeLast() }
let container = XMLKeyedEncodingContainer<NestedKey>(
referencing: encoder,
codingPath: codingPath,
wrapping: sharedKeyed
)
return KeyedEncodingContainer(container)
}
mutating func nestedChoiceContainer<NestedKey>(
keyedBy _: NestedKey.Type,
forKey key: Key
) -> KeyedEncodingContainer<NestedKey> {
let sharedChoice = SharedBox(ChoiceBox())
self.container.withShared { container in
container.element = sharedChoice
container.key = converted(key).stringValue
}
codingPath.append(key)
defer { self.codingPath.removeLast() }
let container = XMLChoiceEncodingContainer<NestedKey>(
referencing: encoder,
codingPath: codingPath,
wrapping: sharedChoice
)
return KeyedEncodingContainer(container)
}
public mutating func nestedUnkeyedContainer(
forKey key: Key
) -> UnkeyedEncodingContainer {
let sharedUnkeyed = SharedBox(UnkeyedBox())
container.withShared { container in
container.element = sharedUnkeyed
container.key = converted(key).stringValue
}
codingPath.append(key)
defer { self.codingPath.removeLast() }
return XMLUnkeyedEncodingContainer(
referencing: encoder,
codingPath: codingPath,
wrapping: sharedUnkeyed
)
}
public mutating func superEncoder() -> Encoder {
return XMLReferencingEncoder(
referencing: encoder,
key: XMLKey.super,
convertedKey: converted(XMLKey.super),
wrapping: container
)
}
public mutating func superEncoder(forKey key: Key) -> Encoder {
return XMLReferencingEncoder(
referencing: encoder,
key: key,
convertedKey: converted(key),
wrapping: container
)
}
}
// Copyright (c) 2017-2020 Shawn Moore and XMLCoder contributors
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
//
// Created by Shawn Moore on 11/22/17.
//
import Foundation
class XMLEncoderImplementation: Encoder {
// MARK: Properties
/// The encoder's storage.
var storage: XMLEncodingStorage
/// Options set on the top-level encoder.
let options: XMLEncoder.Options
/// The path to the current point in encoding.
public var codingPath: [CodingKey]
public var nodeEncodings: [(CodingKey) -> XMLEncoder.NodeEncoding]
/// Contextual user-provided information for use during encoding.
public var userInfo: [CodingUserInfoKey: Any] {
return options.userInfo
}
// MARK: - Initialization
/// Initializes `self` with the given top-level encoder options.
init(
options: XMLEncoder.Options,
nodeEncodings: [(CodingKey) -> XMLEncoder.NodeEncoding],
codingPath: [CodingKey] = []
) {
self.options = options
storage = XMLEncodingStorage()
self.codingPath = codingPath
self.nodeEncodings = nodeEncodings
}
/// Returns whether a new element can be encoded at this coding path.
///
/// `true` if an element has not yet been encoded at this coding path; `false` otherwise.
var canEncodeNewValue: Bool {
// Every time a new value gets encoded, the key it's encoded for is
// pushed onto the coding path (even if it's a nil key from an unkeyed container).
// At the same time, every time a container is requested, a new value
// gets pushed onto the storage stack.
// If there are more values on the storage stack than on the coding path,
// it means the value is requesting more than one container, which
// violates the precondition.
//
// This means that anytime something that can request a new container
// goes onto the stack, we MUST push a key onto the coding path.
// Things which will not request containers do not need to have the
// coding path extended for them (but it doesn't matter if it is,
// because they will not reach here).
return storage.count == codingPath.count
}
// MARK: - Encoder Methods
public func container<Key>(keyedBy _: Key.Type) -> KeyedEncodingContainer<Key> {
guard canEncodeNewValue else {
return mergeWithExistingKeyedContainer(keyedBy: Key.self)
}
if Key.self is XMLChoiceCodingKey.Type {
return choiceContainer(keyedBy: Key.self)
} else {
return keyedContainer(keyedBy: Key.self)
}
}
public func unkeyedContainer() -> UnkeyedEncodingContainer {
// If an existing unkeyed container was already requested, return that one.
let topContainer: SharedBox<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? SharedBox<UnkeyedBox> else {
preconditionFailure(
"""
Attempt to push new unkeyed encoding container when already previously encoded \
at this path.
"""
)
}
topContainer = container
}
return XMLUnkeyedEncodingContainer(referencing: self, codingPath: codingPath, wrapping: topContainer)
}
public func singleValueContainer() -> SingleValueEncodingContainer {
return self
}
private func keyedContainer<Key>(keyedBy _: Key.Type) -> KeyedEncodingContainer<Key> {
let container = XMLKeyedEncodingContainer<Key>(
referencing: self,
codingPath: codingPath,
wrapping: storage.pushKeyedContainer()
)
return KeyedEncodingContainer(container)
}
private func choiceContainer<Key>(keyedBy _: Key.Type) -> KeyedEncodingContainer<Key> {
let container = XMLChoiceEncodingContainer<Key>(
referencing: self,
codingPath: codingPath,
wrapping: storage.pushChoiceContainer()
)
return KeyedEncodingContainer(container)
}
private func mergeWithExistingKeyedContainer<Key>(keyedBy _: Key.Type) -> KeyedEncodingContainer<Key> {
switch storage.lastContainer {
case let keyed as SharedBox<KeyedBox>:
let container = XMLKeyedEncodingContainer<Key>(
referencing: self,
codingPath: codingPath,
wrapping: keyed
)
return KeyedEncodingContainer(container)
case let choice as SharedBox<ChoiceBox>:
_ = storage.popContainer()
let keyed = KeyedBox(
elements: KeyedBox.Elements([choice.withShared { ($0.key, $0.element) }]),
attributes: []
)
let container = XMLKeyedEncodingContainer<Key>(
referencing: self,
codingPath: codingPath,
wrapping: storage.pushKeyedContainer(keyed)
)
return KeyedEncodingContainer(container)
default:
preconditionFailure(
"""
No existing keyed encoding container to merge with.
"""
)
}
}
}
extension XMLEncoderImplementation {
/// Returns the given value boxed in a container appropriate for pushing onto the container stack.
func box() -> SimpleBox {
return NullBox()
}
func box(_ value: Bool) -> SimpleBox {
return BoolBox(value)
}
func box(_ value: Decimal) -> SimpleBox {
return DecimalBox(value)
}
func box<T: BinaryInteger & SignedInteger & Encodable>(_ value: T) -> SimpleBox {
return IntBox(value)
}
func box<T: BinaryInteger & UnsignedInteger & Encodable>(_ value: T) -> SimpleBox {
return UIntBox(value)
}
func box(_ value: Float) throws -> SimpleBox {
return try box(value, FloatBox.self)
}
func box(_ value: Double) throws -> SimpleBox {
return try box(value, DoubleBox.self)
}
func box<T: BinaryFloatingPoint & Encodable, B: ValueBox>(
_ value: T,
_: B.Type
) throws -> SimpleBox where B.Unboxed == T {
guard value.isInfinite || value.isNaN else {
return B(value)
}
guard case let .convertToString(
positiveInfinity: posInfString,
negativeInfinity: negInfString,
nan: nanString
) = options.nonConformingFloatEncodingStrategy else {
throw EncodingError._invalidFloatingPointValue(value, at: codingPath)
}
if value == T.infinity {
return StringBox(posInfString)
} else if value == -T.infinity {
return StringBox(negInfString)
} else {
return StringBox(nanString)
}
}
func box(_ value: String) -> SimpleBox {
return StringBox(value)
}
func box(_ value: Date) throws -> Box {
switch options.dateEncodingStrategy {
case .deferredToDate:
try value.encode(to: self)
return storage.popContainer()
case .secondsSince1970:
return DateBox(value, format: .secondsSince1970)
case .millisecondsSince1970:
return DateBox(value, format: .millisecondsSince1970)
case .iso8601:
return DateBox(value, format: .iso8601)
case let .formatted(formatter):
return DateBox(value, format: .formatter(formatter))
case let .custom(closure):
let depth = storage.count
try closure(value, self)
guard storage.count > depth else {
return KeyedBox()
}
return storage.popContainer()
}
}
func box(_ value: Data) throws -> Box {
switch options.dataEncodingStrategy {
case .deferredToData:
try value.encode(to: self)
return storage.popContainer()
case .base64:
return DataBox(value, format: .base64)
case let .custom(closure):
let depth = storage.count
try closure(value, self)
guard storage.count > depth else {
return KeyedBox()
}
return storage.popContainer()
}
}
func box(_ value: URL) -> SimpleBox {
return URLBox(value)
}
func box<T: Encodable>(_ value: T) throws -> Box {
if T.self == Date.self || T.self == NSDate.self,
let value = value as? Date
{
return try box(value)
} else if T.self == Data.self || T.self == NSData.self,
let value = value as? Data
{
return try box(value)
} else if T.self == URL.self || T.self == NSURL.self,
let value = value as? URL
{
return box(value)
} else if T.self == Decimal.self || T.self == NSDecimalNumber.self,
let value = value as? Decimal
{
return box(value)
}
let depth = storage.count
try value.encode(to: self)
// The top container should be a new container.
guard storage.count > depth else {
return KeyedBox()
}
let lastContainer = storage.popContainer()
guard let sharedBox = lastContainer as? TypeErasedSharedBoxProtocol else {
return lastContainer
}
return sharedBox.typeErasedUnbox()
}
}
// Copyright (c) 2017-2020 Shawn Moore and XMLCoder contributors
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
//
// Created by Shawn Moore on 11/22/17.
//
import Foundation
// MARK: - Encoding Storage and Containers
struct XMLEncodingStorage {
// MARK: Properties
/// The container stack.
private var containers: [Box] = []
// MARK: - Initialization
/// Initializes `self` with no containers.
init() {}
// MARK: - Modifying the Stack
var count: Int {
return containers.count
}
var lastContainer: Box? {
return containers.last
}
mutating func pushKeyedContainer(_ keyedBox: KeyedBox = KeyedBox()) -> SharedBox<KeyedBox> {
let container = SharedBox(keyedBox)
containers.append(container)
return container
}
mutating func pushChoiceContainer() -> SharedBox<ChoiceBox> {
let container = SharedBox(ChoiceBox())
containers.append(container)
return container
}
mutating func pushUnkeyedContainer() -> SharedBox<UnkeyedBox> {
let container = SharedBox(UnkeyedBox())
containers.append(container)
return container
}
mutating func push(container: Box) {
if let keyedBox = container as? KeyedBox {
containers.append(SharedBox(keyedBox))
} else if let unkeyedBox = container as? UnkeyedBox {
containers.append(SharedBox(unkeyedBox))
} else {
containers.append(container)
}
}
mutating func popContainer() -> Box {
precondition(!containers.isEmpty, "Empty container stack.")
return containers.popLast()!
}
}
// Copyright (c) 2018-2020 XMLCoder contributors
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
//
// Created by Vincent Esche on 11/20/18.
//
import Foundation
struct XMLKeyedEncodingContainer<K: CodingKey>: KeyedEncodingContainerProtocol {
typealias Key = K
// MARK: Properties
/// A reference to the encoder we're writing to.
private let encoder: XMLEncoderImplementation
/// A reference to the container we're writing to.
private var container: SharedBox<KeyedBox>
/// The path of coding keys taken to get to this point in encoding.
public private(set) var codingPath: [CodingKey]
// MARK: - Initialization
/// Initializes `self` with the given references.
init(
referencing encoder: XMLEncoderImplementation,
codingPath: [CodingKey],
wrapping container: SharedBox<KeyedBox>
) {
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 .convertToKebabCase:
let newKeyString = XMLEncoder.KeyEncodingStrategy
._convertToKebabCase(key.stringValue)
return XMLKey(stringValue: newKeyString, intValue: key.intValue)
case let .custom(converter):
return converter(codingPath + [key])
case .capitalized:
let newKeyString = XMLEncoder.KeyEncodingStrategy
._convertToCapitalized(key.stringValue)
return XMLKey(stringValue: newKeyString, intValue: key.intValue)
case .uppercased:
let newKeyString = XMLEncoder.KeyEncodingStrategy
._convertToUppercased(key.stringValue)
return XMLKey(stringValue: newKeyString, intValue: key.intValue)
case .lowercased:
let newKeyString = XMLEncoder.KeyEncodingStrategy
._convertToLowercased(key.stringValue)
return XMLKey(stringValue: newKeyString, intValue: key.intValue)
}
}
// MARK: - KeyedEncodingContainerProtocol Methods
public mutating func encodeNil(forKey key: Key) throws {
container.withShared {
$0.elements.append(NullBox(), at: converted(key).stringValue)
}
}
public mutating func encode<T: Encodable>(
_ value: T,
forKey key: Key
) throws {
return try encode(value, forKey: key) { encoder, value in
try encoder.box(value)
}
}
private mutating func encode<T: Encodable>(
_ value: T,
forKey key: Key,
encode: (XMLEncoderImplementation, T) throws -> Box
) throws {
defer {
_ = self.encoder.nodeEncodings.removeLast()
self.encoder.codingPath.removeLast()
}
guard let strategy = encoder.nodeEncodings.last else {
preconditionFailure(
"Attempt to access node encoding strategy from empty stack."
)
}
encoder.codingPath.append(key)
let nodeEncodings = encoder.options.nodeEncodingStrategy.nodeEncodings(
forType: T.self,
with: encoder
)
encoder.nodeEncodings.append(nodeEncodings)
let box = try encode(encoder, value)
let oldSelf = self
let attributeEncoder: (T, Key, Box) throws -> () = { value, key, box in
guard let attribute = box as? SimpleBox else {
throw EncodingError.invalidValue(value, EncodingError.Context(
codingPath: [],
debugDescription: "Complex values cannot be encoded as attributes."
))
}
oldSelf.container.withShared { container in
container.attributes.append(attribute, at: oldSelf.converted(key).stringValue)
}
}
let elementEncoder: (T, Key, Box) throws -> () = { _, key, box in
oldSelf.container.withShared { container in
container.elements.append(box, at: oldSelf.converted(key).stringValue)
}
}
defer {
self = oldSelf
}
switch strategy(key) {
case .attribute:
try attributeEncoder(value, key, box)
case .element:
try elementEncoder(value, key, box)
case .both:
try attributeEncoder(value, key, box)
try elementEncoder(value, key, box)
}
}
public mutating func nestedContainer<NestedKey>(
keyedBy _: NestedKey.Type,
forKey key: Key
) -> KeyedEncodingContainer<NestedKey> {
if NestedKey.self is XMLChoiceCodingKey.Type {
return nestedChoiceContainer(keyedBy: NestedKey.self, forKey: key)
} else {
return nestedKeyedContainer(keyedBy: NestedKey.self, forKey: key)
}
}
mutating func nestedKeyedContainer<NestedKey>(
keyedBy _: NestedKey.Type,
forKey key: Key
) -> KeyedEncodingContainer<NestedKey> {
let sharedKeyed = SharedBox(KeyedBox())
self.container.withShared { container in
container.elements.append(sharedKeyed, at: converted(key).stringValue)
}
codingPath.append(key)
defer { self.codingPath.removeLast() }
let container = XMLKeyedEncodingContainer<NestedKey>(
referencing: encoder,
codingPath: codingPath,
wrapping: sharedKeyed
)
return KeyedEncodingContainer(container)
}
mutating func nestedChoiceContainer<NestedKey>(
keyedBy _: NestedKey.Type,
forKey key: Key
) -> KeyedEncodingContainer<NestedKey> {
let sharedChoice = SharedBox(ChoiceBox())
self.container.withShared { container in
container.elements.append(sharedChoice, at: converted(key).stringValue)
}
codingPath.append(key)
defer { self.codingPath.removeLast() }
let container = XMLChoiceEncodingContainer<NestedKey>(
referencing: encoder,
codingPath: codingPath,
wrapping: sharedChoice
)
return KeyedEncodingContainer(container)
}
public mutating func nestedUnkeyedContainer(
forKey key: Key
) -> UnkeyedEncodingContainer {
let sharedUnkeyed = SharedBox(UnkeyedBox())
container.withShared { container in
container.elements.append(sharedUnkeyed, at: converted(key).stringValue)
}
codingPath.append(key)
defer { self.codingPath.removeLast() }
return XMLUnkeyedEncodingContainer(
referencing: encoder,
codingPath: codingPath,
wrapping: sharedUnkeyed
)
}
public mutating func superEncoder() -> Encoder {
return XMLReferencingEncoder(
referencing: encoder,
key: XMLKey.super,
convertedKey: converted(XMLKey.super),
wrapping: container
)
}
public mutating func superEncoder(forKey key: Key) -> Encoder {
return XMLReferencingEncoder(
referencing: encoder,
key: key,
convertedKey: converted(key),
wrapping: container
)
}
}
// Copyright (c) 2017-2020 Shawn Moore and XMLCoder contributors
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
//
// Created by Shawn Moore on 11/25/17.
//
import Foundation
/// XMLReferencingEncoder is a special subclass of _XMLEncoder which has its
/// own storage, but references the contents of a different encoder.
/// It's used in superEncoder(), which returns a new encoder for encoding a
// superclass -- the lifetime of the encoder should not escape the scope it's
/// created in, but it doesn't necessarily know when it's done being used
/// (to write to the original container).
class XMLReferencingEncoder: XMLEncoderImplementation {
// MARK: Reference types.
/// The type of container we're referencing.
private enum Reference {
/// Referencing a specific index in an unkeyed container.
case unkeyed(SharedBox<UnkeyedBox>, Int)
/// Referencing a specific key in a keyed container.
case keyed(SharedBox<KeyedBox>, String)
/// Referencing a specific key in a keyed container.
case choice(SharedBox<ChoiceBox>, String)
}
// MARK: - Properties
/// The encoder we're referencing.
let encoder: XMLEncoderImplementation
/// The container reference itself.
private let reference: Reference
// MARK: - Initialization
/// Initializes `self` by referencing the given array container in the given encoder.
init(
referencing encoder: XMLEncoderImplementation,
at index: Int,
wrapping sharedUnkeyed: SharedBox<UnkeyedBox>
) {
self.encoder = encoder
reference = .unkeyed(sharedUnkeyed, index)
super.init(
options: encoder.options,
nodeEncodings: encoder.nodeEncodings,
codingPath: encoder.codingPath
)
codingPath.append(XMLKey(index: index))
}
/// Initializes `self` by referencing the given dictionary container in the given encoder.
init(
referencing encoder: XMLEncoderImplementation,
key: CodingKey,
convertedKey: CodingKey,
wrapping sharedKeyed: SharedBox<KeyedBox>
) {
self.encoder = encoder
reference = .keyed(sharedKeyed, convertedKey.stringValue)
super.init(
options: encoder.options,
nodeEncodings: encoder.nodeEncodings,
codingPath: encoder.codingPath
)
codingPath.append(key)
}
init(
referencing encoder: XMLEncoderImplementation,
key: CodingKey,
convertedKey: CodingKey,
wrapping sharedKeyed: SharedBox<ChoiceBox>
) {
self.encoder = encoder
reference = .choice(sharedKeyed, convertedKey.stringValue)
super.init(
options: encoder.options,
nodeEncodings: encoder.nodeEncodings,
codingPath: encoder.codingPath
)
codingPath.append(key)
}
// MARK: - Coding Path Operations
override var canEncodeNewValue: Bool {
// With a regular encoder, the storage and coding path grow together.
// A referencing encoder, however, inherits its parents coding path, as well as the key it was created for.
// We have to take this into account.
return storage.count == codingPath.count - encoder.codingPath.count - 1
}
// MARK: - Deinitialization
// Finalizes `self` by writing the contents of our storage to the referenced encoder's storage.
deinit {
let box: Box
switch self.storage.count {
case 0: box = KeyedBox()
case 1: box = self.storage.popContainer()
default: fatalError("Referencing encoder deallocated with multiple containers on stack.")
}
switch self.reference {
case let .unkeyed(sharedUnkeyedBox, index):
sharedUnkeyedBox.withShared { unkeyedBox in
unkeyedBox.insert(box, at: index)
}
case let .keyed(sharedKeyedBox, key):
sharedKeyedBox.withShared { keyedBox in
keyedBox.elements.append(box, at: key)
}
case let .choice(sharedChoiceBox, key):
sharedChoiceBox.withShared { choiceBox in
choiceBox.element = box
choiceBox.key = key
}
}
}
}
// Copyright (c) 2018-2020 XMLCoder contributors
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
//
// Created by Vincent Esche on 11/20/18.
//
import Foundation
struct XMLUnkeyedEncodingContainer: UnkeyedEncodingContainer {
// MARK: Properties
/// A reference to the encoder we're writing to.
private let encoder: XMLEncoderImplementation
/// A reference to the container we're writing to.
private let container: SharedBox<UnkeyedBox>
/// The path of coding keys taken to get to this point in encoding.
public private(set) var codingPath: [CodingKey]
/// The number of elements encoded into the container.
public var count: Int {
return container.withShared { $0.count }
}
// MARK: - Initialization
/// Initializes `self` with the given references.
init(
referencing encoder: XMLEncoderImplementation,
codingPath: [CodingKey],
wrapping container: SharedBox<UnkeyedBox>
) {
self.encoder = encoder
self.codingPath = codingPath
self.container = container
}
// MARK: - UnkeyedEncodingContainer Methods
public mutating func encodeNil() throws {
container.withShared { container in
container.append(encoder.box())
}
}
public mutating func encode<T: Encodable>(_ value: T) throws {
try encode(value) { encoder, value in
try encoder.box(value)
}
}
private mutating func encode<T: Encodable>(
_ value: T,
encode: (XMLEncoderImplementation, T) throws -> Box
) rethrows {
encoder.codingPath.append(XMLKey(index: count))
defer { self.encoder.codingPath.removeLast() }
try container.withShared { container in
container.append(try encode(encoder, value))
}
}
public mutating func nestedContainer<NestedKey>(
keyedBy _: NestedKey.Type
) -> KeyedEncodingContainer<NestedKey> {
if NestedKey.self is XMLChoiceCodingKey.Type {
return nestedChoiceContainer(keyedBy: NestedKey.self)
} else {
return nestedKeyedContainer(keyedBy: NestedKey.self)
}
}
public mutating func nestedKeyedContainer<NestedKey>(keyedBy _: NestedKey.Type) -> KeyedEncodingContainer<NestedKey> {
codingPath.append(XMLKey(index: count))
defer { self.codingPath.removeLast() }
let sharedKeyed = SharedBox(KeyedBox())
self.container.withShared { container in
container.append(sharedKeyed)
}
let container = XMLKeyedEncodingContainer<NestedKey>(
referencing: encoder,
codingPath: codingPath,
wrapping: sharedKeyed
)
return KeyedEncodingContainer(container)
}
public mutating func nestedChoiceContainer<NestedKey>(keyedBy _: NestedKey.Type) -> KeyedEncodingContainer<NestedKey> {
codingPath.append(XMLKey(index: count))
defer { self.codingPath.removeLast() }
let sharedChoice = SharedBox(ChoiceBox())
self.container.withShared { container in
container.append(sharedChoice)
}
let container = XMLChoiceEncodingContainer<NestedKey>(
referencing: encoder,
codingPath: codingPath,
wrapping: sharedChoice
)
return KeyedEncodingContainer(container)
}
public mutating func nestedUnkeyedContainer() -> UnkeyedEncodingContainer {
codingPath.append(XMLKey(index: count))
defer { self.codingPath.removeLast() }
let sharedUnkeyed = SharedBox(UnkeyedBox())
container.withShared { container in
container.append(sharedUnkeyed)
}
return XMLUnkeyedEncodingContainer(
referencing: encoder,
codingPath: codingPath,
wrapping: sharedUnkeyed
)
}
public mutating func superEncoder() -> Encoder {
return XMLReferencingEncoder(
referencing: encoder,
at: count,
wrapping: container
)
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment