From a798ae07615cb5dec4c773c3c5936c47822d5d3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lison=20Fernandes?= Date: Mon, 6 Jan 2025 21:59:54 +0000 Subject: [PATCH] [PM-7014] Track MessagePack fork and turn off CI / recurring workflows (#3456) * Remove messagepack submodule * Migrate MessagePack fork to this repo * Disable build CI * Disable Renovate * Disable Crowdin recurring job * Address workflow linter errors --- .github/renovate.json | 1 + .github/workflows/build-beta.yml | 18 +- .github/workflows/build.yml | 54 +- .github/workflows/crowdin-pull.yml | 2 - .github/workflows/pr-labeler.yml | 3 +- .gitignore | 16 +- .gitmodules | 3 - lib/MessagePack | 1 - lib/MessagePack/LICENSE.md | 19 + .../MessagePack-FlightSchool.podspec | 32 ++ .../MessagePack.playground/Contents.swift | 13 + .../contents.xcplayground | 4 + .../MessagePackTests_Info.plist | 25 + .../MessagePack_Info.plist | 25 + .../MessagePack.xcodeproj/project.pbxproj | 543 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/WorkspaceSettings.xcsettings | 8 + .../xcschemes/MessagePack.xcscheme | 99 ++++ .../contents.xcworkspacedata | 10 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/WorkspaceSettings.xcsettings | 8 + lib/MessagePack/Package.swift | 28 + lib/MessagePack/README.md | 87 +++ .../Sources/MessagePack/AnyCodingKey.swift | 28 + lib/MessagePack/Sources/MessagePack/Box.swift | 44 ++ .../Sources/MessagePack/DataSpec.swift | 60 ++ .../Decoder/KeyedDecodingContainer.swift | 178 ++++++ .../Decoder/MessagePackDecoder.swift | 168 ++++++ .../SingleValueDecodingContainer.swift | 226 ++++++++ .../Decoder/UnkeyedDecodingContainer.swift | 235 ++++++++ .../Encoder/KeyedEncodingContainer.swift | 90 +++ .../Encoder/MessagePackEncoder.swift | 99 ++++ .../SingleValueEncodingContainer.swift | 264 +++++++++ .../Encoder/UnkeyedEncodingContainer.swift | 88 +++ .../MessagePack/FixedWidthInteger+Bytes.swift | 20 + lib/MessagePack/Tests/LinuxMain.swift | 8 + .../Tests/MessagePackTests/Airport.swift | 63 ++ .../MessagePackDecodingTests.swift | 301 ++++++++++ .../MessagePackEncodingTests.swift | 127 ++++ .../MessagePackPerformanceTests.swift | 23 + .../MessagePackRoundTripTests.swift | 106 ++++ 42 files changed, 3093 insertions(+), 57 deletions(-) delete mode 100644 .gitmodules delete mode 160000 lib/MessagePack create mode 100644 lib/MessagePack/LICENSE.md create mode 100644 lib/MessagePack/MessagePack-FlightSchool.podspec create mode 100644 lib/MessagePack/MessagePack.playground/Contents.swift create mode 100644 lib/MessagePack/MessagePack.playground/contents.xcplayground create mode 100644 lib/MessagePack/MessagePack.xcodeproj/MessagePackTests_Info.plist create mode 100644 lib/MessagePack/MessagePack.xcodeproj/MessagePack_Info.plist create mode 100644 lib/MessagePack/MessagePack.xcodeproj/project.pbxproj create mode 100644 lib/MessagePack/MessagePack.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 lib/MessagePack/MessagePack.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 lib/MessagePack/MessagePack.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 lib/MessagePack/MessagePack.xcodeproj/xcshareddata/xcschemes/MessagePack.xcscheme create mode 100644 lib/MessagePack/MessagePack.xcworkspace/contents.xcworkspacedata create mode 100644 lib/MessagePack/MessagePack.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 lib/MessagePack/MessagePack.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 lib/MessagePack/Package.swift create mode 100644 lib/MessagePack/README.md create mode 100644 lib/MessagePack/Sources/MessagePack/AnyCodingKey.swift create mode 100644 lib/MessagePack/Sources/MessagePack/Box.swift create mode 100644 lib/MessagePack/Sources/MessagePack/DataSpec.swift create mode 100644 lib/MessagePack/Sources/MessagePack/Decoder/KeyedDecodingContainer.swift create mode 100644 lib/MessagePack/Sources/MessagePack/Decoder/MessagePackDecoder.swift create mode 100644 lib/MessagePack/Sources/MessagePack/Decoder/SingleValueDecodingContainer.swift create mode 100644 lib/MessagePack/Sources/MessagePack/Decoder/UnkeyedDecodingContainer.swift create mode 100644 lib/MessagePack/Sources/MessagePack/Encoder/KeyedEncodingContainer.swift create mode 100644 lib/MessagePack/Sources/MessagePack/Encoder/MessagePackEncoder.swift create mode 100644 lib/MessagePack/Sources/MessagePack/Encoder/SingleValueEncodingContainer.swift create mode 100644 lib/MessagePack/Sources/MessagePack/Encoder/UnkeyedEncodingContainer.swift create mode 100644 lib/MessagePack/Sources/MessagePack/FixedWidthInteger+Bytes.swift create mode 100644 lib/MessagePack/Tests/LinuxMain.swift create mode 100644 lib/MessagePack/Tests/MessagePackTests/Airport.swift create mode 100644 lib/MessagePack/Tests/MessagePackTests/MessagePackDecodingTests.swift create mode 100644 lib/MessagePack/Tests/MessagePackTests/MessagePackEncodingTests.swift create mode 100644 lib/MessagePack/Tests/MessagePackTests/MessagePackPerformanceTests.swift create mode 100644 lib/MessagePack/Tests/MessagePackTests/MessagePackRoundTripTests.swift diff --git a/.github/renovate.json b/.github/renovate.json index 2f6fafa4a..1b76b5967 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -1,4 +1,5 @@ { + "enabled": false, "$schema": "https://docs.renovatebot.com/renovate-schema.json", "extends": [ "config:base", diff --git a/.github/workflows/build-beta.yml b/.github/workflows/build-beta.yml index 2d6981739..5e70a4aff 100644 --- a/.github/workflows/build-beta.yml +++ b/.github/workflows/build-beta.yml @@ -47,9 +47,9 @@ jobs: runs-on: macos-14 needs: setup env: - ios_folder_path: src/App/Platforms/iOS - app_output_name: App - app_ci_output_filename: App_x64_Debug + _IOS_FOLDER_PATH: src/App/Platforms/iOS + _APP_OUTPUT_NAME: App + _APP_CI_OUTPUT_FILENAME: App_x64_Debug steps: - name: Set XCode version uses: maxim-lobanov/setup-xcode@60606e260d2fc5762a71e64e74b2174e8ea3c8bd # v1.6.0 @@ -135,7 +135,7 @@ jobs: echo "### CFBundleVersion $BUILD_NUMBER" >> $GITHUB_STEP_SUMMARY - perl -0777 -pi.bak -e 's/CFBundleVersion<\/key>\s*1<\/string>/CFBundleVersion<\/key>\n\t'"$BUILD_NUMBER"'<\/string>/' ./${{ env.ios_folder_path }}/Info.plist + perl -0777 -pi.bak -e 's/CFBundleVersion<\/key>\s*1<\/string>/CFBundleVersion<\/key>\n\t'"$BUILD_NUMBER"'<\/string>/' ./${{ env._IOS_FOLDER_PATH }}/Info.plist perl -0777 -pi.bak -e 's/CFBundleVersion<\/key>\s*1<\/string>/CFBundleVersion<\/key>\n\t'"$BUILD_NUMBER"'<\/string>/' ./src/iOS.Extension/Info.plist perl -0777 -pi.bak -e 's/CFBundleVersion<\/key>\s*1<\/string>/CFBundleVersion<\/key>\n\t'"$BUILD_NUMBER"'<\/string>/' ./src/iOS.Autofill/Info.plist perl -0777 -pi.bak -e 's/CFBundleVersion<\/key>\s*1<\/string>/CFBundleVersion<\/key>\n\t'"$BUILD_NUMBER"'<\/string>/' ./src/iOS.ShareExtension/Info.plist @@ -145,7 +145,7 @@ jobs: - name: Update Entitlements run: | echo "##### Updating Entitlements" - perl -0777 -pi.bak -e 's/aps-environment<\/key>\s*development<\/string>/aps-environment<\/key>\n\tbeta<\/string>/' ./${{ env.ios_folder_path }}/Entitlements.plist + perl -0777 -pi.bak -e 's/aps-environment<\/key>\s*development<\/string>/aps-environment<\/key>\n\tbeta<\/string>/' ./${{ env._IOS_FOLDER_PATH }}/Entitlements.plist - name: Get certificates run: | @@ -245,8 +245,8 @@ jobs: ARCHIVE_PATH: ./${{ env.main_app_folder_path }}/bin/Debug/${{ env.target-net-version }}-ios/iossimulator-x64 EXPORT_PATH: ./bitwarden-export run: | - zip -r -q ${{ env.app_ci_output_filename }}.app.zip $ARCHIVE_PATH - mv ${{ env.app_ci_output_filename }}.app.zip $EXPORT_PATH + zip -r -q ${{ env._APP_CI_OUTPUT_FILENAME }}.app.zip $ARCHIVE_PATH + mv ${{ env._APP_CI_OUTPUT_FILENAME }}.app.zip $EXPORT_PATH - name: Show Bitwarden Export shell: bash @@ -276,8 +276,8 @@ jobs: - name: Upload .app file for Automation CI uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b # v4.3.4 with: - name: ${{ env.app_ci_output_filename }}.app.zip - path: ./bitwarden-export/${{ env.app_ci_output_filename }}.app.zip + name: ${{ env._APP_CI_OUTPUT_FILENAME }}.app.zip + path: ./bitwarden-export/${{ env._APP_CI_OUTPUT_FILENAME }}.app.zip if-no-files-found: error - name: Install AppCenter CLI diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1b04a7936..d0aedd6ba 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,12 +1,6 @@ name: Build on: - push: - branches-ignore: - - "l10n_master" - - "gh-pages" - paths-ignore: - - ".github/workflows/**" workflow_dispatch: env: @@ -70,8 +64,8 @@ jobs: matrix: variant: ["prod", "qa"] env: - android_folder_path: src\App\Platforms\Android - android_folder_path_bash: src/App/Platforms/Android + _ANDROID_FOLDER_PATH: src\App\Platforms\Android + _ANDROID_FOLDER_PATH_BASH: src/App/Platforms/Android steps: - name: Checkout repo uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 @@ -126,9 +120,9 @@ jobs: mkdir -p $HOME/secrets az storage blob download --account-name $ACCOUNT_NAME --container-name $CONTAINER_NAME \ - --name app_play-keystore.jks --file ./${{ env.android_folder_path_bash }}/app_play-keystore.jks --output none + --name app_play-keystore.jks --file ./${{ env._ANDROID_FOLDER_PATH_BASH }}/app_play-keystore.jks --output none az storage blob download --account-name $ACCOUNT_NAME --container-name $CONTAINER_NAME \ - --name app_upload-keystore.jks --file ./${{ env.android_folder_path_bash }}/app_upload-keystore.jks --output none + --name app_upload-keystore.jks --file ./${{ env._ANDROID_FOLDER_PATH_BASH }}/app_upload-keystore.jks --output none az storage blob download --account-name $ACCOUNT_NAME --container-name $CONTAINER_NAME \ --name play_creds.json --file $HOME/secrets/play_creds.json --output none shell: bash @@ -140,7 +134,7 @@ jobs: CONTAINER_NAME: mobile run: | az storage blob download --account-name $ACCOUNT_NAME --container-name $CONTAINER_NAME \ - --name google-services.json --file ./${{ env.android_folder_path_bash }}/google-services.json --output none + --name google-services.json --file ./${{ env._ANDROID_FOLDER_PATH_BASH }}/google-services.json --output none shell: bash - name: Increment version @@ -149,7 +143,7 @@ jobs: echo "##### Setting Android Version Code to $BUILD_NUMBER" | tee -a $GITHUB_STEP_SUMMARY sed -i "s/android:versionCode=\"1\"/android:versionCode=\"$BUILD_NUMBER\"/" \ - ./${{ env.android_folder_path_bash }}/AndroidManifest.xml + ./${{ env._ANDROID_FOLDER_PATH_BASH }}/AndroidManifest.xml shell: bash - name: Restore packages @@ -193,7 +187,7 @@ jobs: } Write-Output "##### Sign Google Play Bundle Release Configuration" - $signingUploadKeyStore = "$($env:GITHUB_WORKSPACE)\${{ env.android_folder_path }}\app_upload-keystore.jks" + $signingUploadKeyStore = "$($env:GITHUB_WORKSPACE)\${{ env._ANDROID_FOLDER_PATH }}\app_upload-keystore.jks" dotnet publish $projToBuild -c Release -f ${{ env.target-net-version }}-android ` /p:AndroidPackageFormats=aab ` /p:AndroidKeyStore=true ` @@ -210,7 +204,7 @@ jobs: Write-Output "##### Sign APK Release Configuration" - $signingPlayKeyStore = "$($env:GITHUB_WORKSPACE)\${{ env.android_folder_path }}\app_play-keystore.jks" + $signingPlayKeyStore = "$($env:GITHUB_WORKSPACE)\${{ env._ANDROID_FOLDER_PATH }}\app_play-keystore.jks" dotnet publish $projToBuild -c Release -f ${{ env.target-net-version }}-android ` /p:AndroidKeyStore=true ` /p:AndroidSigningKeyStore=$signingPlayKeyStore ` @@ -295,9 +289,9 @@ jobs: name: F-Droid Build runs-on: windows-2022 env: - android_folder_path: src\App\Platforms\Android - android_folder_path_bash: src/App/Platforms/Android - android_manifest_path: src/App/Platforms/Android/AndroidManifest.xml + _ANDROID_FOLDER_PATH: src\App\Platforms\Android + _ANDROID_FOLDER_PATH_BASH: src/App/Platforms/Android + _ANDROID_MANIFEST_PATH: src/App/Platforms/Android/AndroidManifest.xml steps: - name: Checkout repo uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 @@ -350,7 +344,7 @@ jobs: FILE: app_fdroid-keystore.jks run: | az storage blob download --account-name $ACCOUNT_NAME --container-name $CONTAINER_NAME --name $FILE \ - --file ${{ env.android_folder_path_bash }}/$FILE --output none + --file ${{ env._ANDROID_FOLDER_PATH_BASH }}/$FILE --output none shell: bash - name: Increment version @@ -359,14 +353,14 @@ jobs: echo "##### Setting F-Droid Version Code to $BUILD_NUMBER" | tee -a $GITHUB_STEP_SUMMARY sed -i "s/android:versionCode=\"1\"/android:versionCode=\"$BUILD_NUMBER\"/" \ - ./${{ env.android_manifest_path }} + ./${{ env._ANDROID_MANIFEST_PATH }} shell: bash - name: Clean for F-Droid run: | $directoryBuildProps = $($env:GITHUB_WORKSPACE + "/Directory.Build.props"); - $androidManifest = $($env:GITHUB_WORKSPACE + "/${{ env.android_manifest_path }}"); + $androidManifest = $($env:GITHUB_WORKSPACE + "/${{ env._ANDROID_MANIFEST_PATH }}"); Write-Output "##### Back up project files" @@ -399,7 +393,7 @@ jobs: Write-Output "##### Sign FDroid" - $signingFdroidKeyStore = "$($env:GITHUB_WORKSPACE)\${{ env.android_folder_path }}\app_fdroid-keystore.jks" + $signingFdroidKeyStore = "$($env:GITHUB_WORKSPACE)\${{ env._ANDROID_FOLDER_PATH }}\app_fdroid-keystore.jks" dotnet build $projToBuild -c Release -f ${{ env.target-net-version }}-android ` /p:AndroidKeyStore=true ` /p:AndroidSigningKeyStore=$signingFdroidKeyStore ` @@ -439,9 +433,9 @@ jobs: runs-on: macos-14 needs: setup env: - ios_folder_path: src/App/Platforms/iOS - app_output_name: App - app_ci_output_filename: App_x64_Debug + _IOS_FOLDER_PATH: src/App/Platforms/iOS + _APP_OUTPUT_NAME: App + _APP_CI_OUTPUT_FILENAME: App_x64_Debug steps: - name: Checkout repo uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 @@ -521,7 +515,7 @@ jobs: BUILD_NUMBER=$((8000 + $GITHUB_RUN_NUMBER)) echo "##### Setting iOS CFBundleVersion to $BUILD_NUMBER" | tee -a $GITHUB_STEP_SUMMARY - perl -0777 -pi.bak -e 's/CFBundleVersion<\/key>\s*1<\/string>/CFBundleVersion<\/key>\n\t'"$BUILD_NUMBER"'<\/string>/' ./${{ env.ios_folder_path }}/Info.plist + perl -0777 -pi.bak -e 's/CFBundleVersion<\/key>\s*1<\/string>/CFBundleVersion<\/key>\n\t'"$BUILD_NUMBER"'<\/string>/' ./${{ env._IOS_FOLDER_PATH }}/Info.plist perl -0777 -pi.bak -e 's/CFBundleVersion<\/key>\s*1<\/string>/CFBundleVersion<\/key>\n\t'"$BUILD_NUMBER"'<\/string>/' ./src/iOS.Extension/Info.plist perl -0777 -pi.bak -e 's/CFBundleVersion<\/key>\s*1<\/string>/CFBundleVersion<\/key>\n\t'"$BUILD_NUMBER"'<\/string>/' ./src/iOS.Autofill/Info.plist perl -0777 -pi.bak -e 's/CFBundleVersion<\/key>\s*1<\/string>/CFBundleVersion<\/key>\n\t'"$BUILD_NUMBER"'<\/string>/' ./src/iOS.ShareExtension/Info.plist @@ -531,7 +525,7 @@ jobs: - name: Update Entitlements run: | echo "##### Updating Entitlements" - perl -0777 -pi.bak -e 's/aps-environment<\/key>\s*development<\/string>/aps-environment<\/key>\n\tproduction<\/string>/' ./${{ env.ios_folder_path }}/Entitlements.plist + perl -0777 -pi.bak -e 's/aps-environment<\/key>\s*development<\/string>/aps-environment<\/key>\n\tproduction<\/string>/' ./${{ env._IOS_FOLDER_PATH }}/Entitlements.plist - name: Get certificates run: | @@ -615,8 +609,8 @@ jobs: ARCHIVE_PATH: ./${{ env.main_app_folder_path }}/bin/Debug/${{ env.target-net-version }}-ios/iossimulator-x64 EXPORT_PATH: ./bitwarden-export run: | - zip -r -q ${{ env.app_ci_output_filename }}.app.zip $ARCHIVE_PATH - mv ${{ env.app_ci_output_filename }}.app.zip $EXPORT_PATH + zip -r -q ${{ env._APP_CI_OUTPUT_FILENAME }}.app.zip $ARCHIVE_PATH + mv ${{ env._APP_CI_OUTPUT_FILENAME }}.app.zip $EXPORT_PATH - name: Copy all dSYMs files to upload env: @@ -641,8 +635,8 @@ jobs: - name: Upload .app file for Automation CI uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b # v4.3.4 with: - name: ${{ env.app_ci_output_filename }}.app.zip - path: ./bitwarden-export/${{ env.app_ci_output_filename }}.app.zip + name: ${{ env._APP_CI_OUTPUT_FILENAME }}.app.zip + path: ./bitwarden-export/${{ env._APP_CI_OUTPUT_FILENAME }}.app.zip if-no-files-found: error - name: Install AppCenter CLI diff --git a/.github/workflows/crowdin-pull.yml b/.github/workflows/crowdin-pull.yml index 0e3b7bdd2..9e2a7ada8 100644 --- a/.github/workflows/crowdin-pull.yml +++ b/.github/workflows/crowdin-pull.yml @@ -3,8 +3,6 @@ name: Crowdin Sync on: workflow_dispatch: inputs: {} - schedule: - - cron: '0 0 * * 5' jobs: crowdin-sync: diff --git a/.github/workflows/pr-labeler.yml b/.github/workflows/pr-labeler.yml index 320319ee9..e44fe1ad9 100644 --- a/.github/workflows/pr-labeler.yml +++ b/.github/workflows/pr-labeler.yml @@ -11,6 +11,7 @@ jobs: pull-requests: write runs-on: ubuntu-22.04 steps: - - uses: actions/labeler@8558fd74291d67161a8a78ce36a881fa63b766a9 # v5.0.0 + - name: Label PR + uses: actions/labeler@8558fd74291d67161a8a78ce36a881fa63b766a9 # v5.0.0 with: sync-labels: true diff --git a/.gitignore b/.gitignore index 1e0f2d44b..84b0b903f 100644 --- a/.gitignore +++ b/.gitignore @@ -296,17 +296,11 @@ iOSInjectionProject/ 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 -# *.xcodeproj -# Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata -# hence it is not needed unless you have added a package configuration file to your project -# .swiftpm - -.build/ +# xcode / swift package manager - used by the MessagePack lib +/.build +/Packages +/*.xcodeproj +.swiftpm # CocoaPods # We recommend against adding the Pods directory to your .gitignore. However diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index e5c10debf..000000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "lib/MessagePack"] - path = lib/MessagePack - url = https://github.com/bitwarden/MessagePack.git diff --git a/lib/MessagePack b/lib/MessagePack deleted file mode 160000 index 1ecb15e31..000000000 --- a/lib/MessagePack +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 1ecb15e31176023f6aa0b4948859b197b771d357 diff --git a/lib/MessagePack/LICENSE.md b/lib/MessagePack/LICENSE.md new file mode 100644 index 000000000..184e5815f --- /dev/null +++ b/lib/MessagePack/LICENSE.md @@ -0,0 +1,19 @@ +Copyright 2018 Read Evaluate Press, LLC + +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/lib/MessagePack/MessagePack-FlightSchool.podspec b/lib/MessagePack/MessagePack-FlightSchool.podspec new file mode 100644 index 000000000..9635d20ff --- /dev/null +++ b/lib/MessagePack/MessagePack-FlightSchool.podspec @@ -0,0 +1,32 @@ +Pod::Spec.new do |s| + s.name = 'MessagePack-FlightSchool' + s.module_name = 'MessagePack' + s.version = '1.2.4' + s.summary = 'A MessagePack encoder and decoder for Codable types.' + + s.description = <<-DESC + This functionality is discussed in Chapter 7 of + Flight School Guide to Swift Codable. + DESC + + s.homepage = 'https://flight.school/books/codable/' + + s.license = { type: 'MIT', file: 'LICENSE.md' } + + s.author = { 'Mattt' => 'mattt@flight.school' } + + s.social_media_url = 'https://twitter.com/mattt' + + s.ios.deployment_target = '8.0' + s.osx.deployment_target = '10.10' + s.watchos.deployment_target = '2.0' + s.tvos.deployment_target = '9.0' + + s.source = { git: 'https://github.com/Flight-School/MessagePack.git', + tag: s.version.to_s } + + s.source_files = 'Sources/**/*.swift' + + s.swift_version = '4.2' + s.static_framework = true +end diff --git a/lib/MessagePack/MessagePack.playground/Contents.swift b/lib/MessagePack/MessagePack.playground/Contents.swift new file mode 100644 index 000000000..06076437a --- /dev/null +++ b/lib/MessagePack/MessagePack.playground/Contents.swift @@ -0,0 +1,13 @@ +import MessagePack + +let encoder = MessagePackEncoder() + +let value: String = "hello" +let encodedData = try encoder.encode(value) + +print("Bytes: ", encodedData.map{ String($0, radix: 16, uppercase: true) }) + +let decoder = MessagePackDecoder() +let decodedValue = try decoder.decode(String.self, from: encodedData) + +decodedValue == value diff --git a/lib/MessagePack/MessagePack.playground/contents.xcplayground b/lib/MessagePack/MessagePack.playground/contents.xcplayground new file mode 100644 index 000000000..a93d4844a --- /dev/null +++ b/lib/MessagePack/MessagePack.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/lib/MessagePack/MessagePack.xcodeproj/MessagePackTests_Info.plist b/lib/MessagePack/MessagePack.xcodeproj/MessagePackTests_Info.plist new file mode 100644 index 000000000..7c23420d0 --- /dev/null +++ b/lib/MessagePack/MessagePack.xcodeproj/MessagePackTests_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/lib/MessagePack/MessagePack.xcodeproj/MessagePack_Info.plist b/lib/MessagePack/MessagePack.xcodeproj/MessagePack_Info.plist new file mode 100644 index 000000000..57ada9f9d --- /dev/null +++ b/lib/MessagePack/MessagePack.xcodeproj/MessagePack_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/lib/MessagePack/MessagePack.xcodeproj/project.pbxproj b/lib/MessagePack/MessagePack.xcodeproj/project.pbxproj new file mode 100644 index 000000000..5ef110db7 --- /dev/null +++ b/lib/MessagePack/MessagePack.xcodeproj/project.pbxproj @@ -0,0 +1,543 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXAggregateTarget section */ + "MessagePack::MessagePackPackageTests::ProductTarget" /* MessagePackPackageTests */ = { + isa = PBXAggregateTarget; + buildConfigurationList = OBJ_57 /* Build configuration list for PBXAggregateTarget "MessagePackPackageTests" */; + buildPhases = ( + ); + dependencies = ( + OBJ_60 /* PBXTargetDependency */, + ); + name = MessagePackPackageTests; + productName = MessagePackPackageTests; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 1BC312FF2992DE9C00177F2A /* DataSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1BC312FE2992DE9C00177F2A /* DataSpec.swift */; }; + OBJ_38 /* AnyCodingKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_9 /* AnyCodingKey.swift */; }; + OBJ_39 /* Box.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_10 /* Box.swift */; }; + OBJ_40 /* KeyedDecodingContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_12 /* KeyedDecodingContainer.swift */; }; + OBJ_41 /* MessagePackDecoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_13 /* MessagePackDecoder.swift */; }; + OBJ_42 /* SingleValueDecodingContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_14 /* SingleValueDecodingContainer.swift */; }; + OBJ_43 /* UnkeyedDecodingContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_15 /* UnkeyedDecodingContainer.swift */; }; + OBJ_44 /* KeyedEncodingContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_17 /* KeyedEncodingContainer.swift */; }; + OBJ_45 /* MessagePackEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_18 /* MessagePackEncoder.swift */; }; + OBJ_46 /* SingleValueEncodingContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_19 /* SingleValueEncodingContainer.swift */; }; + OBJ_47 /* UnkeyedEncodingContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_20 /* UnkeyedEncodingContainer.swift */; }; + OBJ_48 /* FixedWidthInteger+Bytes.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_21 /* FixedWidthInteger+Bytes.swift */; }; + OBJ_55 /* Package.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_6 /* Package.swift */; }; + OBJ_66 /* Airport.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_24 /* Airport.swift */; }; + OBJ_67 /* MessagePackDecodingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_25 /* MessagePackDecodingTests.swift */; }; + OBJ_68 /* MessagePackEncodingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_26 /* MessagePackEncodingTests.swift */; }; + OBJ_69 /* MessagePackPerformanceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_27 /* MessagePackPerformanceTests.swift */; }; + OBJ_70 /* MessagePackRoundTripTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_28 /* MessagePackRoundTripTests.swift */; }; + OBJ_72 /* MessagePack.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = "MessagePack::MessagePack::Product" /* MessagePack.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 1BC312FC2989A1AD00177F2A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = OBJ_1 /* Project object */; + proxyType = 1; + remoteGlobalIDString = "MessagePack::MessagePack"; + remoteInfo = MessagePack; + }; + 1BC312FD2989A1B200177F2A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = OBJ_1 /* Project object */; + proxyType = 1; + remoteGlobalIDString = "MessagePack::MessagePackTests"; + remoteInfo = MessagePackTests; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 1BC312FE2992DE9C00177F2A /* DataSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataSpec.swift; sourceTree = ""; }; + "MessagePack::MessagePack::Product" /* MessagePack.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = MessagePack.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + "MessagePack::MessagePackTests::Product" /* MessagePackTests.xctest */ = {isa = PBXFileReference; lastKnownFileType = file; path = MessagePackTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + OBJ_10 /* Box.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Box.swift; sourceTree = ""; }; + OBJ_12 /* KeyedDecodingContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyedDecodingContainer.swift; sourceTree = ""; }; + OBJ_13 /* MessagePackDecoder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessagePackDecoder.swift; sourceTree = ""; }; + OBJ_14 /* SingleValueDecodingContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SingleValueDecodingContainer.swift; sourceTree = ""; }; + OBJ_15 /* UnkeyedDecodingContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnkeyedDecodingContainer.swift; sourceTree = ""; }; + OBJ_17 /* KeyedEncodingContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyedEncodingContainer.swift; sourceTree = ""; }; + OBJ_18 /* MessagePackEncoder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessagePackEncoder.swift; sourceTree = ""; }; + OBJ_19 /* SingleValueEncodingContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SingleValueEncodingContainer.swift; sourceTree = ""; }; + OBJ_20 /* UnkeyedEncodingContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnkeyedEncodingContainer.swift; sourceTree = ""; }; + OBJ_21 /* FixedWidthInteger+Bytes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FixedWidthInteger+Bytes.swift"; sourceTree = ""; }; + OBJ_24 /* Airport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Airport.swift; sourceTree = ""; }; + OBJ_25 /* MessagePackDecodingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessagePackDecodingTests.swift; sourceTree = ""; }; + OBJ_26 /* MessagePackEncodingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessagePackEncodingTests.swift; sourceTree = ""; }; + OBJ_27 /* MessagePackPerformanceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessagePackPerformanceTests.swift; sourceTree = ""; }; + OBJ_28 /* MessagePackRoundTripTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessagePackRoundTripTests.swift; sourceTree = ""; }; + OBJ_29 /* MessagePack.xcworkspace */ = {isa = PBXFileReference; lastKnownFileType = wrapper.workspace; path = MessagePack.xcworkspace; sourceTree = SOURCE_ROOT; }; + OBJ_6 /* Package.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; path = Package.swift; sourceTree = ""; }; + OBJ_9 /* AnyCodingKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnyCodingKey.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + OBJ_49 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + OBJ_71 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 0; + files = ( + OBJ_72 /* MessagePack.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + OBJ_11 /* Decoder */ = { + isa = PBXGroup; + children = ( + OBJ_12 /* KeyedDecodingContainer.swift */, + OBJ_13 /* MessagePackDecoder.swift */, + OBJ_14 /* SingleValueDecodingContainer.swift */, + OBJ_15 /* UnkeyedDecodingContainer.swift */, + ); + path = Decoder; + sourceTree = ""; + }; + OBJ_16 /* Encoder */ = { + isa = PBXGroup; + children = ( + OBJ_17 /* KeyedEncodingContainer.swift */, + OBJ_18 /* MessagePackEncoder.swift */, + OBJ_19 /* SingleValueEncodingContainer.swift */, + OBJ_20 /* UnkeyedEncodingContainer.swift */, + ); + path = Encoder; + sourceTree = ""; + }; + OBJ_22 /* Tests */ = { + isa = PBXGroup; + children = ( + OBJ_23 /* MessagePackTests */, + ); + name = Tests; + sourceTree = SOURCE_ROOT; + }; + OBJ_23 /* MessagePackTests */ = { + isa = PBXGroup; + children = ( + OBJ_24 /* Airport.swift */, + OBJ_25 /* MessagePackDecodingTests.swift */, + OBJ_26 /* MessagePackEncodingTests.swift */, + OBJ_27 /* MessagePackPerformanceTests.swift */, + OBJ_28 /* MessagePackRoundTripTests.swift */, + ); + name = MessagePackTests; + path = Tests/MessagePackTests; + sourceTree = SOURCE_ROOT; + }; + OBJ_30 /* Products */ = { + isa = PBXGroup; + children = ( + "MessagePack::MessagePackTests::Product" /* MessagePackTests.xctest */, + "MessagePack::MessagePack::Product" /* MessagePack.framework */, + ); + name = Products; + sourceTree = BUILT_PRODUCTS_DIR; + }; + OBJ_5 /* */ = { + isa = PBXGroup; + children = ( + OBJ_6 /* Package.swift */, + OBJ_7 /* Sources */, + OBJ_22 /* Tests */, + OBJ_29 /* MessagePack.xcworkspace */, + OBJ_30 /* Products */, + ); + name = ""; + sourceTree = ""; + }; + OBJ_7 /* Sources */ = { + isa = PBXGroup; + children = ( + OBJ_8 /* MessagePack */, + ); + name = Sources; + sourceTree = SOURCE_ROOT; + }; + OBJ_8 /* MessagePack */ = { + isa = PBXGroup; + children = ( + OBJ_9 /* AnyCodingKey.swift */, + OBJ_10 /* Box.swift */, + OBJ_11 /* Decoder */, + OBJ_16 /* Encoder */, + OBJ_21 /* FixedWidthInteger+Bytes.swift */, + 1BC312FE2992DE9C00177F2A /* DataSpec.swift */, + ); + name = MessagePack; + path = Sources/MessagePack; + sourceTree = SOURCE_ROOT; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + "MessagePack::MessagePack" /* MessagePack */ = { + isa = PBXNativeTarget; + buildConfigurationList = OBJ_34 /* Build configuration list for PBXNativeTarget "MessagePack" */; + buildPhases = ( + OBJ_37 /* Sources */, + OBJ_49 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = MessagePack; + productName = MessagePack; + productReference = "MessagePack::MessagePack::Product" /* MessagePack.framework */; + productType = "com.apple.product-type.framework"; + }; + "MessagePack::MessagePackTests" /* MessagePackTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = OBJ_62 /* Build configuration list for PBXNativeTarget "MessagePackTests" */; + buildPhases = ( + OBJ_65 /* Sources */, + OBJ_71 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + OBJ_73 /* PBXTargetDependency */, + ); + name = MessagePackTests; + productName = MessagePackTests; + productReference = "MessagePack::MessagePackTests::Product" /* MessagePackTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + "MessagePack::SwiftPMPackageDescription" /* MessagePackPackageDescription */ = { + isa = PBXNativeTarget; + buildConfigurationList = OBJ_51 /* Build configuration list for PBXNativeTarget "MessagePackPackageDescription" */; + buildPhases = ( + OBJ_54 /* Sources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = MessagePackPackageDescription; + productName = MessagePackPackageDescription; + productType = "com.apple.product-type.framework"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + OBJ_1 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 9999; + }; + buildConfigurationList = OBJ_2 /* Build configuration list for PBXProject "MessagePack" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + English, + en, + ); + mainGroup = OBJ_5 /* */; + productRefGroup = OBJ_30 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + "MessagePack::MessagePack" /* MessagePack */, + "MessagePack::SwiftPMPackageDescription" /* MessagePackPackageDescription */, + "MessagePack::MessagePackPackageTests::ProductTarget" /* MessagePackPackageTests */, + "MessagePack::MessagePackTests" /* MessagePackTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + OBJ_37 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 0; + files = ( + OBJ_38 /* AnyCodingKey.swift in Sources */, + OBJ_39 /* Box.swift in Sources */, + OBJ_40 /* KeyedDecodingContainer.swift in Sources */, + OBJ_41 /* MessagePackDecoder.swift in Sources */, + OBJ_42 /* SingleValueDecodingContainer.swift in Sources */, + OBJ_43 /* UnkeyedDecodingContainer.swift in Sources */, + OBJ_44 /* KeyedEncodingContainer.swift in Sources */, + OBJ_45 /* MessagePackEncoder.swift in Sources */, + OBJ_46 /* SingleValueEncodingContainer.swift in Sources */, + OBJ_47 /* UnkeyedEncodingContainer.swift in Sources */, + 1BC312FF2992DE9C00177F2A /* DataSpec.swift in Sources */, + OBJ_48 /* FixedWidthInteger+Bytes.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + OBJ_54 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 0; + files = ( + OBJ_55 /* Package.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + OBJ_65 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 0; + files = ( + OBJ_66 /* Airport.swift in Sources */, + OBJ_67 /* MessagePackDecodingTests.swift in Sources */, + OBJ_68 /* MessagePackEncodingTests.swift in Sources */, + OBJ_69 /* MessagePackPerformanceTests.swift in Sources */, + OBJ_70 /* MessagePackRoundTripTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + OBJ_60 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = "MessagePack::MessagePackTests" /* MessagePackTests */; + targetProxy = 1BC312FD2989A1B200177F2A /* PBXContainerItemProxy */; + }; + OBJ_73 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = "MessagePack::MessagePack" /* MessagePack */; + targetProxy = 1BC312FC2989A1AD00177F2A /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + OBJ_3 /* Debug */ = { + 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_35 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ENABLE_TESTABILITY = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PLATFORM_DIR)/Developer/Library/Frameworks", + ); + HEADER_SEARCH_PATHS = "$(inherited)"; + INFOPLIST_FILE = MessagePack.xcodeproj/MessagePack_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 = MessagePack; + PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited)"; + SWIFT_VERSION = 4.0; + TARGET_NAME = MessagePack; + }; + name = Debug; + }; + OBJ_36 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ENABLE_TESTABILITY = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PLATFORM_DIR)/Developer/Library/Frameworks", + ); + HEADER_SEARCH_PATHS = "$(inherited)"; + INFOPLIST_FILE = MessagePack.xcodeproj/MessagePack_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 = MessagePack; + PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited)"; + SWIFT_VERSION = 4.0; + TARGET_NAME = MessagePack; + }; + name = Release; + }; + OBJ_4 /* Release */ = { + 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_52 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + LD = /usr/bin/true; + OTHER_SWIFT_FLAGS = "-swift-version 4 -I $(TOOLCHAIN_DIR)/usr/lib/swift/pm/4 -target x86_64-apple-macosx10.10 -sdk /Applications/Xcode-beta.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk"; + SWIFT_VERSION = 4.0; + }; + name = Debug; + }; + OBJ_53 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + LD = /usr/bin/true; + OTHER_SWIFT_FLAGS = "-swift-version 4 -I $(TOOLCHAIN_DIR)/usr/lib/swift/pm/4 -target x86_64-apple-macosx10.10 -sdk /Applications/Xcode-beta.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk"; + SWIFT_VERSION = 4.0; + }; + name = Release; + }; + OBJ_58 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + }; + name = Debug; + }; + OBJ_59 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + }; + name = Release; + }; + OBJ_63 /* Debug */ = { + 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 = MessagePack.xcodeproj/MessagePackTests_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.0; + TARGET_NAME = MessagePackTests; + }; + name = Debug; + }; + OBJ_64 /* Release */ = { + 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 = MessagePack.xcodeproj/MessagePackTests_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.0; + TARGET_NAME = MessagePackTests; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + OBJ_2 /* Build configuration list for PBXProject "MessagePack" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + OBJ_3 /* Debug */, + OBJ_4 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + OBJ_34 /* Build configuration list for PBXNativeTarget "MessagePack" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + OBJ_35 /* Debug */, + OBJ_36 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + OBJ_51 /* Build configuration list for PBXNativeTarget "MessagePackPackageDescription" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + OBJ_52 /* Debug */, + OBJ_53 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + OBJ_57 /* Build configuration list for PBXAggregateTarget "MessagePackPackageTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + OBJ_58 /* Debug */, + OBJ_59 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + OBJ_62 /* Build configuration list for PBXNativeTarget "MessagePackTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + OBJ_63 /* Debug */, + OBJ_64 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = OBJ_1 /* Project object */; +} diff --git a/lib/MessagePack/MessagePack.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/lib/MessagePack/MessagePack.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..fe1aa713e --- /dev/null +++ b/lib/MessagePack/MessagePack.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/lib/MessagePack/MessagePack.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/lib/MessagePack/MessagePack.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/lib/MessagePack/MessagePack.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/lib/MessagePack/MessagePack.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/lib/MessagePack/MessagePack.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 000000000..08de0be8d --- /dev/null +++ b/lib/MessagePack/MessagePack.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded + + + diff --git a/lib/MessagePack/MessagePack.xcodeproj/xcshareddata/xcschemes/MessagePack.xcscheme b/lib/MessagePack/MessagePack.xcodeproj/xcshareddata/xcschemes/MessagePack.xcscheme new file mode 100644 index 000000000..09f7d79d9 --- /dev/null +++ b/lib/MessagePack/MessagePack.xcodeproj/xcshareddata/xcschemes/MessagePack.xcscheme @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/MessagePack/MessagePack.xcworkspace/contents.xcworkspacedata b/lib/MessagePack/MessagePack.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..fb648b8a1 --- /dev/null +++ b/lib/MessagePack/MessagePack.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/lib/MessagePack/MessagePack.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/lib/MessagePack/MessagePack.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/lib/MessagePack/MessagePack.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/lib/MessagePack/MessagePack.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/lib/MessagePack/MessagePack.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 000000000..08de0be8d --- /dev/null +++ b/lib/MessagePack/MessagePack.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded + + + diff --git a/lib/MessagePack/Package.swift b/lib/MessagePack/Package.swift new file mode 100644 index 000000000..ba984af18 --- /dev/null +++ b/lib/MessagePack/Package.swift @@ -0,0 +1,28 @@ +// swift-tools-version:4.0 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import PackageDescription + +let package = Package( + name: "MessagePack", + products: [ + // Products define the executables and libraries produced by a package, and make them visible to other packages. + .library( + name: "MessagePack", + targets: ["MessagePack"]), + ], + dependencies: [ + // Dependencies declare other packages that this package depends on. + // .package(url: /* package url */, from: "1.0.0"), + ], + targets: [ + // Targets are the basic building blocks of a package. A target can define a module or a test suite. + // Targets can depend on other targets in this package, and on products in packages which this package depends on. + .target( + name: "MessagePack", + dependencies: []), + .testTarget( + name: "MessagePackTests", + dependencies: ["MessagePack"]), + ] +) diff --git a/lib/MessagePack/README.md b/lib/MessagePack/README.md new file mode 100644 index 000000000..19f1df346 --- /dev/null +++ b/lib/MessagePack/README.md @@ -0,0 +1,87 @@ +# MessagePack + +[![Build Status][build status badge]][build status] + +A [MessagePack](https://msgpack.org/) encoder and decoder for `Codable` types. + +This functionality is discussed in Chapter 7 of +[Flight School Guide to Swift Codable](https://flight.school/books/codable). + +## Requirements + +- Swift 4.2+ + +## Usage + +### Encoding Messages + +```swift +import MessagePack + +let encoder = MessagePackEncoder() +let value = try! encoder.encode(["a": 1, "b": 2, "c": 3]) +// [0x83, 0xA1, 0x62, 0x02, 0xA1, 0x61, 0x01, 0xA1, 0x63, 0x03] +``` + +### Decoding Messages + +```swift +import MessagePack + +let decoder = MessagePackDecoder() +let data = Data(bytes: [0xCB, 0x40, 0x09, 0x21, 0xF9, 0xF0, 0x1B, 0x86, 0x6E]) +let value = try! decoder.decode(Double.self, from: data) +// 3.14159 +``` + +## Installation + +### Swift Package Manager + +Add the MessagePack package to your target dependencies in `Package.swift`: + +```swift +import PackageDescription + +let package = Package( + name: "YourProject", + dependencies: [ + .package( + url: "https://github.com/Flight-School/MessagePack", + from: "1.2.3" + ), + ] +) +``` + +Then run the `swift build` command to build your project. + +### CocoaPods + +You can install `MessagePack` via CocoaPods, +by adding the following line to your `Podfile`: + +```ruby +pod 'MessagePack-FlightSchool', '~> 1.2.4' +``` + +Run the `pod install` command to download the library +and integrate it into your Xcode project. + +> **Note** +> The module name for this library is "MessagePack" --- +> that is, to use it, you add `import MessagePack` to the top of your Swift code +> just as you would by any other installation method. +> The pod is called "MessagePack-FlightSchool" +> because there's an existing pod with the name "MessagePack". + +## License + +MIT + +## Contact + +Mattt ([@mattt](https://twitter.com/mattt)) + +[build status]: https://github.com/Flight-School/MessagePack/actions?query=workflow%3ACI +[build status badge]: https://github.com/Flight-School/MessagePack/workflows/CI/badge.svg diff --git a/lib/MessagePack/Sources/MessagePack/AnyCodingKey.swift b/lib/MessagePack/Sources/MessagePack/AnyCodingKey.swift new file mode 100644 index 000000000..60747693b --- /dev/null +++ b/lib/MessagePack/Sources/MessagePack/AnyCodingKey.swift @@ -0,0 +1,28 @@ +struct AnyCodingKey: CodingKey, Equatable { + var stringValue: String + var intValue: Int? + + init?(stringValue: String) { + self.stringValue = stringValue + self.intValue = nil + } + + init?(intValue: Int) { + self.stringValue = "\(intValue)" + self.intValue = intValue + } + + init(_ base: Key) where Key : CodingKey { + if let intValue = base.intValue { + self.init(intValue: intValue)! + } else { + self.init(stringValue: base.stringValue)! + } + } +} + +extension AnyCodingKey: Hashable { + var hashValue: Int { + return self.intValue?.hashValue ?? self.stringValue.hashValue + } +} diff --git a/lib/MessagePack/Sources/MessagePack/Box.swift b/lib/MessagePack/Sources/MessagePack/Box.swift new file mode 100644 index 000000000..fb222ab02 --- /dev/null +++ b/lib/MessagePack/Sources/MessagePack/Box.swift @@ -0,0 +1,44 @@ +import Foundation + +struct Box { + let value: Value + init(_ value: Value) { + self.value = value + } +} + +extension Box: Encodable where Value: Encodable { + func encode(to encoder: Encoder) throws { + try self.value.encode(to: encoder) + } +} + +extension Box: Decodable where Value: Decodable { + init(from decoder: Decoder) throws { + self.init(try Value(from: decoder)) + } +} + +extension Box where Value == Data { + init(from decoder: Decoder) throws { + let container = try decoder.singleValueContainer() + self.init(try container.decode(Value.self)) + } + + func encode(to encoder: Encoder) throws { + var container = encoder.singleValueContainer() + try container.encode(self.value) + } +} + +extension Box where Value == Date { + init(from decoder: Decoder) throws { + let container = try decoder.singleValueContainer() + self.init(try container.decode(Value.self)) + } + + func encode(to encoder: Encoder) throws { + var container = encoder.singleValueContainer() + try container.encode(self.value) + } +} diff --git a/lib/MessagePack/Sources/MessagePack/DataSpec.swift b/lib/MessagePack/Sources/MessagePack/DataSpec.swift new file mode 100644 index 000000000..268b771ad --- /dev/null +++ b/lib/MessagePack/Sources/MessagePack/DataSpec.swift @@ -0,0 +1,60 @@ +import Foundation + +public struct DataSpec { + let name: String + let isObj: Bool + let isArray: Bool + let dataSpecBuilder: DataSpecBuilder? + + init(_ name: String, _ isObj: Bool, _ isArray: Bool, _ dataSpecBuilder: DataSpecBuilder?) { + self.name = name + self.isObj = isObj + self.isArray = isArray + self.dataSpecBuilder = dataSpecBuilder + } +} + +public class DataSpecBuilder : NSCopying { + var specs: [DataSpec] = [] + var specsIterator: IndexingIterator<[DataSpec]> + + init() { + specsIterator = IndexingIterator(_elements: []) + } + + func append(_ name: String) -> DataSpecBuilder { + return append(DataSpec(name, false, false, nil)) + } + + func appendObj(_ name: String, _ dataSpecBuilder: DataSpecBuilder) -> DataSpecBuilder { + return append(DataSpec(name, true, false, dataSpecBuilder)) + } + + func appendArray(_ name: String) -> DataSpecBuilder { + return append(DataSpec(name, false, true, nil)) + } + + func appendArray(_ name: String, _ dataSpecBuilder: DataSpecBuilder) -> DataSpecBuilder { + return append(DataSpec(name, false, true, dataSpecBuilder)) + } + + func append(_ spec: DataSpec) -> DataSpecBuilder { + specs.append(spec) + return self + } + + func build() -> DataSpecBuilder { + specsIterator = specs.makeIterator() + return self + } + + func next() -> DataSpec { + return specsIterator.next()! + } + + public func copy(with zone: NSZone? = nil) -> Any { + let b = DataSpecBuilder() + b.specs = specs + return b.build() + } +} diff --git a/lib/MessagePack/Sources/MessagePack/Decoder/KeyedDecodingContainer.swift b/lib/MessagePack/Sources/MessagePack/Decoder/KeyedDecodingContainer.swift new file mode 100644 index 000000000..914bfe049 --- /dev/null +++ b/lib/MessagePack/Sources/MessagePack/Decoder/KeyedDecodingContainer.swift @@ -0,0 +1,178 @@ +import Foundation + +extension _MessagePackDecoder { + final class KeyedContainer where Key: CodingKey { + lazy var nestedContainers: [String: MessagePackDecodingContainer] = { + guard let count = self.count else { + return [:] + } + + var nestedContainers: [String: MessagePackDecodingContainer] = [:] + + let unkeyedContainer = UnkeyedContainer(data: self.data.suffix(from: self.index), codingPath: self.codingPath, userInfo: self.userInfo) + if currentSpec != nil && currentSpec!.isObj { + unkeyedContainer.count = count + } else { + unkeyedContainer.count = count * 2 + } + + do { + var iterator = unkeyedContainer.nestedContainers.makeIterator() + + for _ in 0.. [CodingKey] { + return self.codingPath + [key] + } + + init(data: Data, codingPath: [CodingKey], userInfo: [CodingUserInfoKey : Any]) { + self.codingPath = codingPath + self.userInfo = userInfo + self.data = data + self.index = self.data.startIndex + } + + func checkCanDecodeValue(forKey key: Key) throws { + guard self.contains(key) else { + let context = DecodingError.Context(codingPath: self.codingPath, debugDescription: "key not found: \(key)") + throw DecodingError.keyNotFound(key, context) + } + } + } +} + +extension _MessagePackDecoder.KeyedContainer: KeyedDecodingContainerProtocol { + var allKeys: [Key] { + return self.nestedContainers.keys.map{ Key(stringValue: $0)! } + } + + func contains(_ key: Key) -> Bool { + return self.nestedContainers.keys.contains(key.stringValue) + } + + func decodeNil(forKey key: Key) throws -> Bool { + try checkCanDecodeValue(forKey: key) + + let nestedContainer = self.nestedContainers[key.stringValue] + + switch nestedContainer { + case let singleValueContainer as _MessagePackDecoder.SingleValueContainer: + return singleValueContainer.decodeNil() + case is _MessagePackDecoder.UnkeyedContainer, + is _MessagePackDecoder.KeyedContainer: + return false + default: + let context = DecodingError.Context(codingPath: self.codingPath, debugDescription: "cannot decode nil for key: \(key)") + throw DecodingError.typeMismatch(Any?.self, context) + } + } + + func decode(_ type: T.Type, forKey key: Key) throws -> T where T : Decodable { + try checkCanDecodeValue(forKey: key) + + let container = self.nestedContainers[key.stringValue]! + let decoder = MessagePackDecoder() + + if userInfo.keys.contains(MessagePackDecoder.dataSpecKey) { + decoder.userInfo[MessagePackDecoder.dataSpecKey] = container.currentSpec!.dataSpecBuilder?.copy() as? DataSpecBuilder + if container.currentSpec!.isArray { + decoder.userInfo[MessagePackDecoder.isArrayDataSpecKey] = true + } + } + + let value = try decoder.decode(T.self, from: container.data) + + return value + } + + func nestedUnkeyedContainer(forKey key: Key) throws -> UnkeyedDecodingContainer { + try checkCanDecodeValue(forKey: key) + + guard let unkeyedContainer = self.nestedContainers[key.stringValue] as? _MessagePackDecoder.UnkeyedContainer else { + throw DecodingError.dataCorruptedError(forKey: key, in: self, debugDescription: "cannot decode nested container for key: \(key)") + } + + return unkeyedContainer + } + + func nestedContainer(keyedBy type: NestedKey.Type, forKey key: Key) throws -> KeyedDecodingContainer where NestedKey : CodingKey { + try checkCanDecodeValue(forKey: key) + + guard let keyedContainer = self.nestedContainers[key.stringValue] as? _MessagePackDecoder.KeyedContainer else { + throw DecodingError.dataCorruptedError(forKey: key, in: self, debugDescription: "cannot decode nested container for key: \(key)") + } + + return KeyedDecodingContainer(keyedContainer) + } + + func superDecoder() throws -> Decoder { + return _MessagePackDecoder(data: self.data) + } + + func superDecoder(forKey key: Key) throws -> Decoder { + let decoder = _MessagePackDecoder(data: self.data) + decoder.codingPath = [key] + + return decoder + } +} + +extension _MessagePackDecoder.KeyedContainer: MessagePackDecodingContainer {} diff --git a/lib/MessagePack/Sources/MessagePack/Decoder/MessagePackDecoder.swift b/lib/MessagePack/Sources/MessagePack/Decoder/MessagePackDecoder.swift new file mode 100644 index 000000000..b88a4bdb4 --- /dev/null +++ b/lib/MessagePack/Sources/MessagePack/Decoder/MessagePackDecoder.swift @@ -0,0 +1,168 @@ +import Foundation + +/** + An object that decodes instances of a data type from MessagePack objects. + */ +final public class MessagePackDecoder { + public init() {} + + /** + A dictionary you use to customize the decoding process + by providing contextual information. + */ + public var userInfo: [CodingUserInfoKey : Any] = [:] + + /** + Returns a value of the type you specify, + decoded from a MessagePack object. + + - Parameters: + - type: The type of the value to decode + from the supplied MessagePack object. + - data: The MessagePack object to decode. + - Throws: `DecodingError.dataCorrupted(_:)` + if the data is not valid MessagePack. + */ + public func decode(_ type: T.Type, from data: Data) throws -> T where T : Decodable { + let decoder = _MessagePackDecoder(data: data) + decoder.userInfo = self.userInfo + decoder.userInfo[MessagePackDecoder.nonMatchingFloatDecodingStrategyKey] = nonMatchingFloatDecodingStrategy + + switch type { + case is Data.Type: + let box = try Box(from: decoder) + return box.value as! T + case is Date.Type: + let box = try Box(from: decoder) + return box.value as! T + default: + return try T(from: decoder) + } + } + + /** + The strategy used by a decoder when it encounters format mismatches for floating point values. + */ + public var nonMatchingFloatDecodingStrategy: NonMatchingFloatDecodingStrategy = .strict + + /** + The strategies for decoding floating point values when their format doesn't match. + */ + public enum NonMatchingFloatDecodingStrategy { + + /// Throws a DecodingError.typeMismatch + case strict + + /// Performs a cast + case cast + } + + internal static var nonMatchingFloatDecodingStrategyKey: CodingUserInfoKey { + return CodingUserInfoKey(rawValue: "nonMatchingFloatDecodingStrategyKey")! + } + + static var dataSpecKey : CodingUserInfoKey { + return CodingUserInfoKey(rawValue: "dataSpecKey")! + } + + static var isArrayDataSpecKey : CodingUserInfoKey { + return CodingUserInfoKey(rawValue: "isArrayDataSpecKey")! + } +} + +// MARK: - TopLevelDecoder + +#if canImport(Combine) +import Combine + +extension MessagePackDecoder: TopLevelDecoder { + public typealias Input = Data +} +#endif + +// MARK: - + +final class _MessagePackDecoder { + var codingPath: [CodingKey] = [] + + var userInfo: [CodingUserInfoKey : Any] = [:] + + var container: MessagePackDecodingContainer? + fileprivate var data: Data + + init(data: Data) { + self.data = data + } +} + +extension _MessagePackDecoder: Decoder { + fileprivate func assertCanCreateContainer() { + precondition(self.container == nil) + } + + func container(keyedBy type: Key.Type) -> KeyedDecodingContainer where Key : CodingKey { + assertCanCreateContainer() + + let container = KeyedContainer(data: self.data, codingPath: self.codingPath, userInfo: self.userInfo) + + if userInfo.keys.contains(MessagePackDecoder.dataSpecKey) { + container.currentSpec = DataSpec("", true, false, nil) + } + + self.container = container + + return KeyedDecodingContainer(container) + } + + func unkeyedContainer() -> UnkeyedDecodingContainer { + assertCanCreateContainer() + + let container = UnkeyedContainer(data: self.data, codingPath: self.codingPath, userInfo: self.userInfo) + self.container = container + + return container + } + + func singleValueContainer() -> SingleValueDecodingContainer { + assertCanCreateContainer() + + let container = SingleValueContainer(data: self.data, codingPath: self.codingPath, userInfo: self.userInfo) + self.container = container + + return container + } +} + +protocol MessagePackDecodingContainer: class { + var codingPath: [CodingKey] { get set } + + var userInfo: [CodingUserInfoKey : Any] { get } + + var data: Data { get set } + var index: Data.Index { get set } + + var currentSpec: DataSpec? { get set } +} + +extension MessagePackDecodingContainer { + func readByte() throws -> UInt8 { + return try read(1).first! + } + + func read(_ length: Int) throws -> Data { + let nextIndex = self.index.advanced(by: length) + guard nextIndex <= self.data.endIndex else { + let context = DecodingError.Context(codingPath: self.codingPath, debugDescription: "Unexpected end of data") + throw DecodingError.dataCorrupted(context) + } + defer { self.index = nextIndex } + + return self.data.subdata(in: self.index..(_ type: T.Type) throws -> T where T : FixedWidthInteger { + let stride = MemoryLayout.stride + let bytes = [UInt8](try read(stride)) + return T(bytes: bytes) + } +} diff --git a/lib/MessagePack/Sources/MessagePack/Decoder/SingleValueDecodingContainer.swift b/lib/MessagePack/Sources/MessagePack/Decoder/SingleValueDecodingContainer.swift new file mode 100644 index 000000000..36cfa265b --- /dev/null +++ b/lib/MessagePack/Sources/MessagePack/Decoder/SingleValueDecodingContainer.swift @@ -0,0 +1,226 @@ +import Foundation + +#if os(Linux) +let NSEC_PER_SEC: UInt64 = 1000000000 +#endif + +extension _MessagePackDecoder { + final class SingleValueContainer { + var codingPath: [CodingKey] + var userInfo: [CodingUserInfoKey: Any] + var data: Data + var index: Data.Index + var currentSpec: DataSpec? + + init(data: Data, codingPath: [CodingKey], userInfo: [CodingUserInfoKey : Any]) { + self.codingPath = codingPath + self.userInfo = userInfo + self.data = data + self.index = self.data.startIndex + } + + func checkCanDecode(_ type: T.Type, format: UInt8) throws { + guard self.index <= self.data.endIndex else { + throw DecodingError.dataCorruptedError(in: self, debugDescription: "Unexpected end of data") + } + + guard self.data[self.index] == format else { + let context = DecodingError.Context(codingPath: self.codingPath, debugDescription: "Invalid format: \(format)") + throw DecodingError.typeMismatch(type, context) + } + } + + var nonMatchingFloatDecodingStrategy: MessagePackDecoder.NonMatchingFloatDecodingStrategy { + return userInfo[MessagePackDecoder.nonMatchingFloatDecodingStrategyKey] as? MessagePackDecoder.NonMatchingFloatDecodingStrategy ?? .strict + } + } +} + +extension _MessagePackDecoder.SingleValueContainer: SingleValueDecodingContainer { + func decodeNil() -> Bool { + let format = try? readByte() + return format == 0xc0 + } + + func decode(_ type: Bool.Type) throws -> Bool { + let format = try readByte() + switch format { + case 0xc2: return false + case 0xc3: return true + default: + let context = DecodingError.Context(codingPath: self.codingPath, debugDescription: "Invalid format: \(format)") + throw DecodingError.typeMismatch(Bool.self, context) + } + } + + func decode(_ type: String.Type) throws -> String { + let length: Int + let format = try readByte() + switch format { + case 0xa0...0xbf: + length = Int(format - 0xa0) + case 0xd9: + length = Int(try read(UInt8.self)) + case 0xda: + length = Int(try read(UInt16.self)) + case 0xdb: + length = Int(try read(UInt32.self)) + default: + throw DecodingError.dataCorruptedError(in: self, debugDescription: "Invalid format for String length: \(format)") + } + + let data = try read(length) + guard let string = String(data: data, encoding: .utf8) else { + let context = DecodingError.Context(codingPath: self.codingPath, debugDescription: "Couldn't decode string with UTF-8 encoding") + throw DecodingError.dataCorrupted(context) + } + + return string + } + + func decode(_ type: Double.Type) throws -> Double { + let format = try readByte() + switch format { + case 0xca: + switch nonMatchingFloatDecodingStrategy { + case .strict: + break + case .cast: + let bitPattern = try read(UInt32.self) + return Double(Float(bitPattern: bitPattern)) + } + case 0xcb: + let bitPattern = try read(UInt64.self) + return Double(bitPattern: bitPattern) + default: + break + } + let context = DecodingError.Context(codingPath: self.codingPath, debugDescription: "Invalid format: \(format)") + throw DecodingError.typeMismatch(Double.self, context) + } + + func decode(_ type: Float.Type) throws -> Float { + let format = try readByte() + switch format { + case 0xca: + let bitPattern = try read(UInt32.self) + return Float(bitPattern: bitPattern) + case 0xcb: + switch nonMatchingFloatDecodingStrategy { + case .strict: + break + case .cast: + let bitPattern = try read(UInt64.self) + return Float(Double(bitPattern: bitPattern)) + } + default: + break + } + let context = DecodingError.Context(codingPath: self.codingPath, debugDescription: "Invalid format: \(format)") + throw DecodingError.typeMismatch(Float.self, context) + } + + func decode(_ type: T.Type) throws -> T where T : BinaryInteger & Decodable { + let format = try readByte() + var t: T? + + switch format { + case 0x00...0x7f: + t = T(format) + case 0xcc: + t = T(exactly: try read(UInt8.self)) + case 0xcd: + t = T(exactly: try read(UInt16.self)) + case 0xce: + t = T(exactly: try read(UInt32.self)) + case 0xcf: + t = T(exactly: try read(UInt64.self)) + case 0xd0: + t = T(exactly: try read(Int8.self)) + case 0xd1: + t = T(exactly: try read(Int16.self)) + case 0xd2: + t = T(exactly: try read(Int32.self)) + case 0xd3: + t = T(exactly: try read(Int64.self)) + case 0xe0...0xff: + t = T(exactly: Int8(bitPattern: format)) + default: + t = nil + } + + guard let value = t else { + let context = DecodingError.Context(codingPath: self.codingPath, debugDescription: "Invalid format: \(format)") + throw DecodingError.typeMismatch(T.self, context) + } + + return value + } + + func decode(_ type: Date.Type) throws -> Date { + let format = try readByte() + + var seconds: TimeInterval + var nanoseconds: TimeInterval + + switch format { + case 0xd6: + _ = try read(Int8.self) // -1 + nanoseconds = 0 + seconds = TimeInterval(try read(UInt32.self)) + case 0xd7: + _ = try read(Int8.self) // -1 + let bitPattern = try read(UInt64.self) + nanoseconds = TimeInterval(UInt32(bitPattern >> 34)) + seconds = TimeInterval(UInt32(bitPattern & 0x03_FF_FF_FF_FF)) + case 0xc7: + _ = try read(Int8.self) // 12 + _ = try read(Int8.self) // -1 + nanoseconds = TimeInterval(try read(UInt32.self)) + seconds = TimeInterval(try read(Int64.self)) + default: + let context = DecodingError.Context(codingPath: self.codingPath, debugDescription: "Invalid format: \(format)") + throw DecodingError.typeMismatch(Date.self, context) + } + + let timeInterval = TimeInterval(seconds) + nanoseconds / Double(NSEC_PER_SEC) + + return Date(timeIntervalSince1970: timeInterval) + } + + func decode(_ type: Data.Type) throws -> Data { + let length: Int + let format = try readByte() + switch format { + case 0xc4: + length = Int(try read(UInt8.self)) + case 0xc5: + length = Int(try read(UInt16.self)) + case 0xc6: + length = Int(try read(UInt32.self)) + default: + throw DecodingError.dataCorruptedError(in: self, debugDescription: "Invalid format for Data length: \(format)") + } + + return self.data.subdata(in: self.index..(_ type: T.Type) throws -> T where T : Decodable { + switch type { + case is Data.Type: + return try decode(Data.self) as! T + case is Date.Type: + return try decode(Date.self) as! T + default: + let decoder = _MessagePackDecoder(data: self.data) + let value = try T(from: decoder) + if let nextIndex = decoder.container?.index { + self.index = nextIndex + } + + return value + } + } +} + +extension _MessagePackDecoder.SingleValueContainer: MessagePackDecodingContainer {} diff --git a/lib/MessagePack/Sources/MessagePack/Decoder/UnkeyedDecodingContainer.swift b/lib/MessagePack/Sources/MessagePack/Decoder/UnkeyedDecodingContainer.swift new file mode 100644 index 000000000..e2d94bfb9 --- /dev/null +++ b/lib/MessagePack/Sources/MessagePack/Decoder/UnkeyedDecodingContainer.swift @@ -0,0 +1,235 @@ +import Foundation + +extension _MessagePackDecoder { + final class UnkeyedContainer { + var codingPath: [CodingKey] + + var nestedCodingPath: [CodingKey] { + return self.codingPath + [AnyCodingKey(intValue: self.count ?? 0)!] + } + + var userInfo: [CodingUserInfoKey: Any] + + var data: Data + var index: Data.Index + var currentSpec: DataSpec? + + lazy var count: Int? = { + do { + let format = try self.readByte() + switch format { + case 0x90...0x9f: + return Int(format & 0x0F) + case 0xdc: + return Int(try read(UInt16.self)) + case 0xdd: + return Int(try read(UInt32.self)) + default: + return nil + } + } catch { + return nil + } + }() + + var currentIndex: Int = 0 + + lazy var nestedContainers: [MessagePackDecodingContainer] = { + guard let count = self.count else { + return [] + } + + var nestedContainers: [MessagePackDecodingContainer] = [] + + do { + for _ in 0..= count + } + + func checkCanDecodeValue() throws { + guard !self.isAtEnd else { + throw DecodingError.dataCorruptedError(in: self, debugDescription: "Unexpected end of data") + } + } + } +} + +extension _MessagePackDecoder.UnkeyedContainer: UnkeyedDecodingContainer { + func decodeNil() throws -> Bool { + try checkCanDecodeValue() + defer { self.currentIndex += 1 } + + let nestedContainer = self.nestedContainers[self.currentIndex] + + switch nestedContainer { + case let singleValueContainer as _MessagePackDecoder.SingleValueContainer: + return singleValueContainer.decodeNil() + case is _MessagePackDecoder.UnkeyedContainer, + is _MessagePackDecoder.KeyedContainer: + return false + default: + let context = DecodingError.Context(codingPath: self.codingPath, debugDescription: "cannot decode nil for index: \(self.currentIndex)") + throw DecodingError.typeMismatch(Any?.self, context) + } + } + + func decode(_ type: T.Type) throws -> T where T : Decodable { + try checkCanDecodeValue() + defer { self.currentIndex += 1 } + + if userInfo.keys.contains(MessagePackDecoder.isArrayDataSpecKey) { + currentSpec = DataSpec("", false, true, (userInfo[MessagePackDecoder.dataSpecKey] as? DataSpecBuilder)?.copy() as? DataSpecBuilder) + } + + let container = self.nestedContainers[self.currentIndex] + let decoder = MessagePackDecoder() + + if userInfo.keys.contains(MessagePackDecoder.dataSpecKey) { + decoder.userInfo[MessagePackDecoder.dataSpecKey] = (userInfo[MessagePackDecoder.dataSpecKey] as? DataSpecBuilder)?.copy() as? DataSpecBuilder + } + + let value = try decoder.decode(T.self, from: container.data) + + return value + } + + func nestedUnkeyedContainer() throws -> UnkeyedDecodingContainer { + try checkCanDecodeValue() + defer { self.currentIndex += 1 } + + let container = self.nestedContainers[self.currentIndex] as! _MessagePackDecoder.UnkeyedContainer + + return container + } + + func nestedContainer(keyedBy type: NestedKey.Type) throws -> KeyedDecodingContainer where NestedKey : CodingKey { + try checkCanDecodeValue() + defer { self.currentIndex += 1 } + + let container = self.nestedContainers[self.currentIndex] as! _MessagePackDecoder.KeyedContainer + + return KeyedDecodingContainer(container) + } + + func superDecoder() throws -> Decoder { + return _MessagePackDecoder(data: self.data) + } +} + +extension _MessagePackDecoder.UnkeyedContainer { + func decodeContainer() throws -> MessagePackDecodingContainer { + try checkCanDecodeValue() + defer { self.currentIndex += 1 } + + let startIndex = self.index + + var currDataSpec: DataSpec? = nil + if currentSpec != nil && currentSpec!.isArray && currentSpec!.dataSpecBuilder != nil { + currDataSpec = DataSpec("", true, false, currentSpec!.dataSpecBuilder!.copy() as? DataSpecBuilder) + } else { + let dataSpec = self.userInfo[MessagePackDecoder.dataSpecKey] as? DataSpecBuilder + if let currDS = dataSpec?.next() { + currDataSpec = DataSpec(currDS.name, currDS.isObj, currDS.isArray, currDS.dataSpecBuilder?.copy() as? DataSpecBuilder) + } + } + + let length: Int + let format = try self.readByte() + switch format { + case 0x00...0x7f, + 0xc0, 0xc2, 0xc3, + 0xe0...0xff: + length = 0 + case 0xcc, 0xd0, 0xd4: + length = 1 + case 0xcd, 0xd1, 0xd5: + length = 2 + case 0xca, 0xce, 0xd2: + length = 4 + case 0xcb, 0xcf, 0xd3: + length = 8 + case 0xd6: + length = 5 + case 0xd7: + length = 9 + case 0xd8: + length = 16 + case 0xa0...0xbf: + length = Int(format - 0xa0) + case 0xc4, 0xc7, 0xd9: + length = Int(try read(UInt8.self)) + case 0xc5, 0xc8, 0xda: + length = Int(try read(UInt16.self)) + case 0xc6, 0xc9, 0xdb: + length = Int(try read(UInt32.self)) + case 0x80...0x8f, 0xde, 0xdf: + let container = _MessagePackDecoder.KeyedContainer(data: self.data.suffix(from: startIndex), codingPath: self.nestedCodingPath, userInfo: self.userInfo) + container.currentSpec = currDataSpec + _ = container.nestedContainers // FIXME + self.index = container.index + + return container + case 0x90...0x9f, 0xdc, 0xdd: + if currDataSpec != nil && currDataSpec!.isObj { + var objUserInfo = self.userInfo + objUserInfo[MessagePackDecoder.dataSpecKey] = currDataSpec!.dataSpecBuilder! + + let container = _MessagePackDecoder.KeyedContainer(data: self.data.suffix(from: startIndex), codingPath: self.nestedCodingPath, userInfo: objUserInfo) + container.currentSpec = currDataSpec + _ = container.nestedContainers // FIXME + self.index = container.index + + return container + } + + var arrUserInfo = self.userInfo + if currDataSpec != nil && currDataSpec!.isArray { + arrUserInfo[MessagePackDecoder.dataSpecKey] = currDataSpec!.dataSpecBuilder! + } + + let container = _MessagePackDecoder.UnkeyedContainer(data: self.data.suffix(from: startIndex), codingPath: self.nestedCodingPath, userInfo: arrUserInfo) + container.currentSpec = currDataSpec + _ = container.nestedContainers // FIXME + + self.index = container.index + + return container + default: + throw DecodingError.dataCorruptedError(in: self, debugDescription: "Invalid format: \(format)") + } + + let range: Range = startIndex.. where Key: CodingKey { + private var storage: [AnyCodingKey: _MessagePackEncodingContainer] = [:] + + var codingPath: [CodingKey] + var userInfo: [CodingUserInfoKey: Any] + + func nestedCodingPath(forKey key: CodingKey) -> [CodingKey] { + return self.codingPath + [key] + } + + init(codingPath: [CodingKey], userInfo: [CodingUserInfoKey : Any]) { + self.codingPath = codingPath + self.userInfo = userInfo + } + } +} + +extension _MessagePackEncoder.KeyedContainer: KeyedEncodingContainerProtocol { + func encodeNil(forKey key: Key) throws { + var container = self.nestedSingleValueContainer(forKey: key) + try container.encodeNil() + } + + func encode(_ value: T, forKey key: Key) throws where T : Encodable { + var container = self.nestedSingleValueContainer(forKey: key) + try container.encode(value) + } + + private func nestedSingleValueContainer(forKey key: Key) -> SingleValueEncodingContainer { + let container = _MessagePackEncoder.SingleValueContainer(codingPath: self.nestedCodingPath(forKey: key), userInfo: self.userInfo) + self.storage[AnyCodingKey(key)] = container + return container + } + + func nestedUnkeyedContainer(forKey key: Key) -> UnkeyedEncodingContainer { + let container = _MessagePackEncoder.UnkeyedContainer(codingPath: self.nestedCodingPath(forKey: key), userInfo: self.userInfo) + self.storage[AnyCodingKey(key)] = container + + return container + } + + func nestedContainer(keyedBy keyType: NestedKey.Type, forKey key: Key) -> KeyedEncodingContainer where NestedKey : CodingKey { + let container = _MessagePackEncoder.KeyedContainer(codingPath: self.nestedCodingPath(forKey: key), userInfo: self.userInfo) + self.storage[AnyCodingKey(key)] = container + + return KeyedEncodingContainer(container) + } + + func superEncoder() -> Encoder { + fatalError("Unimplemented") // FIXME + } + + func superEncoder(forKey key: Key) -> Encoder { + fatalError("Unimplemented") // FIXME + } +} + +extension _MessagePackEncoder.KeyedContainer: _MessagePackEncodingContainer { + var data: Data { + var data = Data() + + let length = storage.count + if let uint16 = UInt16(exactly: length) { + if length <= 15 { + data.append(0x80 + UInt8(length)) + } else { + data.append(0xde) + data.append(contentsOf: uint16.bytes) + } + } else if let uint32 = UInt32(exactly: length) { + data.append(0xdf) + data.append(contentsOf: uint32.bytes) + } else { + fatalError() + } + + for (key, container) in self.storage { + let keyContainer = _MessagePackEncoder.SingleValueContainer(codingPath: self.codingPath, userInfo: self.userInfo) + try! keyContainer.encode(key.stringValue) + data.append(keyContainer.data) + + data.append(container.data) + } + + return data + } +} diff --git a/lib/MessagePack/Sources/MessagePack/Encoder/MessagePackEncoder.swift b/lib/MessagePack/Sources/MessagePack/Encoder/MessagePackEncoder.swift new file mode 100644 index 000000000..d2b6a0839 --- /dev/null +++ b/lib/MessagePack/Sources/MessagePack/Encoder/MessagePackEncoder.swift @@ -0,0 +1,99 @@ +import Foundation + +/** + An object that encodes instances of a data type as MessagePack objects. + */ +final public class MessagePackEncoder { + public init() {} + + /** + A dictionary you use to customize the encoding process + by providing contextual information. + */ + public var userInfo: [CodingUserInfoKey : Any] = [:] + + /** + Returns a MessagePack-encoded representation of the value you supply. + + - Parameters: + - value: The value to encode as MessagePack. + - Throws: `EncodingError.invalidValue(_:_:)` + if the value can't be encoded as a MessagePack object. + */ + public func encode(_ value: T) throws -> Data where T : Encodable { + let encoder = _MessagePackEncoder() + encoder.userInfo = self.userInfo + + switch value { + case let data as Data: + try Box(data).encode(to: encoder) + case let date as Date: + try Box(date).encode(to: encoder) + default: + try value.encode(to: encoder) + } + + return encoder.data + } +} + +// MARK: - TopLevelEncoder + +#if canImport(Combine) +import Combine + +extension MessagePackEncoder: TopLevelEncoder { + public typealias Input = Data +} +#endif + +// MARK: - + +protocol _MessagePackEncodingContainer { + var data: Data { get } +} + +class _MessagePackEncoder { + var codingPath: [CodingKey] = [] + + var userInfo: [CodingUserInfoKey : Any] = [:] + + fileprivate var container: _MessagePackEncodingContainer? + + var data: Data { + return container?.data ?? Data() + } +} + +extension _MessagePackEncoder: Encoder { + fileprivate func assertCanCreateContainer() { + precondition(self.container == nil) + } + + func container(keyedBy type: Key.Type) -> KeyedEncodingContainer where Key : CodingKey { + assertCanCreateContainer() + + let container = KeyedContainer(codingPath: self.codingPath, userInfo: self.userInfo) + self.container = container + + return KeyedEncodingContainer(container) + } + + func unkeyedContainer() -> UnkeyedEncodingContainer { + assertCanCreateContainer() + + let container = UnkeyedContainer(codingPath: self.codingPath, userInfo: self.userInfo) + self.container = container + + return container + } + + func singleValueContainer() -> SingleValueEncodingContainer { + assertCanCreateContainer() + + let container = SingleValueContainer(codingPath: self.codingPath, userInfo: self.userInfo) + self.container = container + + return container + } +} diff --git a/lib/MessagePack/Sources/MessagePack/Encoder/SingleValueEncodingContainer.swift b/lib/MessagePack/Sources/MessagePack/Encoder/SingleValueEncodingContainer.swift new file mode 100644 index 000000000..9006b3e4d --- /dev/null +++ b/lib/MessagePack/Sources/MessagePack/Encoder/SingleValueEncodingContainer.swift @@ -0,0 +1,264 @@ +import Foundation + +extension _MessagePackEncoder { + final class SingleValueContainer { + private var storage: Data = Data() + + fileprivate var canEncodeNewValue = true + fileprivate func checkCanEncode(value: Any?) throws { + guard self.canEncodeNewValue else { + let context = EncodingError.Context(codingPath: self.codingPath, debugDescription: "Attempt to encode value through single value container when previously value already encoded.") + throw EncodingError.invalidValue(value as Any, context) + } + } + + var codingPath: [CodingKey] + var userInfo: [CodingUserInfoKey: Any] + + init(codingPath: [CodingKey], userInfo: [CodingUserInfoKey : Any]) { + self.codingPath = codingPath + self.userInfo = userInfo + } + } +} + +extension _MessagePackEncoder.SingleValueContainer: SingleValueEncodingContainer { + func encodeNil() throws { + try checkCanEncode(value: nil) + defer { self.canEncodeNewValue = false } + + self.storage.append(0xc0) + } + + func encode(_ value: Bool) throws { + try checkCanEncode(value: nil) + defer { self.canEncodeNewValue = false } + + switch value { + case false: + self.storage.append(0xc2) + case true: + self.storage.append(0xc3) + } + } + + func encode(_ value: String) throws { + try checkCanEncode(value: value) + defer { self.canEncodeNewValue = false } + + guard let data = value.data(using: .utf8) else { + let context = EncodingError.Context(codingPath: self.codingPath, debugDescription: "Cannot encode string using UTF-8 encoding.") + throw EncodingError.invalidValue(value, context) + } + + let length = data.count + if let uint8 = UInt8(exactly: length) { + if (uint8 <= 31) { + self.storage.append(0xa0 + uint8) + } else { + self.storage.append(0xd9) + self.storage.append(contentsOf: uint8.bytes) + } + } else if let uint16 = UInt16(exactly: length) { + self.storage.append(0xda) + self.storage.append(contentsOf: uint16.bytes) + } else if let uint32 = UInt32(exactly: length) { + self.storage.append(0xdb) + self.storage.append(contentsOf: uint32.bytes) + } else { + let context = EncodingError.Context(codingPath: self.codingPath, debugDescription: "Cannot encode string with length \(length).") + throw EncodingError.invalidValue(value, context) + } + + self.storage.append(data) + } + + func encode(_ value: Double) throws { + try checkCanEncode(value: value) + defer { self.canEncodeNewValue = false } + + self.storage.append(0xcb) + self.storage.append(contentsOf: value.bitPattern.bytes) + } + + func encode(_ value: Float) throws { + try checkCanEncode(value: value) + defer { self.canEncodeNewValue = false } + + self.storage.append(0xca) + self.storage.append(contentsOf: value.bitPattern.bytes) + } + + func encode(_ value: T) throws where T : BinaryInteger & Encodable { + try checkCanEncode(value: value) + defer { self.canEncodeNewValue = false } + + if value < 0 { + if let int8 = Int8(exactly: value) { + return try encode(int8) + } else if let int16 = Int16(exactly: value) { + return try encode(int16) + } else if let int32 = Int32(exactly: value) { + return try encode(int32) + } else if let int64 = Int64(exactly: value) { + return try encode(int64) + } + } else { + if let uint8 = UInt8(exactly: value) { + return try encode(uint8) + } else if let uint16 = UInt16(exactly: value) { + return try encode(uint16) + } else if let uint32 = UInt32(exactly: value) { + return try encode(uint32) + } else if let uint64 = UInt64(exactly: value) { + return try encode(uint64) + } + } + + let context = EncodingError.Context(codingPath: self.codingPath, debugDescription: "Cannot encode integer \(value).") + throw EncodingError.invalidValue(value, context) + } + + func encode(_ value: Int8) throws { + try checkCanEncode(value: value) + defer { self.canEncodeNewValue = false } + + if (value >= 0 && value <= 127) { + self.storage.append(UInt8(value)) + } else if (value < 0 && value >= -31) { + self.storage.append(0xe0 + (0x1f & UInt8(truncatingIfNeeded: value))) + } else { + self.storage.append(0xd0) + self.storage.append(contentsOf: value.bytes) + } + } + + func encode(_ value: Int16) throws { + try checkCanEncode(value: value) + defer { self.canEncodeNewValue = false } + + self.storage.append(0xd1) + self.storage.append(contentsOf: value.bytes) + } + + func encode(_ value: Int32) throws { + try checkCanEncode(value: value) + defer { self.canEncodeNewValue = false } + + self.storage.append(0xd2) + self.storage.append(contentsOf: value.bytes) + } + + func encode(_ value: Int64) throws { + try checkCanEncode(value: value) + defer { self.canEncodeNewValue = false } + + self.storage.append(0xd3) + self.storage.append(contentsOf: value.bytes) + } + + func encode(_ value: UInt8) throws { + try checkCanEncode(value: value) + defer { self.canEncodeNewValue = false } + + if (value <= 127) { + self.storage.append(value) + } else { + self.storage.append(0xcc) + self.storage.append(contentsOf: value.bytes) + } + } + + func encode(_ value: UInt16) throws { + try checkCanEncode(value: value) + defer { self.canEncodeNewValue = false } + + self.storage.append(0xcd) + self.storage.append(contentsOf: value.bytes) + } + + func encode(_ value: UInt32) throws { + try checkCanEncode(value: value) + defer { self.canEncodeNewValue = false } + + self.storage.append(0xce) + self.storage.append(contentsOf: value.bytes) + } + + func encode(_ value: UInt64) throws { + try checkCanEncode(value: value) + defer { self.canEncodeNewValue = false } + + self.storage.append(0xcf) + self.storage.append(contentsOf: value.bytes) + } + + func encode(_ value: Date) throws { + try checkCanEncode(value: value) + defer { self.canEncodeNewValue = false } + + let timeInterval = value.timeIntervalSince1970 + let (integral, fractional) = modf(timeInterval) + + let seconds = Int64(integral) + let nanoseconds = UInt32(fractional * Double(NSEC_PER_SEC)) + + if seconds < 0 || seconds > UInt32.max { + self.storage.append(0xc7) + self.storage.append(0x0C) + self.storage.append(0xFF) + self.storage.append(contentsOf: nanoseconds.bytes) + self.storage.append(contentsOf: seconds.bytes) + } else if nanoseconds > 0 { + self.storage.append(0xd7) + self.storage.append(0xFF) + self.storage.append(contentsOf: ((UInt64(nanoseconds) << 34) + UInt64(seconds)).bytes) + } else { + self.storage.append(0xd6) + self.storage.append(0xFF) + self.storage.append(contentsOf: UInt32(seconds).bytes) + } + } + + func encode(_ value: Data) throws { + let length = value.count + if let uint8 = UInt8(exactly: length) { + self.storage.append(0xc4) + self.storage.append(uint8) + self.storage.append(value) + } else if let uint16 = UInt16(exactly: length) { + self.storage.append(0xc5) + self.storage.append(contentsOf: uint16.bytes) + self.storage.append(value) + } else if let uint32 = UInt32(exactly: length) { + self.storage.append(0xc6) + self.storage.append(contentsOf: uint32.bytes) + self.storage.append(value) + } else { + let context = EncodingError.Context(codingPath: self.codingPath, debugDescription: "Cannot encode data of length \(value.count).") + throw EncodingError.invalidValue(value, context) + } + } + + func encode(_ value: T) throws where T : Encodable { + try checkCanEncode(value: value) + defer { self.canEncodeNewValue = false } + + switch value { + case let data as Data: + try self.encode(data) + case let date as Date: + try self.encode(date) + default: + let encoder = _MessagePackEncoder() + try value.encode(to: encoder) + self.storage.append(encoder.data) + } + } +} + +extension _MessagePackEncoder.SingleValueContainer: _MessagePackEncodingContainer { + var data: Data { + return storage + } +} diff --git a/lib/MessagePack/Sources/MessagePack/Encoder/UnkeyedEncodingContainer.swift b/lib/MessagePack/Sources/MessagePack/Encoder/UnkeyedEncodingContainer.swift new file mode 100644 index 000000000..46477ed56 --- /dev/null +++ b/lib/MessagePack/Sources/MessagePack/Encoder/UnkeyedEncodingContainer.swift @@ -0,0 +1,88 @@ +import Foundation + +extension _MessagePackEncoder { + final class UnkeyedContainer { + private var storage: [_MessagePackEncodingContainer] = [] + + var count: Int { + return storage.count + } + + var codingPath: [CodingKey] + + var nestedCodingPath: [CodingKey] { + return self.codingPath + [AnyCodingKey(intValue: self.count)!] + } + + var userInfo: [CodingUserInfoKey: Any] + + init(codingPath: [CodingKey], userInfo: [CodingUserInfoKey : Any]) { + self.codingPath = codingPath + self.userInfo = userInfo + } + } +} + +extension _MessagePackEncoder.UnkeyedContainer: UnkeyedEncodingContainer { + func encodeNil() throws { + var container = self.nestedSingleValueContainer() + try container.encodeNil() + } + + func encode(_ value: T) throws where T : Encodable { + var container = self.nestedSingleValueContainer() + try container.encode(value) + } + + private func nestedSingleValueContainer() -> SingleValueEncodingContainer { + let container = _MessagePackEncoder.SingleValueContainer(codingPath: self.nestedCodingPath, userInfo: self.userInfo) + self.storage.append(container) + + return container + } + + func nestedContainer(keyedBy keyType: NestedKey.Type) -> KeyedEncodingContainer where NestedKey : CodingKey { + let container = _MessagePackEncoder.KeyedContainer(codingPath: self.nestedCodingPath, userInfo: self.userInfo) + self.storage.append(container) + + return KeyedEncodingContainer(container) + } + + func nestedUnkeyedContainer() -> UnkeyedEncodingContainer { + let container = _MessagePackEncoder.UnkeyedContainer(codingPath: self.nestedCodingPath, userInfo: self.userInfo) + self.storage.append(container) + + return container + } + + func superEncoder() -> Encoder { + fatalError("Unimplemented") // FIXME + } +} + +extension _MessagePackEncoder.UnkeyedContainer: _MessagePackEncodingContainer { + var data: Data { + var data = Data() + + let length = storage.count + if let uint16 = UInt16(exactly: length) { + if uint16 <= 15 { + data.append(UInt8(0x90 + uint16)) + } else { + data.append(0xdc) + data.append(contentsOf: uint16.bytes) + } + } else if let uint32 = UInt32(exactly: length) { + data.append(0xdd) + data.append(contentsOf: uint32.bytes) + } else { + fatalError() + } + + for container in storage { + data.append(container.data) + } + + return data + } +} diff --git a/lib/MessagePack/Sources/MessagePack/FixedWidthInteger+Bytes.swift b/lib/MessagePack/Sources/MessagePack/FixedWidthInteger+Bytes.swift new file mode 100644 index 000000000..1a30c262c --- /dev/null +++ b/lib/MessagePack/Sources/MessagePack/FixedWidthInteger+Bytes.swift @@ -0,0 +1,20 @@ +extension FixedWidthInteger { + init(bytes: [UInt8]) { + self = bytes.withUnsafeBufferPointer { + $0.baseAddress!.withMemoryRebound(to: Self.self, capacity: 1) { + $0.pointee + } + }.bigEndian + } + + var bytes: [UInt8] { + let capacity = MemoryLayout.size + var mutableValue = self.bigEndian + return withUnsafePointer(to: &mutableValue) { + return $0.withMemoryRebound(to: UInt8.self, capacity: capacity) { + return Array(UnsafeBufferPointer(start: $0, count: capacity)) + } + } + } +} + diff --git a/lib/MessagePack/Tests/LinuxMain.swift b/lib/MessagePack/Tests/LinuxMain.swift new file mode 100644 index 000000000..120e5d2bd --- /dev/null +++ b/lib/MessagePack/Tests/LinuxMain.swift @@ -0,0 +1,8 @@ +import XCTest +@testable import MessagePackTests + +XCTMain([ + testCase(MessagePackDecodingTests.allTests), + testCase(MessagePackEncodingTests.allTests), + testCase(MessagePackRoundTripTests.allTests), +]) diff --git a/lib/MessagePack/Tests/MessagePackTests/Airport.swift b/lib/MessagePack/Tests/MessagePackTests/Airport.swift new file mode 100644 index 000000000..b39bf95fe --- /dev/null +++ b/lib/MessagePack/Tests/MessagePackTests/Airport.swift @@ -0,0 +1,63 @@ +struct Airport: Codable, Equatable { + let name: String + let iata: String + let icao: String + let coordinates: [Double] + + struct Runway: Codable, Equatable { + enum Surface: String, Codable, Equatable { + case rigid, flexible, gravel, sealed, unpaved, other + } + + let direction: String + let distance: Int + let surface: Surface + } + + let runways: [Runway] + + let instrumentApproachProcedures: [String] + + static var example: Airport { + return Airport( + name: "Portland International Airport", + iata: "PDX", + icao: "KPDX", + coordinates: [-122.5975, + 45.5886111111111], + runways: [ + Airport.Runway( + direction: "3/21", + distance: 1829, + surface: .flexible + ) + ], + instrumentApproachProcedures: [ + "HI-ILS OR LOC RWY 28", + "HI-ILS OR LOC/DME RWY 10", + "ILS OR LOC RWY 10L", + "ILS OR LOC RWY 10R", + "ILS OR LOC RWY 28L", + "ILS OR LOC RWY 28R", + "ILS RWY 10R (SA CAT I)", + "ILS RWY 10R (CAT II - III)", + "RNAV (RNP) Y RWY 28L", + "RNAV (RNP) Y RWY 28R", + "RNAV (RNP) Z RWY 10L", + "RNAV (RNP) Z RWY 10R", + "RNAV (RNP) Z RWY 28L", + "RNAV (RNP) Z RWY 28R", + "RNAV (GPS) X RWY 28L", + "RNAV (GPS) X RWY 28R", + "RNAV (GPS) Y RWY 10L", + "RNAV (GPS) Y RWY 10R", + "LOC/DME RWY 21", + "VOR-A", + "HI-TACAN RWY 10", + "TACAN RWY 28", + "COLUMBIA VISUAL RWY 10L/", + "MILL VISUAL RWY 28L/R" + ] + ) + } +} diff --git a/lib/MessagePack/Tests/MessagePackTests/MessagePackDecodingTests.swift b/lib/MessagePack/Tests/MessagePackTests/MessagePackDecodingTests.swift new file mode 100644 index 000000000..daa6369e9 --- /dev/null +++ b/lib/MessagePack/Tests/MessagePackTests/MessagePackDecodingTests.swift @@ -0,0 +1,301 @@ +import XCTest +@testable import MessagePack + +class MessagePackDecodingTests: XCTestCase { + var decoder: MessagePackDecoder! + + override func setUp() { + self.decoder = MessagePackDecoder() + } + + func assertTypeMismatch(_ expression: @autoclosure () throws -> T, + _ message: @autoclosure () -> String = "", + file: StaticString = #file, + line: UInt = #line) -> Any.Type? { + var error: Error? + XCTAssertThrowsError(expression, message, + file: file, line: line) { + error = $0 + } + guard case .typeMismatch(let type, _) = error as? DecodingError else { + XCTFail(file: file, line: line) + return nil + } + return type + } + + func testDecodeNil() { + let data = Data(bytes: [0xC0]) + let value = try! decoder.decode(Int?.self, from: data) + XCTAssertNil(value) + } + + func testDecodeFalse() { + let data = Data(bytes: [0xc2]) + let value = try! decoder.decode(Bool.self, from: data) + XCTAssertEqual(value, false) + } + + func testDecodeTrue() { + let data = Data(bytes: [0xc3]) + let value = try! decoder.decode(Bool.self, from: data) + XCTAssertEqual(value, true) + } + + func testDecodeInt() { + let data = Data(bytes: [0x2A]) + let value = try! decoder.decode(Int.self, from: data) + XCTAssertEqual(value, 42) + } + + func testDecodeNegativeInt() { + let data = Data(bytes: [0xFF]) + let value = try! decoder.decode(Int.self, from: data) + XCTAssertEqual(value, -1) + } + + func testDecodeUInt() { + let data = Data(bytes: [0xCC, 0x80]) + let value = try! decoder.decode(Int.self, from: data) + XCTAssertEqual(value, 128) + } + + func testDecodeFloat() { + let data = Data(bytes: [0xCA, 0x40, 0x48, 0xF5, 0xC3]) + let value = try! decoder.decode(Float.self, from: data) + XCTAssertEqual(value, 3.14) + } + + func testDecodeFloatToDouble() { + let data = Data(bytes: [0xCA, 0x40, 0x48, 0xF5, 0xC3]) + let type = assertTypeMismatch(try decoder.decode(Double.self, from: data)) + XCTAssertTrue(type is Double.Type) + decoder.nonMatchingFloatDecodingStrategy = .cast + let value = try! decoder.decode(Double.self, from: data) + XCTAssertEqual(value, 3.14, accuracy: 1e-6) + } + + func testDecodeDouble() { + let data = Data(bytes: [0xCB, 0x40, 0x09, 0x21, 0xF9, 0xF0, 0x1B, 0x86, 0x6E]) + let value = try! decoder.decode(Double.self, from: data) + XCTAssertEqual(value, 3.14159) + } + + func testDecodeDoubleToFloat() { + let data = Data(bytes: [0xCB, 0x40, 0x09, 0x21, 0xF9, 0xF0, 0x1B, 0x86, 0x6E]) + let type = assertTypeMismatch(try decoder.decode(Float.self, from: data)) + XCTAssertTrue(type is Float.Type) + decoder.nonMatchingFloatDecodingStrategy = .cast + let value = try! decoder.decode(Float.self, from: data) + XCTAssertEqual(value, 3.14159) + } + + func testDecodeFixedArray() { + let data = Data(bytes: [0x93, 0x01, 0x02, 0x03]) + let value = try! decoder.decode([Int].self, from: data) + XCTAssertEqual(value, [1, 2, 3]) + } + + func testDecodeVariableArray() { + let data = Data(bytes: [0xdc] + [0x00, 0x10] + Array(0x01...0x10)) + let value = try! decoder.decode([Int].self, from: data) + XCTAssertEqual(value, Array(1...16)) + } + + func testDecodeFixedDictionary() { + let data = Data(bytes: [0x83, 0xA1, 0x62, 0x02, 0xA1, 0x61, 0x01, 0xA1, 0x63, 0x03]) + let value = try! decoder.decode([String: Int].self, from: data) + XCTAssertEqual(value, ["a": 1, "b": 2, "c": 3]) + } + + func testDecodeData() { + let data = Data(bytes: [0xC4, 0x05, 0x68, 0x65, 0x6C, 0x6C, 0x6F]) + let value = try! decoder.decode(Data.self, from: data) + XCTAssertEqual(value, "hello".data(using: .utf8)) + } + + func testDecodeDate() { + let data = Data(bytes: [0xD6, 0xFF, 0x00, 0x00, 0x00, 0x01]) + let date = Date(timeIntervalSince1970: 1) + let value = try! decoder.decode(Date.self, from: data) + XCTAssertEqual(value, date) + } + + func testDecodeDistantPast() { + let data = Data(bytes: [0xC7, 0x0C, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xF1, 0x88, 0x6B, 0x66, 0x00]) + let date = Date.distantPast + let value = try! decoder.decode(Date.self, from: data) + XCTAssertEqual(value, date) + } + + func testDecodeDistantFuture() { + let data = Data(bytes: [0xC7, 0x0C, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0xEC, 0x31, 0x88, 0x00]) + let date = Date.distantFuture + let value = try! decoder.decode(Date.self, from: data) + XCTAssertEqual(value, date) + } + + func testDecodeArrayWithDate() { + let data = Data(bytes: [0x91, 0xD6, 0xFF, 0x00, 0x00, 0x00, 0x01]) + let date = Date(timeIntervalSince1970: 1) + let value = try! decoder.decode([Date].self, from: data) + XCTAssertEqual(value, [date]) + } + + func testDecodeDictionaryWithDate() { + let data = Data(bytes: [0x81, 0xA1, 0x31, 0xD6, 0xFF, 0x00, 0x00, 0x00, 0x01]) + let date = Date(timeIntervalSince1970: 1) + let value = try! decoder.decode([String: Date].self, from: data) + XCTAssertEqual(value, ["1": date]) + } + + func testDecodeBv() { + let b64 = "lK50ZXN0aW5nIHN0cmluZyeSpnF3ZXF3ZagxMjNpY29uc5OU2SRlMTZkYTYwMi0zMjE1LTRiZDYtYjY5MC00Y2Q4NmEwZmU3NjSoQ2lwaGVyIDEBk61jaXBodXNlcm5hbWUxrWFkZmFmZHcyMzQxMzGSkblodHRwczovL3d3dy5nb29nbGUuY29tLmFykbVodHRwczovL3d3dy5hcHBsZS5jb22U2SRhNjExMWU2Ny1hMTMwLTRiM2ItODM5NS0xZjIzMDFjNjk3ZjeoQ2lwaGVyIDIBk6g0MzEzMjEzMatqbGpsbHl1bHVpecCU2SRiOGIwODM3MC0xNGU0LTQzZmUtYjBkOS04ZjJlMDlmODJkYzWoQ2lwaGVyIDMBk6twaW9waW9waXBpb6x6eGN6eHZ6eHZ4enaSkbdodHRwczovL3d3dy52aXNhLmNvbS5hcpG1aHR0cHM6Ly93d3cuZG9ja3MuY29t" // array mode with envData and ciphers + +// let b64 = "hKFirnRlc3Rpbmcgc3RyaW5noWMnp2VudkRhdGGCpGJhc2WmcXdlcXdlpWljb25zqDEyM2ljb25zp2NpcGhlcnOThKJpZNkkMDA4YmE0NDctZjU0Mi00OWVjLWJjYTktMDMzZTQ2OTU0YTBipG5hbWWoQ2lwaGVyIDGkdHlwZQGlbG9naW6DqHVzZXJuYW1lrWNpcGh1c2VybmFtZTGkdG90cK1hZGZhZmR3MjM0MTMxpHVyaXOSgaN1cmm5aHR0cHM6Ly93d3cuZ29vZ2xlLmNvbS5hcoGjdXJptWh0dHBzOi8vd3d3LmFwcGxlLmNvbYSiaWTZJDQ1ZTBhODJiLTgyZGQtNDJiZi05ODhhLTAyYTkyNGM4Yzg5M6RuYW1lqENpcGhlciAypHR5cGUBpWxvZ2lug6h1c2VybmFtZag0MzEzMjEzMaR0b3Rwq2psamxseXVsdWl5pHVyaXPAhKJpZNkkZTBjZWU5NDEtZDI1Ni00MjdiLWJkNWUtNDMxMmMwN2U1NDI5pG5hbWWoQ2lwaGVyIDOkdHlwZQGlbG9naW6DqHVzZXJuYW1lq3Bpb3Bpb3BpcGlvpHRvdHCsenhjenh2enh2eHp2pHVyaXOSgaN1cmm3aHR0cHM6Ly93d3cudmlzYS5jb20uYXKBo3VyabVodHRwczovL3d3dy5kb2Nrcy5jb20=" // dict mode with envData and ciphers + + do { + if let d = Data(base64Encoded: b64) { + let decoder = MessagePackDecoder() + decoder.userInfo[MessagePackDecoder.dataSpecKey] = DataSpecBuilder() + .append("b") + .append("c") + .appendObj("envData", DataSpecBuilder() + .append("base") + .append("icons") + .build()) + .appendArray("ciphers", DataSpecBuilder() + .append("id") + .append("name") + .append("type") + .appendObj("login", DataSpecBuilder() + .append("username") + .append("totp") + .appendArray("uris", DataSpecBuilder() + .append("uri") + .build()) + .build()) + .build()) + .build() + + let codTest = try decoder.decode(CodableTest.self, from: d) + + XCTAssertEqual(codTest.b, "testing string") + XCTAssertEqual(codTest.envData.base, "qweqwe") + XCTAssertEqual(codTest.envData.icons, "123icons") + XCTAssertTrue(codTest.ciphers!.count > 1) + } else { + XCTAssertEqual(1, 0) + } + } catch let error { + XCTFail("E: \(error)") + } + } + + static var allTests = [ + ("testDecodeNil", testDecodeNil), + ("testDecodeFalse", testDecodeFalse), + ("testDecodeTrue", testDecodeTrue), + ("testDecodeInt", testDecodeInt), + ("testDecodeUInt", testDecodeUInt), + ("testDecodeFloat", testDecodeFloat), + ("testDecodeFloatToDouble", testDecodeFloatToDouble), + ("testDecodeDouble", testDecodeDouble), + ("testDecodeDoubleToFloat", testDecodeDoubleToFloat), + ("testDecodeFixedArray", testDecodeFixedArray), + ("testDecodeFixedDictionary", testDecodeFixedDictionary), + ("testDecodeData", testDecodeData), + ("testDecodeDistantPast", testDecodeDistantPast), + ("testDecodeDistantFuture", testDecodeDistantFuture), + ("testDecodeArrayWithDate", testDecodeArrayWithDate), + ("testDecodeDictionaryWithDate", testDecodeDictionaryWithDate), + ("testDecodeBv", testDecodeBv) + ] +} + +struct CodableTest : Codable { + enum CodingKeys: Int, CodingKey { + case b + case c + case envData + case ciphers + } + + var b: String + var c: Int + var envData: EnvironmentUrlDataDto + var ciphers: [Cipher]? + + func printt() { + print("B: \(b)") + print("C: \(c)") + print("ENVDATA") + envData.printt() + + if let cs = ciphers { + print("CIPHERS") + for c in cs { + c.printt() + print("----------------------------") + } + } + + print("###########################") + } +} + +struct EnvironmentUrlDataDto : Codable { + var base: String? + var icons: String? + + func printt() { + print("Base: \(base ?? "")") + print("Icons: \(icons ?? "")") + } +} + +struct Cipher:Identifiable,Codable{ + enum CodingKeys: Int, CodingKey { + case id + case name + case login + } + + var id:String + var name:String? + var userId:String? + var login:Login + + func printt() { + print("id: \(id)") + print("name: \(name ?? "")") + print("LOGIN") + login.printt() + } +} + +struct Login:Codable{ + var username:String? + var totp:String? + var uris:[LoginUri]? + + func printt() { + print("username: \(username ?? "")") + print("totp: \(totp ?? "")") + print("URIS") + if let us = uris { + for u in us { + u.printt() + print("----------------------------") + } + } + } +} + +struct LoginUri:Codable{ + var uri:String? + + func printt() { + print("Uri: \(uri ?? "")") + } +} diff --git a/lib/MessagePack/Tests/MessagePackTests/MessagePackEncodingTests.swift b/lib/MessagePack/Tests/MessagePackTests/MessagePackEncodingTests.swift new file mode 100644 index 000000000..1e5768442 --- /dev/null +++ b/lib/MessagePack/Tests/MessagePackTests/MessagePackEncodingTests.swift @@ -0,0 +1,127 @@ +import XCTest +@testable import MessagePack + +class MessagePackEncodingTests: XCTestCase { + var encoder: MessagePackEncoder! + + override func setUp() { + self.encoder = MessagePackEncoder() + } + + func testEncodeNil() { + let value = try! encoder.encode(nil as Int?) + XCTAssertEqual(value, Data(bytes: [0xc0])) + } + + func testEncodeFalse() { + let value = try! encoder.encode(false) + XCTAssertEqual(value, Data(bytes: [0xc2])) + } + + func testEncodeTrue() { + let value = try! encoder.encode(true) + XCTAssertEqual(value, Data(bytes: [0xc3])) + } + + func testEncodeInt() { + let value = try! encoder.encode(42 as Int) + XCTAssertEqual(value, Data(bytes: [0x2A])) + } + + func testEncodeUInt() { + let value = try! encoder.encode(128 as UInt) + XCTAssertEqual(value, Data(bytes: [0xCC, 0x80])) + } + + func testEncodeFloat() { + let value = try! encoder.encode(3.14 as Float) + XCTAssertEqual(value, Data(bytes: [0xCA, 0x40, 0x48, 0xF5, 0xC3])) + } + + func testEncodeDouble() { + let value = try! encoder.encode(3.14159 as Double) + XCTAssertEqual(value, Data(bytes: [0xCB, 0x40, 0x09, 0x21, 0xF9, 0xF0, 0x1B, 0x86, 0x6E])) + } + + func testEncodeString() { + let value = try! encoder.encode("hello") + XCTAssertEqual(value, Data(bytes: [0xA5, 0x68, 0x65, 0x6C, 0x6C, 0x6F])) + } + + func testEncodeFixedArray() { + let value = try! encoder.encode([1, 2, 3]) + XCTAssertEqual(value, Data(bytes: [0x93, 0x01, 0x02, 0x03])) + } + + func testEncodeVariableArray() { + let value = try! encoder.encode(Array(1...16)) + XCTAssertEqual(value, Data(bytes: [0xdc] + [0x00, 0x10] + Array(0x01...0x10))) + } + + func testEncodeFixedDictionary() { + let value = try! encoder.encode(["a": 1]) + XCTAssertEqual(value, Data(bytes: [0x81, 0xA1, 0x61, 0x01])) + } + + func testEncodeVariableDictionary() { + let letters = "abcdefghijklmnopqrstuvwxyz".unicodeScalars + let dictionary = Dictionary(uniqueKeysWithValues: zip(letters.map { String($0) }, 1...26)) + let value = try! encoder.encode(dictionary) + XCTAssertEqual(value.count, 81) + XCTAssert(value.starts(with: [0xde] + [0x00, 0x1A])) + } + + func testEncodeData() { + let data = "hello".data(using: .utf8) + let value = try! encoder.encode(data) + XCTAssertEqual(value, Data(bytes: [0xC4, 0x05, 0x68, 0x65, 0x6C, 0x6C, 0x6F])) + } + + func testEncodeDate() { + let date = Date(timeIntervalSince1970: 1) + let value = try! encoder.encode(date) + XCTAssertEqual(value, Data(bytes: [0xD6, 0xFF, 0x00, 0x00, 0x00, 0x01])) + } + + func testEncodeDistantPast() { + let date = Date.distantPast + let value = try! encoder.encode(date) + XCTAssertEqual(value, Data(bytes: [0xC7, 0x0C, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xF1, 0x88, 0x6B, 0x66, 0x00])) + } + + func testEncodeDistantFuture() { + let date = Date.distantFuture + let value = try! encoder.encode(date) + XCTAssertEqual(value, Data(bytes: [0xC7, 0x0C, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0xEC, 0x31, 0x88, 0x00])) + } + + func testEncodeArrayWithDate() { + let date = Date(timeIntervalSince1970: 1) + let value = try! encoder.encode([date]) + XCTAssertEqual(value, Data(bytes: [0x91, 0xD6, 0xFF, 0x00, 0x00, 0x00, 0x01])) + } + + func testEncodeDictionaryWithDate() { + let date = Date(timeIntervalSince1970: 1) + let value = try! encoder.encode(["1": date]) + XCTAssertEqual(value, Data(bytes: [0x81, 0xA1, 0x31, 0xD6, 0xFF, 0x00, 0x00, 0x00, 0x01])) + } + + static var allTests = [ + ("testEncodeFalse", testEncodeFalse), + ("testEncodeTrue", testEncodeTrue), + ("testEncodeInt", testEncodeInt), + ("testEncodeUInt", testEncodeUInt), + ("testEncodeFloat", testEncodeFloat), + ("testEncodeDouble", testEncodeDouble), + ("testEncodeFixedArray", testEncodeFixedArray), + ("testEncodeVariableArray", testEncodeVariableArray), + ("testEncodeFixedDictionary", testEncodeFixedDictionary), + ("testEncodeVariableDictionary", testEncodeVariableDictionary), + ("testEncodeDate", testEncodeDate), + ("testEncodeDistantPast", testEncodeDistantPast), + ("testEncodeDistantFuture", testEncodeDistantFuture), + ("testEncodeArrayWithDate", testEncodeArrayWithDate), + ("testEncodeDictionaryWithDate", testEncodeDictionaryWithDate) + ] +} diff --git a/lib/MessagePack/Tests/MessagePackTests/MessagePackPerformanceTests.swift b/lib/MessagePack/Tests/MessagePackTests/MessagePackPerformanceTests.swift new file mode 100644 index 000000000..b57a3517a --- /dev/null +++ b/lib/MessagePack/Tests/MessagePackTests/MessagePackPerformanceTests.swift @@ -0,0 +1,23 @@ +import XCTest +@testable import MessagePack + +class MessagePackPerformanceTests: XCTestCase { + var encoder: MessagePackEncoder! + var decoder: MessagePackDecoder! + + override func setUp() { + self.encoder = MessagePackEncoder() + self.decoder = MessagePackDecoder() + } + + func testPerformance() { + let count = 100 + let values = [Airport](repeating: .example, count: count) + + self.measure { + let encoded = try! encoder.encode(values) + let decoded = try! decoder.decode([Airport].self, from: encoded) + XCTAssertEqual(decoded.count, count) + } + } +} diff --git a/lib/MessagePack/Tests/MessagePackTests/MessagePackRoundTripTests.swift b/lib/MessagePack/Tests/MessagePackTests/MessagePackRoundTripTests.swift new file mode 100644 index 000000000..a0304c7cd --- /dev/null +++ b/lib/MessagePack/Tests/MessagePackTests/MessagePackRoundTripTests.swift @@ -0,0 +1,106 @@ +import XCTest +@testable import MessagePack + +class MessagePackRoundTripTests: XCTestCase { + var encoder: MessagePackEncoder! + var decoder: MessagePackDecoder! + + override func setUp() { + self.encoder = MessagePackEncoder() + self.decoder = MessagePackDecoder() + } + + func testRoundTripAirport() { + let value = Airport.example + let encoded = try! encoder.encode(value) + let decoded = try! decoder.decode(Airport.self, from: encoded) + + XCTAssertEqual(value.name, decoded.name) + XCTAssertEqual(value.iata, decoded.iata) + XCTAssertEqual(value.icao, decoded.icao) + XCTAssertEqual(value.coordinates[0], decoded.coordinates[0], accuracy: 0.01) + XCTAssertEqual(value.coordinates[1], decoded.coordinates[1], accuracy: 0.01) + XCTAssertEqual(value.runways[0].direction, decoded.runways[0].direction) + XCTAssertEqual(value.runways[0].distance, decoded.runways[0].distance) + XCTAssertEqual(value.runways[0].surface, decoded.runways[0].surface) + } + + func testRoundTripParachutePack() { + struct Parachute: Codable, Equatable { + enum Canopy: String, Codable, Equatable { + case round, cruciform, rogalloWing, annular, ramAir + } + + let canpoy: Canopy + let surfaceArea: Double + } + + struct ParachutePack: Codable, Equatable { + let main: Parachute? + let reserve: Parachute? + } + + let value = ParachutePack(main: Parachute(canpoy: .ramAir, surfaceArea: 200), reserve: nil) + let encoded = try! encoder.encode(value) + let decoded = try! decoder.decode(ParachutePack.self, from: encoded) + + XCTAssertEqual(value, decoded) + } + + func testRoundTripArray() { + let count: UInt8 = 100 + var bytes: [UInt8] = [0xdc, 0x00, count] + var encoded: [Int] = [] + for n in 1...count { + bytes.append(n) + encoded.append(Int(n)) + } + + let data = Data(bytes: bytes) + let decoded = try! decoder.decode([Int].self, from: data) + XCTAssertEqual(encoded, decoded) + } + + func testRoundTripDictionary() { + let (a, z): (UInt8, UInt8) = (0x61, 0x7a) + var bytes: [UInt8] = [0xde, 0x00, 0x1A] + var encoded: [String: Int] = [:] + for n in a...z { + bytes.append(contentsOf: [0xA1, n, n]) + encoded[String(Unicode.Scalar(n))] = Int(n) + } + + let data = Data(bytes: bytes) + let decoded = try! decoder.decode([String: Int].self, from: data) + XCTAssertEqual(encoded, decoded) + } + + func testRoundTripDate() { + var bytes: [UInt8] = [0xD6, 0xFF] + + let dateComponents = DateComponents(year: 2018, month: 4, day: 20) + let encoded = Calendar.current.date(from: dateComponents)! + + let secondsSince1970 = UInt32(encoded.timeIntervalSince1970) + bytes.append(contentsOf: secondsSince1970.bytes) + + let data = Data(bytes: bytes) + let decoded = try! decoder.decode(Date.self, from: data) + XCTAssertEqual(encoded, decoded) + } + + func testRoundTripDateWithNanoseconds() { + let encoded = Date() + let data = try! self.encoder.encode(encoded) + let decoded = try! self.decoder.decode(Date.self, from: data) + XCTAssertEqual(encoded.timeIntervalSinceReferenceDate, decoded.timeIntervalSinceReferenceDate, accuracy: 0.0001) + } + + static var allTests = [ + ("testRoundTripAirport", testRoundTripAirport), + ("testRoundTripArray", testRoundTripArray), + ("testRoundTripDictionary", testRoundTripDictionary), + ("testRoundTripDate", testRoundTripDate), + ("testRoundTripDateWithNanoseconds", testRoundTripDateWithNanoseconds) + ] +}