├── .gitattributes ├── .github └── workflows │ ├── ci.yml │ └── release.yml ├── .gitignore ├── .gitmodules ├── .vscode └── settings.json ├── Assets └── .gitkeep ├── LICENSE_1_0.txt ├── Makefile ├── Packages ├── manifest.json ├── net.yutopp.vjson │ ├── .gitignore │ ├── LICENSE.txt │ ├── LICENSE.txt.meta │ ├── README.md │ ├── README.md.meta │ ├── Runtime.meta │ ├── Runtime │ │ ├── Attribute.cs │ │ ├── Attribute.cs.meta │ │ ├── IValidator.cs │ │ ├── IValidator.cs.meta │ │ ├── Internal.meta │ │ ├── Internal │ │ │ ├── State.cs │ │ │ └── State.cs.meta │ │ ├── JsonDeserializer.cs │ │ ├── JsonDeserializer.cs.meta │ │ ├── JsonReader.cs │ │ ├── JsonReader.cs.meta │ │ ├── JsonSerializer.cs │ │ ├── JsonSerializer.cs.meta │ │ ├── JsonWriter.cs │ │ ├── JsonWriter.cs.meta │ │ ├── Node.cs │ │ ├── Node.cs.meta │ │ ├── Schema.meta │ │ ├── Schema │ │ │ ├── Attribute.cs │ │ │ ├── Attribute.cs.meta │ │ │ ├── JsonSchema.cs │ │ │ ├── JsonSchema.cs.meta │ │ │ ├── RefTag.cs │ │ │ ├── RefTag.cs.meta │ │ │ ├── Registry.cs │ │ │ ├── Registry.cs.meta │ │ │ ├── Validator.cs │ │ │ └── Validator.cs.meta │ │ ├── TypeHelper.cs │ │ ├── TypeHelper.cs.meta │ │ ├── TypeHelper.g.cs │ │ ├── TypeHelper.g.cs.meta │ │ ├── Unity.net.yutopp.vjson.asmdef │ │ └── Unity.net.yutopp.vjson.asmdef.meta │ ├── Tests.meta │ ├── Tests │ │ ├── Runtime.meta │ │ └── Runtime │ │ │ ├── JsonReaderTest.cs │ │ │ ├── JsonReaderTest.cs.meta │ │ │ ├── JsonSerializerTest.cs │ │ │ ├── JsonSerializerTest.cs.meta │ │ │ ├── JsonWriterTest.cs │ │ │ ├── JsonWriterTest.cs.meta │ │ │ ├── NodeTest.cs │ │ │ ├── NodeTest.cs.meta │ │ │ ├── Schema.meta │ │ │ ├── Schema │ │ │ ├── RegistryTests.cs │ │ │ ├── RegistryTests.cs.meta │ │ │ ├── SchemaTest.cs │ │ │ ├── SchemaTest.cs.meta │ │ │ ├── ValidatorTest.cs │ │ │ └── ValidatorTest.cs.meta │ │ │ ├── Unity.net.yutopp.vjson.Tests.asmdef │ │ │ └── Unity.net.yutopp.vjson.Tests.asmdef.meta │ ├── package.json │ └── package.json.meta └── packages-lock.json ├── ProjectSettings ├── AudioManager.asset ├── ClusterInputManager.asset ├── DynamicsManager.asset ├── EditorBuildSettings.asset ├── EditorSettings.asset ├── GraphicsSettings.asset ├── InputManager.asset ├── NavMeshAreas.asset ├── NetworkManager.asset ├── PackageManagerSettings.asset ├── Physics2DSettings.asset ├── PresetManager.asset ├── ProjectSettings.asset ├── ProjectVersion.txt ├── QualitySettings.asset ├── TagManager.asset ├── TimeManager.asset ├── UnityConnectSettings.asset ├── VFXManager.asset └── XRSettings.asset ├── README.md ├── ci └── run-unity-editor-tests.sh ├── pre-process ├── TypeHelper.g.template.cs └── generator.py └── standalone-project ├── .gitignore ├── Benchmarks ├── Benchmarks.csproj └── Program.cs ├── Tests └── Tests.csproj ├── VJson.sln └── VJson └── VJson.csproj /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | *.cs text eol=lf 3 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | pull_request: 7 | types: [opened, synchronize, reopened] 8 | 9 | jobs: 10 | test_dotnet: 11 | runs-on: ubuntu-20.04 12 | steps: 13 | - name: setup env 14 | run: sudo apt-get update -yy && sudo apt-get install -yy make git python3 15 | 16 | - uses: actions/checkout@v3 17 | with: 18 | submodules: recursive 19 | 20 | - uses: actions/setup-dotnet@v1 21 | with: 22 | dotnet-version: '5.0.x' 23 | 24 | - run: make setup 25 | 26 | - run: make test-dotnet 27 | 28 | coverage: 29 | needs: [test_dotnet] 30 | runs-on: ubuntu-20.04 31 | steps: 32 | - name: setup env 33 | run: sudo apt-get update -yy && sudo apt-get install -yy make git python3 34 | 35 | - uses: actions/checkout@v3 36 | with: 37 | submodules: recursive 38 | 39 | - uses: actions/setup-dotnet@v1 40 | with: 41 | dotnet-version: '5.0.x' 42 | 43 | - run: | 44 | curl -s https://codecov.io/bash > codecov 45 | chmod +x codecov 46 | 47 | - run: make setup 48 | 49 | - run: make coverage-dotnet 50 | 51 | - run: ./codecov -f coverage/lcov.info 52 | 53 | test_unity: 54 | strategy: 55 | matrix: 56 | include: 57 | - unity_version: 2019.4.22f1 58 | docker_container: unityci/editor:ubuntu-2019.4.22f1-base-0.11.0 59 | ulf_secrets_key: UNITY_2019_4_ULF 60 | 61 | runs-on: ubuntu-20.04 62 | container: ${{ matrix.docker_container }} 63 | env: 64 | HAS_XSLTPROC: 1 # To export JUnit formatted Test Summary 65 | steps: 66 | - name: setup env 67 | run: | 68 | apt update -yy && apt install -yy --no-install-recommends software-properties-common 69 | add-apt-repository -yy ppa:git-core/ppa 70 | apt update -yy && apt install -yy --no-install-recommends make git python3 xsltproc 71 | env: 72 | DEBIAN_FRONTEND: noninteractive 73 | 74 | - run: /usr/bin/unity-editor -quit -batchmode -createManualActivationFile || true 75 | if: env.UNITY_ULF == '' 76 | env: 77 | UNITY_ULF: ${{ secrets[matrix.ulf_secrets_key] }} 78 | 79 | - uses: actions/upload-artifact@v1 80 | with: 81 | name: Unity_v${{ matrix.unity_version }}.alf 82 | path: ./Unity_v${{ matrix.unity_version }}.alf 83 | if: env.UNITY_ULF == '' 84 | env: 85 | UNITY_ULF: ${{ secrets[matrix.ulf_secrets_key] }} 86 | 87 | - run: echo "Secret key '$SECRETS_KEY' is empty" && exit 1 88 | if: env.UNITY_ULF == '' 89 | env: 90 | SECRETS_KEY: ${{ matrix.ulf_secrets_key }} 91 | UNITY_ULF: ${{ secrets[matrix.ulf_secrets_key] }} 92 | 93 | - name: setup unity license 94 | run: | 95 | mkdir -p ~/.cache/unity3d 96 | mkdir -p ~/.local/share/unity3d/Unity/ 97 | echo "$UNITY_ULF" | base64 -d > ~/.local/share/unity3d/Unity/Unity_lic.ulf 98 | env: 99 | UNITY_ULF: ${{ secrets[matrix.ulf_secrets_key] }} 100 | 101 | - uses: actions/checkout@v3 102 | with: 103 | submodules: recursive 104 | 105 | - run: make setup 106 | 107 | - name: download RuntimeUnitTestToolkit 108 | run: | 109 | curl -sL https://github.com/Cysharp/RuntimeUnitTestToolkit/releases/download/2.4.0/RuntimeUnitTestToolkit.2.4.0.unitypackage --output RuntimeUnitTestToolkit.unitypackage 110 | 111 | - name: import test runner package (RuntimeUnitTestToolkit) 112 | run: | 113 | /usr/bin/unity-editor \ 114 | -projectPath "$(pwd)" \ 115 | -quit -batchmode -nographics -silent-crashes -logFile \ 116 | -importPackage "$(pwd)/RuntimeUnitTestToolkit.unitypackage" 117 | 118 | - name: built unit-tests (Linux64, mono) 119 | run: | 120 | /usr/bin/unity-editor \ 121 | -projectPath "$(pwd)" \ 122 | -quit -batchmode -nographics -silent-crashes -logFile \ 123 | -executeMethod UnitTestBuilder.BuildUnitTest \ 124 | /headless /ScriptBackend Mono2x /BuildTarget StandaloneLinux64 125 | 126 | - name: run unit-tests 127 | run: | 128 | xvfb-run --auto-servernum --server-args='-screen 0 640x480x24' \ 129 | ./bin/UnitTest/StandaloneLinux64_Mono2x/test 130 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: release 2 | 3 | on: 4 | push: 5 | tags: ['v*'] 6 | 7 | jobs: 8 | publish_to_npm: 9 | runs-on: ubuntu-20.04 10 | steps: 11 | - uses: actions/checkout@v3 12 | with: 13 | submodules: recursive 14 | 15 | - uses: actions/setup-node@v1 16 | with: 17 | node-version: 14 18 | registry-url: https://registry.npmjs.org/ 19 | 20 | - name: publish to npm 21 | if: startsWith( github.ref, 'refs/tags/v' ) 22 | working-directory: ./Packages/net.yutopp.vjson 23 | env: 24 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 25 | REF: ${{ github.ref }} 26 | run: | 27 | cp ../../README.md README.md 28 | cp ../../LICENSE_1_0.txt LICENSE.txt 29 | npm version "${REF#refs/tags/v}" 30 | npm publish --access public 31 | 32 | publish_to_nuget: 33 | runs-on: ubuntu-20.04 34 | steps: 35 | - name: setup env 36 | run: sudo apt-get update -yy && sudo apt-get install -yy make git 37 | 38 | - uses: actions/checkout@v3 39 | with: 40 | submodules: recursive 41 | 42 | - uses: actions/setup-dotnet@v1 43 | with: 44 | dotnet-version: '5.0.x' 45 | 46 | - name: publish to nuget 47 | if: startsWith( github.ref, 'refs/tags/v' ) 48 | env: 49 | NUGET_KEY: ${{ secrets.NUGET_KEY }} 50 | REF: ${{ github.ref }} 51 | run: | 52 | export PROJECT_VERSION="${REF#refs/tags/v}" 53 | make publish-to-nuget 54 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # 2 | # https://raw.githubusercontent.com/github/gitignore/master/Unity.gitignore 3 | # 4 | [Ll]ibrary/ 5 | [Tt]emp/ 6 | [Oo]bj/ 7 | [Bb]uild/ 8 | [Bb]uilds/ 9 | [Ll]ogs/ 10 | 11 | # Never ignore Asset meta data 12 | ![Aa]ssets/**/*.meta 13 | 14 | # Uncomment this line if you wish to ignore the asset store tools plugin 15 | # [Aa]ssets/AssetStoreTools* 16 | 17 | # Visual Studio cache directory 18 | .vs/ 19 | 20 | # Gradle cache directory 21 | .gradle/ 22 | 23 | # Autogenerated VS/MD/Consulo solution and project files 24 | ExportedObj/ 25 | .consulo/ 26 | *.csproj 27 | *.unityproj 28 | *.sln 29 | *.suo 30 | *.tmp 31 | *.user 32 | *.userprefs 33 | *.pidb 34 | *.booproj 35 | *.svd 36 | *.pdb 37 | *.mdb 38 | *.opendb 39 | *.VC.db 40 | 41 | # Unity3D generated meta files 42 | *.pidb.meta 43 | *.pdb.meta 44 | *.mdb.meta 45 | 46 | # Unity3D generated file on crash reports 47 | sysinfo.txt 48 | 49 | # Builds 50 | *.apk 51 | *.unitypackage 52 | 53 | # Crashlytics generated file 54 | crashlytics-build.properties 55 | 56 | # 57 | # 58 | # 59 | Assets/RuntimeUnitTestToolkit/ 60 | Assets/RuntimeUnitTestToolkit.meta 61 | 62 | bin/ 63 | .nuget/ 64 | test-results 65 | lcov.info 66 | coverage.*.info 67 | codecov 68 | BenchmarkDotNet.Artifacts 69 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "Assets/VJson/Editor/Tests/Schema/JSON-Schema-Test-Suite"] 2 | path = Assets/VJson/Editor/Tests/Schema/JSON-Schema-Test-Suite 3 | url = https://github.com/json-schema-org/JSON-Schema-Test-Suite 4 | [submodule "JSON-Schema-Test-Suite"] 5 | path = JSON-Schema-Test-Suite 6 | url = https://github.com/json-schema-org/JSON-Schema-Test-Suite 7 | [submodule "nunit-transforms"] 8 | path = nunit-transforms 9 | url = https://github.com/nunit/nunit-transforms.git 10 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.exclude": 3 | { 4 | "**/.DS_Store":true, 5 | "**/.git":true, 6 | "**/.gitignore":true, 7 | "**/.gitmodules":true, 8 | "**/*.booproj":true, 9 | "**/*.pidb":true, 10 | "**/*.suo":true, 11 | "**/*.user":true, 12 | "**/*.userprefs":true, 13 | "**/*.unityproj":true, 14 | "**/*.dll":true, 15 | "**/*.exe":true, 16 | "**/*.pdf":true, 17 | "**/*.mid":true, 18 | "**/*.midi":true, 19 | "**/*.wav":true, 20 | "**/*.gif":true, 21 | "**/*.ico":true, 22 | "**/*.jpg":true, 23 | "**/*.jpeg":true, 24 | "**/*.png":true, 25 | "**/*.psd":true, 26 | "**/*.tga":true, 27 | "**/*.tif":true, 28 | "**/*.tiff":true, 29 | "**/*.3ds":true, 30 | "**/*.3DS":true, 31 | "**/*.fbx":true, 32 | "**/*.FBX":true, 33 | "**/*.lxo":true, 34 | "**/*.LXO":true, 35 | "**/*.ma":true, 36 | "**/*.MA":true, 37 | "**/*.obj":true, 38 | "**/*.OBJ":true, 39 | "**/*.asset":true, 40 | "**/*.cubemap":true, 41 | "**/*.flare":true, 42 | "**/*.mat":true, 43 | "**/*.meta":true, 44 | "**/*.prefab":true, 45 | // "**/*.unity":true, 46 | "build/":true, 47 | "Build/":true, 48 | "Library/":true, 49 | "library/":true, 50 | "obj/":true, 51 | "Obj/":true, 52 | "ProjectSettings/":true, 53 | "temp/":true, 54 | "Temp/":true 55 | } 56 | } -------------------------------------------------------------------------------- /Assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yutopp/VJson/88817839dfdb6b3212d8f196a025dfe78d319b76/Assets/.gitkeep -------------------------------------------------------------------------------- /LICENSE_1_0.txt: -------------------------------------------------------------------------------- 1 | Boost Software License - Version 1.0 - August 17th, 2003 2 | 3 | Permission is hereby granted, free of charge, to any person or organization 4 | obtaining a copy of the software and accompanying documentation covered by 5 | this license (the "Software") to use, reproduce, display, distribute, 6 | execute, and transmit the Software, and to prepare derivative works of the 7 | Software, and to permit third-parties to whom the Software is furnished to 8 | do so, all subject to the following: 9 | 10 | The copyright notices in the Software and this entire statement, including 11 | the above license grant, this restriction and the following disclaimer, 12 | must be included in all copies of the Software, in whole or in part, and 13 | all derivative works of the Software, unless such copies or derivative 14 | works are solely in the form of machine-executable object code generated by 15 | a source language processor. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 20 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 21 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PROJECT_NAME:=VJson 2 | 3 | PACKAGE_NAME:=net.yutopp.vjson 4 | PACKAGE_DIR:=Packages/${PACKAGE_NAME} 5 | PACKAGE_JSON_PATH:=${PACKAGE_DIR}/package.json 6 | 7 | PROJECT_DIR:=standalone-project 8 | PROJECT_TEST_DIR:=${PROJECT_DIR}/Tests 9 | 10 | DOTNET_FRAMEWORK=net5.0 11 | 12 | PRE_PROCESS_DIR:=pre-process 13 | 14 | .PHONY: test 15 | test: test-dotnet 16 | 17 | .PHONY: setup 18 | setup: pre-generated-files 19 | 20 | .PHONY: pre-generated-files 21 | pre-generated-files: ${PACKAGE_DIR}/Runtime/TypeHelper.g.cs 22 | 23 | ${PACKAGE_DIR}/Runtime/TypeHelper.g.cs: ${PRE_PROCESS_DIR}/generator.py ${PRE_PROCESS_DIR}/TypeHelper.g.template.cs 24 | python3 ${PRE_PROCESS_DIR}/generator.py ${PRE_PROCESS_DIR}/TypeHelper.g.template.cs > $@ 25 | 26 | # .NET Standard 2.x, .NET5.0 27 | .PHONY: restore-dotnet 28 | restore-dotnet: 29 | dotnet restore ${PROJECT_TEST_DIR} 30 | 31 | .PHONY: test-dotnet 32 | test-dotnet: restore-dotnet 33 | mkdir -p test-results/dotnet 34 | dotnet test ${PROJECT_TEST_DIR} -f ${DOTNET_FRAMEWORK} -r test-results/dotnet/results.xml 35 | 36 | .PHONY: coverage-dotnet 37 | coverage-dotnet: restore-dotnet 38 | mkdir -p coverage 39 | dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=lcov -f ${DOTNET_FRAMEWORK} ${PROJECT_TEST_DIR} 40 | cp ${PROJECT_TEST_DIR}/coverage.${DOTNET_FRAMEWORK}.info coverage/lcov.info 41 | 42 | .PHONY: benchmark-dotnet 43 | benchmark-dotnet: 44 | dotnet run -p ${PROJECT_DIR}/Benchmarks -c Release -f ${DOTNET_FRAMEWORK} -- --job short --runtimes core 45 | 46 | # 47 | .PHONY: publish-to-nuget 48 | publish-to-nuget: 49 | dotnet pack ${PROJECT_DIR}/${PROJECT_NAME} -c Release -p:PackageVersion=$(PROJECT_VERSION) 50 | dotnet nuget push $(PROJECT_DIR)/$(PROJECT_NAME)/bin/Release/*.nupkg \ 51 | --api-key $(NUGET_KEY) \ 52 | --source https://api.nuget.org/v3/index.json 53 | -------------------------------------------------------------------------------- /Packages/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "com.unity.ide.vscode": "1.2.4", 4 | "com.unity.test-framework": "1.1.22", 5 | "com.unity.ugui": "1.0.0", 6 | "com.unity.modules.ai": "1.0.0", 7 | "com.unity.modules.androidjni": "1.0.0", 8 | "com.unity.modules.animation": "1.0.0", 9 | "com.unity.modules.assetbundle": "1.0.0", 10 | "com.unity.modules.audio": "1.0.0", 11 | "com.unity.modules.cloth": "1.0.0", 12 | "com.unity.modules.director": "1.0.0", 13 | "com.unity.modules.imageconversion": "1.0.0", 14 | "com.unity.modules.imgui": "1.0.0", 15 | "com.unity.modules.jsonserialize": "1.0.0", 16 | "com.unity.modules.particlesystem": "1.0.0", 17 | "com.unity.modules.physics": "1.0.0", 18 | "com.unity.modules.physics2d": "1.0.0", 19 | "com.unity.modules.screencapture": "1.0.0", 20 | "com.unity.modules.terrain": "1.0.0", 21 | "com.unity.modules.terrainphysics": "1.0.0", 22 | "com.unity.modules.tilemap": "1.0.0", 23 | "com.unity.modules.ui": "1.0.0", 24 | "com.unity.modules.uielements": "1.0.0", 25 | "com.unity.modules.umbra": "1.0.0", 26 | "com.unity.modules.unityanalytics": "1.0.0", 27 | "com.unity.modules.unitywebrequest": "1.0.0", 28 | "com.unity.modules.unitywebrequestassetbundle": "1.0.0", 29 | "com.unity.modules.unitywebrequestaudio": "1.0.0", 30 | "com.unity.modules.unitywebrequesttexture": "1.0.0", 31 | "com.unity.modules.unitywebrequestwww": "1.0.0", 32 | "com.unity.modules.vehicles": "1.0.0", 33 | "com.unity.modules.video": "1.0.0", 34 | "com.unity.modules.vr": "1.0.0", 35 | "com.unity.modules.wind": "1.0.0", 36 | "com.unity.modules.xr": "1.0.0" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Packages/net.yutopp.vjson/.gitignore: -------------------------------------------------------------------------------- 1 | /README.md 2 | /LICENSE.txt 3 | -------------------------------------------------------------------------------- /Packages/net.yutopp.vjson/LICENSE.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yutopp/VJson/88817839dfdb6b3212d8f196a025dfe78d319b76/Packages/net.yutopp.vjson/LICENSE.txt -------------------------------------------------------------------------------- /Packages/net.yutopp.vjson/LICENSE.txt.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a33f8618048317ba1a25cac4a142d386 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Packages/net.yutopp.vjson/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yutopp/VJson/88817839dfdb6b3212d8f196a025dfe78d319b76/Packages/net.yutopp.vjson/README.md -------------------------------------------------------------------------------- /Packages/net.yutopp.vjson/README.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 40bfa0eadb56b9c85971c82aa6ae0132 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Packages/net.yutopp.vjson/Runtime.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a993c396598224dd7b8442b1729c687a 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Packages/net.yutopp.vjson/Runtime/Attribute.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2019- yutopp (yutopp@gmail.com) 3 | // 4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | // file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | 8 | using System; 9 | using System.Collections; 10 | using System.Reflection; 11 | 12 | namespace VJson 13 | { 14 | public enum EnumConversionType 15 | { 16 | AsInt, 17 | AsString, 18 | } 19 | 20 | // NOTE: 21 | // If you are using VJson on pureC#, this Attribute will not have any effect. 22 | // However, as long as you are using it on Unity and IL2CPP, this Attribute will be effective in preventing unnecessary optimization. 23 | // 24 | // See: https://docs.unity3d.com/2019.4/Documentation/ScriptReference/Scripting.PreserveAttribute.html 25 | // > For 3rd party libraries that do not want to take on a dependency on UnityEngine.dll, 26 | // > it is also possible to define their own PreserveAttribute. The code stripper will respect that too, 27 | // > and it will consider any attribute with the exact name "PreserveAttribute" as a reason not to strip the thing it is applied on, 28 | // > regardless of the namespace or assembly of the attribute. 29 | public class PreserveAttribute : System.Attribute { } 30 | 31 | [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum)] 32 | public sealed class JsonAttribute : PreserveAttribute 33 | { 34 | public bool ImplicitConstructable; // Only for classes 35 | public EnumConversionType EnumConversion; // Only for enums 36 | } 37 | 38 | [AttributeUsage(AttributeTargets.Field)] 39 | public sealed class JsonFieldAttribute : PreserveAttribute 40 | { 41 | public string Name; 42 | public int Order = 0; 43 | public Type[] TypeHints; 44 | 45 | public static string FieldName(JsonFieldAttribute f, FieldInfo fi) 46 | { 47 | if (f != null && !string.IsNullOrEmpty(f.Name)) 48 | { 49 | return f.Name; 50 | } 51 | 52 | return fi.Name; 53 | } 54 | 55 | public static int FieldOrder(JsonFieldAttribute f) 56 | { 57 | if (f != null) 58 | { 59 | return f.Order; 60 | } 61 | 62 | return 0; 63 | } 64 | } 65 | 66 | [AttributeUsage(AttributeTargets.Field)] 67 | public sealed class JsonFieldIgnorableAttribute : PreserveAttribute 68 | { 69 | public object WhenValueIs; 70 | public int WhenLengthIs; 71 | 72 | public static bool IsIgnorable(JsonFieldIgnorableAttribute f, T o) 73 | { 74 | if (f == null) 75 | { 76 | return false; 77 | } 78 | 79 | // Value 80 | if (Object.Equals(o, f.WhenValueIs)) 81 | { 82 | return true; 83 | } 84 | 85 | // Length 86 | var a = o as Array; 87 | if (a != null) 88 | { 89 | return a.Length == f.WhenLengthIs; 90 | } 91 | 92 | var l = o as IList; 93 | if (l != null) 94 | { 95 | return l.Count == f.WhenLengthIs; 96 | } 97 | 98 | // Others 99 | return false; 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /Packages/net.yutopp.vjson/Runtime/Attribute.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6a445b67708ca60488537856b31b0cb9 3 | timeCreated: 1550036451 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Packages/net.yutopp.vjson/Runtime/IValidator.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2019- yutopp (yutopp@gmail.com) 3 | // 4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | // file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | 8 | namespace VJson 9 | { 10 | public interface IValidator 11 | { 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Packages/net.yutopp.vjson/Runtime/IValidator.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2ec10726970f22d40a4ada336e96e018 3 | timeCreated: 1549510320 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Packages/net.yutopp.vjson/Runtime/Internal.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b3f5b9bae155547b98ece943298f7d46 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Packages/net.yutopp.vjson/Runtime/Internal/State.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2019- yutopp (yutopp@gmail.com) 3 | // 4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | // file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | 8 | using System; 9 | using System.Collections.Generic; 10 | using System.Linq; 11 | 12 | namespace VJson.Internal 13 | { 14 | internal struct State 15 | { 16 | string _elemName; 17 | string ElemName 18 | { 19 | get 20 | { 21 | return !string.IsNullOrEmpty(_elemName) ? _elemName : "(root)"; 22 | } 23 | } 24 | 25 | internal State NestAsElem(int elem) 26 | { 27 | return new State() 28 | { 29 | _elemName = String.Format("{0}[{1}]", ElemName, elem), 30 | }; 31 | } 32 | 33 | internal State NestAsElem(string elem) 34 | { 35 | return new State() 36 | { 37 | _elemName = String.Format("{0}[\"{1}\"]", ElemName, elem), 38 | }; 39 | } 40 | 41 | internal string CreateMessage(string format, params object[] args) 42 | { 43 | return String.Format("{0}: {1}.", ElemName, String.Format(format, args)); 44 | } 45 | } 46 | 47 | internal static class StateExtension 48 | { 49 | public static string CreateNodeConversionFailureMessage(this State s, INode fromNode, IEnumerable toTypes) 50 | { 51 | var toTypesStr = string.Format("one of [{0}]", 52 | string.Join(", ", toTypes.Select(t => t.ToString()).ToArray())); 53 | return CreateNodeConversionFailureMessage(s, fromNode, toTypesStr); 54 | } 55 | 56 | public static string CreateNodeConversionFailureMessage(this State s, INode fromNode, Type toType) 57 | { 58 | var toTypeStr = toType.ToString(); 59 | 60 | switch (fromNode.Kind) 61 | { 62 | case NodeKind.Null: 63 | if (!TypeHelper.IsBoxed(toType)) 64 | { 65 | toTypeStr = string.Format("non-boxed value({0})", toTypeStr); 66 | } 67 | break; 68 | } 69 | 70 | return CreateNodeConversionFailureMessage(s, fromNode, toTypeStr); 71 | } 72 | 73 | private static string CreateNodeConversionFailureMessage(this State s, INode fromNode, string toDetail) 74 | { 75 | var fromNodeStr = string.Format("{0} node", fromNode.Kind); 76 | switch (fromNode.Kind) 77 | { 78 | case NodeKind.Boolean: 79 | fromNodeStr = string.Format("{0} ({1})", fromNodeStr, ((BooleanNode)fromNode).Value); 80 | break; 81 | 82 | case NodeKind.Integer: 83 | fromNodeStr = string.Format("{0} ({1})", fromNodeStr, ((IntegerNode)fromNode).Value); 84 | break; 85 | 86 | case NodeKind.Float: 87 | fromNodeStr = string.Format("{0} ({1})", fromNodeStr, ((FloatNode)fromNode).Value); 88 | break; 89 | } 90 | 91 | return s.CreateMessage("{0} cannot convert to {1}", fromNodeStr, toDetail); 92 | } 93 | 94 | public static string CreateTypeConversionFailureMessage(this State s, 95 | T fromValue, 96 | Type toType, 97 | string reason = null) 98 | { 99 | var introStr = string.Format("{0} value", typeof(T).ToString()); 100 | 101 | var kind = Node.KindOfType(typeof(T)); 102 | switch (kind) 103 | { 104 | case NodeKind.Boolean: 105 | case NodeKind.Integer: 106 | case NodeKind.Float: 107 | introStr = string.Format("{0} ({1})", introStr, fromValue); 108 | break; 109 | } 110 | 111 | var msgBase = string.Format("{0} cannot convert to {1}", introStr, toType); 112 | if (reason != null) 113 | { 114 | msgBase = string.Format("{0} (Reason: {1})", msgBase, reason); 115 | } 116 | return s.CreateMessage(msgBase); 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /Packages/net.yutopp.vjson/Runtime/Internal/State.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1ab0ed349f969498fba4e5507e01bd54 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Packages/net.yutopp.vjson/Runtime/JsonDeserializer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d65bb258fe72f91478e552ebea808790 3 | timeCreated: 1550036451 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Packages/net.yutopp.vjson/Runtime/JsonReader.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2019- yutopp (yutopp@gmail.com) 3 | // 4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | // file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | 8 | using System; 9 | using System.Globalization; 10 | using System.IO; 11 | using System.Text; 12 | using System.Text.RegularExpressions; 13 | 14 | namespace VJson 15 | { 16 | public sealed class JsonReader : IDisposable 17 | { 18 | private ReaderWrapper _reader; 19 | 20 | private StringBuilder _strCache = new StringBuilder(); 21 | 22 | public JsonReader(Stream s) 23 | { 24 | _reader = new ReaderWrapper(s); 25 | } 26 | 27 | public void Dispose() 28 | { 29 | if (_reader != null) 30 | { 31 | ((IDisposable)_reader).Dispose(); 32 | } 33 | } 34 | 35 | public INode Read() 36 | { 37 | var node = ReadElement(); 38 | 39 | var next = _reader.Peek(); 40 | if (next != -1) 41 | { 42 | throw NodeExpectedError("EOS"); 43 | } 44 | 45 | return node; 46 | } 47 | 48 | INode ReadElement() 49 | { 50 | SkipWS(); 51 | var node = ReadValue(); 52 | SkipWS(); 53 | 54 | return node; 55 | } 56 | 57 | INode ReadValue() 58 | { 59 | INode node = null; 60 | 61 | if ((node = ReadObject()) != null) 62 | { 63 | return node; 64 | } 65 | 66 | if ((node = ReadArray()) != null) 67 | { 68 | return node; 69 | } 70 | 71 | if ((node = ReadString()) != null) 72 | { 73 | return node; 74 | } 75 | 76 | if ((node = ReadNumber()) != null) 77 | { 78 | return node; 79 | } 80 | 81 | if ((node = ReadLiteral()) != null) 82 | { 83 | return node; 84 | } 85 | 86 | throw NodeExpectedError("value"); 87 | } 88 | 89 | INode ReadObject() 90 | { 91 | var next = _reader.Peek(); 92 | if (next != '{') 93 | { 94 | return null; 95 | } 96 | _reader.Read(); // Discard 97 | 98 | var node = new ObjectNode(); 99 | 100 | for (int i = 0; ; ++i) 101 | { 102 | SkipWS(); 103 | 104 | next = _reader.Peek(); 105 | if (next == '}') 106 | { 107 | _reader.Read(); // Discard 108 | break; 109 | } 110 | 111 | if (i > 0) 112 | { 113 | if (next != ',') 114 | { 115 | throw TokenExpectedError(','); 116 | } 117 | _reader.Read(); // Discard 118 | } 119 | 120 | SkipWS(); 121 | INode keyNode = ReadString(); 122 | if (keyNode == null) 123 | { 124 | throw NodeExpectedError("string"); 125 | } 126 | SkipWS(); 127 | 128 | next = _reader.Peek(); 129 | if (next != ':') 130 | { 131 | throw TokenExpectedError(':'); 132 | } 133 | _reader.Read(); // Discard 134 | 135 | INode elemNode = ReadElement(); 136 | if (elemNode == null) 137 | { 138 | throw NodeExpectedError("element"); 139 | } 140 | 141 | node.AddElement(((StringNode)keyNode).Value, elemNode); 142 | } 143 | 144 | return node; 145 | } 146 | 147 | INode ReadArray() 148 | { 149 | var next = _reader.Peek(); 150 | if (next != '[') 151 | { 152 | return null; 153 | } 154 | _reader.Read(); // Discard 155 | 156 | var node = new ArrayNode(); 157 | 158 | for (int i = 0; ; ++i) 159 | { 160 | SkipWS(); 161 | 162 | next = _reader.Peek(); 163 | if (next == ']') 164 | { 165 | _reader.Read(); // Discard 166 | break; 167 | } 168 | 169 | if (i > 0) 170 | { 171 | if (next != ',') 172 | { 173 | throw TokenExpectedError(','); 174 | } 175 | _reader.Read(); // Discard 176 | } 177 | 178 | INode elemNode = ReadElement(); 179 | if (elemNode == null) 180 | { 181 | throw NodeExpectedError("element"); 182 | } 183 | 184 | node.AddElement(elemNode); 185 | } 186 | 187 | return node; 188 | } 189 | 190 | INode ReadString() 191 | { 192 | var next = _reader.Peek(); 193 | if (next != '"') 194 | { 195 | return null; 196 | } 197 | _reader.Read(); // Discard 198 | 199 | for (; ; ) 200 | { 201 | next = _reader.Peek(); 202 | switch (next) 203 | { 204 | case '"': 205 | _reader.Read(); // Discard 206 | 207 | var span = CommitBuffer(); 208 | var str = Regex.Unescape(span); 209 | return new StringNode(str); 210 | 211 | case '\\': 212 | _reader.Read(); // Discard 213 | 214 | if (!ReadEscape()) 215 | { 216 | throw NodeExpectedError("escape"); 217 | }; 218 | break; 219 | 220 | default: 221 | var c = _reader.Read(); // Consume 222 | var codePoint = c; 223 | var isPair = char.IsHighSurrogate((char)c); 224 | if (isPair) 225 | { 226 | next = _reader.Read(); // Consume 227 | if (!char.IsLowSurrogate((char)next)) 228 | { 229 | throw NodeExpectedError("low-surrogate"); 230 | } 231 | codePoint = char.ConvertToUtf32((char)c, (char)next); 232 | } 233 | 234 | if (codePoint < 0x20 || codePoint > 0x10ffff) 235 | { 236 | throw NodeExpectedError("unicode char (0x20 <= char <= 0x10ffff"); 237 | } 238 | 239 | SaveToBuffer(c); 240 | if (isPair) 241 | { 242 | SaveToBuffer(next); 243 | } 244 | 245 | break; 246 | } 247 | } 248 | } 249 | 250 | bool ReadEscape() 251 | { 252 | var next = _reader.Peek(); 253 | switch (next) 254 | { 255 | case '\"': 256 | SaveToBuffer('\\'); 257 | SaveToBuffer(_reader.Read()); 258 | return true; 259 | 260 | case '\\': 261 | SaveToBuffer('\\'); 262 | SaveToBuffer(_reader.Read()); 263 | return true; 264 | 265 | case '/': 266 | // Escape is not required in C# 267 | SaveToBuffer(_reader.Read()); 268 | return true; 269 | 270 | case 'b': 271 | SaveToBuffer('\\'); 272 | SaveToBuffer(_reader.Read()); 273 | return true; 274 | 275 | case 'n': 276 | SaveToBuffer('\\'); 277 | SaveToBuffer(_reader.Read()); 278 | return true; 279 | 280 | case 'r': 281 | SaveToBuffer('\\'); 282 | SaveToBuffer(_reader.Read()); 283 | return true; 284 | 285 | case 't': 286 | SaveToBuffer('\\'); 287 | SaveToBuffer(_reader.Read()); 288 | return true; 289 | 290 | case 'u': 291 | SaveToBuffer('\\'); 292 | SaveToBuffer(_reader.Read()); 293 | for (int i = 0; i < 4; ++i) 294 | { 295 | if (!ReadHex()) 296 | { 297 | throw NodeExpectedError("hex"); 298 | } 299 | } 300 | return true; 301 | 302 | default: 303 | return false; 304 | } 305 | } 306 | 307 | bool ReadHex() 308 | { 309 | if (ReadDigit()) 310 | { 311 | return true; 312 | } 313 | 314 | var next = _reader.Peek(); 315 | if (next >= 'A' && next <= 'F') 316 | { 317 | SaveToBuffer(_reader.Read()); 318 | return true; 319 | } 320 | 321 | if (next >= 'a' && next <= 'f') 322 | { 323 | SaveToBuffer(_reader.Read()); 324 | return true; 325 | } 326 | 327 | return false; 328 | } 329 | 330 | INode ReadNumber() 331 | { 332 | if (!ReadInt()) 333 | { 334 | return null; 335 | } 336 | 337 | var isFloat = false; 338 | isFloat |= ReadFrac(); 339 | isFloat |= ReadExp(); 340 | 341 | var span = CommitBuffer(); 342 | if (isFloat) 343 | { 344 | var v = double.Parse(span, CultureInfo.InvariantCulture); // TODO: Fix for large numbers 345 | return new FloatNode(v); 346 | } else { 347 | var v = long.Parse(span, CultureInfo.InvariantCulture); // TODO: Fix for large numbers 348 | return new IntegerNode(v); 349 | } 350 | } 351 | 352 | bool ReadInt() 353 | { 354 | if (ReadOneNine()) 355 | { 356 | ReadDigits(); 357 | return true; 358 | } 359 | 360 | if (ReadDigit()) 361 | { 362 | return true; 363 | } 364 | 365 | var next = _reader.Peek(); 366 | if (next != '-') 367 | { 368 | return false; 369 | } 370 | 371 | SaveToBuffer(_reader.Read()); 372 | 373 | if (ReadOneNine()) 374 | { 375 | ReadDigits(); 376 | return true; 377 | } 378 | 379 | if (ReadDigit()) 380 | { 381 | return true; 382 | } 383 | 384 | throw NodeExpectedError("number"); 385 | } 386 | 387 | bool ReadDigits() 388 | { 389 | if (!ReadDigit()) 390 | { 391 | return false; 392 | } 393 | 394 | while (ReadDigit()) { } 395 | return true; 396 | } 397 | 398 | bool ReadDigit() 399 | { 400 | var next = _reader.Peek(); 401 | if (next != '0') 402 | { 403 | return ReadOneNine(); 404 | } 405 | 406 | SaveToBuffer(_reader.Read()); 407 | 408 | return true; 409 | } 410 | 411 | bool ReadOneNine() 412 | { 413 | var next = _reader.Peek(); 414 | if (next < '1' || next > '9') 415 | { 416 | return false; 417 | } 418 | 419 | SaveToBuffer(_reader.Read()); 420 | 421 | return true; 422 | } 423 | 424 | bool ReadFrac() 425 | { 426 | var next = _reader.Peek(); 427 | if (next != '.') 428 | { 429 | return false; 430 | } 431 | 432 | SaveToBuffer(_reader.Read()); 433 | 434 | if (!ReadDigits()) 435 | { 436 | throw NodeExpectedError("digits"); 437 | } 438 | 439 | return true; 440 | } 441 | 442 | bool ReadExp() 443 | { 444 | var next = _reader.Peek(); 445 | if (next != 'E' && next != 'e') 446 | { 447 | return false; 448 | } 449 | 450 | SaveToBuffer(_reader.Read()); 451 | 452 | ReadSign(); 453 | 454 | if (!ReadDigits()) 455 | { 456 | throw NodeExpectedError("digits"); 457 | } 458 | 459 | return true; 460 | } 461 | 462 | bool ReadSign() 463 | { 464 | var next = _reader.Peek(); 465 | if (next != '+' && next != '-') 466 | { 467 | return false; 468 | } 469 | 470 | SaveToBuffer(_reader.Read()); 471 | 472 | return true; 473 | } 474 | 475 | INode ReadLiteral() 476 | { 477 | var s = String.Empty; 478 | 479 | var next = _reader.Peek(); 480 | switch (next) 481 | { 482 | case 't': 483 | // Maybe true 484 | s = ConsumeChars(4); 485 | if (s.ToLower() != "true") 486 | { 487 | throw NodeExpectedError("true"); 488 | } 489 | return new BooleanNode(true); 490 | 491 | case 'f': 492 | // Maybe false 493 | s = ConsumeChars(5); 494 | if (s.ToLower() != "false") 495 | { 496 | throw NodeExpectedError("false"); 497 | } 498 | return new BooleanNode(false); 499 | 500 | case 'n': 501 | // Maybe null 502 | s = ConsumeChars(4); 503 | if (s.ToLower() != "null") 504 | { 505 | throw NodeExpectedError("null"); 506 | } 507 | return new NullNode(); 508 | 509 | default: 510 | return null; 511 | } 512 | } 513 | 514 | void SkipWS() 515 | { 516 | for (; ; ) 517 | { 518 | var next = _reader.Peek(); 519 | switch (next) 520 | { 521 | case 0x0009: 522 | case 0x000a: 523 | case 0x000d: 524 | case 0x0020: 525 | _reader.Read(); // Discard 526 | break; 527 | 528 | default: 529 | return; 530 | } 531 | } 532 | } 533 | 534 | void SaveToBuffer(int c) 535 | { 536 | _strCache.Append((char)c); 537 | } 538 | 539 | string CommitBuffer() 540 | { 541 | var span = _strCache.ToString(); 542 | _strCache.Length = 0; 543 | 544 | return span; 545 | } 546 | 547 | string ConsumeChars(int length) 548 | { 549 | for (int i = 0; i < length; ++i) 550 | { 551 | var c = _reader.Read(); 552 | SaveToBuffer(c); 553 | } 554 | return CommitBuffer(); 555 | } 556 | 557 | ParseFailedException NodeExpectedError(string expected) 558 | { 559 | var msg = String.Format("A node \"{0}\" is expected but '{1}' is provided", expected, _reader.LastToken); 560 | return new ParseFailedException(msg, _reader.Position); 561 | } 562 | 563 | ParseFailedException TokenExpectedError(char expected) 564 | { 565 | var msg = String.Format("A charactor '{0}' is expected but '{1}' is provided", expected, _reader.LastToken); 566 | return new ParseFailedException(msg, _reader.Position); 567 | } 568 | 569 | private class ReaderWrapper : IDisposable 570 | { 571 | private StreamReader _reader; 572 | 573 | public ulong Position 574 | { 575 | get; private set; 576 | } 577 | 578 | private int _lastToken; 579 | public string LastToken 580 | { 581 | get 582 | { 583 | if (_lastToken == -1) { 584 | return ""; 585 | } 586 | return ((char)_lastToken).ToString(); 587 | } 588 | } 589 | 590 | public ReaderWrapper(Stream s) 591 | { 592 | _reader = new StreamReader(s); // Encodings will be auto detected 593 | Position = 0; 594 | } 595 | 596 | public void Dispose() 597 | { 598 | if (_reader != null) 599 | { 600 | ((IDisposable)_reader).Dispose(); 601 | } 602 | } 603 | 604 | public int Peek() 605 | { 606 | _lastToken = _reader.Peek(); 607 | return _lastToken; 608 | } 609 | 610 | public int Read() 611 | { 612 | ++Position; 613 | 614 | _lastToken = _reader.Read(); 615 | return _lastToken; 616 | } 617 | } 618 | } 619 | 620 | public class ParseFailedException : Exception 621 | { 622 | public ParseFailedException(string message, ulong pos) 623 | : base(String.Format("{0} (at position {1})", message, pos)) 624 | { 625 | } 626 | } 627 | } 628 | -------------------------------------------------------------------------------- /Packages/net.yutopp.vjson/Runtime/JsonReader.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4d2b09458723c944fbc27a8972373501 3 | timeCreated: 1549512001 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Packages/net.yutopp.vjson/Runtime/JsonSerializer.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2019- yutopp (yutopp@gmail.com) 3 | // 4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | // file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | 8 | using System; 9 | using System.IO; 10 | using System.Text; 11 | using System.Collections.Generic; 12 | 13 | namespace VJson 14 | { 15 | public sealed class JsonSerializer 16 | { 17 | private Type _type; 18 | 19 | public JsonSerializer(Type type) 20 | { 21 | this._type = type; 22 | } 23 | 24 | #region Serializer 25 | 26 | public void Serialize(Stream s, T o, int indent = 0) 27 | { 28 | using (var w = new JsonWriter(s, indent)) 29 | { 30 | SerializeValue(w, o); 31 | } 32 | } 33 | 34 | public string Serialize(T o, int indent = 0) 35 | { 36 | using (var s = new MemoryStream()) 37 | { 38 | Serialize(s, o, indent); 39 | return Encoding.UTF8.GetString(s.ToArray()); 40 | } 41 | } 42 | 43 | public INode SerializeToNode(T o) 44 | { 45 | // TODO: fix performance... 46 | byte[] buffer = null; 47 | using (var s = new MemoryStream()) 48 | { 49 | Serialize(s, o, 0); 50 | buffer = s.ToArray(); 51 | } 52 | 53 | using (var s = new MemoryStream(buffer)) 54 | { 55 | var d = new JsonDeserializer(typeof(INode)); 56 | return d.Deserialize(s) as INode; 57 | } 58 | } 59 | 60 | void SerializeValue(JsonWriter writer, T o) 61 | { 62 | if (o != null && o is INode) { 63 | // unwrap INode 64 | SerializeValue(writer, (o as INode).GenericContent); 65 | return; 66 | } 67 | var kind = Node.KindOfValue(o); 68 | 69 | switch (kind) 70 | { 71 | case NodeKind.String: 72 | case NodeKind.Integer: 73 | case NodeKind.Float: 74 | case NodeKind.Boolean: 75 | SerializePrimitive(writer, o); 76 | return; 77 | case NodeKind.Array: 78 | SerializeArray(writer, o); 79 | return; 80 | case NodeKind.Object: 81 | SerializeObject(writer, o); 82 | return; 83 | case NodeKind.Null: 84 | SerializeNull(writer, o); 85 | return; 86 | } 87 | } 88 | 89 | static readonly Dictionary> writeActionMap = new Dictionary>() 90 | { 91 | {typeof(short), (writer, v) => writer.WriteValue((short)v)}, 92 | {typeof(ushort), (writer, v) => writer.WriteValue((ushort)v)}, 93 | {typeof(int), (writer, v) => writer.WriteValue((int)v)}, 94 | {typeof(uint), (writer, v) => writer.WriteValue((uint)v)}, 95 | {typeof(long), (writer, v) => writer.WriteValue((long)v)}, 96 | {typeof(ulong), (writer, v) => writer.WriteValue((ulong)v)}, 97 | {typeof(float), (writer, v) => writer.WriteValue((float)v)}, 98 | {typeof(double), (writer, v) => writer.WriteValue((double)v)}, 99 | {typeof(bool), (writer, v) => writer.WriteValue((bool)v)}, 100 | {typeof(byte), (writer, v) => writer.WriteValue((byte)v)}, 101 | {typeof(sbyte), (writer, v) => writer.WriteValue((sbyte)v)}, 102 | {typeof(char), (writer, v) => writer.WriteValue((char)v)}, 103 | {typeof(string), (writer, v) => writer.WriteValue((string)v)}, 104 | {typeof(decimal), (writer, v) => writer.WriteValue((decimal)v)}, 105 | }; 106 | 107 | void SerializePrimitive(JsonWriter writer, T o) 108 | { 109 | var ty = o.GetType(); 110 | if (ty.IsEnum) 111 | { 112 | var attr = TypeHelper.GetCustomAttribute(ty); 113 | switch (attr != null ? attr.EnumConversion : EnumConversionType.AsInt) 114 | { 115 | case EnumConversionType.AsInt: 116 | // Convert to simple integer 117 | SerializeValue(writer, Convert.ChangeType(o, Enum.GetUnderlyingType(ty))); 118 | break; 119 | 120 | case EnumConversionType.AsString: 121 | SerializeValue(writer, TypeHelper.GetStringEnumNameOf(o)); 122 | break; 123 | } 124 | 125 | return; 126 | } 127 | 128 | if (writeActionMap.TryGetValue(ty, out var write)) 129 | { 130 | write(writer, o); 131 | } 132 | else 133 | { 134 | throw new Exception( 135 | string.Format( 136 | "SerializePrimitive method require primitive type, but {0} is not primitive type ({1})", 137 | o, 138 | ty.ToString() 139 | ) 140 | ); 141 | } 142 | } 143 | 144 | void SerializeArray(JsonWriter writer, T o) 145 | { 146 | writer.WriteArrayStart(); 147 | 148 | foreach (var elem in TypeHelper.ToIEnumerable(o)) 149 | { 150 | SerializeValue(writer, elem); 151 | } 152 | 153 | writer.WriteArrayEnd(); 154 | } 155 | 156 | void SerializeObject(JsonWriter writer, T o) 157 | { 158 | writer.WriteObjectStart(); 159 | 160 | foreach (var kv in TypeHelper.ToKeyValues(o)) 161 | { 162 | writer.WriteObjectKey(kv.Key); 163 | SerializeValue(writer, kv.Value); 164 | } 165 | 166 | writer.WriteObjectEnd(); 167 | } 168 | 169 | void SerializeNull(JsonWriter writer, T o) 170 | { 171 | writer.WriteValueNull(); 172 | } 173 | #endregion 174 | 175 | #region Deserializer 176 | public object Deserialize(String text) 177 | { 178 | var d = new JsonDeserializer(_type); 179 | return d.Deserialize(text); 180 | } 181 | 182 | public object Deserialize(Stream s) 183 | { 184 | var d = new JsonDeserializer(_type); 185 | return d.Deserialize(s); 186 | } 187 | #endregion 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /Packages/net.yutopp.vjson/Runtime/JsonSerializer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cccccf60b4aea4455a8faff82136476b 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Packages/net.yutopp.vjson/Runtime/JsonWriter.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2019- yutopp (yutopp@gmail.com) 3 | // 4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | // file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | 8 | using System; 9 | using System.Collections.Generic; 10 | using System.Linq; 11 | using System.IO; 12 | 13 | namespace VJson 14 | { 15 | /// 16 | /// Write JSON data to streams as UTF-8. 17 | /// 18 | // TODO: Add [Preserve] in Unity 19 | public sealed class JsonWriter : IDisposable 20 | { 21 | struct State 22 | { 23 | public StateKind Kind; 24 | public int Depth; 25 | } 26 | 27 | enum StateKind 28 | { 29 | ObjectKeyHead, 30 | ObjectKeyOther, 31 | ObjectValue, 32 | ArrayHead, 33 | ArrayOther, 34 | None, 35 | } 36 | 37 | private StreamWriter _writer; 38 | private int _indent; 39 | private string _indentStr = null; 40 | 41 | private Stack _states = new Stack(); 42 | 43 | public JsonWriter(Stream s, int indent = 0) 44 | { 45 | _writer = new StreamWriter(s); // UTF-8 by default 46 | _indent = indent; 47 | if (_indent > 0) { 48 | _indentStr = new String(' ', _indent); 49 | } 50 | 51 | _states.Push(new State 52 | { 53 | Kind = StateKind.None, 54 | Depth = 0, 55 | }); 56 | } 57 | 58 | public void Dispose() 59 | { 60 | if (_writer != null) 61 | { 62 | ((IDisposable)_writer).Dispose(); 63 | } 64 | } 65 | 66 | public void WriteObjectStart() 67 | { 68 | var state = _states.Peek(); 69 | if (state.Kind == StateKind.ObjectKeyHead || state.Kind == StateKind.ObjectKeyOther) 70 | { 71 | throw new Exception(""); 72 | } 73 | 74 | WriteDelimiter(); 75 | _writer.Write("{"); 76 | 77 | _states.Push(new State 78 | { 79 | Kind = StateKind.ObjectKeyHead, 80 | Depth = state.Depth + 1, 81 | }); 82 | } 83 | 84 | public void WriteObjectKey(string key) 85 | { 86 | var state = _states.Peek(); 87 | if (state.Kind != StateKind.ObjectKeyHead && state.Kind != StateKind.ObjectKeyOther) 88 | { 89 | throw new Exception(""); 90 | } 91 | 92 | WriteValue(key); 93 | _writer.Write(":"); 94 | 95 | _states.Pop(); 96 | _states.Push(new State 97 | { 98 | Kind = StateKind.ObjectValue, 99 | Depth = state.Depth, 100 | }); 101 | } 102 | 103 | public void WriteObjectEnd() 104 | { 105 | var state = _states.Peek(); 106 | if (state.Kind != StateKind.ObjectKeyHead && state.Kind != StateKind.ObjectKeyOther) 107 | { 108 | throw new Exception(""); 109 | } 110 | 111 | _states.Pop(); 112 | 113 | if (state.Kind == StateKind.ObjectKeyOther) 114 | { 115 | WriteIndentBreakForHuman(_states.Peek().Depth); 116 | } 117 | _writer.Write("}"); 118 | } 119 | 120 | public void WriteArrayStart() 121 | { 122 | var state = _states.Peek(); 123 | if (state.Kind == StateKind.ObjectKeyHead || state.Kind == StateKind.ObjectKeyOther) 124 | { 125 | throw new Exception(""); 126 | } 127 | 128 | WriteDelimiter(); 129 | _writer.Write("["); 130 | 131 | _states.Push(new State 132 | { 133 | Kind = StateKind.ArrayHead, 134 | Depth = state.Depth + 1, 135 | }); 136 | } 137 | 138 | public void WriteArrayEnd() 139 | { 140 | var state = _states.Peek(); 141 | if (state.Kind != StateKind.ArrayHead && state.Kind != StateKind.ArrayOther) 142 | { 143 | throw new Exception(""); 144 | } 145 | 146 | _states.Pop(); 147 | 148 | if (state.Kind == StateKind.ArrayOther) 149 | { 150 | WriteIndentBreakForHuman(_states.Peek().Depth); 151 | } 152 | _writer.Write("]"); 153 | } 154 | 155 | public void WriteValue(bool v) 156 | { 157 | WriteDelimiter(); 158 | 159 | _writer.Write(v ? "true" : "false"); 160 | } 161 | 162 | public void WriteValue(byte v) 163 | { 164 | WritePrimitive(v); 165 | } 166 | 167 | public void WriteValue(sbyte v) 168 | { 169 | WritePrimitive(v); 170 | } 171 | 172 | public void WriteValue(char v) 173 | { 174 | WritePrimitive(v); 175 | } 176 | 177 | public void WriteValue(decimal v) 178 | { 179 | WritePrimitive(v); 180 | } 181 | 182 | public void WriteValue(double v) 183 | { 184 | WritePrimitive(v); 185 | } 186 | 187 | public void WriteValue(float v) 188 | { 189 | WritePrimitive(v); 190 | } 191 | 192 | public void WriteValue(int v) 193 | { 194 | WritePrimitive(v); 195 | } 196 | 197 | public void WriteValue(uint v) 198 | { 199 | WritePrimitive(v); 200 | } 201 | 202 | public void WriteValue(long v) 203 | { 204 | WritePrimitive(v); 205 | } 206 | 207 | public void WriteValue(ulong v) 208 | { 209 | WritePrimitive(v); 210 | } 211 | 212 | public void WriteValue(short v) 213 | { 214 | WritePrimitive(v); 215 | } 216 | 217 | public void WriteValue(ushort v) 218 | { 219 | WritePrimitive(v); 220 | } 221 | 222 | public void WriteValue(string v) 223 | { 224 | WriteDelimiter(); 225 | 226 | _writer.Write('\"'); 227 | _writer.Write(Escape(v).ToArray()); 228 | _writer.Write('\"'); 229 | } 230 | 231 | public void WriteValueNull() 232 | { 233 | WriteDelimiter(); 234 | 235 | _writer.Write("null"); 236 | } 237 | 238 | void WritePrimitive(char v) 239 | { 240 | WritePrimitive((int)v); 241 | } 242 | 243 | void WritePrimitive(float v) 244 | { 245 | WritePrimitive(string.Format("{0:G9}", v)); 246 | } 247 | 248 | void WritePrimitive(double v) 249 | { 250 | WritePrimitive(string.Format("{0:G17}", v)); 251 | } 252 | 253 | void WritePrimitive(T v) 254 | { 255 | WriteDelimiter(); 256 | 257 | _writer.Write(v); 258 | } 259 | 260 | void WriteIndentBreakForHuman(int depth) 261 | { 262 | if (_indent > 0) 263 | { 264 | _writer.Write('\n'); 265 | 266 | for (int i = 0; i < depth; ++i) 267 | { 268 | _writer.Write(_indentStr); 269 | } 270 | } 271 | } 272 | 273 | void WriteSpaceForHuman() 274 | { 275 | if (_indent > 0) 276 | { 277 | _writer.Write(' '); 278 | } 279 | } 280 | 281 | void WriteDelimiter() 282 | { 283 | var state = _states.Peek(); 284 | if (state.Kind == StateKind.ArrayHead) 285 | { 286 | WriteIndentBreakForHuman(state.Depth); 287 | 288 | _states.Pop(); 289 | _states.Push(new State 290 | { 291 | Kind = StateKind.ArrayOther, 292 | Depth = state.Depth 293 | }); 294 | return; 295 | } 296 | 297 | if (state.Kind == StateKind.ObjectKeyHead) 298 | { 299 | WriteIndentBreakForHuman(state.Depth); 300 | } 301 | 302 | if (state.Kind == StateKind.ArrayOther || state.Kind == StateKind.ObjectKeyOther) 303 | { 304 | _writer.Write(","); 305 | 306 | WriteIndentBreakForHuman(state.Depth); 307 | } 308 | 309 | if (state.Kind == StateKind.ObjectValue) 310 | { 311 | WriteSpaceForHuman(); 312 | 313 | _states.Pop(); 314 | _states.Push(new State 315 | { 316 | Kind = StateKind.ObjectKeyOther, 317 | Depth = state.Depth 318 | }); 319 | } 320 | } 321 | 322 | IEnumerable Escape(string s) 323 | { 324 | foreach(var c in s) 325 | { 326 | char modified = default(char); 327 | if (c <= 0x20 || c == '\"' || c == '\\') 328 | { 329 | switch(c) 330 | { 331 | case '\"': 332 | modified = '\"'; 333 | break; 334 | 335 | case '\\': 336 | modified = '\\'; 337 | break; 338 | 339 | case '\b': 340 | modified = 'b'; 341 | break; 342 | 343 | case '\n': 344 | modified = 'n'; 345 | break; 346 | 347 | case '\r': 348 | modified = 'r'; 349 | break; 350 | 351 | case '\t': 352 | modified = 't'; 353 | break; 354 | } 355 | } 356 | 357 | if (modified != default(char)) 358 | { 359 | yield return '\\'; 360 | yield return modified; 361 | } 362 | else 363 | { 364 | yield return c; 365 | } 366 | } 367 | } 368 | } 369 | } 370 | -------------------------------------------------------------------------------- /Packages/net.yutopp.vjson/Runtime/JsonWriter.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 31cf548ff3527e4498975282a843c75c 3 | timeCreated: 1549497719 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Packages/net.yutopp.vjson/Runtime/Node.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2019- yutopp (yutopp@gmail.com) 3 | // 4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | // file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | 8 | using System; 9 | using System.Collections; 10 | using System.Collections.Generic; 11 | using System.Linq; 12 | 13 | namespace VJson 14 | { 15 | public enum NodeKind 16 | { 17 | Object, 18 | Array, 19 | String, 20 | Integer, // Number 21 | Float, // Number 22 | Boolean, 23 | Null, 24 | 25 | Undefined, 26 | } 27 | 28 | public struct NodeKindWrapped 29 | { 30 | public NodeKind Kind; 31 | public bool Wrapped; 32 | } 33 | 34 | public interface INode 35 | { 36 | NodeKind Kind { get; } 37 | 38 | INode this[int index] { get; } 39 | INode this[string key] { get; } 40 | 41 | object GenericContent { get; } 42 | } 43 | 44 | public sealed class BooleanNode : INode 45 | { 46 | public static NodeKind KIND = NodeKind.Boolean; 47 | public static Type TYPE = typeof(bool); 48 | 49 | public NodeKind Kind { get { return KIND; } } 50 | 51 | public INode this[int index] { get { return UndefinedNode.Undef; } } 52 | public INode this[string key] { get { return UndefinedNode.Undef; } } 53 | 54 | public bool Value { get; private set; } 55 | public object GenericContent { get { return Value; } } 56 | 57 | public BooleanNode(bool v) 58 | { 59 | Value = v; 60 | } 61 | 62 | public override bool Equals(object rhsObj) 63 | { 64 | var rhs = rhsObj as BooleanNode; 65 | if (rhs == null) 66 | { 67 | return false; 68 | } 69 | 70 | return Value.Equals(rhs.Value); 71 | } 72 | 73 | public override int GetHashCode() 74 | { 75 | return Value.GetHashCode(); 76 | } 77 | 78 | public override string ToString() 79 | { 80 | return "BOOLEAN: " + Value; 81 | } 82 | } 83 | 84 | public sealed class NullNode : INode 85 | { 86 | public static NodeKind KIND = NodeKind.Null; 87 | public static Type TYPE = typeof(object); 88 | 89 | public NodeKind Kind { get { return KIND; } } 90 | 91 | public INode this[int index] { get { return UndefinedNode.Undef; } } 92 | public INode this[string key] { get { return UndefinedNode.Undef; } } 93 | 94 | public object GenericContent { get { return null; } } 95 | 96 | public static readonly INode Null = new NullNode(); 97 | 98 | public override bool Equals(object rhsObj) 99 | { 100 | var rhs = rhsObj as NullNode; 101 | if (rhs == null) 102 | { 103 | return false; 104 | } 105 | 106 | return true; 107 | } 108 | 109 | public override int GetHashCode() 110 | { 111 | return 0; 112 | } 113 | 114 | public override string ToString() 115 | { 116 | return "NULL"; 117 | } 118 | } 119 | 120 | public sealed class UndefinedNode : INode 121 | { 122 | public static NodeKind KIND = NodeKind.Undefined; 123 | public static Type TYPE = typeof(object); 124 | 125 | public NodeKind Kind { get { return KIND; } } 126 | 127 | public INode this[int index] { get { return Undef; } } 128 | public INode this[string key] { get { return Undef; } } 129 | 130 | public object GenericContent { get { return null; } } 131 | 132 | public static readonly INode Undef = new UndefinedNode(); 133 | 134 | public override bool Equals(object rhsObj) 135 | { 136 | var rhs = rhsObj as UndefinedNode; 137 | if (rhs == null) 138 | { 139 | return false; 140 | } 141 | 142 | return true; 143 | } 144 | 145 | public override int GetHashCode() 146 | { 147 | return 0; 148 | } 149 | 150 | public override string ToString() 151 | { 152 | return "UNDEFINED"; 153 | } 154 | } 155 | 156 | public sealed class IntegerNode : INode 157 | { 158 | public static NodeKind KIND = NodeKind.Integer; 159 | public static Type TYPE = typeof(long); 160 | 161 | public NodeKind Kind { get { return KIND; } } 162 | 163 | public INode this[int index] { get { return UndefinedNode.Undef; } } 164 | public INode this[string key] { get { return UndefinedNode.Undef; } } 165 | 166 | public long Value { get; private set; } 167 | public object GenericContent { get { return Value; } } 168 | 169 | public IntegerNode(long v) 170 | { 171 | Value = v; 172 | } 173 | 174 | public override bool Equals(object rhsObj) 175 | { 176 | var rhs = rhsObj as IntegerNode; 177 | if (rhs == null) 178 | { 179 | return false; 180 | } 181 | 182 | return Value.Equals(rhs.Value); 183 | } 184 | 185 | public override int GetHashCode() 186 | { 187 | return Value.GetHashCode(); 188 | } 189 | 190 | public override string ToString() 191 | { 192 | return "NUMBER(Int): " + Value; 193 | } 194 | } 195 | 196 | public sealed class FloatNode : INode 197 | { 198 | public static NodeKind KIND = NodeKind.Float; 199 | public static Type TYPE = typeof(double); 200 | 201 | public NodeKind Kind { get { return KIND; } } 202 | 203 | public INode this[int index] { get { return UndefinedNode.Undef; } } 204 | public INode this[string key] { get { return UndefinedNode.Undef; } } 205 | 206 | public double Value { get; private set; } 207 | public object GenericContent { get { return Value; } } 208 | 209 | public FloatNode(double v) 210 | { 211 | Value = v; 212 | } 213 | 214 | public override bool Equals(object rhsObj) 215 | { 216 | var rhs = rhsObj as FloatNode; 217 | if (rhs == null) 218 | { 219 | return false; 220 | } 221 | 222 | return Value.Equals(rhs.Value); 223 | } 224 | 225 | public override int GetHashCode() 226 | { 227 | return Value.GetHashCode(); 228 | } 229 | 230 | public override string ToString() 231 | { 232 | return "NUMBER(Float): " + Value; 233 | } 234 | } 235 | 236 | public sealed class StringNode : INode 237 | { 238 | public static NodeKind KIND = NodeKind.String; 239 | public static Type TYPE = typeof(string); 240 | 241 | public NodeKind Kind { get { return KIND; } } 242 | 243 | public INode this[int index] { get { return UndefinedNode.Undef; } } 244 | public INode this[string key] { get { return UndefinedNode.Undef; } } 245 | 246 | public string Value { get; private set; } 247 | public object GenericContent { get { return Value; } } 248 | 249 | public StringNode(string v) 250 | { 251 | Value = v; 252 | } 253 | 254 | public override bool Equals(object rhsObj) 255 | { 256 | var rhs = rhsObj as StringNode; 257 | if (rhs == null) 258 | { 259 | return false; 260 | } 261 | 262 | return Value.Equals(rhs.Value); 263 | } 264 | 265 | public override int GetHashCode() 266 | { 267 | return Value.GetHashCode(); 268 | } 269 | 270 | public override string ToString() 271 | { 272 | return "STRING: " + Value; 273 | } 274 | } 275 | 276 | public sealed class ObjectNode : INode, IEnumerable> 277 | { 278 | public static NodeKind KIND = NodeKind.Object; 279 | public static Type TYPE = typeof(Dictionary); 280 | 281 | public NodeKind Kind { get { return KIND; } } 282 | 283 | public Dictionary Elems; 284 | 285 | public INode this[int index] { get { return UndefinedNode.Undef; } } 286 | public INode this[string key] 287 | { 288 | get 289 | { 290 | INode n = null; 291 | if (Elems != null) 292 | { 293 | Elems.TryGetValue(key, out n); 294 | } 295 | 296 | return n != null ? n : UndefinedNode.Undef; 297 | } 298 | } 299 | 300 | public object GenericContent { get { return Elems != null ? Elems : new Dictionary(); } } 301 | 302 | public ObjectNode() 303 | { 304 | } 305 | 306 | public ObjectNode(Dictionary v) 307 | { 308 | Elems = v; 309 | } 310 | 311 | public void AddElement(string key, INode elem) 312 | { 313 | if (Elems == null) 314 | { 315 | Elems = new Dictionary(); 316 | } 317 | 318 | Elems.Add(key, elem); // TODO: check duplication 319 | } 320 | 321 | public void RemoveElement(string key) 322 | { 323 | if (Elems == null) 324 | { 325 | return; 326 | } 327 | 328 | Elems.Remove(key); 329 | } 330 | 331 | public IEnumerator> GetEnumerator() 332 | { 333 | if (Elems != null) 334 | { 335 | return Elems.OrderBy(p => p.Key).GetEnumerator(); 336 | } 337 | 338 | return Enumerable.Empty>().GetEnumerator(); 339 | } 340 | 341 | IEnumerator IEnumerable.GetEnumerator() 342 | { 343 | return GetEnumerator(); 344 | } 345 | 346 | public override bool Equals(object rhsObj) 347 | { 348 | var rhs = rhsObj as ObjectNode; 349 | if (rhs == null) 350 | { 351 | return false; 352 | } 353 | 354 | if (Elems == null) 355 | { 356 | return rhs.Elems == null; 357 | } 358 | 359 | return Elems.OrderBy(p => p.Key).SequenceEqual(rhs.Elems.OrderBy(p => p.Key)); 360 | } 361 | 362 | public override int GetHashCode() 363 | { 364 | if (Elems == null) 365 | { 366 | return 0; 367 | } 368 | 369 | return Elems.GetHashCode(); 370 | } 371 | 372 | public override string ToString() 373 | { 374 | if (Elems == null) 375 | { 376 | return "OBJECT: {}"; 377 | } 378 | 379 | return "OBJECT: " + String.Join("; ", Elems.OrderBy(p => p.Key).Select(p => p.Key + " = " + p.Value).ToArray()); 380 | } 381 | } 382 | 383 | public sealed class ArrayNode : INode, IEnumerable 384 | { 385 | public static NodeKind KIND = NodeKind.Array; 386 | public static Type TYPE = typeof(List); 387 | 388 | public NodeKind Kind { get { return KIND; } } 389 | 390 | public List Elems; 391 | 392 | public INode this[int index] 393 | { 394 | get 395 | { 396 | var elem = Elems != null ? Elems.ElementAtOrDefault(index) : null; 397 | return elem != null ? elem : UndefinedNode.Undef; 398 | } 399 | } 400 | public INode this[string key] { get { return UndefinedNode.Undef; } } 401 | 402 | public object GenericContent { get { return Elems != null ? Elems : new List(); } } 403 | 404 | public ArrayNode() 405 | { 406 | } 407 | 408 | public ArrayNode(List v) 409 | { 410 | Elems = v; 411 | } 412 | 413 | public void AddElement(INode elem) 414 | { 415 | if (Elems == null) 416 | { 417 | Elems = new List(); 418 | } 419 | 420 | Elems.Add(elem); // TODO: check duplication 421 | } 422 | 423 | public void RemoveElementAt(int index) 424 | { 425 | if (Elems == null) 426 | { 427 | return; 428 | } 429 | 430 | if (index >= 0 && index < Elems.Count) 431 | { 432 | Elems.RemoveAt(index); 433 | } 434 | } 435 | 436 | public IEnumerator GetEnumerator() 437 | { 438 | if (Elems != null) 439 | { 440 | return Elems.GetEnumerator(); 441 | } 442 | 443 | return Enumerable.Empty().GetEnumerator(); 444 | } 445 | 446 | IEnumerator IEnumerable.GetEnumerator() 447 | { 448 | return GetEnumerator(); 449 | } 450 | 451 | public override bool Equals(object rhsObj) 452 | { 453 | var rhs = rhsObj as ArrayNode; 454 | if (rhs == null) 455 | { 456 | return false; 457 | } 458 | 459 | if (Elems == null) 460 | { 461 | return rhs.Elems == null; 462 | } 463 | 464 | return Elems.SequenceEqual(rhs.Elems); 465 | } 466 | 467 | public override int GetHashCode() 468 | { 469 | if (Elems == null) 470 | { 471 | return 0; 472 | } 473 | 474 | return Elems.GetHashCode(); 475 | } 476 | 477 | public override string ToString() 478 | { 479 | if (Elems == null) 480 | { 481 | return "ARRAY: []"; 482 | } 483 | 484 | return "ARRAY: " + String.Join("; ", Elems.Select(e => e.ToString()).ToArray()); 485 | } 486 | } 487 | 488 | public static class Node 489 | { 490 | // TODO: optimize 491 | public static NodeKind KindOfValue(T o) 492 | { 493 | if (o == null) 494 | { 495 | return NodeKind.Null; 496 | } 497 | 498 | var ty = o.GetType(); 499 | return KindOfType(ty); 500 | } 501 | 502 | public static NodeKindWrapped KindOfTypeWrapped(Type ty) 503 | { 504 | if (typeof(INode).IsAssignableFrom(ty)) 505 | { 506 | return new NodeKindWrapped { 507 | Kind = _nodeKindTable[ty], 508 | Wrapped = true, 509 | }; 510 | } 511 | 512 | return new NodeKindWrapped { 513 | Kind = KindOfType(ty), 514 | Wrapped = false, 515 | }; 516 | } 517 | 518 | public static NodeKind KindOfType(Type ty) 519 | { 520 | // Unwrap all Nullables 521 | // Any class values are nullable, however this library does not treat them as nullables. 522 | // Thus we adjust logic of Nullable to as same as class values. Nullable will be treated as T. 523 | var optInnerTy = Nullable.GetUnderlyingType(ty); 524 | if (optInnerTy != null) 525 | { 526 | return KindOfType(optInnerTy); 527 | } 528 | 529 | if (_primitiveTable.TryGetValue(ty, out var k)) 530 | { 531 | return k; 532 | } 533 | 534 | // Enum(integer or string) 535 | if (ty.IsEnum) 536 | { 537 | var attr = TypeHelper.GetCustomAttribute(ty); 538 | return attr != null && attr.EnumConversion == EnumConversionType.AsString 539 | ? NodeKind.String 540 | : NodeKind.Integer; 541 | } 542 | 543 | // Arrays 544 | // If elem type exists, it can treat as Array(IEnumerable) 545 | var elemTy = TypeHelper.ElemTypeOfIEnumerable(ty); 546 | if (elemTy != null) 547 | { 548 | return NodeKind.Array; 549 | } 550 | 551 | // Others 552 | return NodeKind.Object; 553 | } 554 | 555 | public static Type ValueTypeOfKind(NodeKind kind) 556 | { 557 | return _nodeTypeTable[kind]; 558 | } 559 | 560 | static Dictionary _primitiveTable = new Dictionary 561 | { 562 | {typeof(bool), NodeKind.Boolean}, 563 | {typeof(byte), NodeKind.Integer}, 564 | {typeof(sbyte), NodeKind.Integer}, 565 | {typeof(char), NodeKind.Integer}, 566 | {typeof(decimal), NodeKind.Integer}, 567 | {typeof(double), NodeKind.Float}, 568 | {typeof(float), NodeKind.Float}, 569 | {typeof(int), NodeKind.Integer}, 570 | {typeof(uint), NodeKind.Integer}, 571 | {typeof(long), NodeKind.Integer}, 572 | {typeof(ulong), NodeKind.Integer}, 573 | {typeof(short), NodeKind.Integer}, 574 | {typeof(ushort), NodeKind.Integer}, 575 | {typeof(string), NodeKind.String}, 576 | }; 577 | 578 | static Dictionary _nodeKindTable = new Dictionary 579 | { 580 | {typeof(INode), ObjectNode.KIND}, // Can become any object 581 | 582 | {typeof(BooleanNode), BooleanNode.KIND}, 583 | {typeof(NullNode), NullNode.KIND}, 584 | {typeof(UndefinedNode), UndefinedNode.KIND}, 585 | {typeof(IntegerNode), IntegerNode.KIND}, 586 | {typeof(FloatNode), FloatNode.KIND}, 587 | {typeof(StringNode), StringNode.KIND}, 588 | {typeof(ObjectNode), ObjectNode.KIND}, 589 | {typeof(ArrayNode), ArrayNode.KIND}, 590 | }; 591 | 592 | static Dictionary _nodeTypeTable = new Dictionary 593 | { 594 | {BooleanNode.KIND, BooleanNode.TYPE}, 595 | {NullNode.KIND, NullNode.TYPE}, 596 | {UndefinedNode.KIND, UndefinedNode.TYPE}, 597 | {IntegerNode.KIND, IntegerNode.TYPE}, 598 | {FloatNode.KIND, FloatNode.TYPE}, 599 | {StringNode.KIND, StringNode.TYPE}, 600 | {ObjectNode.KIND, ObjectNode.TYPE}, 601 | {ArrayNode.KIND, ArrayNode.TYPE}, 602 | }; 603 | } 604 | } 605 | -------------------------------------------------------------------------------- /Packages/net.yutopp.vjson/Runtime/Node.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d6000afeb7d23dc409ff5f4f7e9b789e 3 | timeCreated: 1549510227 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Packages/net.yutopp.vjson/Runtime/Schema.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: edbb1936e5a241849997d2add5ebc29f 3 | folderAsset: yes 4 | timeCreated: 1550036451 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Packages/net.yutopp.vjson/Runtime/Schema/Attribute.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2019- yutopp (yutopp@gmail.com) 3 | // 4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | // file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | 8 | using System; 9 | using System.Collections.Generic; 10 | 11 | namespace VJson.Schema 12 | { 13 | [AttributeUsage(AttributeTargets.Class | AttributeTargets.Field, Inherited = false)] 14 | public class JsonSchemaAttribute : PreserveAttribute 15 | { 16 | #region Core 17 | public string Schema; 18 | public string Id; 19 | public string Ref; 20 | #endregion 21 | 22 | #region Metadata 23 | public string Title; 24 | public string Description; 25 | #endregion 26 | 27 | #region 6.1: Any instances 28 | // public object Type; 29 | // public object[] Enum; 30 | // public object Const; 31 | #endregion 32 | 33 | #region 6.2: Numeric instances 34 | public double MultipleOf = double.MinValue; 35 | public double Maximum = double.MinValue; 36 | public double ExclusiveMaximum = double.MinValue; 37 | public double Minimum = double.MaxValue; 38 | public double ExclusiveMinimum = double.MaxValue; 39 | #endregion 40 | 41 | #region 6.3. Strings 42 | public int MaxLength = int.MinValue; 43 | public int MinLength = int.MaxValue; 44 | public string Pattern; 45 | #endregion 46 | 47 | #region 6.4: Arrays 48 | // public object Items; 49 | // public JsonSchemaAttribute AdditionalItems; 50 | public int MaxItems = int.MinValue; 51 | public int MinItems = int.MaxValue; 52 | public bool UniqueItems = false; 53 | // contains 54 | #endregion 55 | 56 | #region 6.5: Objects 57 | public int MaxProperties = int.MinValue; 58 | public int MinProperties = int.MaxValue; 59 | public string[] Required; // Use [JsonSchemaRequired] instead when specify it by attributes. 60 | // public Dictionary Properties; 61 | // public Dictionary PatternProperties; 62 | // public JsonSchemaAttribute AdditionalProperties; 63 | // public object Dependencies; // Use [JsonSchemaDependencies] instead when specify it by attributes. 64 | // propertyNames 65 | #endregion 66 | 67 | #region 6.7: Subschemas With Boolean Logic 68 | // public List AllOf; 69 | // public List AnyOf; 70 | // public List OneOf; 71 | // public JsonSchemaAttribute Not; 72 | #endregion 73 | } 74 | 75 | [AttributeUsage(AttributeTargets.Field, Inherited = false)] 76 | public sealed class ItemsJsonSchemaAttribute : JsonSchemaAttribute 77 | { 78 | } 79 | 80 | [AttributeUsage(AttributeTargets.Field, Inherited = false)] 81 | public sealed class JsonSchemaRequiredAttribute : PreserveAttribute 82 | { 83 | } 84 | 85 | [AttributeUsage(AttributeTargets.Field, Inherited = false)] 86 | public sealed class JsonSchemaDependenciesAttribute : PreserveAttribute 87 | { 88 | public string[] Dependencies { get; private set; } 89 | 90 | public JsonSchemaDependenciesAttribute(params string[] deps) 91 | { 92 | Dependencies = deps; 93 | } 94 | } 95 | 96 | public enum InfluenceRange 97 | { 98 | Entiry, 99 | AdditionalProperties, 100 | } 101 | 102 | [AttributeUsage(AttributeTargets.Field, Inherited = false)] 103 | public class JsonSchemaRefAttribute : PreserveAttribute 104 | { 105 | public Type TagType { get; private set; } 106 | public InfluenceRange Influence { get; private set; } 107 | 108 | public JsonSchemaRefAttribute(Type tagType, InfluenceRange influence = InfluenceRange.Entiry) 109 | { 110 | Type schemaBaseType; 111 | if (!RefChecker.IsRefTagDerived(tagType, out schemaBaseType)) 112 | { 113 | throw new ArgumentException("IRefTag must be derived by tagType"); 114 | } 115 | 116 | TagType = tagType; 117 | Influence = influence; 118 | } 119 | } 120 | 121 | [AttributeUsage(AttributeTargets.Field, Inherited = false)] 122 | public sealed class ItemsJsonSchemaRefAttribute : JsonSchemaRefAttribute 123 | { 124 | public ItemsJsonSchemaRefAttribute(Type tagType, InfluenceRange influence = InfluenceRange.Entiry) 125 | : base(tagType, influence) 126 | { 127 | } 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /Packages/net.yutopp.vjson/Runtime/Schema/Attribute.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3a1bae1c6bc3d1a42b42a63e0a1ddbd5 3 | timeCreated: 1550036451 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Packages/net.yutopp.vjson/Runtime/Schema/JsonSchema.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 907a783850c89134384509ef3d84f3ea 3 | timeCreated: 1550036451 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Packages/net.yutopp.vjson/Runtime/Schema/RefTag.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2019- yutopp (yutopp@gmail.com) 3 | // 4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | // file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | 8 | using System; 9 | 10 | namespace VJson.Schema 11 | { 12 | public class RefTag where T : struct 13 | { 14 | } 15 | 16 | internal static class RefChecker 17 | { 18 | public static bool IsRefTagDerived(Type ty, out Type elemType) 19 | { 20 | var baseType = ty.BaseType; 21 | if (baseType != null) 22 | { 23 | return IsRefTag(baseType, out elemType); 24 | } 25 | 26 | elemType = null; 27 | return false; 28 | } 29 | 30 | public static bool IsRefTag(Type ty, out Type elemType) 31 | { 32 | if (ty.IsGenericType && ty.GetGenericTypeDefinition() == typeof(RefTag<>)) 33 | { 34 | elemType = ty.GetGenericArguments()[0]; 35 | return true; 36 | } 37 | 38 | elemType = null; 39 | return false; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Packages/net.yutopp.vjson/Runtime/Schema/RefTag.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0e556e3a8d68c438ca64d4ef901055d3 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Packages/net.yutopp.vjson/Runtime/Schema/Registry.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2019- yutopp (yutopp@gmail.com) 3 | // 4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | // file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | 8 | using System.Collections.Generic; 9 | 10 | namespace VJson.Schema 11 | { 12 | public sealed class JsonSchemaRegistry 13 | { 14 | readonly Dictionary _registory = new Dictionary(); 15 | 16 | public JsonSchema Resolve(string id) 17 | { 18 | JsonSchema j = null; 19 | if (_registory.TryGetValue(id, out j)) 20 | { 21 | return j; 22 | } 23 | 24 | return null; 25 | } 26 | 27 | public void Register(string id, JsonSchema j) 28 | { 29 | _registory.Add(id, j); 30 | } 31 | 32 | public IEnumerable GetRegisteredIDs() 33 | { 34 | return _registory.Keys; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Packages/net.yutopp.vjson/Runtime/Schema/Registry.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 69761237819d6dd41a20b6f97a0fcf93 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Packages/net.yutopp.vjson/Runtime/Schema/Validator.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 41d8144a7595fd6498a3fc1505e47071 3 | timeCreated: 1550036451 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Packages/net.yutopp.vjson/Runtime/TypeHelper.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2019- yutopp (yutopp@gmail.com) 3 | // 4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | // file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | 8 | using System; 9 | using System.Collections; 10 | using System.Collections.Generic; 11 | using System.Linq; 12 | using System.Reflection; 13 | 14 | namespace VJson 15 | { 16 | static partial class TypeHelper 17 | { 18 | public static bool IsBoxed(Type ty) 19 | { 20 | if (ty.IsClass) { 21 | return true; 22 | } 23 | 24 | var optInnerTy = Nullable.GetUnderlyingType(ty); 25 | return optInnerTy != null; 26 | } 27 | 28 | public static T GetCustomAttribute(FieldInfo fi) where T : Attribute 29 | { 30 | return (T)fi.GetCustomAttributes(typeof(T), false) 31 | .Where(a => a.GetType() == typeof(T)) 32 | .FirstOrDefault(); 33 | } 34 | 35 | public static T GetCustomAttribute(Type ty) where T : Attribute 36 | { 37 | return (T)ty.GetCustomAttributes(typeof(T), false) 38 | .Where(a => a.GetType() == typeof(T)) 39 | .FirstOrDefault(); 40 | } 41 | 42 | // TODO: implement cache 43 | public static string[] GetStringEnumNames(Type ty) 44 | { 45 | var enumFields = ty.GetFields(BindingFlags.Static|BindingFlags.Public); 46 | return enumFields.Select(fi => { 47 | var attr = GetCustomAttribute(fi); 48 | if (attr != null && attr.Name != null) { 49 | return attr.Name; 50 | } 51 | 52 | return fi.Name; 53 | }).ToArray(); 54 | } 55 | 56 | public static string GetStringEnumNameOf(object e) 57 | { 58 | var eTy = e.GetType(); 59 | var enumIndex = Array.IndexOf(Enum.GetValues(eTy), e); 60 | 61 | return GetStringEnumNames(eTy)[enumIndex]; 62 | } 63 | 64 | public static IEnumerable ToIEnumerable(object o) 65 | { 66 | var ty = o.GetType(); 67 | if (ty.IsArray) 68 | { 69 | if (ty.HasElementType && ty.GetElementType().IsClass) 70 | { 71 | return ((IEnumerable)o); 72 | } 73 | else 74 | { 75 | return ((IEnumerable)o).Cast(); 76 | } 77 | } 78 | else 79 | { 80 | return ((IEnumerable)o).Cast(); 81 | } 82 | } 83 | 84 | public static Type ElemTypeOfIEnumerable(Type ty) 85 | { 86 | if (ty.IsArray) 87 | { 88 | if (ty.HasElementType) 89 | { 90 | return ty.GetElementType(); 91 | } 92 | 93 | return null; 94 | } 95 | 96 | if (ty.IsGenericType && ty.GetGenericTypeDefinition() == typeof(List<>)) 97 | { 98 | return ty.GetGenericArguments()[0]; 99 | } 100 | 101 | return null; 102 | } 103 | 104 | public static IEnumerable> ToKeyValues(object o) 105 | { 106 | var pairs = ToRankedKeyValuesUnordered(o).ToList(); 107 | pairs.Sort(new RankedKeyValueComparer()); 108 | 109 | return pairs.Select(v => new KeyValuePair(v.Key.Key, v.Value)); 110 | } 111 | 112 | public static IEnumerable GetSerializableFields(Type ty) 113 | { 114 | var publicFields = ty.GetFields(BindingFlags.Public | BindingFlags.Instance); 115 | var privateFields = ty.GetFields(BindingFlags.NonPublic | BindingFlags.Instance).Where(field => { 116 | return GetCustomAttribute(field) != null; 117 | }); 118 | return publicFields.Concat(privateFields); 119 | } 120 | 121 | private struct RankedKey 122 | { 123 | public int Order; 124 | public string Key; 125 | } 126 | 127 | class RankedKeyValueComparer : IComparer> 128 | { 129 | public int Compare(KeyValuePair a, KeyValuePair b) 130 | { 131 | throw new NotImplementedException(); 132 | } 133 | 134 | int IComparer>.Compare(KeyValuePair a, 135 | KeyValuePair b) 136 | { 137 | if (a.Key.Order != b.Key.Order) 138 | { 139 | return a.Key.Order - b.Key.Order; // TODO: Concider when values are overflowed... 140 | } 141 | 142 | return string.Compare(a.Key.Key, b.Key.Key); 143 | } 144 | } 145 | 146 | private static IEnumerable> ToRankedKeyValuesUnordered(object o) 147 | { 148 | var ty = o.GetType(); 149 | if (ty.IsGenericType && ty.GetGenericTypeDefinition() == typeof(Dictionary<,>)) 150 | { 151 | var keyType = ty.GetGenericArguments()[0]; 152 | if (keyType != typeof(string)) 153 | { 154 | // TODO: Should allow them and call `ToString`? 155 | throw new NotImplementedException(); 156 | } 157 | 158 | foreach (DictionaryEntry elem in (IDictionary)o) 159 | { 160 | yield return new KeyValuePair( 161 | new RankedKey{ 162 | Order = 0, // Dictionary has no order infomation 163 | Key = (string)elem.Key, 164 | }, 165 | elem.Value); 166 | } 167 | } 168 | else 169 | { 170 | var fields = GetSerializableFields(ty); 171 | foreach (var field in fields) 172 | { 173 | var fieldAttr = GetCustomAttribute(field); 174 | 175 | // TODO: duplication check 176 | var elemName = JsonFieldAttribute.FieldName(fieldAttr, field); 177 | var elemValue = field.GetValue(o); 178 | 179 | var fieldIgnoreAttr = GetCustomAttribute(field); 180 | if (JsonFieldIgnorableAttribute.IsIgnorable(fieldIgnoreAttr, elemValue)) 181 | { 182 | continue; 183 | } 184 | 185 | yield return new KeyValuePair( 186 | new RankedKey{ 187 | Order = JsonFieldAttribute.FieldOrder(fieldAttr), 188 | Key = elemName, 189 | }, 190 | elemValue); 191 | } 192 | } 193 | } 194 | 195 | class DeepEqualityComparer : EqualityComparer 196 | { 197 | public override bool Equals(object a, object b) 198 | { 199 | return DeepEquals(a, b); 200 | } 201 | 202 | public override int GetHashCode(object a) 203 | { 204 | return a.GetHashCode(); 205 | } 206 | } 207 | 208 | public static bool DeepEquals(object lhs, object rhs) 209 | { 210 | var lhsKind = Node.KindOfValue(lhs); 211 | var rhsKind = Node.KindOfValue(rhs); 212 | if (lhsKind != rhsKind) 213 | { 214 | return false; 215 | } 216 | 217 | switch (lhsKind) 218 | { 219 | case NodeKind.Boolean: 220 | case NodeKind.Integer: 221 | case NodeKind.Float: 222 | case NodeKind.String: 223 | return Object.Equals(lhs, rhs); 224 | 225 | case NodeKind.Array: 226 | var lhsArr = ToIEnumerable(lhs); 227 | var rhsArr = ToIEnumerable(rhs); 228 | return lhsArr.SequenceEqual(rhsArr, new DeepEqualityComparer()); 229 | 230 | case NodeKind.Object: 231 | #if NETCOREAPP2_0 232 | var lhsKvs = new Dictionary(ToKeyValues(lhs)); 233 | var rhsKvs = new Dictionary(ToKeyValues(rhs)); 234 | #else 235 | var lhsKvs = new Dictionary(); 236 | foreach (var kv in ToKeyValues(lhs)) 237 | { 238 | lhsKvs.Add(kv.Key, kv.Value); 239 | } 240 | var rhsKvs = new Dictionary(); 241 | foreach (var kv in ToKeyValues(rhs)) 242 | { 243 | rhsKvs.Add(kv.Key, kv.Value); 244 | } 245 | #endif 246 | if (!lhsKvs.Keys.SequenceEqual(rhsKvs.Keys)) 247 | { 248 | return false; 249 | } 250 | return lhsKvs.All(kv => DeepEquals(kv.Value, rhsKvs[kv.Key])); 251 | 252 | case NodeKind.Null: 253 | return true; 254 | 255 | default: 256 | throw new NotImplementedException(); 257 | } 258 | } 259 | } 260 | } 261 | -------------------------------------------------------------------------------- /Packages/net.yutopp.vjson/Runtime/TypeHelper.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 553478ad8edd3a049b542b4a51cc0d53 3 | timeCreated: 1550036451 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Packages/net.yutopp.vjson/Runtime/TypeHelper.g.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2019- yutopp (yutopp@gmail.com) 3 | // 4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | // file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | 8 | // THIS FILE IS AUTOMATICALLY GENERATED from TypeHelper.g.template.cs 9 | 10 | using System; 11 | using System.Collections.Generic; 12 | 13 | namespace VJson 14 | { 15 | static partial class TypeHelper 16 | { 17 | private static readonly Dictionary> _convTable = 18 | new Dictionary> 19 | { 20 | { 21 | typeof(bool), new Dictionary 22 | { 23 | { typeof(bool), null }, 24 | } 25 | }, 26 | { 27 | typeof(double), new Dictionary 28 | { 29 | { typeof(decimal), (object i, out object o) => ConvertFromDoubleToDecimal((double)i, out o) }, 30 | { typeof(double), null }, 31 | { typeof(float), (object i, out object o) => ConvertFromDoubleToFloat((double)i, out o) }, 32 | } 33 | }, 34 | { 35 | typeof(long), new Dictionary 36 | { 37 | { typeof(byte), (object i, out object o) => ConvertFromLongToByte((long)i, out o) }, 38 | { typeof(sbyte), (object i, out object o) => ConvertFromLongToSbyte((long)i, out o) }, 39 | { typeof(char), (object i, out object o) => ConvertFromLongToChar((long)i, out o) }, 40 | { typeof(decimal), (object i, out object o) => ConvertFromLongToDecimal((long)i, out o) }, 41 | { typeof(double), (object i, out object o) => ConvertFromLongToDouble((long)i, out o) }, 42 | { typeof(float), (object i, out object o) => ConvertFromLongToFloat((long)i, out o) }, 43 | { typeof(int), (object i, out object o) => ConvertFromLongToInt((long)i, out o) }, 44 | { typeof(uint), (object i, out object o) => ConvertFromLongToUint((long)i, out o) }, 45 | { typeof(long), null }, 46 | { typeof(ulong), (object i, out object o) => ConvertFromLongToUlong((long)i, out o) }, 47 | { typeof(short), (object i, out object o) => ConvertFromLongToShort((long)i, out o) }, 48 | { typeof(ushort), (object i, out object o) => ConvertFromLongToUshort((long)i, out o) }, 49 | } 50 | }, 51 | { 52 | typeof(string), new Dictionary 53 | { 54 | { typeof(string), null }, 55 | } 56 | }, 57 | }; 58 | 59 | private static bool ConvertFromDoubleToDecimal(double i, out object o) { 60 | try 61 | { 62 | o = checked((decimal)i); 63 | return true; 64 | } 65 | catch(OverflowException) 66 | { 67 | o = null; 68 | return false; 69 | } 70 | } 71 | 72 | private static bool ConvertFromDoubleToFloat(double i, out object o) { 73 | try 74 | { 75 | o = checked((float)i); 76 | return true; 77 | } 78 | catch(OverflowException) 79 | { 80 | o = null; 81 | return false; 82 | } 83 | } 84 | 85 | private static bool ConvertFromLongToByte(long i, out object o) { 86 | try 87 | { 88 | if ( i < 0 ) 89 | { 90 | throw new OverflowException(); 91 | } 92 | o = checked((byte)i); 93 | return true; 94 | } 95 | catch(OverflowException) 96 | { 97 | o = null; 98 | return false; 99 | } 100 | } 101 | 102 | private static bool ConvertFromLongToSbyte(long i, out object o) { 103 | try 104 | { 105 | o = checked((sbyte)i); 106 | return true; 107 | } 108 | catch(OverflowException) 109 | { 110 | o = null; 111 | return false; 112 | } 113 | } 114 | 115 | private static bool ConvertFromLongToChar(long i, out object o) { 116 | try 117 | { 118 | if ( i < 0 ) 119 | { 120 | throw new OverflowException(); 121 | } 122 | o = checked((char)i); 123 | return true; 124 | } 125 | catch(OverflowException) 126 | { 127 | o = null; 128 | return false; 129 | } 130 | } 131 | 132 | private static bool ConvertFromLongToDecimal(long i, out object o) { 133 | try 134 | { 135 | o = checked((decimal)i); 136 | return true; 137 | } 138 | catch(OverflowException) 139 | { 140 | o = null; 141 | return false; 142 | } 143 | } 144 | 145 | private static bool ConvertFromLongToDouble(long i, out object o) { 146 | try 147 | { 148 | o = checked((double)i); 149 | return true; 150 | } 151 | catch(OverflowException) 152 | { 153 | o = null; 154 | return false; 155 | } 156 | } 157 | 158 | private static bool ConvertFromLongToFloat(long i, out object o) { 159 | try 160 | { 161 | o = checked((float)i); 162 | return true; 163 | } 164 | catch(OverflowException) 165 | { 166 | o = null; 167 | return false; 168 | } 169 | } 170 | 171 | private static bool ConvertFromLongToInt(long i, out object o) { 172 | try 173 | { 174 | o = checked((int)i); 175 | return true; 176 | } 177 | catch(OverflowException) 178 | { 179 | o = null; 180 | return false; 181 | } 182 | } 183 | 184 | private static bool ConvertFromLongToUint(long i, out object o) { 185 | try 186 | { 187 | if ( i < 0 ) 188 | { 189 | throw new OverflowException(); 190 | } 191 | o = checked((uint)i); 192 | return true; 193 | } 194 | catch(OverflowException) 195 | { 196 | o = null; 197 | return false; 198 | } 199 | } 200 | 201 | private static bool ConvertFromLongToUlong(long i, out object o) { 202 | try 203 | { 204 | if ( i < 0 ) 205 | { 206 | throw new OverflowException(); 207 | } 208 | o = checked((ulong)i); 209 | return true; 210 | } 211 | catch(OverflowException) 212 | { 213 | o = null; 214 | return false; 215 | } 216 | } 217 | 218 | private static bool ConvertFromLongToShort(long i, out object o) { 219 | try 220 | { 221 | o = checked((short)i); 222 | return true; 223 | } 224 | catch(OverflowException) 225 | { 226 | o = null; 227 | return false; 228 | } 229 | } 230 | 231 | private static bool ConvertFromLongToUshort(long i, out object o) { 232 | try 233 | { 234 | if ( i < 0 ) 235 | { 236 | throw new OverflowException(); 237 | } 238 | o = checked((ushort)i); 239 | return true; 240 | } 241 | catch(OverflowException) 242 | { 243 | o = null; 244 | return false; 245 | } 246 | } 247 | 248 | public delegate bool Converter(object input, out object output); 249 | 250 | public static bool GetConverter(Type fromTy, Type toTy, out Converter converter) 251 | { 252 | Dictionary conv; 253 | if (!_convTable.TryGetValue(fromTy, out conv)) 254 | { 255 | converter = null; 256 | return false; 257 | } 258 | 259 | return conv.TryGetValue(toTy, out converter); 260 | } 261 | } 262 | } 263 | 264 | -------------------------------------------------------------------------------- /Packages/net.yutopp.vjson/Runtime/TypeHelper.g.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e84c498ee9aca4f19bf7ec64969aeec9 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Packages/net.yutopp.vjson/Runtime/Unity.net.yutopp.vjson.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Unity.net.yutopp.vjson" 3 | } 4 | -------------------------------------------------------------------------------- /Packages/net.yutopp.vjson/Runtime/Unity.net.yutopp.vjson.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2fe7776f9beaa911d822d28414d9d672 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Packages/net.yutopp.vjson/Tests.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 96d2fb653af8e6ba6be0ec39a4a4043d 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Packages/net.yutopp.vjson/Tests/Runtime.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 14ee0339a97209a549cebb2c96d4ac4f 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Packages/net.yutopp.vjson/Tests/Runtime/JsonReaderTest.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2019- yutopp (yutopp@gmail.com) 3 | // 4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | // file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | 8 | using System; 9 | using System.IO; 10 | using System.Text; 11 | using System.Collections.Generic; 12 | using NUnit.Framework; 13 | 14 | namespace VJson.UnitTests 15 | { 16 | class JsonReaderPassTests 17 | { 18 | [Test] 19 | [TestCaseSource("FixtureArgs")] 20 | public void ReadTest(INode expected, string src) 21 | { 22 | using (var s = new MemoryStream(Encoding.UTF8.GetBytes(src))) 23 | using (var r = new JsonReader(s)) 24 | { 25 | var actual = r.Read(); 26 | 27 | Assert.That(actual, Is.EqualTo(expected)); 28 | } 29 | } 30 | 31 | // 32 | static object[] FixtureArgs = { 33 | // Boolean 34 | new object[] { 35 | new BooleanNode(true), 36 | @"true", 37 | }, 38 | new object[] { 39 | new BooleanNode(false), 40 | @"false", 41 | }, 42 | new object[] { 43 | new BooleanNode(true), 44 | @" true ", 45 | }, 46 | new object[] { 47 | new BooleanNode(false), 48 | @" false ", 49 | }, 50 | 51 | // Null 52 | new object[] { 53 | new NullNode(), 54 | @"null", 55 | }, 56 | new object[] { 57 | new NullNode(), 58 | @" null ", 59 | }, 60 | 61 | // Numbers 62 | new object[] { 63 | new IntegerNode(123), 64 | @"123", 65 | }, 66 | new object[] { 67 | new IntegerNode(123), 68 | @" 123 ", 69 | }, 70 | new object[] { 71 | new IntegerNode(0), 72 | @"0", 73 | }, 74 | new object[] { 75 | new IntegerNode(9), 76 | @"9", 77 | }, 78 | new object[] { 79 | new IntegerNode(-123), 80 | @"-123", 81 | }, 82 | new object[] { 83 | new IntegerNode(-0), 84 | @"-0", 85 | }, 86 | new object[] { 87 | new IntegerNode(-9), 88 | @"-9", 89 | }, 90 | new object[] { 91 | new FloatNode(-9.0), 92 | @"-9.0", 93 | }, 94 | new object[] { 95 | new FloatNode(-9.0e0), 96 | @"-9.0e0", 97 | }, 98 | new object[] { 99 | new FloatNode(-9.0e+0), 100 | @"-9.0e+0", 101 | }, 102 | new object[] { 103 | new FloatNode(-9.0e-0), 104 | @"-9.0e-0", 105 | }, 106 | new object[] { 107 | new FloatNode(-9e0), 108 | @"-9e0", 109 | }, 110 | new object[] { 111 | new FloatNode(-9e+0), 112 | @"-9e+0", 113 | }, 114 | new object[] { 115 | new FloatNode(-9e-0), 116 | @"-9e-0", 117 | }, 118 | new object[] { 119 | new FloatNode(3.14), 120 | @"3.14", 121 | }, 122 | new object[] { 123 | new FloatNode(-3.14), 124 | @"-3.14", 125 | }, 126 | new object[] { 127 | new FloatNode(3.14e12), 128 | @"3.14e12", 129 | }, 130 | 131 | // Strings 132 | new object[] { 133 | new StringNode("abc"), 134 | @"""abc""", 135 | }, 136 | new object[] { 137 | new StringNode(""), 138 | @"""""", 139 | }, 140 | new object[] { 141 | new StringNode("abc"), 142 | @" ""abc"" ", 143 | }, 144 | new object[] { 145 | new StringNode("あいうえお"), 146 | @"""あいうえお""", 147 | }, 148 | new object[] { 149 | new StringNode("\""), 150 | "\"\\\"\"", 151 | }, 152 | new object[] { 153 | new StringNode("\\"), 154 | "\"\\\\\"", 155 | }, 156 | new object[] { 157 | new StringNode("/"), 158 | "\"\\/\"", 159 | }, 160 | new object[] { 161 | new StringNode("/"), 162 | "\"/\"", 163 | }, 164 | new object[] { 165 | new StringNode("\b"), 166 | @"""\b""", 167 | }, 168 | new object[] { 169 | new StringNode("\n"), 170 | @"""\n""", 171 | }, 172 | new object[] { 173 | new StringNode("\r"), 174 | @"""\r""", 175 | }, 176 | new object[] { 177 | new StringNode("\t"), 178 | @"""\t""", 179 | }, 180 | new object[] { 181 | new StringNode("あ"), 182 | @"""\u3042""", 183 | }, 184 | new object[] { 185 | new StringNode("http://"), 186 | @"""http:\/\/""", 187 | }, 188 | new object[] { 189 | new StringNode("🍣"), 190 | @"""🍣""", 191 | }, 192 | 193 | // Objects 194 | new object[] { 195 | new ObjectNode(), 196 | @"{}", 197 | }, 198 | new object[] { 199 | new ObjectNode() 200 | { 201 | Elems = new Dictionary 202 | { 203 | {"abc", new IntegerNode(1)}, 204 | } 205 | }, 206 | @"{""abc"":1}", 207 | }, 208 | new object[] { 209 | new ObjectNode() { 210 | Elems = new Dictionary 211 | { 212 | {"abc", new IntegerNode(1)}, 213 | {"def", new IntegerNode(2)}, 214 | } 215 | }, 216 | @"{""abc"":1,""def"":2}", 217 | }, 218 | new object[] { 219 | new ObjectNode() { 220 | Elems = new Dictionary 221 | { 222 | {"abc", new IntegerNode(1)}, 223 | {"def", new IntegerNode(2)}, 224 | } 225 | }, 226 | @" { ""abc"" : 1 , ""def"" : 2 } ", 227 | }, 228 | 229 | // Arrays 230 | new object[] { 231 | new ArrayNode(), 232 | @"[]", 233 | }, 234 | new object[] { 235 | new ArrayNode() 236 | { 237 | Elems = new List 238 | { 239 | new StringNode("abc"), 240 | } 241 | }, 242 | @"[""abc""]", 243 | }, 244 | new object[] { 245 | new ArrayNode() { 246 | Elems = new List 247 | { 248 | new StringNode("abc"), 249 | new IntegerNode(1), 250 | } 251 | }, 252 | @"[""abc"",1]", 253 | }, 254 | new object[] { 255 | new ArrayNode() { 256 | Elems = new List 257 | { 258 | new StringNode("abc"), 259 | new IntegerNode(1), 260 | } 261 | }, 262 | @" [ ""abc"" , 1 ] ", 263 | }, 264 | 265 | // Compound 266 | new object[] { 267 | new ArrayNode() { 268 | Elems = new List{ 269 | new ObjectNode(), 270 | new ObjectNode { 271 | Elems = new Dictionary{ 272 | {"a", new ObjectNode { 273 | Elems = new Dictionary{ 274 | {"b", new ArrayNode { 275 | Elems = new List{ 276 | new NullNode(), 277 | new IntegerNode(1), 278 | new StringNode("🍣"), 279 | }, 280 | } 281 | }, 282 | }, 283 | } 284 | }, 285 | }, 286 | }, 287 | }, 288 | }, 289 | @"[{}, {""a"": {""b"": [null, 1, ""🍣""]}}]", 290 | }, 291 | }; 292 | } 293 | 294 | class JsonReaderFailTests 295 | { 296 | [Test] 297 | [TestCaseSource("FixtureArgs")] 298 | public void ReadTest(string expectedMsg, string src) 299 | { 300 | using (var s = new MemoryStream(Encoding.UTF8.GetBytes(src))) 301 | using (var r = new JsonReader(s)) 302 | { 303 | var ex = Assert.Throws(() => r.Read()); 304 | Assert.AreEqual(expectedMsg, ex.Message); 305 | } 306 | } 307 | 308 | // 309 | static object[] FixtureArgs = { 310 | new object[] { 311 | "A node \"value\" is expected but '' is provided (at position 0)", 312 | "", 313 | }, 314 | 315 | new object[] { 316 | "A node \"EOS\" is expected but '1' is provided (at position 3)", 317 | @" 012 ", 318 | }, 319 | }; 320 | } 321 | } 322 | -------------------------------------------------------------------------------- /Packages/net.yutopp.vjson/Tests/Runtime/JsonReaderTest.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8bd2b0dc2e58d4c47b11b6f619d845ca 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Packages/net.yutopp.vjson/Tests/Runtime/JsonSerializerTest.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 65e10d45d37b25447987b51fdc847870 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Packages/net.yutopp.vjson/Tests/Runtime/JsonWriterTest.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2019- yutopp (yutopp@gmail.com) 3 | // 4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | // file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | 8 | using System.IO; 9 | using System.Text; 10 | using NUnit.Framework; 11 | 12 | namespace VJson.UnitTests 13 | { 14 | public class JsonWriterPrimitiveValueTests 15 | { 16 | [Test] 17 | public void ValueWriteTest() 18 | { 19 | using (var s = new MemoryStream()) 20 | { 21 | using (var f = new JsonWriter(s)) 22 | { 23 | f.WriteValue(1); 24 | } 25 | 26 | var actual = Encoding.UTF8.GetString(s.ToArray()); 27 | Assert.AreEqual("1", actual); 28 | } 29 | } 30 | 31 | [Test] 32 | public void EmojiValueWriteTest() 33 | { 34 | using (var s = new MemoryStream()) 35 | { 36 | using (var f = new JsonWriter(s)) 37 | { 38 | f.WriteValue("🍣"); 39 | } 40 | 41 | // Check UTF-8 sequence 42 | var actualArr = s.ToArray(); 43 | Assert.AreEqual(6, actualArr.Length); 44 | Assert.AreEqual(0x22, actualArr[0]); 45 | Assert.AreEqual(0xF0, actualArr[1]); 46 | Assert.AreEqual(0x9F, actualArr[2]); 47 | Assert.AreEqual(0x8D, actualArr[3]); 48 | Assert.AreEqual(0xA3, actualArr[4]); 49 | Assert.AreEqual(0x22, actualArr[5]); 50 | 51 | var actual = Encoding.UTF8.GetString(s.ToArray()); 52 | Assert.AreEqual("\"🍣\"", actual); 53 | } 54 | } 55 | 56 | [Test] 57 | public void EscapeSequenceValueWriteTest() 58 | { 59 | using (var s = new MemoryStream()) 60 | { 61 | using (var f = new JsonWriter(s)) 62 | { 63 | f.WriteValue("\"\\/\b\n\r\t"); 64 | } 65 | 66 | var actual = Encoding.UTF8.GetString(s.ToArray()); 67 | Assert.AreEqual("\"\\\"\\\\/\\b\\n\\r\\t\"", actual); 68 | } 69 | } 70 | } 71 | 72 | public class JsonWriterObjectTests 73 | { 74 | [Test] 75 | public void EmptyTest() 76 | { 77 | using (var s = new MemoryStream()) 78 | { 79 | using (var f = new JsonWriter(s)) 80 | { 81 | f.WriteObjectStart(); 82 | f.WriteObjectEnd(); 83 | } 84 | 85 | var actual = Encoding.UTF8.GetString(s.ToArray()); 86 | Assert.AreEqual(@"{}", actual); 87 | } 88 | } 89 | 90 | [Test] 91 | public void SingleTest() 92 | { 93 | using (var s = new MemoryStream()) 94 | { 95 | using (var f = new JsonWriter(s)) 96 | { 97 | f.WriteObjectStart(); 98 | f.WriteObjectKey("foo"); 99 | f.WriteValue(42); 100 | f.WriteObjectEnd(); 101 | } 102 | 103 | var actual = Encoding.UTF8.GetString(s.ToArray()); 104 | Assert.AreEqual(@"{""foo"":42}", actual); 105 | } 106 | } 107 | 108 | [Test] 109 | public void MultiTest() 110 | { 111 | using (var s = new MemoryStream()) 112 | { 113 | using (var f = new JsonWriter(s)) 114 | { 115 | f.WriteObjectStart(); 116 | f.WriteObjectKey("foo"); 117 | f.WriteValue(42); 118 | 119 | f.WriteObjectKey("bar"); 120 | f.WriteValue(84); 121 | f.WriteObjectEnd(); 122 | } 123 | 124 | var actual = Encoding.UTF8.GetString(s.ToArray()); 125 | Assert.AreEqual(@"{""foo"":42,""bar"":84}", actual); 126 | } 127 | } 128 | 129 | [Test] 130 | public void NestedTest() 131 | { 132 | using (var s = new MemoryStream()) 133 | { 134 | using (var f = new JsonWriter(s)) 135 | { 136 | f.WriteObjectStart(); 137 | f.WriteObjectKey("foo"); 138 | 139 | f.WriteObjectStart(); 140 | f.WriteObjectKey("bar"); 141 | f.WriteValue(84); 142 | f.WriteObjectEnd(); 143 | 144 | f.WriteObjectEnd(); 145 | } 146 | 147 | var actual = Encoding.UTF8.GetString(s.ToArray()); 148 | Assert.AreEqual(@"{""foo"":{""bar"":84}}", actual); 149 | } 150 | } 151 | } 152 | 153 | public class JsonWriterArrayTests 154 | { 155 | [Test] 156 | public void EmptyTest() 157 | { 158 | using (var s = new MemoryStream()) 159 | { 160 | using (var f = new JsonWriter(s)) 161 | { 162 | f.WriteArrayStart(); 163 | f.WriteArrayEnd(); 164 | } 165 | 166 | var actual = Encoding.UTF8.GetString(s.ToArray()); 167 | Assert.AreEqual(@"[]", actual); 168 | } 169 | } 170 | 171 | [Test] 172 | public void SingleTest() 173 | { 174 | using (var s = new MemoryStream()) 175 | { 176 | using (var f = new JsonWriter(s)) 177 | { 178 | f.WriteArrayStart(); 179 | f.WriteValue(42); 180 | f.WriteArrayEnd(); 181 | } 182 | 183 | var actual = Encoding.UTF8.GetString(s.ToArray()); 184 | Assert.AreEqual(@"[42]", actual); 185 | } 186 | } 187 | 188 | [Test] 189 | public void MultiTest() 190 | { 191 | using (var s = new MemoryStream()) 192 | { 193 | using (var f = new JsonWriter(s)) 194 | { 195 | f.WriteArrayStart(); 196 | f.WriteValue(42); 197 | f.WriteValue("aaa"); 198 | f.WriteArrayEnd(); 199 | } 200 | 201 | var actual = Encoding.UTF8.GetString(s.ToArray()); 202 | Assert.AreEqual(@"[42,""aaa""]", actual); 203 | } 204 | } 205 | 206 | [Test] 207 | public void NestedTest() 208 | { 209 | using (var s = new MemoryStream()) 210 | { 211 | using (var f = new JsonWriter(s)) 212 | { 213 | f.WriteArrayStart(); 214 | f.WriteValue(42); 215 | f.WriteArrayStart(); 216 | f.WriteValue("aaa"); 217 | f.WriteArrayEnd(); 218 | f.WriteArrayEnd(); 219 | } 220 | 221 | var actual = Encoding.UTF8.GetString(s.ToArray()); 222 | Assert.AreEqual(@"[42,[""aaa""]]", actual); 223 | } 224 | } 225 | } 226 | 227 | public class JsonWriterCompoundTests 228 | { 229 | [Test] 230 | public void CompoundTest() 231 | { 232 | using (var s = new MemoryStream()) 233 | { 234 | using (var f = new JsonWriter(s)) 235 | { 236 | f.WriteArrayStart(); 237 | 238 | f.WriteObjectStart(); 239 | f.WriteObjectKey("foo"); 240 | f.WriteValue(42); 241 | f.WriteObjectEnd(); 242 | 243 | f.WriteObjectStart(); 244 | f.WriteObjectKey("foo"); 245 | f.WriteArrayStart(); 246 | f.WriteValue(84); 247 | f.WriteArrayEnd(); 248 | f.WriteObjectEnd(); 249 | 250 | f.WriteArrayEnd(); 251 | } 252 | 253 | var actual = Encoding.UTF8.GetString(s.ToArray()); 254 | Assert.AreEqual(@"[{""foo"":42},{""foo"":[84]}]", actual); 255 | } 256 | } 257 | } 258 | } 259 | -------------------------------------------------------------------------------- /Packages/net.yutopp.vjson/Tests/Runtime/JsonWriterTest.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 63ae29223a992744ea8c4eb29d666c83 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Packages/net.yutopp.vjson/Tests/Runtime/NodeTest.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b508ff4e02018214abf93a9d8d29f85d 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Packages/net.yutopp.vjson/Tests/Runtime/Schema.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7ec4da88af00e4047bac43cc1a6a9872 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Packages/net.yutopp.vjson/Tests/Runtime/Schema/RegistryTests.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2019- yutopp (yutopp@gmail.com) 3 | // 4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | // file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | 8 | using NUnit.Framework; 9 | 10 | namespace VJson.Schema.UnitTests 11 | { 12 | public class JsonSchemaRegistryTests 13 | { 14 | [Test] 15 | public void BasicOperationTest() 16 | { 17 | var r = new JsonSchemaRegistry(); 18 | 19 | Assert.Null(r.Resolve("=TEST=")); 20 | Assert.That(r.GetRegisteredIDs(), Is.EquivalentTo(new string[] { })); 21 | 22 | var s = new JsonSchema(); 23 | r.Register("a", s); 24 | 25 | Assert.That(r.Resolve("a"), Is.EqualTo(s)); 26 | Assert.That(r.GetRegisteredIDs(), Is.EquivalentTo(new string[] { "a" })); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Packages/net.yutopp.vjson/Tests/Runtime/Schema/RegistryTests.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: eadbe01ea67bbce4987382130c0908fa 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Packages/net.yutopp.vjson/Tests/Runtime/Schema/SchemaTest.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2019- yutopp (yutopp@gmail.com) 3 | // 4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | // file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | 8 | using System; 9 | using System.IO; 10 | using System.Collections.Generic; 11 | using NUnit.Framework; 12 | 13 | namespace VJson.Schema.UnitTests 14 | { 15 | // 16 | // http://json-schema.org/learn/miscellaneous-examples.html 17 | // 18 | [JsonSchema(Title = "Person")] 19 | class Person 20 | { 21 | [JsonSchema(Description = "The person's first name.")] 22 | public string firstName = default(string); 23 | 24 | [JsonSchema(Description = "The person's last name.")] 25 | public string lastName = default(string); 26 | 27 | [JsonSchema(Description = "Age in years which must be equal to or greater than zero.", 28 | Minimum = 0)] 29 | public int age = default(int); 30 | } 31 | 32 | public class JsonSchemaFromClassTests 33 | { 34 | [Test] 35 | public void CreateFromPersonTest() 36 | { 37 | var schema = JsonSchema.CreateFromType(); 38 | Assert.IsNotNull(schema); 39 | 40 | Assert.AreEqual("Person", schema.Title); 41 | Assert.AreEqual(null, schema.Description); 42 | 43 | //Assert.AreEqual(NodeKind.Object, schema.Kind); 44 | 45 | Assert.That(schema.Properties.Count, Is.EqualTo(3)); 46 | 47 | Assert.That(schema.Properties["firstName"], 48 | Is.EqualTo(new JsonSchema 49 | { 50 | Description = "The person's first name.", 51 | Type = "string", 52 | }) 53 | ); 54 | Assert.That(schema.Properties["lastName"], 55 | Is.EqualTo(new JsonSchema 56 | { 57 | Description = "The person's last name.", 58 | Type = "string", 59 | }) 60 | ); 61 | Assert.That(schema.Properties["age"], 62 | Is.EqualTo(new JsonSchema 63 | { 64 | Description = "Age in years which must be equal to or greater than zero.", 65 | Type = "integer", 66 | Minimum = 0, 67 | }) 68 | ); 69 | } 70 | } 71 | 72 | [JsonSchema(Title = "a", Description = "b")] 73 | public class JsonSchemaFormatTests 74 | { 75 | [Test] 76 | [TestCaseSource(nameof(SchemaStringArgs))] 77 | public void SchemaFormatTest(Type ty, string expected) 78 | { 79 | var schema = JsonSchema.CreateFromType(ty); 80 | Assert.AreEqual(expected, schema.ToString()); 81 | } 82 | 83 | public abstract class Gb2 {} 84 | 85 | [JsonSchema(Id = "g2")] 86 | public sealed class G2 : Gb2 {} 87 | 88 | public static object[] SchemaStringArgs = new object[] { 89 | new object[] { 90 | typeof(int), 91 | "{\"type\":\"integer\"}", 92 | }, 93 | new object[] { 94 | typeof(double), 95 | "{\"type\":\"number\"}", 96 | }, 97 | new object[] { 98 | typeof(bool), 99 | "{\"type\":\"boolean\"}", 100 | }, 101 | new object[] { 102 | typeof(string), 103 | "{\"type\":\"string\"}", 104 | }, 105 | new object[] { 106 | typeof(object[]), 107 | "{\"type\":\"array\",\"items\":{}}", 108 | }, 109 | new object[] { 110 | typeof(int[]), 111 | "{\"type\":\"array\",\"items\":{\"type\":\"integer\"}}", 112 | }, 113 | new object[] { 114 | typeof(float[]), 115 | "{\"type\":\"array\",\"items\":{\"type\":\"number\"}}", 116 | }, 117 | new object[] { 118 | typeof(List), 119 | "{\"type\":\"array\",\"items\":{}}", 120 | }, 121 | new object[] { 122 | typeof(List), 123 | "{\"type\":\"array\",\"items\":{\"type\":\"integer\"}}", 124 | }, 125 | new object[] { 126 | typeof(List), 127 | "{\"type\":\"array\",\"items\":{\"type\":\"number\"}}", 128 | }, 129 | new object[] { 130 | typeof(Dictionary), 131 | "{\"type\":\"object\"}", 132 | }, 133 | new object[] { 134 | typeof(object), 135 | "{}", 136 | }, 137 | new object[] { 138 | typeof(JsonSchemaFormatTests), 139 | "{\"title\":\"a\",\"description\":\"b\",\"type\":\"object\",\"properties\":{}}", 140 | }, 141 | new object[] { 142 | typeof(JsonSchemaFormatTests[]), 143 | "{\"type\":\"array\",\"items\":{\"$ref\":\"VJson.Schema.UnitTests.JsonSchemaFormatTests\"}}", 144 | }, 145 | new object[] { 146 | typeof(List), 147 | "{\"type\":\"array\",\"items\":{\"$ref\":\"VJson.Schema.UnitTests.JsonSchemaFormatTests\"}}", 148 | }, 149 | new object[] { 150 | typeof(ValidatorWithSerializerTests.NotRequiredObject), 151 | "{\"$id\":\"not_required_object.json\",\"type\":\"object\",\"properties\":{\"X\":{\"type\":\"integer\",\"minimum\":1}}}", 152 | }, 153 | new object[] { 154 | typeof(ValidatorWithSerializerTests.NotRequiredObjectWithIgnorable), 155 | "{\"type\":\"object\",\"properties\":{\"X\":{\"type\":\"integer\",\"minimum\":1}}}", 156 | }, 157 | new object[] { 158 | typeof(ValidatorWithSerializerTests.HasDictionary), 159 | "{\"type\":\"object\",\"properties\":{\"FP\":{\"type\":\"object\"}}}", 160 | }, 161 | new object[] { 162 | typeof(ValidatorWithSerializerTests.HasEnumerable), 163 | "{\"type\":\"object\",\"properties\":{\"Fs\":{\"type\":\"array\",\"items\":{\"type\":\"number\",\"maximum\":1,\"minimum\":0}},\"FsList\":{\"type\":\"array\",\"items\":{\"type\":\"number\"}},\"Os\":{\"type\":\"array\"},\"OsList\":{\"type\":\"array\"}}}", 164 | }, 165 | new object[] { 166 | typeof(ValidatorWithSerializerTests.HasRequiredItems), 167 | "{\"type\":\"object\",\"required\":[\"Xs\"],\"properties\":{\"Xs\":{\"type\":\"array\",\"items\":{\"type\":\"integer\",\"minimum\":0},\"minItems\":1}}}", 168 | }, 169 | new object[] { 170 | typeof(ValidatorWithSerializerTests.HasRequiredString), 171 | "{\"type\":\"object\",\"required\":[\"S\"],\"properties\":{\"S\":{\"type\":\"string\"}}}", 172 | }, 173 | new object[] { 174 | typeof(ValidatorWithSerializerTests.HasRequiredButIgnorableString), 175 | "{\"type\":\"object\",\"required\":[\"S\"],\"properties\":{\"S\":{\"type\":\"string\"}}}", 176 | }, 177 | new object[] { 178 | typeof(ValidatorWithSerializerTests.HasDeps), 179 | "{\"type\":\"object\",\"properties\":{\"X\":{\"type\":\"integer\",\"minimum\":0},\"Y\":{\"type\":\"integer\"}},\"dependencies\":{\"Y\":[\"X\"]}}", 180 | }, 181 | new object[] { 182 | typeof(ValidatorWithSerializerTests.HasNested), 183 | "{\"type\":\"object\",\"required\":[\"C\"],\"properties\":{\"C\":{\"$ref\":\"VJson.Schema.UnitTests.ValidatorWithSerializerTests+HasNestedChild\"}}}", 184 | }, 185 | new object[] { 186 | typeof(ValidatorWithSerializerTests.DerivingBase), 187 | "{\"type\":\"object\",\"properties\":{\"X\":{\"type\":\"string\",\"minLength\":1}}}", 188 | }, 189 | new object[] { 190 | typeof(ValidatorWithSerializerTests.Deriving), 191 | "{\"type\":\"object\",\"properties\":{\"X\":{},\"Y\":{\"type\":\"string\",\"minLength\":2}},\"allOf\":[{\"$ref\":\"VJson.Schema.UnitTests.ValidatorWithSerializerTests+DerivingBase\"}]}", 192 | }, 193 | new object[] { 194 | typeof(ValidatorWithSerializerTests.MoreDeriving), 195 | "{\"type\":\"object\",\"properties\":{\"X\":{},\"Y\":{},\"Z\":{\"type\":\"string\",\"minLength\":3}},\"allOf\":[{\"$ref\":\"VJson.Schema.UnitTests.ValidatorWithSerializerTests+Deriving\"}]}", 196 | }, 197 | new object[] { 198 | typeof(VJson.UnitTests.EnumAsInt), 199 | "{\"type\":\"integer\",\"enum\":[0,1,100]}", 200 | }, 201 | new object[] { 202 | typeof(VJson.UnitTests.EnumAsString), 203 | "{\"type\":\"string\",\"enum\":[\"NameA\",\"NameB\",\"OtherName\"]}", 204 | }, 205 | new object[] { 206 | typeof(Nullable), 207 | "{\"type\":\"integer\"}", 208 | }, 209 | new object[] { 210 | typeof(int?), 211 | "{\"type\":\"integer\"}", 212 | }, 213 | new object[] { 214 | typeof(ValidatorWithSerializerTests.HasNullable), 215 | "{\"type\":\"object\",\"properties\":{\"X\":{\"type\":\"integer\"}}}", 216 | }, 217 | new object[] { 218 | typeof(ValidatorWithSerializerTests.HasStrEnum), 219 | "{\"type\":\"object\",\"properties\":{\"E\":{\"type\":\"string\",\"enum\":[\"NameA\",\"NameB\",\"OtherName\"]}}}", 220 | }, 221 | new object[] { 222 | typeof(ValidatorWithSerializerTests.HasNumEnum), 223 | "{\"type\":\"object\",\"properties\":{\"E\":{\"type\":\"integer\",\"enum\":[0,1,100]}}}", 224 | }, 225 | new object[] { 226 | typeof(ValidatorWithSerializerTests.CustomTag), 227 | "{\"type\":\"integer\",\"minimum\":0}", 228 | }, 229 | new object[] { 230 | typeof(ValidatorWithSerializerTests.HasCustomTagInt), 231 | "{\"type\":\"object\",\"properties\":{\"X\":{\"type\":\"integer\",\"allOf\":[{\"$ref\":\"VJson.Schema.UnitTests.ValidatorWithSerializerTests+CustomTag`1[System.Int32]\"}]}}}", 232 | }, 233 | new object[] { 234 | typeof(ValidatorWithSerializerTests.HasCustomTagArray), 235 | "{\"type\":\"object\",\"properties\":{\"Xs\":{\"type\":\"array\",\"items\":{\"type\":\"integer\",\"allOf\":[{\"$ref\":\"VJson.Schema.UnitTests.ValidatorWithSerializerTests+CustomTag`1[System.Int32]\"}]}}}}", 236 | }, 237 | new object[] { 238 | typeof(ValidatorWithSerializerTests.HasCustomTagDict), 239 | "{\"type\":\"object\",\"properties\":{\"Xs\":{\"type\":\"object\",\"additionalProperties\":{\"allOf\":[{\"$ref\":\"VJson.Schema.UnitTests.ValidatorWithSerializerTests+CustomTag`1[System.Int32]\"}]}}}}", 240 | }, 241 | new object[] { 242 | typeof(ValidatorWithSerializerTests.HasCustomTagArrayDict), 243 | "{\"type\":\"object\",\"properties\":{\"Xs\":{\"type\":\"array\",\"items\":{\"type\":\"object\",\"additionalProperties\":{\"allOf\":[{\"$ref\":\"VJson.Schema.UnitTests.ValidatorWithSerializerTests+CustomTag`1[System.Int32]\"}]}}}}}", 244 | }, 245 | new object[] { 246 | typeof(ValidatorWithSerializerTests.CustomTag), 247 | "{\"type\":\"number\",\"minimum\":0}", 248 | }, 249 | // ↓ Run same test cases twice, it will be broken on IL2CPP. Thus added as test cases. 250 | // See: https://github.com/yutopp/VJson/blob/120020a1c90dd1f0275d0f9353eef4e089943b0a/Packages/net.yutopp.vjson/Runtime/Schema/JsonSchema.cs#L385 251 | new object[] { 252 | typeof(G2), 253 | @"{""$id"":""g2"",""type"":""object"",""properties"":{},""allOf"":[{""$ref"":""VJson.Schema.UnitTests.JsonSchemaFormatTests+Gb2""}]}", 254 | }, 255 | new object[] { 256 | typeof(G2), 257 | @"{""$id"":""g2"",""type"":""object"",""properties"":{},""allOf"":[{""$ref"":""VJson.Schema.UnitTests.JsonSchemaFormatTests+Gb2""}]}", 258 | }, 259 | // ↑ 260 | }; 261 | } 262 | 263 | #if VJSON_FULL_TESTS 264 | public class JsonSchemaFromTestCasesTests 265 | { 266 | [Json] 267 | sealed class TestCase 268 | { 269 | [JsonField] public string description = default; 270 | [JsonField] public JsonSchema schema = default; 271 | [JsonField] public UnitTest[] tests = default; 272 | } 273 | 274 | [Json] 275 | sealed class UnitTest 276 | { 277 | [JsonField] public string description = default; 278 | [JsonField] public object data = default; 279 | [JsonField] public bool valid = default; 280 | } 281 | 282 | [Test] 283 | [TestCase("additionalItems.json")] 284 | [TestCase("additionalProperties.json")] 285 | [TestCase("allOf.json")] 286 | [TestCase("anyOf.json")] 287 | [TestCase("boolean_schema.json")] 288 | //[TestCase("const.json")] 289 | //[TestCase("contains.json")] 290 | //[TestCase("default.json")] 291 | //[TestCase("definitions.json")] 292 | [TestCase("dependencies.json")] 293 | [TestCase("enum.json")] 294 | [TestCase("exclusiveMaximum.json")] 295 | [TestCase("exclusiveMinimum.json")] 296 | //[TestCase("if-then-else.json")] 297 | [TestCase("items.json")] 298 | [TestCase("maximum.json")] 299 | [TestCase("maxItems.json")] 300 | [TestCase("maxLength.json")] 301 | [TestCase("maxProperties.json")] 302 | [TestCase("minimum.json")] 303 | [TestCase("minItems.json")] 304 | [TestCase("minLength.json")] 305 | [TestCase("minProperties.json")] 306 | [TestCase("multipleOf.json")] 307 | [TestCase("not.json")] 308 | [TestCase("oneOf.json")] 309 | //[TestCase("optional")] 310 | [TestCase("pattern.json")] 311 | [TestCase("patternProperties.json")] 312 | [TestCase("properties.json")] 313 | //[TestCase("propertyNames.json")] 314 | //[TestCase("ref.json")] 315 | //[TestCase("refRemote.json")] 316 | [TestCase("required.json")] 317 | [TestCase("type.json")] 318 | [TestCase("uniqueItems.json")] 319 | public void ValidationTest(string casePath) 320 | { 321 | var path = Path.Combine(Path.Combine(Path.Combine("JSON-Schema-Test-Suite", "tests"), "draft7"), casePath); 322 | using (var fs = File.OpenRead(path)) 323 | { 324 | var d = new JsonSerializer(typeof(TestCase[])); 325 | var cases = (TestCase[])d.Deserialize(fs); 326 | 327 | foreach (var c in cases) 328 | { 329 | foreach (var t in c.tests) 330 | { 331 | var ex = c.schema.Validate(t.data); 332 | 333 | Assert.That(ex == null, 334 | Is.EqualTo(t.valid), 335 | String.Format("{0} / {1} ({2})", ex, t.description, c.description)); 336 | } 337 | } 338 | } 339 | } 340 | } 341 | #endif 342 | } 343 | -------------------------------------------------------------------------------- /Packages/net.yutopp.vjson/Tests/Runtime/Schema/SchemaTest.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 17469e4b52b6faa4b88142ebfa2da85c 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Packages/net.yutopp.vjson/Tests/Runtime/Schema/ValidatorTest.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5e746a58c7101194aaa2cca4b6b3da0d 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Packages/net.yutopp.vjson/Tests/Runtime/Unity.net.yutopp.vjson.Tests.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Unity.net.yutopp.vjson.Tests", 3 | "references": [ 4 | "Unity.net.yutopp.vjson", 5 | "UnityEngine.TestRunner", 6 | "UnityEditor.TestRunner" 7 | ], 8 | "includePlatforms": [], 9 | "excludePlatforms": [], 10 | "allowUnsafeCode": false, 11 | "overrideReferences": true, 12 | "precompiledReferences": [ 13 | "nunit.framework.dll" 14 | ], 15 | "autoReferenced": false, 16 | "defineConstraints": [ 17 | "UNITY_INCLUDE_TESTS" 18 | ], 19 | "versionDefines": [], 20 | "noEngineReferences": false 21 | } -------------------------------------------------------------------------------- /Packages/net.yutopp.vjson/Tests/Runtime/Unity.net.yutopp.vjson.Tests.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 60f4314ad64134b758771394d9eab678 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Packages/net.yutopp.vjson/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "net.yutopp.vjson", 3 | "version": "0.0.0", 4 | "displayName": "VJson", 5 | "description": "A JSON serializer/deserializer (with JsonSchema support) library written in pure C#.", 6 | "unity": "2019.4", 7 | "dependencies": {}, 8 | "keywords": [ 9 | "unity", 10 | "unity3d", 11 | "json" 12 | ], 13 | "category": "", 14 | "author": { 15 | "name": "yutopp" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Packages/net.yutopp.vjson/package.json.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9ad963c60d824a8159cc3ed5270a92d9 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Packages/packages-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "com.unity.ext.nunit": { 4 | "version": "1.0.6", 5 | "depth": 1, 6 | "source": "registry", 7 | "dependencies": {}, 8 | "url": "https://packages.unity.com" 9 | }, 10 | "com.unity.ide.vscode": { 11 | "version": "1.2.4", 12 | "depth": 0, 13 | "source": "registry", 14 | "dependencies": {}, 15 | "url": "https://packages.unity.com" 16 | }, 17 | "com.unity.test-framework": { 18 | "version": "1.1.22", 19 | "depth": 0, 20 | "source": "registry", 21 | "dependencies": { 22 | "com.unity.ext.nunit": "1.0.6", 23 | "com.unity.modules.imgui": "1.0.0", 24 | "com.unity.modules.jsonserialize": "1.0.0" 25 | }, 26 | "url": "https://packages.unity.com" 27 | }, 28 | "com.unity.ugui": { 29 | "version": "1.0.0", 30 | "depth": 0, 31 | "source": "builtin", 32 | "dependencies": { 33 | "com.unity.modules.ui": "1.0.0", 34 | "com.unity.modules.imgui": "1.0.0" 35 | } 36 | }, 37 | "net.yutopp.vjson": { 38 | "version": "file:net.yutopp.vjson", 39 | "depth": 0, 40 | "source": "embedded", 41 | "dependencies": {} 42 | }, 43 | "com.unity.modules.ai": { 44 | "version": "1.0.0", 45 | "depth": 0, 46 | "source": "builtin", 47 | "dependencies": {} 48 | }, 49 | "com.unity.modules.androidjni": { 50 | "version": "1.0.0", 51 | "depth": 0, 52 | "source": "builtin", 53 | "dependencies": {} 54 | }, 55 | "com.unity.modules.animation": { 56 | "version": "1.0.0", 57 | "depth": 0, 58 | "source": "builtin", 59 | "dependencies": {} 60 | }, 61 | "com.unity.modules.assetbundle": { 62 | "version": "1.0.0", 63 | "depth": 0, 64 | "source": "builtin", 65 | "dependencies": {} 66 | }, 67 | "com.unity.modules.audio": { 68 | "version": "1.0.0", 69 | "depth": 0, 70 | "source": "builtin", 71 | "dependencies": {} 72 | }, 73 | "com.unity.modules.cloth": { 74 | "version": "1.0.0", 75 | "depth": 0, 76 | "source": "builtin", 77 | "dependencies": { 78 | "com.unity.modules.physics": "1.0.0" 79 | } 80 | }, 81 | "com.unity.modules.director": { 82 | "version": "1.0.0", 83 | "depth": 0, 84 | "source": "builtin", 85 | "dependencies": { 86 | "com.unity.modules.audio": "1.0.0", 87 | "com.unity.modules.animation": "1.0.0" 88 | } 89 | }, 90 | "com.unity.modules.imageconversion": { 91 | "version": "1.0.0", 92 | "depth": 0, 93 | "source": "builtin", 94 | "dependencies": {} 95 | }, 96 | "com.unity.modules.imgui": { 97 | "version": "1.0.0", 98 | "depth": 0, 99 | "source": "builtin", 100 | "dependencies": {} 101 | }, 102 | "com.unity.modules.jsonserialize": { 103 | "version": "1.0.0", 104 | "depth": 0, 105 | "source": "builtin", 106 | "dependencies": {} 107 | }, 108 | "com.unity.modules.particlesystem": { 109 | "version": "1.0.0", 110 | "depth": 0, 111 | "source": "builtin", 112 | "dependencies": {} 113 | }, 114 | "com.unity.modules.physics": { 115 | "version": "1.0.0", 116 | "depth": 0, 117 | "source": "builtin", 118 | "dependencies": {} 119 | }, 120 | "com.unity.modules.physics2d": { 121 | "version": "1.0.0", 122 | "depth": 0, 123 | "source": "builtin", 124 | "dependencies": {} 125 | }, 126 | "com.unity.modules.screencapture": { 127 | "version": "1.0.0", 128 | "depth": 0, 129 | "source": "builtin", 130 | "dependencies": { 131 | "com.unity.modules.imageconversion": "1.0.0" 132 | } 133 | }, 134 | "com.unity.modules.subsystems": { 135 | "version": "1.0.0", 136 | "depth": 1, 137 | "source": "builtin", 138 | "dependencies": { 139 | "com.unity.modules.jsonserialize": "1.0.0" 140 | } 141 | }, 142 | "com.unity.modules.terrain": { 143 | "version": "1.0.0", 144 | "depth": 0, 145 | "source": "builtin", 146 | "dependencies": {} 147 | }, 148 | "com.unity.modules.terrainphysics": { 149 | "version": "1.0.0", 150 | "depth": 0, 151 | "source": "builtin", 152 | "dependencies": { 153 | "com.unity.modules.physics": "1.0.0", 154 | "com.unity.modules.terrain": "1.0.0" 155 | } 156 | }, 157 | "com.unity.modules.tilemap": { 158 | "version": "1.0.0", 159 | "depth": 0, 160 | "source": "builtin", 161 | "dependencies": { 162 | "com.unity.modules.physics2d": "1.0.0" 163 | } 164 | }, 165 | "com.unity.modules.ui": { 166 | "version": "1.0.0", 167 | "depth": 0, 168 | "source": "builtin", 169 | "dependencies": {} 170 | }, 171 | "com.unity.modules.uielements": { 172 | "version": "1.0.0", 173 | "depth": 0, 174 | "source": "builtin", 175 | "dependencies": { 176 | "com.unity.modules.imgui": "1.0.0", 177 | "com.unity.modules.jsonserialize": "1.0.0" 178 | } 179 | }, 180 | "com.unity.modules.umbra": { 181 | "version": "1.0.0", 182 | "depth": 0, 183 | "source": "builtin", 184 | "dependencies": {} 185 | }, 186 | "com.unity.modules.unityanalytics": { 187 | "version": "1.0.0", 188 | "depth": 0, 189 | "source": "builtin", 190 | "dependencies": { 191 | "com.unity.modules.unitywebrequest": "1.0.0", 192 | "com.unity.modules.jsonserialize": "1.0.0" 193 | } 194 | }, 195 | "com.unity.modules.unitywebrequest": { 196 | "version": "1.0.0", 197 | "depth": 0, 198 | "source": "builtin", 199 | "dependencies": {} 200 | }, 201 | "com.unity.modules.unitywebrequestassetbundle": { 202 | "version": "1.0.0", 203 | "depth": 0, 204 | "source": "builtin", 205 | "dependencies": { 206 | "com.unity.modules.assetbundle": "1.0.0", 207 | "com.unity.modules.unitywebrequest": "1.0.0" 208 | } 209 | }, 210 | "com.unity.modules.unitywebrequestaudio": { 211 | "version": "1.0.0", 212 | "depth": 0, 213 | "source": "builtin", 214 | "dependencies": { 215 | "com.unity.modules.unitywebrequest": "1.0.0", 216 | "com.unity.modules.audio": "1.0.0" 217 | } 218 | }, 219 | "com.unity.modules.unitywebrequesttexture": { 220 | "version": "1.0.0", 221 | "depth": 0, 222 | "source": "builtin", 223 | "dependencies": { 224 | "com.unity.modules.unitywebrequest": "1.0.0", 225 | "com.unity.modules.imageconversion": "1.0.0" 226 | } 227 | }, 228 | "com.unity.modules.unitywebrequestwww": { 229 | "version": "1.0.0", 230 | "depth": 0, 231 | "source": "builtin", 232 | "dependencies": { 233 | "com.unity.modules.unitywebrequest": "1.0.0", 234 | "com.unity.modules.unitywebrequestassetbundle": "1.0.0", 235 | "com.unity.modules.unitywebrequestaudio": "1.0.0", 236 | "com.unity.modules.audio": "1.0.0", 237 | "com.unity.modules.assetbundle": "1.0.0", 238 | "com.unity.modules.imageconversion": "1.0.0" 239 | } 240 | }, 241 | "com.unity.modules.vehicles": { 242 | "version": "1.0.0", 243 | "depth": 0, 244 | "source": "builtin", 245 | "dependencies": { 246 | "com.unity.modules.physics": "1.0.0" 247 | } 248 | }, 249 | "com.unity.modules.video": { 250 | "version": "1.0.0", 251 | "depth": 0, 252 | "source": "builtin", 253 | "dependencies": { 254 | "com.unity.modules.audio": "1.0.0", 255 | "com.unity.modules.ui": "1.0.0", 256 | "com.unity.modules.unitywebrequest": "1.0.0" 257 | } 258 | }, 259 | "com.unity.modules.vr": { 260 | "version": "1.0.0", 261 | "depth": 0, 262 | "source": "builtin", 263 | "dependencies": { 264 | "com.unity.modules.jsonserialize": "1.0.0", 265 | "com.unity.modules.physics": "1.0.0", 266 | "com.unity.modules.xr": "1.0.0" 267 | } 268 | }, 269 | "com.unity.modules.wind": { 270 | "version": "1.0.0", 271 | "depth": 0, 272 | "source": "builtin", 273 | "dependencies": {} 274 | }, 275 | "com.unity.modules.xr": { 276 | "version": "1.0.0", 277 | "depth": 0, 278 | "source": "builtin", 279 | "dependencies": { 280 | "com.unity.modules.physics": "1.0.0", 281 | "com.unity.modules.jsonserialize": "1.0.0", 282 | "com.unity.modules.subsystems": "1.0.0" 283 | } 284 | } 285 | } 286 | } 287 | -------------------------------------------------------------------------------- /ProjectSettings/AudioManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!11 &1 4 | AudioManager: 5 | m_ObjectHideFlags: 0 6 | m_Volume: 1 7 | Rolloff Scale: 1 8 | Doppler Factor: 1 9 | Default Speaker Mode: 2 10 | m_SampleRate: 0 11 | m_DSPBufferSize: 1024 12 | m_VirtualVoiceCount: 512 13 | m_RealVoiceCount: 32 14 | m_SpatializerPlugin: 15 | m_AmbisonicDecoderPlugin: 16 | m_DisableAudio: 0 17 | m_VirtualizeEffects: 1 18 | -------------------------------------------------------------------------------- /ProjectSettings/ClusterInputManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!236 &1 4 | ClusterInputManager: 5 | m_ObjectHideFlags: 0 6 | m_Inputs: [] 7 | -------------------------------------------------------------------------------- /ProjectSettings/DynamicsManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!55 &1 4 | PhysicsManager: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 7 7 | m_Gravity: {x: 0, y: -9.81, z: 0} 8 | m_DefaultMaterial: {fileID: 0} 9 | m_BounceThreshold: 2 10 | m_SleepThreshold: 0.005 11 | m_DefaultContactOffset: 0.01 12 | m_DefaultSolverIterations: 6 13 | m_DefaultSolverVelocityIterations: 1 14 | m_QueriesHitBackfaces: 0 15 | m_QueriesHitTriggers: 1 16 | m_EnableAdaptiveForce: 0 17 | m_ClothInterCollisionDistance: 0 18 | m_ClothInterCollisionStiffness: 0 19 | m_ContactsGeneration: 1 20 | m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 21 | m_AutoSimulation: 1 22 | m_AutoSyncTransforms: 1 23 | m_ClothInterCollisionSettingsToggle: 0 24 | m_ContactPairsMode: 0 25 | m_BroadphaseType: 0 26 | m_WorldBounds: 27 | m_Center: {x: 0, y: 0, z: 0} 28 | m_Extent: {x: 250, y: 250, z: 250} 29 | m_WorldSubdivisions: 8 30 | -------------------------------------------------------------------------------- /ProjectSettings/EditorBuildSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1045 &1 4 | EditorBuildSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | m_Scenes: [] 8 | m_configObjects: {} 9 | -------------------------------------------------------------------------------- /ProjectSettings/EditorSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!159 &1 4 | EditorSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 9 7 | m_ExternalVersionControlSupport: Hidden Meta Files 8 | m_SerializationMode: 2 9 | m_LineEndingsForNewScripts: 1 10 | m_DefaultBehaviorMode: 0 11 | m_PrefabRegularEnvironment: {fileID: 0} 12 | m_PrefabUIEnvironment: {fileID: 0} 13 | m_SpritePackerMode: 0 14 | m_SpritePackerPaddingPower: 1 15 | m_EtcTextureCompressorBehavior: 1 16 | m_EtcTextureFastCompressor: 1 17 | m_EtcTextureNormalCompressor: 2 18 | m_EtcTextureBestCompressor: 4 19 | m_ProjectGenerationIncludedExtensions: txt;xml;fnt;cd;asmdef;rsp;asmref 20 | m_ProjectGenerationRootNamespace: 21 | m_CollabEditorSettings: 22 | inProgressEnabled: 1 23 | m_EnableTextureStreamingInEditMode: 1 24 | m_EnableTextureStreamingInPlayMode: 1 25 | m_AsyncShaderCompilation: 1 26 | m_EnterPlayModeOptionsEnabled: 0 27 | m_EnterPlayModeOptions: 3 28 | m_ShowLightmapResolutionOverlay: 1 29 | m_UseLegacyProbeSampleCount: 1 30 | m_AssetPipelineMode: 1 31 | m_CacheServerMode: 0 32 | m_CacheServerEndpoint: 33 | m_CacheServerNamespacePrefix: default 34 | m_CacheServerEnableDownload: 1 35 | m_CacheServerEnableUpload: 1 36 | -------------------------------------------------------------------------------- /ProjectSettings/GraphicsSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!30 &1 4 | GraphicsSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 13 7 | m_Deferred: 8 | m_Mode: 1 9 | m_Shader: {fileID: 69, guid: 0000000000000000f000000000000000, type: 0} 10 | m_DeferredReflections: 11 | m_Mode: 1 12 | m_Shader: {fileID: 74, guid: 0000000000000000f000000000000000, type: 0} 13 | m_ScreenSpaceShadows: 14 | m_Mode: 1 15 | m_Shader: {fileID: 64, guid: 0000000000000000f000000000000000, type: 0} 16 | m_LegacyDeferred: 17 | m_Mode: 1 18 | m_Shader: {fileID: 63, guid: 0000000000000000f000000000000000, type: 0} 19 | m_DepthNormals: 20 | m_Mode: 1 21 | m_Shader: {fileID: 62, guid: 0000000000000000f000000000000000, type: 0} 22 | m_MotionVectors: 23 | m_Mode: 1 24 | m_Shader: {fileID: 75, guid: 0000000000000000f000000000000000, type: 0} 25 | m_LightHalo: 26 | m_Mode: 1 27 | m_Shader: {fileID: 105, guid: 0000000000000000f000000000000000, type: 0} 28 | m_LensFlare: 29 | m_Mode: 1 30 | m_Shader: {fileID: 102, guid: 0000000000000000f000000000000000, type: 0} 31 | m_AlwaysIncludedShaders: 32 | - {fileID: 7, guid: 0000000000000000f000000000000000, type: 0} 33 | - {fileID: 15104, guid: 0000000000000000f000000000000000, type: 0} 34 | - {fileID: 15105, guid: 0000000000000000f000000000000000, type: 0} 35 | - {fileID: 15106, guid: 0000000000000000f000000000000000, type: 0} 36 | - {fileID: 10753, guid: 0000000000000000f000000000000000, type: 0} 37 | - {fileID: 10770, guid: 0000000000000000f000000000000000, type: 0} 38 | - {fileID: 10783, guid: 0000000000000000f000000000000000, type: 0} 39 | - {fileID: 16000, guid: 0000000000000000f000000000000000, type: 0} 40 | - {fileID: 16001, guid: 0000000000000000f000000000000000, type: 0} 41 | - {fileID: 17000, guid: 0000000000000000f000000000000000, type: 0} 42 | m_PreloadedShaders: [] 43 | m_SpritesDefaultMaterial: {fileID: 10754, guid: 0000000000000000f000000000000000, 44 | type: 0} 45 | m_CustomRenderPipeline: {fileID: 0} 46 | m_TransparencySortMode: 0 47 | m_TransparencySortAxis: {x: 0, y: 0, z: 1} 48 | m_DefaultRenderingPath: 1 49 | m_DefaultMobileRenderingPath: 1 50 | m_TierSettings: [] 51 | m_LightmapStripping: 0 52 | m_FogStripping: 0 53 | m_InstancingStripping: 0 54 | m_LightmapKeepPlain: 1 55 | m_LightmapKeepDirCombined: 1 56 | m_LightmapKeepDynamicPlain: 1 57 | m_LightmapKeepDynamicDirCombined: 1 58 | m_LightmapKeepShadowMask: 1 59 | m_LightmapKeepSubtractive: 1 60 | m_FogKeepLinear: 1 61 | m_FogKeepExp: 1 62 | m_FogKeepExp2: 1 63 | m_AlbedoSwatchInfos: [] 64 | m_LightsUseLinearIntensity: 0 65 | m_LightsUseColorTemperature: 0 66 | m_LogWhenShaderIsCompiled: 0 67 | m_AllowEnlightenSupportForUpgradedProject: 1 68 | -------------------------------------------------------------------------------- /ProjectSettings/InputManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!13 &1 4 | InputManager: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | m_Axes: 8 | - serializedVersion: 3 9 | m_Name: Horizontal 10 | descriptiveName: 11 | descriptiveNegativeName: 12 | negativeButton: left 13 | positiveButton: right 14 | altNegativeButton: a 15 | altPositiveButton: d 16 | gravity: 3 17 | dead: 0.001 18 | sensitivity: 3 19 | snap: 1 20 | invert: 0 21 | type: 0 22 | axis: 0 23 | joyNum: 0 24 | - serializedVersion: 3 25 | m_Name: Vertical 26 | descriptiveName: 27 | descriptiveNegativeName: 28 | negativeButton: down 29 | positiveButton: up 30 | altNegativeButton: s 31 | altPositiveButton: w 32 | gravity: 3 33 | dead: 0.001 34 | sensitivity: 3 35 | snap: 1 36 | invert: 0 37 | type: 0 38 | axis: 0 39 | joyNum: 0 40 | - serializedVersion: 3 41 | m_Name: Fire1 42 | descriptiveName: 43 | descriptiveNegativeName: 44 | negativeButton: 45 | positiveButton: left ctrl 46 | altNegativeButton: 47 | altPositiveButton: mouse 0 48 | gravity: 1000 49 | dead: 0.001 50 | sensitivity: 1000 51 | snap: 0 52 | invert: 0 53 | type: 0 54 | axis: 0 55 | joyNum: 0 56 | - serializedVersion: 3 57 | m_Name: Fire2 58 | descriptiveName: 59 | descriptiveNegativeName: 60 | negativeButton: 61 | positiveButton: left alt 62 | altNegativeButton: 63 | altPositiveButton: mouse 1 64 | gravity: 1000 65 | dead: 0.001 66 | sensitivity: 1000 67 | snap: 0 68 | invert: 0 69 | type: 0 70 | axis: 0 71 | joyNum: 0 72 | - serializedVersion: 3 73 | m_Name: Fire3 74 | descriptiveName: 75 | descriptiveNegativeName: 76 | negativeButton: 77 | positiveButton: left shift 78 | altNegativeButton: 79 | altPositiveButton: mouse 2 80 | gravity: 1000 81 | dead: 0.001 82 | sensitivity: 1000 83 | snap: 0 84 | invert: 0 85 | type: 0 86 | axis: 0 87 | joyNum: 0 88 | - serializedVersion: 3 89 | m_Name: Jump 90 | descriptiveName: 91 | descriptiveNegativeName: 92 | negativeButton: 93 | positiveButton: space 94 | altNegativeButton: 95 | altPositiveButton: 96 | gravity: 1000 97 | dead: 0.001 98 | sensitivity: 1000 99 | snap: 0 100 | invert: 0 101 | type: 0 102 | axis: 0 103 | joyNum: 0 104 | - serializedVersion: 3 105 | m_Name: Mouse X 106 | descriptiveName: 107 | descriptiveNegativeName: 108 | negativeButton: 109 | positiveButton: 110 | altNegativeButton: 111 | altPositiveButton: 112 | gravity: 0 113 | dead: 0 114 | sensitivity: 0.1 115 | snap: 0 116 | invert: 0 117 | type: 1 118 | axis: 0 119 | joyNum: 0 120 | - serializedVersion: 3 121 | m_Name: Mouse Y 122 | descriptiveName: 123 | descriptiveNegativeName: 124 | negativeButton: 125 | positiveButton: 126 | altNegativeButton: 127 | altPositiveButton: 128 | gravity: 0 129 | dead: 0 130 | sensitivity: 0.1 131 | snap: 0 132 | invert: 0 133 | type: 1 134 | axis: 1 135 | joyNum: 0 136 | - serializedVersion: 3 137 | m_Name: Mouse ScrollWheel 138 | descriptiveName: 139 | descriptiveNegativeName: 140 | negativeButton: 141 | positiveButton: 142 | altNegativeButton: 143 | altPositiveButton: 144 | gravity: 0 145 | dead: 0 146 | sensitivity: 0.1 147 | snap: 0 148 | invert: 0 149 | type: 1 150 | axis: 2 151 | joyNum: 0 152 | - serializedVersion: 3 153 | m_Name: Horizontal 154 | descriptiveName: 155 | descriptiveNegativeName: 156 | negativeButton: 157 | positiveButton: 158 | altNegativeButton: 159 | altPositiveButton: 160 | gravity: 0 161 | dead: 0.19 162 | sensitivity: 1 163 | snap: 0 164 | invert: 0 165 | type: 2 166 | axis: 0 167 | joyNum: 0 168 | - serializedVersion: 3 169 | m_Name: Vertical 170 | descriptiveName: 171 | descriptiveNegativeName: 172 | negativeButton: 173 | positiveButton: 174 | altNegativeButton: 175 | altPositiveButton: 176 | gravity: 0 177 | dead: 0.19 178 | sensitivity: 1 179 | snap: 0 180 | invert: 1 181 | type: 2 182 | axis: 1 183 | joyNum: 0 184 | - serializedVersion: 3 185 | m_Name: Fire1 186 | descriptiveName: 187 | descriptiveNegativeName: 188 | negativeButton: 189 | positiveButton: joystick button 0 190 | altNegativeButton: 191 | altPositiveButton: 192 | gravity: 1000 193 | dead: 0.001 194 | sensitivity: 1000 195 | snap: 0 196 | invert: 0 197 | type: 0 198 | axis: 0 199 | joyNum: 0 200 | - serializedVersion: 3 201 | m_Name: Fire2 202 | descriptiveName: 203 | descriptiveNegativeName: 204 | negativeButton: 205 | positiveButton: joystick button 1 206 | altNegativeButton: 207 | altPositiveButton: 208 | gravity: 1000 209 | dead: 0.001 210 | sensitivity: 1000 211 | snap: 0 212 | invert: 0 213 | type: 0 214 | axis: 0 215 | joyNum: 0 216 | - serializedVersion: 3 217 | m_Name: Fire3 218 | descriptiveName: 219 | descriptiveNegativeName: 220 | negativeButton: 221 | positiveButton: joystick button 2 222 | altNegativeButton: 223 | altPositiveButton: 224 | gravity: 1000 225 | dead: 0.001 226 | sensitivity: 1000 227 | snap: 0 228 | invert: 0 229 | type: 0 230 | axis: 0 231 | joyNum: 0 232 | - serializedVersion: 3 233 | m_Name: Jump 234 | descriptiveName: 235 | descriptiveNegativeName: 236 | negativeButton: 237 | positiveButton: joystick button 3 238 | altNegativeButton: 239 | altPositiveButton: 240 | gravity: 1000 241 | dead: 0.001 242 | sensitivity: 1000 243 | snap: 0 244 | invert: 0 245 | type: 0 246 | axis: 0 247 | joyNum: 0 248 | - serializedVersion: 3 249 | m_Name: Submit 250 | descriptiveName: 251 | descriptiveNegativeName: 252 | negativeButton: 253 | positiveButton: return 254 | altNegativeButton: 255 | altPositiveButton: joystick button 0 256 | gravity: 1000 257 | dead: 0.001 258 | sensitivity: 1000 259 | snap: 0 260 | invert: 0 261 | type: 0 262 | axis: 0 263 | joyNum: 0 264 | - serializedVersion: 3 265 | m_Name: Submit 266 | descriptiveName: 267 | descriptiveNegativeName: 268 | negativeButton: 269 | positiveButton: enter 270 | altNegativeButton: 271 | altPositiveButton: space 272 | gravity: 1000 273 | dead: 0.001 274 | sensitivity: 1000 275 | snap: 0 276 | invert: 0 277 | type: 0 278 | axis: 0 279 | joyNum: 0 280 | - serializedVersion: 3 281 | m_Name: Cancel 282 | descriptiveName: 283 | descriptiveNegativeName: 284 | negativeButton: 285 | positiveButton: escape 286 | altNegativeButton: 287 | altPositiveButton: joystick button 1 288 | gravity: 1000 289 | dead: 0.001 290 | sensitivity: 1000 291 | snap: 0 292 | invert: 0 293 | type: 0 294 | axis: 0 295 | joyNum: 0 296 | -------------------------------------------------------------------------------- /ProjectSettings/NavMeshAreas.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!126 &1 4 | NavMeshProjectSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | areas: 8 | - name: Walkable 9 | cost: 1 10 | - name: Not Walkable 11 | cost: 1 12 | - name: Jump 13 | cost: 2 14 | - name: 15 | cost: 1 16 | - name: 17 | cost: 1 18 | - name: 19 | cost: 1 20 | - name: 21 | cost: 1 22 | - name: 23 | cost: 1 24 | - name: 25 | cost: 1 26 | - name: 27 | cost: 1 28 | - name: 29 | cost: 1 30 | - name: 31 | cost: 1 32 | - name: 33 | cost: 1 34 | - name: 35 | cost: 1 36 | - name: 37 | cost: 1 38 | - name: 39 | cost: 1 40 | - name: 41 | cost: 1 42 | - name: 43 | cost: 1 44 | - name: 45 | cost: 1 46 | - name: 47 | cost: 1 48 | - name: 49 | cost: 1 50 | - name: 51 | cost: 1 52 | - name: 53 | cost: 1 54 | - name: 55 | cost: 1 56 | - name: 57 | cost: 1 58 | - name: 59 | cost: 1 60 | - name: 61 | cost: 1 62 | - name: 63 | cost: 1 64 | - name: 65 | cost: 1 66 | - name: 67 | cost: 1 68 | - name: 69 | cost: 1 70 | - name: 71 | cost: 1 72 | m_LastAgentTypeID: -887442657 73 | m_Settings: 74 | - serializedVersion: 2 75 | agentTypeID: 0 76 | agentRadius: 0.5 77 | agentHeight: 2 78 | agentSlope: 45 79 | agentClimb: 0.75 80 | ledgeDropHeight: 0 81 | maxJumpAcrossDistance: 0 82 | minRegionArea: 2 83 | manualCellSize: 0 84 | cellSize: 0.16666667 85 | manualTileSize: 0 86 | tileSize: 256 87 | accuratePlacement: 0 88 | debug: 89 | m_Flags: 0 90 | m_SettingNames: 91 | - Humanoid 92 | -------------------------------------------------------------------------------- /ProjectSettings/NetworkManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!149 &1 4 | NetworkManager: 5 | m_ObjectHideFlags: 0 6 | m_DebugLevel: 0 7 | m_Sendrate: 15 8 | m_AssetToPrefab: {} 9 | -------------------------------------------------------------------------------- /ProjectSettings/PackageManagerSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!114 &1 4 | MonoBehaviour: 5 | m_ObjectHideFlags: 61 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | m_GameObject: {fileID: 0} 10 | m_Enabled: 1 11 | m_EditorHideFlags: 0 12 | m_Script: {fileID: 13960, guid: 0000000000000000e000000000000000, type: 0} 13 | m_Name: 14 | m_EditorClassIdentifier: 15 | m_ScopedRegistriesSettingsExpanded: 1 16 | oneTimeWarningShown: 0 17 | m_Registries: 18 | - m_Id: main 19 | m_Name: 20 | m_Url: https://packages.unity.com 21 | m_Scopes: [] 22 | m_IsDefault: 1 23 | m_UserSelectedRegistryName: 24 | m_UserAddingNewScopedRegistry: 0 25 | m_RegistryInfoDraft: 26 | m_ErrorMessage: 27 | m_Original: 28 | m_Id: 29 | m_Name: 30 | m_Url: 31 | m_Scopes: [] 32 | m_IsDefault: 0 33 | m_Modified: 0 34 | m_Name: 35 | m_Url: 36 | m_Scopes: 37 | - 38 | m_SelectedScopeIndex: 0 39 | -------------------------------------------------------------------------------- /ProjectSettings/Physics2DSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!19 &1 4 | Physics2DSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 3 7 | m_Gravity: {x: 0, y: -9.81} 8 | m_DefaultMaterial: {fileID: 0} 9 | m_VelocityIterations: 8 10 | m_PositionIterations: 3 11 | m_VelocityThreshold: 1 12 | m_MaxLinearCorrection: 0.2 13 | m_MaxAngularCorrection: 8 14 | m_MaxTranslationSpeed: 100 15 | m_MaxRotationSpeed: 360 16 | m_BaumgarteScale: 0.2 17 | m_BaumgarteTimeOfImpactScale: 0.75 18 | m_TimeToSleep: 0.5 19 | m_LinearSleepTolerance: 0.01 20 | m_AngularSleepTolerance: 2 21 | m_DefaultContactOffset: 0.01 22 | m_JobOptions: 23 | serializedVersion: 2 24 | useMultithreading: 0 25 | useConsistencySorting: 0 26 | m_InterpolationPosesPerJob: 100 27 | m_NewContactsPerJob: 30 28 | m_CollideContactsPerJob: 100 29 | m_ClearFlagsPerJob: 200 30 | m_ClearBodyForcesPerJob: 200 31 | m_SyncDiscreteFixturesPerJob: 50 32 | m_SyncContinuousFixturesPerJob: 50 33 | m_FindNearestContactsPerJob: 100 34 | m_UpdateTriggerContactsPerJob: 100 35 | m_IslandSolverCostThreshold: 100 36 | m_IslandSolverBodyCostScale: 1 37 | m_IslandSolverContactCostScale: 10 38 | m_IslandSolverJointCostScale: 10 39 | m_IslandSolverBodiesPerJob: 50 40 | m_IslandSolverContactsPerJob: 50 41 | m_AutoSimulation: 1 42 | m_QueriesHitTriggers: 1 43 | m_QueriesStartInColliders: 1 44 | m_CallbacksOnDisable: 1 45 | m_AutoSyncTransforms: 1 46 | m_AlwaysShowColliders: 0 47 | m_ShowColliderSleep: 1 48 | m_ShowColliderContacts: 0 49 | m_ShowColliderAABB: 0 50 | m_ContactArrowScale: 0.2 51 | m_ColliderAwakeColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.7529412} 52 | m_ColliderAsleepColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.36078432} 53 | m_ColliderContactColor: {r: 1, g: 0, b: 1, a: 0.6862745} 54 | m_ColliderAABBColor: {r: 1, g: 1, b: 0, a: 0.2509804} 55 | m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 56 | -------------------------------------------------------------------------------- /ProjectSettings/PresetManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1386491679 &1 4 | PresetManager: 5 | m_ObjectHideFlags: 0 6 | m_DefaultList: [] 7 | -------------------------------------------------------------------------------- /ProjectSettings/ProjectVersion.txt: -------------------------------------------------------------------------------- 1 | m_EditorVersion: 2019.4.22f1 2 | m_EditorVersionWithRevision: 2019.4.22f1 (9fdda2fe27ad) 3 | -------------------------------------------------------------------------------- /ProjectSettings/QualitySettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!47 &1 4 | QualitySettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 5 7 | m_CurrentQuality: 5 8 | m_QualitySettings: 9 | - serializedVersion: 2 10 | name: Very Low 11 | pixelLightCount: 0 12 | shadows: 0 13 | shadowResolution: 0 14 | shadowProjection: 1 15 | shadowCascades: 1 16 | shadowDistance: 15 17 | shadowNearPlaneOffset: 3 18 | shadowCascade2Split: 0.33333334 19 | shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} 20 | shadowmaskMode: 0 21 | blendWeights: 1 22 | textureQuality: 1 23 | anisotropicTextures: 0 24 | antiAliasing: 0 25 | softParticles: 0 26 | softVegetation: 0 27 | realtimeReflectionProbes: 0 28 | billboardsFaceCameraPosition: 0 29 | vSyncCount: 0 30 | lodBias: 0.3 31 | maximumLODLevel: 0 32 | streamingMipmapsActive: 0 33 | streamingMipmapsAddAllCameras: 1 34 | streamingMipmapsMemoryBudget: 512 35 | streamingMipmapsRenderersPerFrame: 512 36 | streamingMipmapsMaxLevelReduction: 2 37 | streamingMipmapsMaxFileIORequests: 1024 38 | particleRaycastBudget: 4 39 | asyncUploadTimeSlice: 2 40 | asyncUploadBufferSize: 4 41 | resolutionScalingFixedDPIFactor: 1 42 | excludedTargetPlatforms: [] 43 | - serializedVersion: 2 44 | name: Low 45 | pixelLightCount: 0 46 | shadows: 0 47 | shadowResolution: 0 48 | shadowProjection: 1 49 | shadowCascades: 1 50 | shadowDistance: 20 51 | shadowNearPlaneOffset: 3 52 | shadowCascade2Split: 0.33333334 53 | shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} 54 | shadowmaskMode: 0 55 | blendWeights: 2 56 | textureQuality: 0 57 | anisotropicTextures: 0 58 | antiAliasing: 0 59 | softParticles: 0 60 | softVegetation: 0 61 | realtimeReflectionProbes: 0 62 | billboardsFaceCameraPosition: 0 63 | vSyncCount: 0 64 | lodBias: 0.4 65 | maximumLODLevel: 0 66 | streamingMipmapsActive: 0 67 | streamingMipmapsAddAllCameras: 1 68 | streamingMipmapsMemoryBudget: 512 69 | streamingMipmapsRenderersPerFrame: 512 70 | streamingMipmapsMaxLevelReduction: 2 71 | streamingMipmapsMaxFileIORequests: 1024 72 | particleRaycastBudget: 16 73 | asyncUploadTimeSlice: 2 74 | asyncUploadBufferSize: 4 75 | resolutionScalingFixedDPIFactor: 1 76 | excludedTargetPlatforms: [] 77 | - serializedVersion: 2 78 | name: Medium 79 | pixelLightCount: 1 80 | shadows: 1 81 | shadowResolution: 0 82 | shadowProjection: 1 83 | shadowCascades: 1 84 | shadowDistance: 20 85 | shadowNearPlaneOffset: 3 86 | shadowCascade2Split: 0.33333334 87 | shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} 88 | shadowmaskMode: 0 89 | blendWeights: 2 90 | textureQuality: 0 91 | anisotropicTextures: 1 92 | antiAliasing: 0 93 | softParticles: 0 94 | softVegetation: 0 95 | realtimeReflectionProbes: 0 96 | billboardsFaceCameraPosition: 0 97 | vSyncCount: 1 98 | lodBias: 0.7 99 | maximumLODLevel: 0 100 | streamingMipmapsActive: 0 101 | streamingMipmapsAddAllCameras: 1 102 | streamingMipmapsMemoryBudget: 512 103 | streamingMipmapsRenderersPerFrame: 512 104 | streamingMipmapsMaxLevelReduction: 2 105 | streamingMipmapsMaxFileIORequests: 1024 106 | particleRaycastBudget: 64 107 | asyncUploadTimeSlice: 2 108 | asyncUploadBufferSize: 4 109 | resolutionScalingFixedDPIFactor: 1 110 | excludedTargetPlatforms: [] 111 | - serializedVersion: 2 112 | name: High 113 | pixelLightCount: 2 114 | shadows: 2 115 | shadowResolution: 1 116 | shadowProjection: 1 117 | shadowCascades: 2 118 | shadowDistance: 40 119 | shadowNearPlaneOffset: 3 120 | shadowCascade2Split: 0.33333334 121 | shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} 122 | shadowmaskMode: 1 123 | blendWeights: 2 124 | textureQuality: 0 125 | anisotropicTextures: 1 126 | antiAliasing: 0 127 | softParticles: 0 128 | softVegetation: 1 129 | realtimeReflectionProbes: 1 130 | billboardsFaceCameraPosition: 1 131 | vSyncCount: 1 132 | lodBias: 1 133 | maximumLODLevel: 0 134 | streamingMipmapsActive: 0 135 | streamingMipmapsAddAllCameras: 1 136 | streamingMipmapsMemoryBudget: 512 137 | streamingMipmapsRenderersPerFrame: 512 138 | streamingMipmapsMaxLevelReduction: 2 139 | streamingMipmapsMaxFileIORequests: 1024 140 | particleRaycastBudget: 256 141 | asyncUploadTimeSlice: 2 142 | asyncUploadBufferSize: 4 143 | resolutionScalingFixedDPIFactor: 1 144 | excludedTargetPlatforms: [] 145 | - serializedVersion: 2 146 | name: Very High 147 | pixelLightCount: 3 148 | shadows: 2 149 | shadowResolution: 2 150 | shadowProjection: 1 151 | shadowCascades: 2 152 | shadowDistance: 70 153 | shadowNearPlaneOffset: 3 154 | shadowCascade2Split: 0.33333334 155 | shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} 156 | shadowmaskMode: 1 157 | blendWeights: 4 158 | textureQuality: 0 159 | anisotropicTextures: 2 160 | antiAliasing: 2 161 | softParticles: 1 162 | softVegetation: 1 163 | realtimeReflectionProbes: 1 164 | billboardsFaceCameraPosition: 1 165 | vSyncCount: 1 166 | lodBias: 1.5 167 | maximumLODLevel: 0 168 | streamingMipmapsActive: 0 169 | streamingMipmapsAddAllCameras: 1 170 | streamingMipmapsMemoryBudget: 512 171 | streamingMipmapsRenderersPerFrame: 512 172 | streamingMipmapsMaxLevelReduction: 2 173 | streamingMipmapsMaxFileIORequests: 1024 174 | particleRaycastBudget: 1024 175 | asyncUploadTimeSlice: 2 176 | asyncUploadBufferSize: 4 177 | resolutionScalingFixedDPIFactor: 1 178 | excludedTargetPlatforms: [] 179 | - serializedVersion: 2 180 | name: Ultra 181 | pixelLightCount: 4 182 | shadows: 2 183 | shadowResolution: 2 184 | shadowProjection: 1 185 | shadowCascades: 4 186 | shadowDistance: 150 187 | shadowNearPlaneOffset: 3 188 | shadowCascade2Split: 0.33333334 189 | shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} 190 | shadowmaskMode: 1 191 | blendWeights: 4 192 | textureQuality: 0 193 | anisotropicTextures: 2 194 | antiAliasing: 2 195 | softParticles: 1 196 | softVegetation: 1 197 | realtimeReflectionProbes: 1 198 | billboardsFaceCameraPosition: 1 199 | vSyncCount: 1 200 | lodBias: 2 201 | maximumLODLevel: 0 202 | streamingMipmapsActive: 0 203 | streamingMipmapsAddAllCameras: 1 204 | streamingMipmapsMemoryBudget: 512 205 | streamingMipmapsRenderersPerFrame: 512 206 | streamingMipmapsMaxLevelReduction: 2 207 | streamingMipmapsMaxFileIORequests: 1024 208 | particleRaycastBudget: 4096 209 | asyncUploadTimeSlice: 2 210 | asyncUploadBufferSize: 4 211 | resolutionScalingFixedDPIFactor: 1 212 | excludedTargetPlatforms: [] 213 | m_PerPlatformDefaultQuality: 214 | Android: 2 215 | Nintendo 3DS: 5 216 | Nintendo Switch: 5 217 | PS4: 5 218 | PSP2: 2 219 | Standalone: 5 220 | WebGL: 3 221 | Windows Store Apps: 5 222 | XboxOne: 5 223 | iPhone: 2 224 | tvOS: 2 225 | -------------------------------------------------------------------------------- /ProjectSettings/TagManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!78 &1 4 | TagManager: 5 | serializedVersion: 2 6 | tags: [] 7 | layers: 8 | - Default 9 | - TransparentFX 10 | - Ignore Raycast 11 | - 12 | - Water 13 | - UI 14 | - 15 | - 16 | - 17 | - 18 | - 19 | - 20 | - 21 | - 22 | - 23 | - 24 | - 25 | - 26 | - 27 | - 28 | - 29 | - 30 | - 31 | - 32 | - 33 | - 34 | - 35 | - 36 | - 37 | - 38 | - 39 | - 40 | m_SortingLayers: 41 | - name: Default 42 | uniqueID: 0 43 | locked: 0 44 | -------------------------------------------------------------------------------- /ProjectSettings/TimeManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!5 &1 4 | TimeManager: 5 | m_ObjectHideFlags: 0 6 | Fixed Timestep: 0.02 7 | Maximum Allowed Timestep: 0.33333334 8 | m_TimeScale: 1 9 | Maximum Particle Timestep: 0.03 10 | -------------------------------------------------------------------------------- /ProjectSettings/UnityConnectSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!310 &1 4 | UnityConnectSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 1 7 | m_Enabled: 0 8 | m_TestMode: 0 9 | m_EventOldUrl: https://api.uca.cloud.unity3d.com/v1/events 10 | m_EventUrl: https://cdp.cloud.unity3d.com/v1/events 11 | m_ConfigUrl: https://config.uca.cloud.unity3d.com 12 | m_TestInitMode: 0 13 | CrashReportingSettings: 14 | m_EventUrl: https://perf-events.cloud.unity3d.com 15 | m_Enabled: 0 16 | m_LogBufferSize: 10 17 | m_CaptureEditorExceptions: 1 18 | UnityPurchasingSettings: 19 | m_Enabled: 0 20 | m_TestMode: 0 21 | UnityAnalyticsSettings: 22 | m_Enabled: 0 23 | m_TestMode: 0 24 | m_InitializeOnStartup: 1 25 | UnityAdsSettings: 26 | m_Enabled: 0 27 | m_InitializeOnStartup: 1 28 | m_TestMode: 0 29 | m_IosGameId: 30 | m_AndroidGameId: 31 | m_GameIds: {} 32 | m_GameId: 33 | PerformanceReportingSettings: 34 | m_Enabled: 0 35 | -------------------------------------------------------------------------------- /ProjectSettings/VFXManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!937362698 &1 4 | VFXManager: 5 | m_ObjectHideFlags: 0 6 | m_IndirectShader: {fileID: 0} 7 | m_CopyBufferShader: {fileID: 0} 8 | m_SortShader: {fileID: 0} 9 | m_RenderPipeSettingsPath: 10 | m_FixedTimeStep: 0.016666668 11 | m_MaxDeltaTime: 0.05 12 | -------------------------------------------------------------------------------- /ProjectSettings/XRSettings.asset: -------------------------------------------------------------------------------- 1 | { 2 | "m_SettingKeys": [ 3 | "VR Device Disabled", 4 | "VR Device User Alert" 5 | ], 6 | "m_SettingValues": [ 7 | "False", 8 | "False" 9 | ] 10 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # VJson 🍣 2 | 3 | > A JSON serializer/deserializer (with JsonSchema support) library written in pure C#. 4 | 5 | [![ci](https://github.com/yutopp/VJson/actions/workflows/ci.yml/badge.svg)](https://github.com/yutopp/VJson/actions/workflows/ci.yml) 6 | [![npm](https://img.shields.io/npm/v/net.yutopp.vjson)](https://www.npmjs.com/package/net.yutopp.vjson) 7 | [![NuGet Badge](https://buildstats.info/nuget/vjson)](https://www.nuget.org/packages/VJson/) 8 | [![codecov](https://codecov.io/gh/yutopp/VJson/branch/master/graph/badge.svg)](https://codecov.io/gh/yutopp/VJson) 9 | [![license](https://img.shields.io/github/license/yutopp/VJson.svg)](https://github.com/yutopp/VJson/blob/master/LICENSE_1_0.txt) 10 | 11 | `VJson` is a JSON serializer/deserializer (with JsonSchema support) library written in pure C#. Supported versions are `.NET Standard 2.0` or higher. 12 | This library is developed as a purely C# project, however it also supports that be build with `Unity 2019.4.22f1` or higher. 13 | 14 | ## Installation 15 | 16 | ### For standard C# projects 17 | 18 | You can use [Nuget/VJson](https://www.nuget.org/packages/VJson/). 19 | 20 | ```bash 21 | dotnet add package VJson 22 | ``` 23 | 24 | ### For Unity projects 25 | 26 | #### stable 27 | 28 | Add scoped registry information shown below to your `Packages/manifest.json` if not exists. 29 | 30 | ```json 31 | { 32 | "scopedRegistries": [ 33 | { 34 | "name": "yutopp.net", 35 | "url": "https://registry.npmjs.com", 36 | "scopes": [ 37 | "net.yutopp" 38 | ] 39 | } 40 | ] 41 | } 42 | ``` 43 | 44 | And add `net.yutopp.vjson` to your `Packages/manifest.json` like below. 45 | 46 | ```json 47 | { 48 | "dependencies": { 49 | "net.yutopp.vjson": "*" 50 | } 51 | } 52 | ``` 53 | 54 | #### nightly 55 | 56 | Add a url for VJson git repository to your `Packages/manifest.json` like below. 57 | 58 | ```json 59 | { 60 | "dependencies": { 61 | "net.yutopp.vjson": "https://github.com/yutopp/VJson.git?path=Packages/net.yutopp.vjson" 62 | } 63 | } 64 | ``` 65 | 66 | (TODO: Provide unity packages) 67 | 68 | ## Usage example 69 | 70 | ### Serialize/Deserialize 71 | 72 | ```csharp 73 | // 74 | // For serialization 75 | // 76 | var serializer = new VJson.JsonSerializer(typeof(int)); 77 | 78 | // You can get JSON strings, 79 | var json = serializer.Serialize(42); 80 | 81 | // OR write json data(UTF-8) to streams directly. 82 | using (var s = new MemoryStream()) 83 | { 84 | serializer.Serialize(s, 42); 85 | } 86 | ``` 87 | 88 | ```csharp 89 | // 90 | // For deserialization 91 | // 92 | var serializer = new VJson.JsonSerializer(typeof(int)); 93 | 94 | // You can get Object from strings, 95 | var value = serializer.Deserialize(json); 96 | 97 | // OR read json data(UTF-8) from streams directly. 98 | using (var s = new MemoryStream(Encoding.UTF8.GetBytes(json))) 99 | { 100 | var value = serializer.Deserialize(s); 101 | } 102 | ``` 103 | 104 | `VJson` supports serializing/deserializing of some `System.Collections(.Generics)` classes listed below, 105 | 106 | - List 107 | - Dictionary 108 | - Array 109 | 110 | and user defined classes. For user defined classes, converting only all public fields are supported. 111 | 112 | e.g. 113 | 114 | (It is strongly recommended to always add VJson attributes such as [JsonField] to fields that you want to treat as Json. This will avoid problems with IL2CPP, especially when using Unity.) 115 | 116 | ```csharp 117 | class SomeObject 118 | { 119 | private float _p = 3.14f; // Fields which are non-public will not be exported by default. 120 | [JsonField] long _p2 = 4; // Fields which are non-public BUT having [JsonField] (+etc) attributes will BE exported! 121 | public int X; // Fields which are public will be exported by default, but we strongly recommended to add [JsonField] attributes like below. 122 | [JsonField] public string Y; 123 | } 124 | 125 | var obj = new SomeObject { 126 | X = 10, 127 | Y = "abab", 128 | }, 129 | 130 | var serializer = new VJson.JsonSerializer(typeof(SomeObject)); 131 | var json = serializer.Serialize(obj); 132 | // > {"_p2": 4,"X":10,"Y":"abab"} 133 | 134 | var v = serializer.Deserialize("{\"X\":10,\"Y\":\"abab\"}"); 135 | // > v becomes same as obj. 136 | ``` 137 | 138 | #### Attributes 139 | 140 | ... 141 | 142 | ### JSON Schema and validation 143 | 144 | `VJson` supports JSON Schema draft7. 145 | 146 | (TODO: Write examples) 147 | 148 | #### Attributes 149 | 150 | (TODO: Write examples) 151 | 152 | Other use cases are available at [here](https://github.com/yutopp/VJson/tree/master/Assets/VJson/Editor/Tests). 153 | 154 | ## Tasks 155 | 156 | - [ ] Performance tuning 157 | 158 | ## License 159 | 160 | [Boost Software License - Version 1.0](./LICENSE_1_0.txt) 161 | 162 | ## References 163 | 164 | - [JSON](https://www.json.org/) 165 | - [JSON Schema Specification](https://json-schema.org/specification.html) 166 | 167 | ## Author 168 | 169 | - [@yutopp](https://github.com/yutopp) 170 | -------------------------------------------------------------------------------- /ci/run-unity-editor-tests.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eux 4 | 5 | mkdir -p test-results/unity-editor 6 | mkdir -p test-results/unity-playmode 7 | 8 | function on_exit { 9 | if [ -v HAS_XSLTPROC ]; then 10 | if [ -e test-results/unity-editor/results.xml ]; then 11 | xsltproc --noout --output test-results/unity-editor/results.junit.xml \ 12 | nunit-transforms/nunit3-junit/nunit3-junit.xslt \ 13 | test-results/unity-editor/results.xml 14 | fi 15 | fi 16 | } 17 | trap on_exit EXIT 18 | 19 | # Editor test 20 | xvfb-run --auto-servernum --server-args='-screen 0 640x480x24' \ 21 | /usr/bin/unity-editor -projectPath "$(pwd)" \ 22 | -runEditorTests \ 23 | -logFile \ 24 | -batchmode \ 25 | -nographics \ 26 | -noUpm \ 27 | -testResults $(pwd)/test-results/unity-editor/results.xml 28 | 29 | # Play mode test 30 | xvfb-run --auto-servernum --server-args='-screen 0 640x480x24' \ 31 | /usr/bin/unity-editor -projectPath "$(pwd)" \ 32 | -batchmode \ 33 | -nographics -noUpm \ 34 | -runTests -testPlatform playmode \ 35 | -logFile \ 36 | -testResults "$(pwd)/test-results/unity-playmode/results.xml" 37 | -------------------------------------------------------------------------------- /pre-process/TypeHelper.g.template.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2019- yutopp (yutopp@gmail.com) 3 | // 4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | // file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | 8 | // THIS FILE IS AUTOMATICALLY GENERATED from TypeHelper.g.template.cs 9 | 10 | using System; 11 | using System.Collections.Generic; 12 | 13 | namespace VJson 14 | { 15 | static partial class TypeHelper 16 | { 17 | $body 18 | public delegate bool Converter(object input, out object output); 19 | 20 | public static bool GetConverter(Type fromTy, Type toTy, out Converter converter) 21 | { 22 | Dictionary conv; 23 | if (!_convTable.TryGetValue(fromTy, out conv)) 24 | { 25 | converter = null; 26 | return false; 27 | } 28 | 29 | return conv.TryGetValue(toTy, out converter); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /pre-process/generator.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import textwrap 3 | from string import Template 4 | 5 | def is_convertible(from_kind_tup, to_kind_tup): 6 | (from_kind, _) = from_kind_tup 7 | (to_kind, _) = to_kind_tup 8 | 9 | if from_kind == to_kind: 10 | return True 11 | 12 | if from_kind == "integer" and to_kind == "number": 13 | return True 14 | 15 | return False 16 | 17 | def is_signed_to_unsigned(from_kind_tup, to_kind_tup): 18 | (_, from_signed) = from_kind_tup 19 | (_, to_signed) = to_kind_tup 20 | 21 | if from_signed == "s" and to_signed == "u": 22 | return True 23 | 24 | return False 25 | 26 | def mk_indent(num): 27 | return ' ' * (4 * num) 28 | 29 | def main(args): 30 | template_path = args[1] 31 | 32 | # https://docs.microsoft.com/ja-jp/dotnet/csharp/language-reference/keywords/built-in-types-table 33 | types = [ 34 | "bool", 35 | "byte", 36 | "sbyte", 37 | "char", 38 | "decimal", 39 | "double", 40 | "float", 41 | "int", 42 | "uint", 43 | "long", 44 | "ulong", 45 | "short", 46 | "ushort", 47 | "string", 48 | ] 49 | kinds = { 50 | "bool": ("bool", "_"), 51 | "byte": ("integer", "u"), 52 | "sbyte": ("integer", "s"), 53 | "char": ("integer", "u"), 54 | "decimal": ("number", "_"), 55 | "double": ("number", "_"), 56 | "float": ("number", "_"), 57 | "int": ("integer", "s"), 58 | "uint": ("integer", "u"), 59 | "long": ("integer", "s"), 60 | "ulong": ("integer", "u"), 61 | "short": ("integer", "s"), 62 | "ushort": ("integer", "u"), 63 | "string": ("string", "_"), 64 | } 65 | 66 | from_types = ["bool", "long", "double", "string"] 67 | 68 | # Generate convertion tables 69 | # FromType -> (ToType -> ConversionFunction) 70 | output_tables = "" 71 | output_tables += textwrap.indent(""" 72 | private static readonly Dictionary> _convTable = 73 | new Dictionary> 74 | { 75 | """.lstrip(), mk_indent(2)) 76 | 77 | for from_ty in types: 78 | if from_ty not in from_types: 79 | continue 80 | 81 | output_tables += textwrap.indent(""" 82 | {{ 83 | typeof({0}), new Dictionary 84 | {{ 85 | """.format(from_ty).lstrip(), mk_indent(4)) 86 | 87 | for to_ty in types: 88 | if not is_convertible(kinds[from_ty], kinds[to_ty]): 89 | continue 90 | 91 | if from_ty != to_ty: 92 | output_tables += textwrap.indent(""" 93 | {{ typeof({1}), (object i, out object o) => ConvertFrom{2}To{3}(({0})i, out o) }}, 94 | """.format(from_ty, to_ty, from_ty.capitalize(), to_ty.capitalize()).lstrip(), mk_indent(6)) 95 | else: 96 | output_tables += textwrap.indent(""" 97 | {{ typeof({1}), null }}, 98 | """.format(from_ty, to_ty, from_ty.capitalize(), to_ty.capitalize()).lstrip(), mk_indent(6)) 99 | # print(from_ty, to_ty, is_convertible(kinds[from_ty], kinds[to_ty])) 100 | 101 | output_tables += textwrap.indent(""" 102 | } 103 | }, 104 | """.lstrip('\n'), mk_indent(4)) 105 | 106 | output_tables += textwrap.indent(""" 107 | }; 108 | """.lstrip(), mk_indent(3)) 109 | 110 | # Generate conversion functions 111 | output_funcs = "" 112 | for from_ty in types: 113 | if from_ty not in from_types: 114 | continue 115 | 116 | for to_ty in types: 117 | if not is_convertible(kinds[from_ty], kinds[to_ty]): 118 | continue 119 | 120 | if from_ty == to_ty: 121 | continue 122 | 123 | need_signed_check = is_signed_to_unsigned(kinds[from_ty], kinds[to_ty]) 124 | 125 | output_funcs += textwrap.indent(""" 126 | private static bool ConvertFrom{2}To{3}({0} i, out object o) {{ 127 | try 128 | {{""".format(from_ty, to_ty, from_ty.capitalize(), to_ty.capitalize()), mk_indent(2)) 129 | 130 | if need_signed_check: 131 | output_funcs += textwrap.indent(""" 132 | if ( i < 0 ) 133 | {{ 134 | throw new OverflowException(); 135 | }}""".format(), mk_indent(2)) 136 | 137 | output_funcs += textwrap.indent(""" 138 | o = checked(({1})i); 139 | return true; 140 | }} 141 | catch(OverflowException) 142 | {{ 143 | o = null; 144 | return false; 145 | }} 146 | }} 147 | """.format(from_ty, to_ty, from_ty.capitalize(), to_ty.capitalize()), mk_indent(2)) 148 | 149 | tmpl = Template(open(template_path).read()) 150 | output = tmpl.substitute(body = output_tables + output_funcs) 151 | 152 | print(output) 153 | 154 | if __name__ == "__main__": 155 | main(sys.argv) 156 | -------------------------------------------------------------------------------- /standalone-project/.gitignore: -------------------------------------------------------------------------------- 1 | !**/*.csproj 2 | !**/*.sln -------------------------------------------------------------------------------- /standalone-project/Benchmarks/Benchmarks.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0;net5.0 5 | Exe 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /standalone-project/Benchmarks/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Text; 4 | using VJson; 5 | using BenchmarkDotNet.Attributes; 6 | using BenchmarkDotNet.Running; 7 | 8 | namespace Benchmarks 9 | { 10 | public class Deserializer 11 | { 12 | private readonly byte[] i = Encoding.UTF8.GetBytes("255"); 13 | 14 | [Benchmark] 15 | public object IntegerToByte() { 16 | using(var ms = new MemoryStream(i)) 17 | { 18 | var d = new JsonDeserializer(typeof(byte)); 19 | return d.Deserialize(ms); 20 | } 21 | } 22 | 23 | [Benchmark] 24 | public object IntegerToLong() { 25 | using(var ms = new MemoryStream(i)) 26 | { 27 | var d = new JsonDeserializer(typeof(long)); 28 | return d.Deserialize(ms); 29 | } 30 | } 31 | } 32 | 33 | public class Program 34 | { 35 | public static void Main(string[] args) 36 | { 37 | var summary = BenchmarkRunner.Run(); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /standalone-project/Tests/Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0;net5.0 5 | 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | all 15 | runtime; build; native; contentfiles; analyzers; buildtransitive 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | VJSON_FULL_TESTS 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /standalone-project/VJson.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26124.0 5 | MinimumVisualStudioVersion = 15.0.26124.0 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VJson", "VJson\VJson.csproj", "{63EFA01F-793A-486D-A65F-39029DF64C6F}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj", "{A500B2F2-CF5C-4E8A-B52B-05ACCD6BCDB6}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Benchmarks", "Benchmarks\Benchmarks.csproj", "{63222FEC-933E-4219-A3F4-246FD2AD024F}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Debug|x64 = Debug|x64 16 | Debug|x86 = Debug|x86 17 | Release|Any CPU = Release|Any CPU 18 | Release|x64 = Release|x64 19 | Release|x86 = Release|x86 20 | EndGlobalSection 21 | GlobalSection(SolutionProperties) = preSolution 22 | HideSolutionNode = FALSE 23 | EndGlobalSection 24 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 25 | {A500B2F2-CF5C-4E8A-B52B-05ACCD6BCDB6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 26 | {A500B2F2-CF5C-4E8A-B52B-05ACCD6BCDB6}.Debug|Any CPU.Build.0 = Debug|Any CPU 27 | {A500B2F2-CF5C-4E8A-B52B-05ACCD6BCDB6}.Debug|x64.ActiveCfg = Debug|Any CPU 28 | {A500B2F2-CF5C-4E8A-B52B-05ACCD6BCDB6}.Debug|x64.Build.0 = Debug|Any CPU 29 | {A500B2F2-CF5C-4E8A-B52B-05ACCD6BCDB6}.Debug|x86.ActiveCfg = Debug|Any CPU 30 | {A500B2F2-CF5C-4E8A-B52B-05ACCD6BCDB6}.Debug|x86.Build.0 = Debug|Any CPU 31 | {A500B2F2-CF5C-4E8A-B52B-05ACCD6BCDB6}.Release|Any CPU.ActiveCfg = Release|Any CPU 32 | {A500B2F2-CF5C-4E8A-B52B-05ACCD6BCDB6}.Release|Any CPU.Build.0 = Release|Any CPU 33 | {A500B2F2-CF5C-4E8A-B52B-05ACCD6BCDB6}.Release|x64.ActiveCfg = Release|Any CPU 34 | {A500B2F2-CF5C-4E8A-B52B-05ACCD6BCDB6}.Release|x64.Build.0 = Release|Any CPU 35 | {A500B2F2-CF5C-4E8A-B52B-05ACCD6BCDB6}.Release|x86.ActiveCfg = Release|Any CPU 36 | {A500B2F2-CF5C-4E8A-B52B-05ACCD6BCDB6}.Release|x86.Build.0 = Release|Any CPU 37 | {63EFA01F-793A-486D-A65F-39029DF64C6F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 38 | {63EFA01F-793A-486D-A65F-39029DF64C6F}.Debug|Any CPU.Build.0 = Debug|Any CPU 39 | {63EFA01F-793A-486D-A65F-39029DF64C6F}.Debug|x64.ActiveCfg = Debug|Any CPU 40 | {63EFA01F-793A-486D-A65F-39029DF64C6F}.Debug|x64.Build.0 = Debug|Any CPU 41 | {63EFA01F-793A-486D-A65F-39029DF64C6F}.Debug|x86.ActiveCfg = Debug|Any CPU 42 | {63EFA01F-793A-486D-A65F-39029DF64C6F}.Debug|x86.Build.0 = Debug|Any CPU 43 | {63EFA01F-793A-486D-A65F-39029DF64C6F}.Release|Any CPU.ActiveCfg = Release|Any CPU 44 | {63EFA01F-793A-486D-A65F-39029DF64C6F}.Release|Any CPU.Build.0 = Release|Any CPU 45 | {63EFA01F-793A-486D-A65F-39029DF64C6F}.Release|x64.ActiveCfg = Release|Any CPU 46 | {63EFA01F-793A-486D-A65F-39029DF64C6F}.Release|x64.Build.0 = Release|Any CPU 47 | {63EFA01F-793A-486D-A65F-39029DF64C6F}.Release|x86.ActiveCfg = Release|Any CPU 48 | {63EFA01F-793A-486D-A65F-39029DF64C6F}.Release|x86.Build.0 = Release|Any CPU 49 | {63222FEC-933E-4219-A3F4-246FD2AD024F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 50 | {63222FEC-933E-4219-A3F4-246FD2AD024F}.Debug|Any CPU.Build.0 = Debug|Any CPU 51 | {63222FEC-933E-4219-A3F4-246FD2AD024F}.Debug|x64.ActiveCfg = Debug|Any CPU 52 | {63222FEC-933E-4219-A3F4-246FD2AD024F}.Debug|x64.Build.0 = Debug|Any CPU 53 | {63222FEC-933E-4219-A3F4-246FD2AD024F}.Debug|x86.ActiveCfg = Debug|Any CPU 54 | {63222FEC-933E-4219-A3F4-246FD2AD024F}.Debug|x86.Build.0 = Debug|Any CPU 55 | {63222FEC-933E-4219-A3F4-246FD2AD024F}.Release|Any CPU.ActiveCfg = Release|Any CPU 56 | {63222FEC-933E-4219-A3F4-246FD2AD024F}.Release|Any CPU.Build.0 = Release|Any CPU 57 | {63222FEC-933E-4219-A3F4-246FD2AD024F}.Release|x64.ActiveCfg = Release|Any CPU 58 | {63222FEC-933E-4219-A3F4-246FD2AD024F}.Release|x64.Build.0 = Release|Any CPU 59 | {63222FEC-933E-4219-A3F4-246FD2AD024F}.Release|x86.ActiveCfg = Release|Any CPU 60 | {63222FEC-933E-4219-A3F4-246FD2AD024F}.Release|x86.Build.0 = Release|Any CPU 61 | EndGlobalSection 62 | EndGlobal 63 | -------------------------------------------------------------------------------- /standalone-project/VJson/VJson.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 7.3 6 | 7 | VJson 8 | 0.0.0 9 | yutopp 10 | 11 | https://github.com/yutopp/VJson/blob/master/LICENSE_1_0.txt 12 | https://github.com/yutopp/VJson/ 13 | csharp;json;json-schema;serialization;unity 14 | 15 | A JSON serializer/deserializer library written in pure C#. 16 | Copyright 2019 - 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | --------------------------------------------------------------------------------