diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..312d1f6
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,68 @@
+# Xcode
+#
+# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
+
+## Build generated
+build/
+DerivedData/
+
+## Various settings
+*.pbxuser
+!default.pbxuser
+*.mode1v3
+!default.mode1v3
+*.mode2v3
+!default.mode2v3
+*.perspectivev3
+!default.perspectivev3
+xcuserdata/
+
+## Other
+*.moved-aside
+*.xccheckout
+*.xcscmblueprint
+
+## Obj-C/Swift specific
+*.hmap
+*.ipa
+*.dSYM.zip
+*.dSYM
+
+## Playgrounds
+timeline.xctimeline
+playground.xcworkspace
+
+# Swift Package Manager
+#
+# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
+# Packages/
+# Package.pins
+# Package.resolved
+.build/
+
+# CocoaPods
+#
+# We recommend against adding the Pods directory to your .gitignore. However
+# you should judge for yourself, the pros and cons are mentioned at:
+# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
+#
+# Pods/
+
+# Carthage
+#
+# Add this line if you want to avoid checking in source code from Carthage dependencies.
+# Carthage/Checkouts
+
+Carthage/Build
+
+# fastlane
+#
+# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
+# screenshots whenever they are needed.
+# For more information about the recommended setup visit:
+# https://docs.fastlane.tools/best-practices/source-control/#source-control
+
+fastlane/report.xml
+fastlane/Preview.html
+fastlane/screenshots/**/*.png
+fastlane/test_output
diff --git a/JSONFragmentDecoding.xcodeproj/JSONFragmentDecodingTests_Info.plist b/JSONFragmentDecoding.xcodeproj/JSONFragmentDecodingTests_Info.plist
new file mode 100644
index 0000000..7c23420
--- /dev/null
+++ b/JSONFragmentDecoding.xcodeproj/JSONFragmentDecodingTests_Info.plist
@@ -0,0 +1,25 @@
+
+
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ BNDL
+ CFBundleShortVersionString
+ 1.0
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ $(CURRENT_PROJECT_VERSION)
+ NSPrincipalClass
+
+
+
diff --git a/JSONFragmentDecoding.xcodeproj/JSONFragmentDecoding_Info.plist b/JSONFragmentDecoding.xcodeproj/JSONFragmentDecoding_Info.plist
new file mode 100644
index 0000000..57ada9f
--- /dev/null
+++ b/JSONFragmentDecoding.xcodeproj/JSONFragmentDecoding_Info.plist
@@ -0,0 +1,25 @@
+
+
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ FMWK
+ CFBundleShortVersionString
+ 1.0
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ $(CURRENT_PROJECT_VERSION)
+ NSPrincipalClass
+
+
+
diff --git a/JSONFragmentDecoding.xcodeproj/project.pbxproj b/JSONFragmentDecoding.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..4e258d1
--- /dev/null
+++ b/JSONFragmentDecoding.xcodeproj/project.pbxproj
@@ -0,0 +1,537 @@
+// !$*UTF8*$!
+{
+ archiveVersion = "1";
+ objectVersion = "46";
+ objects = {
+ "JSONFragmentDecoding::JSONFragmentDecoding" = {
+ isa = "PBXNativeTarget";
+ buildConfigurationList = "OBJ_18";
+ buildPhases = (
+ "OBJ_21",
+ "OBJ_23"
+ );
+ dependencies = (
+ );
+ name = "JSONFragmentDecoding";
+ productName = "JSONFragmentDecoding";
+ productReference = "JSONFragmentDecoding::JSONFragmentDecoding::Product";
+ productType = "com.apple.product-type.framework";
+ };
+ "JSONFragmentDecoding::JSONFragmentDecoding::Product" = {
+ isa = "PBXFileReference";
+ path = "JSONFragmentDecoding.framework";
+ sourceTree = "BUILT_PRODUCTS_DIR";
+ };
+ "JSONFragmentDecoding::JSONFragmentDecodingPackageTests::ProductTarget" = {
+ isa = "PBXAggregateTarget";
+ buildConfigurationList = "OBJ_31";
+ buildPhases = (
+ );
+ dependencies = (
+ "OBJ_34"
+ );
+ name = "JSONFragmentDecodingPackageTests";
+ productName = "JSONFragmentDecodingPackageTests";
+ };
+ "JSONFragmentDecoding::JSONFragmentDecodingTests" = {
+ isa = "PBXNativeTarget";
+ buildConfigurationList = "OBJ_36";
+ buildPhases = (
+ "OBJ_39",
+ "OBJ_42"
+ );
+ dependencies = (
+ "OBJ_44"
+ );
+ name = "JSONFragmentDecodingTests";
+ productName = "JSONFragmentDecodingTests";
+ productReference = "JSONFragmentDecoding::JSONFragmentDecodingTests::Product";
+ productType = "com.apple.product-type.bundle.unit-test";
+ };
+ "JSONFragmentDecoding::JSONFragmentDecodingTests::Product" = {
+ isa = "PBXFileReference";
+ path = "JSONFragmentDecodingTests.xctest";
+ sourceTree = "BUILT_PRODUCTS_DIR";
+ };
+ "JSONFragmentDecoding::SwiftPMPackageDescription" = {
+ isa = "PBXNativeTarget";
+ buildConfigurationList = "OBJ_25";
+ buildPhases = (
+ "OBJ_28"
+ );
+ dependencies = (
+ );
+ name = "JSONFragmentDecodingPackageDescription";
+ productName = "JSONFragmentDecodingPackageDescription";
+ productType = "com.apple.product-type.framework";
+ };
+ "OBJ_1" = {
+ isa = "PBXProject";
+ attributes = {
+ LastUpgradeCheck = "9999";
+ };
+ buildConfigurationList = "OBJ_2";
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = "English";
+ hasScannedForEncodings = "0";
+ knownRegions = (
+ "en"
+ );
+ mainGroup = "OBJ_5";
+ productRefGroup = "OBJ_14";
+ projectDirPath = ".";
+ targets = (
+ "JSONFragmentDecoding::JSONFragmentDecoding",
+ "JSONFragmentDecoding::SwiftPMPackageDescription",
+ "JSONFragmentDecoding::JSONFragmentDecodingPackageTests::ProductTarget",
+ "JSONFragmentDecoding::JSONFragmentDecodingTests"
+ );
+ };
+ "OBJ_10" = {
+ isa = "PBXGroup";
+ children = (
+ "OBJ_11"
+ );
+ name = "Tests";
+ path = "";
+ sourceTree = "SOURCE_ROOT";
+ };
+ "OBJ_11" = {
+ isa = "PBXGroup";
+ children = (
+ "OBJ_12",
+ "OBJ_13"
+ );
+ name = "JSONFragmentDecodingTests";
+ path = "Tests/JSONFragmentDecodingTests";
+ sourceTree = "SOURCE_ROOT";
+ };
+ "OBJ_12" = {
+ isa = "PBXFileReference";
+ path = "JSONFragmentDecodingTests.swift";
+ sourceTree = "";
+ };
+ "OBJ_13" = {
+ isa = "PBXFileReference";
+ path = "XCTestManifests.swift";
+ sourceTree = "";
+ };
+ "OBJ_14" = {
+ isa = "PBXGroup";
+ children = (
+ "JSONFragmentDecoding::JSONFragmentDecoding::Product",
+ "JSONFragmentDecoding::JSONFragmentDecodingTests::Product"
+ );
+ name = "Products";
+ path = "";
+ sourceTree = "BUILT_PRODUCTS_DIR";
+ };
+ "OBJ_18" = {
+ isa = "XCConfigurationList";
+ buildConfigurations = (
+ "OBJ_19",
+ "OBJ_20"
+ );
+ defaultConfigurationIsVisible = "0";
+ defaultConfigurationName = "Release";
+ };
+ "OBJ_19" = {
+ isa = "XCBuildConfiguration";
+ buildSettings = {
+ ENABLE_TESTABILITY = "YES";
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(PLATFORM_DIR)/Developer/Library/Frameworks"
+ );
+ HEADER_SEARCH_PATHS = (
+ "$(inherited)"
+ );
+ INFOPLIST_FILE = "JSONFragmentDecoding.xcodeproj/JSONFragmentDecoding_Info.plist";
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(TOOLCHAIN_DIR)/usr/lib/swift/macosx"
+ );
+ OTHER_CFLAGS = (
+ "$(inherited)"
+ );
+ OTHER_LDFLAGS = (
+ "$(inherited)"
+ );
+ OTHER_SWIFT_FLAGS = (
+ "$(inherited)"
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = "JSONFragmentDecoding";
+ PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)";
+ PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
+ SKIP_INSTALL = "YES";
+ SWIFT_ACTIVE_COMPILATION_CONDITIONS = (
+ "$(inherited)"
+ );
+ SWIFT_VERSION = "4.2";
+ TARGET_NAME = "JSONFragmentDecoding";
+ };
+ name = "Debug";
+ };
+ "OBJ_2" = {
+ isa = "XCConfigurationList";
+ buildConfigurations = (
+ "OBJ_3",
+ "OBJ_4"
+ );
+ defaultConfigurationIsVisible = "0";
+ defaultConfigurationName = "Release";
+ };
+ "OBJ_20" = {
+ isa = "XCBuildConfiguration";
+ buildSettings = {
+ ENABLE_TESTABILITY = "YES";
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(PLATFORM_DIR)/Developer/Library/Frameworks"
+ );
+ HEADER_SEARCH_PATHS = (
+ "$(inherited)"
+ );
+ INFOPLIST_FILE = "JSONFragmentDecoding.xcodeproj/JSONFragmentDecoding_Info.plist";
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(TOOLCHAIN_DIR)/usr/lib/swift/macosx"
+ );
+ OTHER_CFLAGS = (
+ "$(inherited)"
+ );
+ OTHER_LDFLAGS = (
+ "$(inherited)"
+ );
+ OTHER_SWIFT_FLAGS = (
+ "$(inherited)"
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = "JSONFragmentDecoding";
+ PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)";
+ PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
+ SKIP_INSTALL = "YES";
+ SWIFT_ACTIVE_COMPILATION_CONDITIONS = (
+ "$(inherited)"
+ );
+ SWIFT_VERSION = "4.2";
+ TARGET_NAME = "JSONFragmentDecoding";
+ };
+ name = "Release";
+ };
+ "OBJ_21" = {
+ isa = "PBXSourcesBuildPhase";
+ files = (
+ "OBJ_22"
+ );
+ };
+ "OBJ_22" = {
+ isa = "PBXBuildFile";
+ fileRef = "OBJ_9";
+ };
+ "OBJ_23" = {
+ isa = "PBXFrameworksBuildPhase";
+ files = (
+ );
+ };
+ "OBJ_25" = {
+ isa = "XCConfigurationList";
+ buildConfigurations = (
+ "OBJ_26",
+ "OBJ_27"
+ );
+ defaultConfigurationIsVisible = "0";
+ defaultConfigurationName = "Release";
+ };
+ "OBJ_26" = {
+ isa = "XCBuildConfiguration";
+ buildSettings = {
+ LD = "/usr/bin/true";
+ OTHER_SWIFT_FLAGS = (
+ "-swift-version",
+ "4.2",
+ "-I",
+ "$(TOOLCHAIN_DIR)/usr/lib/swift/pm/4_2",
+ "-target",
+ "x86_64-apple-macosx10.10",
+ "-sdk",
+ "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk"
+ );
+ SWIFT_VERSION = "4.2";
+ };
+ name = "Debug";
+ };
+ "OBJ_27" = {
+ isa = "XCBuildConfiguration";
+ buildSettings = {
+ LD = "/usr/bin/true";
+ OTHER_SWIFT_FLAGS = (
+ "-swift-version",
+ "4.2",
+ "-I",
+ "$(TOOLCHAIN_DIR)/usr/lib/swift/pm/4_2",
+ "-target",
+ "x86_64-apple-macosx10.10",
+ "-sdk",
+ "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk"
+ );
+ SWIFT_VERSION = "4.2";
+ };
+ name = "Release";
+ };
+ "OBJ_28" = {
+ isa = "PBXSourcesBuildPhase";
+ files = (
+ "OBJ_29"
+ );
+ };
+ "OBJ_29" = {
+ isa = "PBXBuildFile";
+ fileRef = "OBJ_6";
+ };
+ "OBJ_3" = {
+ isa = "XCBuildConfiguration";
+ buildSettings = {
+ CLANG_ENABLE_OBJC_ARC = "YES";
+ COMBINE_HIDPI_IMAGES = "YES";
+ COPY_PHASE_STRIP = "NO";
+ DEBUG_INFORMATION_FORMAT = "dwarf";
+ DYLIB_INSTALL_NAME_BASE = "@rpath";
+ ENABLE_NS_ASSERTIONS = "YES";
+ GCC_OPTIMIZATION_LEVEL = "0";
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)"
+ );
+ MACOSX_DEPLOYMENT_TARGET = "10.10";
+ ONLY_ACTIVE_ARCH = "YES";
+ OTHER_SWIFT_FLAGS = (
+ "-DXcode"
+ );
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = "macosx";
+ SUPPORTED_PLATFORMS = (
+ "macosx",
+ "iphoneos",
+ "iphonesimulator",
+ "appletvos",
+ "appletvsimulator",
+ "watchos",
+ "watchsimulator"
+ );
+ SWIFT_ACTIVE_COMPILATION_CONDITIONS = (
+ "SWIFT_PACKAGE",
+ "DEBUG"
+ );
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ USE_HEADERMAP = "NO";
+ };
+ name = "Debug";
+ };
+ "OBJ_31" = {
+ isa = "XCConfigurationList";
+ buildConfigurations = (
+ "OBJ_32",
+ "OBJ_33"
+ );
+ defaultConfigurationIsVisible = "0";
+ defaultConfigurationName = "Release";
+ };
+ "OBJ_32" = {
+ isa = "XCBuildConfiguration";
+ buildSettings = {
+ };
+ name = "Debug";
+ };
+ "OBJ_33" = {
+ isa = "XCBuildConfiguration";
+ buildSettings = {
+ };
+ name = "Release";
+ };
+ "OBJ_34" = {
+ isa = "PBXTargetDependency";
+ target = "JSONFragmentDecoding::JSONFragmentDecodingTests";
+ };
+ "OBJ_36" = {
+ isa = "XCConfigurationList";
+ buildConfigurations = (
+ "OBJ_37",
+ "OBJ_38"
+ );
+ defaultConfigurationIsVisible = "0";
+ defaultConfigurationName = "Release";
+ };
+ "OBJ_37" = {
+ isa = "XCBuildConfiguration";
+ buildSettings = {
+ CLANG_ENABLE_MODULES = "YES";
+ EMBEDDED_CONTENT_CONTAINS_SWIFT = "YES";
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(PLATFORM_DIR)/Developer/Library/Frameworks"
+ );
+ HEADER_SEARCH_PATHS = (
+ "$(inherited)"
+ );
+ INFOPLIST_FILE = "JSONFragmentDecoding.xcodeproj/JSONFragmentDecodingTests_Info.plist";
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@loader_path/../Frameworks",
+ "@loader_path/Frameworks"
+ );
+ OTHER_CFLAGS = (
+ "$(inherited)"
+ );
+ OTHER_LDFLAGS = (
+ "$(inherited)"
+ );
+ OTHER_SWIFT_FLAGS = (
+ "$(inherited)"
+ );
+ SWIFT_ACTIVE_COMPILATION_CONDITIONS = (
+ "$(inherited)"
+ );
+ SWIFT_VERSION = "4.2";
+ TARGET_NAME = "JSONFragmentDecodingTests";
+ };
+ name = "Debug";
+ };
+ "OBJ_38" = {
+ isa = "XCBuildConfiguration";
+ buildSettings = {
+ CLANG_ENABLE_MODULES = "YES";
+ EMBEDDED_CONTENT_CONTAINS_SWIFT = "YES";
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(PLATFORM_DIR)/Developer/Library/Frameworks"
+ );
+ HEADER_SEARCH_PATHS = (
+ "$(inherited)"
+ );
+ INFOPLIST_FILE = "JSONFragmentDecoding.xcodeproj/JSONFragmentDecodingTests_Info.plist";
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@loader_path/../Frameworks",
+ "@loader_path/Frameworks"
+ );
+ OTHER_CFLAGS = (
+ "$(inherited)"
+ );
+ OTHER_LDFLAGS = (
+ "$(inherited)"
+ );
+ OTHER_SWIFT_FLAGS = (
+ "$(inherited)"
+ );
+ SWIFT_ACTIVE_COMPILATION_CONDITIONS = (
+ "$(inherited)"
+ );
+ SWIFT_VERSION = "4.2";
+ TARGET_NAME = "JSONFragmentDecodingTests";
+ };
+ name = "Release";
+ };
+ "OBJ_39" = {
+ isa = "PBXSourcesBuildPhase";
+ files = (
+ "OBJ_40",
+ "OBJ_41"
+ );
+ };
+ "OBJ_4" = {
+ isa = "XCBuildConfiguration";
+ buildSettings = {
+ CLANG_ENABLE_OBJC_ARC = "YES";
+ COMBINE_HIDPI_IMAGES = "YES";
+ COPY_PHASE_STRIP = "YES";
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ DYLIB_INSTALL_NAME_BASE = "@rpath";
+ GCC_OPTIMIZATION_LEVEL = "s";
+ MACOSX_DEPLOYMENT_TARGET = "10.10";
+ OTHER_SWIFT_FLAGS = (
+ "-DXcode"
+ );
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = "macosx";
+ SUPPORTED_PLATFORMS = (
+ "macosx",
+ "iphoneos",
+ "iphonesimulator",
+ "appletvos",
+ "appletvsimulator",
+ "watchos",
+ "watchsimulator"
+ );
+ SWIFT_ACTIVE_COMPILATION_CONDITIONS = (
+ "SWIFT_PACKAGE"
+ );
+ SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
+ USE_HEADERMAP = "NO";
+ };
+ name = "Release";
+ };
+ "OBJ_40" = {
+ isa = "PBXBuildFile";
+ fileRef = "OBJ_12";
+ };
+ "OBJ_41" = {
+ isa = "PBXBuildFile";
+ fileRef = "OBJ_13";
+ };
+ "OBJ_42" = {
+ isa = "PBXFrameworksBuildPhase";
+ files = (
+ "OBJ_43"
+ );
+ };
+ "OBJ_43" = {
+ isa = "PBXBuildFile";
+ fileRef = "JSONFragmentDecoding::JSONFragmentDecoding::Product";
+ };
+ "OBJ_44" = {
+ isa = "PBXTargetDependency";
+ target = "JSONFragmentDecoding::JSONFragmentDecoding";
+ };
+ "OBJ_5" = {
+ isa = "PBXGroup";
+ children = (
+ "OBJ_6",
+ "OBJ_7",
+ "OBJ_10",
+ "OBJ_14"
+ );
+ path = "";
+ sourceTree = "";
+ };
+ "OBJ_6" = {
+ isa = "PBXFileReference";
+ explicitFileType = "sourcecode.swift";
+ path = "Package.swift";
+ sourceTree = "";
+ };
+ "OBJ_7" = {
+ isa = "PBXGroup";
+ children = (
+ "OBJ_8"
+ );
+ name = "Sources";
+ path = "";
+ sourceTree = "SOURCE_ROOT";
+ };
+ "OBJ_8" = {
+ isa = "PBXGroup";
+ children = (
+ "OBJ_9"
+ );
+ name = "JSONFragmentDecoding";
+ path = "Sources/JSONFragmentDecoding";
+ sourceTree = "SOURCE_ROOT";
+ };
+ "OBJ_9" = {
+ isa = "PBXFileReference";
+ path = "JSONFragmentDecoding.swift";
+ sourceTree = "";
+ };
+ };
+ rootObject = "OBJ_1";
+}
diff --git a/JSONFragmentDecoding.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/JSONFragmentDecoding.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..fe1aa71
--- /dev/null
+++ b/JSONFragmentDecoding.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/JSONFragmentDecoding.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/JSONFragmentDecoding.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
new file mode 100644
index 0000000..18d9810
--- /dev/null
+++ b/JSONFragmentDecoding.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
@@ -0,0 +1,8 @@
+
+
+
+
+ IDEDidComputeMac32BitWarning
+
+
+
diff --git a/JSONFragmentDecoding.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/JSONFragmentDecoding.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
new file mode 100644
index 0000000..a72dc2b
--- /dev/null
+++ b/JSONFragmentDecoding.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
@@ -0,0 +1,8 @@
+
+
+
+
+ IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded
+
+
+
\ No newline at end of file
diff --git a/JSONFragmentDecoding.xcodeproj/xcshareddata/xcschemes/JSONFragmentDecoding-Package.xcscheme b/JSONFragmentDecoding.xcodeproj/xcshareddata/xcschemes/JSONFragmentDecoding-Package.xcscheme
new file mode 100644
index 0000000..1d9df0a
--- /dev/null
+++ b/JSONFragmentDecoding.xcodeproj/xcshareddata/xcschemes/JSONFragmentDecoding-Package.xcscheme
@@ -0,0 +1,81 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/JSONFragmentDecoding.xcodeproj/xcshareddata/xcschemes/JSONFragmentDecoding.xcscheme b/JSONFragmentDecoding.xcodeproj/xcshareddata/xcschemes/JSONFragmentDecoding.xcscheme
new file mode 100644
index 0000000..938e4a8
--- /dev/null
+++ b/JSONFragmentDecoding.xcodeproj/xcshareddata/xcschemes/JSONFragmentDecoding.xcscheme
@@ -0,0 +1,80 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/JSONFragmentDecoding.xcodeproj/xcshareddata/xcschemes/JSONFragmentDecodingTests.xcscheme b/JSONFragmentDecoding.xcodeproj/xcshareddata/xcschemes/JSONFragmentDecodingTests.xcscheme
new file mode 100644
index 0000000..2b878a6
--- /dev/null
+++ b/JSONFragmentDecoding.xcodeproj/xcshareddata/xcschemes/JSONFragmentDecodingTests.xcscheme
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..a0f93b7
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2018 Hamish Knight
+
+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.
diff --git a/Package.swift b/Package.swift
new file mode 100644
index 0000000..30113a2
--- /dev/null
+++ b/Package.swift
@@ -0,0 +1,26 @@
+// swift-tools-version:4.0
+
+import PackageDescription
+
+let package = Package(
+ name: "JSONFragmentDecoding",
+ products: [
+ .library(
+ name: "JSONFragmentDecoding",
+ targets: ["JSONFragmentDecoding"]
+ ),
+ ],
+ dependencies: [
+
+ ],
+ targets: [
+ .target(
+ name: "JSONFragmentDecoding",
+ dependencies: []
+ ),
+ .testTarget(
+ name: "JSONFragmentDecodingTests",
+ dependencies: ["JSONFragmentDecoding"]
+ ),
+ ]
+)
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..c714887
--- /dev/null
+++ b/README.md
@@ -0,0 +1,2 @@
+# JSONFragmentDecoding
+A JSONDecoder extension to allow decoding JSON fragments
diff --git a/Sources/JSONFragmentDecoding/JSONFragmentDecoding.swift b/Sources/JSONFragmentDecoding/JSONFragmentDecoding.swift
new file mode 100644
index 0000000..0a0d3bc
--- /dev/null
+++ b/Sources/JSONFragmentDecoding/JSONFragmentDecoding.swift
@@ -0,0 +1,78 @@
+
+import Foundation
+
+fileprivate extension CodingUserInfoKey {
+ static let fragmentBoxedType = CodingUserInfoKey(
+ rawValue: "CodingUserInfoKey.fragmentBoxedType"
+ )!
+}
+
+fileprivate extension Decodable {
+ static func __decode(
+ from container: inout UnkeyedDecodingContainer
+ ) throws -> Self {
+ return try container.decode(self)
+ }
+}
+
+extension JSONDecoder {
+ private struct FragmentDecodingBox : Decodable {
+ var value: T
+ init(from decoder: Decoder) throws {
+ let type = decoder.userInfo[.fragmentBoxedType] as! T.Type
+ var container = try decoder.unkeyedContainer()
+ self.value = try type.__decode(from: &container)
+ }
+ }
+
+ private func copy() -> JSONDecoder {
+ let decoder = JSONDecoder()
+ decoder.dataDecodingStrategy = dataDecodingStrategy
+ decoder.dateDecodingStrategy = dateDecodingStrategy
+ decoder.keyDecodingStrategy = keyDecodingStrategy
+ decoder.nonConformingFloatDecodingStrategy = nonConformingFloatDecodingStrategy
+ decoder.userInfo = userInfo
+ return decoder
+ }
+
+ public func decode(
+ _ type: T.Type, from data: Data, allowFragments: Bool
+ ) throws -> T {
+ // If we're not allowing fragments, just delegate to decode(_:from:).
+ guard allowFragments else { return try decode(type, from: data) }
+
+ // Box the JSON object in an array so we can pass it off to JSONDecoder.
+ // The round-tripping through JSONSerialization isn't ideal, but it
+ // ensures we do The Right Thing regardless of the encoding of `data`.
+ let jsonObject = try JSONSerialization
+ .jsonObject(with: data, options: .allowFragments)
+ let boxedData = try JSONSerialization.data(withJSONObject: [jsonObject])
+
+ // Copy the decoder so we can mutate the userInfo without having to worry
+ // about data races.
+ let decoder = copy()
+ decoder.userInfo[.fragmentBoxedType] = type
+
+ // Use FragmentDecodingBox to decode the underlying fragment from the
+ // array.
+ //
+ // We're intentionally *not* doing `decode([T].self, ...)` here, as
+ // that loses the dynamic type passed – breaking things like:
+ //
+ // class C : Decodable {}
+ // class D {}
+ //
+ // let type: C.Type = D.self
+ // let data = ...
+ // let decoded = try JSONDecoder().decode(type, from: data, allowFragments: true)
+ //
+ // The above would decode a `C` instead of a `D` if we didn't preserve
+ // the dynamic type.
+ //
+ // (Admittedly this is a bit of contrived example, as by default such types
+ // would decode using keyed containers and therefore not be fragments –
+ // nontheless it is possible for them to implement their decoding such that
+ // they use a single value container).
+ return try decoder.decode(FragmentDecodingBox.self, from: boxedData).value
+ }
+}
diff --git a/Tests/JSONFragmentDecodingTests/JSONFragmentDecodingTests.swift b/Tests/JSONFragmentDecodingTests/JSONFragmentDecodingTests.swift
new file mode 100644
index 0000000..32a6025
--- /dev/null
+++ b/Tests/JSONFragmentDecodingTests/JSONFragmentDecodingTests.swift
@@ -0,0 +1,68 @@
+
+import XCTest
+@testable import JSONFragmentDecoding
+
+func XCTAssertEqual(
+ _ expected: Any.Type, _ actual: Any.Type,
+ file: StaticString = #file, line: UInt = #line) {
+ XCTAssert(
+ expected == actual, "incorrect type \(actual), expected \(expected)",
+ file: file, line: line
+ )
+}
+
+final class JSONFragmentDecodingTests : XCTestCase {
+
+ func testFragmentDecoding() throws {
+
+ XCTAssertEqual(10, try JSONDecoder()
+ .decode(Int.self, from: Data("10".utf8), allowFragments: true))
+
+ XCTAssertEqual("10", try JSONDecoder()
+ .decode(String.self, from: Data("\"10\"".utf8), allowFragments: true))
+ }
+
+ func testExoticFragmentDecoding() throws {
+
+ class C : Decodable {
+ var i: Int
+ required init(from decoder: Decoder) throws {
+ let container = try decoder.singleValueContainer()
+ self.i = try container.decode(Int.self)
+ }
+ }
+ class D : C {}
+
+ let metatype: C.Type = D.self
+ let data = "10".data(using: .utf32BigEndian)!
+ let decoded = try JSONDecoder()
+ .decode(metatype, from: data, allowFragments: true)
+
+ XCTAssertEqual(D.self, type(of: decoded))
+ XCTAssertEqual(10, decoded.i)
+ }
+
+ func testFloatStrategyDecoding() throws {
+ let decoder = JSONDecoder()
+ decoder.nonConformingFloatDecodingStrategy = .convertFromString(
+ positiveInfinity: "inf", negativeInfinity: "-inf", nan: "nan"
+ )
+
+ let decodedInf = try decoder
+ .decode(Double.self, from: Data("\"inf\"".utf8), allowFragments: true)
+ XCTAssertEqual(.infinity, decodedInf)
+
+ let decodedNegInf = try decoder
+ .decode(Double.self, from: Data("\"-inf\"".utf8), allowFragments: true)
+ XCTAssertEqual(-.infinity, decodedNegInf)
+
+ let decodedNan = try decoder
+ .decode(Double.self, from: Data("\"nan\"".utf8), allowFragments: true)
+ XCTAssert(decodedNan.isNaN)
+ }
+
+ static var allTests = [
+ ("testFragmentDecoding", testFragmentDecoding),
+ ("testExoticFragmentDecoding", testExoticFragmentDecoding)
+ ]
+}
diff --git a/Tests/JSONFragmentDecodingTests/XCTestManifests.swift b/Tests/JSONFragmentDecodingTests/XCTestManifests.swift
new file mode 100644
index 0000000..9b4199c
--- /dev/null
+++ b/Tests/JSONFragmentDecodingTests/XCTestManifests.swift
@@ -0,0 +1,9 @@
+import XCTest
+
+#if !os(macOS)
+public func allTests() -> [XCTestCaseEntry] {
+ return [
+ testCase(JSONFragmentDecodingTests.allTests),
+ ]
+}
+#endif
diff --git a/Tests/LinuxMain.swift b/Tests/LinuxMain.swift
new file mode 100644
index 0000000..f237bbb
--- /dev/null
+++ b/Tests/LinuxMain.swift
@@ -0,0 +1,7 @@
+import XCTest
+
+import JSONFragmentDecodingTests
+
+var tests = [XCTestCaseEntry]()
+tests += JSONFragmentDecodingTests.allTests()
+XCTMain(tests)
\ No newline at end of file