├── .circleci └── config.yml ├── .clang-format ├── .codecov.yml ├── .github └── FUNDING.yml ├── .gitignore ├── CHANGELOG.md ├── CMakeLists.txt ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── appveyor.yml ├── doc ├── icon.png └── icon.svg ├── examples ├── cpphttplibconnector.hpp ├── inmemoryconnector.hpp └── warehouse │ ├── main.cpp │ ├── types.h │ ├── warehouseapp.cpp │ └── warehouseapp.hpp ├── include └── jsonrpccxx │ ├── batchclient.hpp │ ├── client.hpp │ ├── common.hpp │ ├── dispatcher.hpp │ ├── iclientconnector.hpp │ ├── server.hpp │ └── typemapper.hpp ├── test ├── batchclient.cpp ├── client.cpp ├── common.cpp ├── dispatcher.cpp ├── integrationtest.hpp ├── main.cpp ├── server.cpp ├── testclientconnector.hpp ├── testserverconnector.hpp ├── typemapper.cpp └── warehouseapp.cpp └── vendor ├── cpp-httplib ├── LICENSE └── httplib.h ├── doctest └── doctest.h └── nlohmann ├── adl_serializer.hpp ├── byte_container_with_subtype.hpp ├── detail ├── conversions │ ├── from_json.hpp │ ├── to_chars.hpp │ └── to_json.hpp ├── exceptions.hpp ├── hash.hpp ├── input │ ├── binary_reader.hpp │ ├── input_adapters.hpp │ ├── json_sax.hpp │ ├── lexer.hpp │ ├── parser.hpp │ └── position_t.hpp ├── iterators │ ├── internal_iterator.hpp │ ├── iter_impl.hpp │ ├── iteration_proxy.hpp │ ├── iterator_traits.hpp │ ├── json_reverse_iterator.hpp │ └── primitive_iterator.hpp ├── json_pointer.hpp ├── json_ref.hpp ├── macro_scope.hpp ├── macro_unscope.hpp ├── meta │ ├── call_std │ │ ├── begin.hpp │ │ └── end.hpp │ ├── cpp_future.hpp │ ├── detected.hpp │ ├── identity_tag.hpp │ ├── is_sax.hpp │ ├── type_traits.hpp │ └── void_t.hpp ├── output │ ├── binary_writer.hpp │ ├── output_adapters.hpp │ └── serializer.hpp ├── string_escape.hpp └── value_t.hpp ├── json.hpp ├── json_fwd.hpp ├── ordered_map.hpp └── thirdparty └── hedley ├── hedley.hpp └── hedley_undef.hpp /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2.1 2 | orbs: 3 | codecov: codecov/codecov@1.0.2 4 | jobs: 5 | "build-linux-gcc": 6 | docker: 7 | - image: "debian:buster" 8 | parallelism: 2 9 | steps: 10 | - checkout 11 | - run: 12 | name: Installing GCC and CMake 13 | command: 'apt-get update && apt-get install -y gcc g++ cmake lcov curl' 14 | - run: 15 | name: Build 16 | command: cmake -DCOMPILE_TESTS=ON -DCOMPILE_EXAMPLES=ON -DCODE_COVERAGE=ON . && cmake --build . 17 | - run: 18 | name: Run tests 19 | command: ./jsonrpccpp-test -s 20 | - run: 21 | name: Create coverage report 22 | command: lcov --directory . --capture --output-file coverage.info && lcov --remove coverage.info '/usr/*' --output-file coverage.info 23 | - codecov/upload: 24 | file: coverage.info 25 | - run: 26 | name: Run example 27 | command: ./example-warehouse 28 | "build-linux-clang": 29 | docker: 30 | - image: "debian:buster" 31 | parallelism: 2 32 | steps: 33 | - checkout 34 | - run: 35 | name: Installing GCC and CMake 36 | command: 'apt-get update && apt-get install -y clang cmake' 37 | - run: 38 | name: Build 39 | command: cmake -DCOMPILE_TESTS=ON -DCOMPILE_EXAMPLES=ON . && cmake --build . 40 | - run: 41 | name: Run tests 42 | command: ./jsonrpccpp-test -s 43 | - run: 44 | name: Run example 45 | command: ./example-warehouse 46 | "build-osx-clang": 47 | macos: 48 | xcode: "14.1.0" 49 | steps: 50 | - checkout 51 | - run: 52 | name: Installing CMake 53 | command: 'brew install cmake' 54 | - run: 55 | name: Build 56 | command: cmake -DCOMPILE_TESTS=ON -DCOMPILE_EXAMPLES=ON . && cmake --build . 57 | - run: 58 | name: Run tests 59 | command: ./jsonrpccpp-test -s 60 | - run: 61 | name: Run example 62 | command: ./example-warehouse 63 | workflows: 64 | version: 2 65 | build: 66 | jobs: 67 | - "build-linux-gcc" 68 | - "build-linux-clang" 69 | - "build-osx-clang" 70 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | Language: Cpp 2 | # BasedOnStyle: LLVM 3 | AccessModifierOffset: -2 4 | AlignAfterOpenBracket: Align 5 | AlignConsecutiveAssignments: false 6 | AlignConsecutiveDeclarations: false 7 | AlignEscapedNewlines: Right 8 | AlignOperands: true 9 | AlignTrailingComments: true 10 | AllowAllParametersOfDeclarationOnNextLine: true 11 | AllowShortBlocksOnASingleLine: false 12 | AllowShortCaseLabelsOnASingleLine: false 13 | AllowShortFunctionsOnASingleLine: All 14 | AllowShortIfStatementsOnASingleLine: false 15 | AllowShortLoopsOnASingleLine: false 16 | AlwaysBreakAfterDefinitionReturnType: None 17 | AlwaysBreakAfterReturnType: None 18 | AlwaysBreakBeforeMultilineStrings: false 19 | AlwaysBreakTemplateDeclarations: Yes 20 | BinPackArguments: true 21 | BinPackParameters: true 22 | BraceWrapping: 23 | AfterClass: false 24 | AfterControlStatement: false 25 | AfterEnum: false 26 | AfterFunction: false 27 | AfterNamespace: false 28 | AfterObjCDeclaration: false 29 | AfterStruct: false 30 | AfterUnion: false 31 | AfterExternBlock: false 32 | BeforeCatch: false 33 | BeforeElse: false 34 | IndentBraces: false 35 | SplitEmptyFunction: true 36 | SplitEmptyRecord: true 37 | SplitEmptyNamespace: true 38 | BreakBeforeBinaryOperators: None 39 | BreakBeforeBraces: Attach 40 | BreakBeforeInheritanceComma: false 41 | BreakInheritanceList: BeforeColon 42 | BreakBeforeTernaryOperators: true 43 | BreakConstructorInitializersBeforeComma: false 44 | BreakConstructorInitializers: BeforeColon 45 | BreakAfterJavaFieldAnnotations: false 46 | BreakStringLiterals: true 47 | ColumnLimit: 160 48 | CommentPragmas: '^ IWYU pragma:' 49 | CompactNamespaces: false 50 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 51 | ConstructorInitializerIndentWidth: 4 52 | ContinuationIndentWidth: 4 53 | Cpp11BracedListStyle: true 54 | DerivePointerAlignment: false 55 | DisableFormat: false 56 | ExperimentalAutoDetectBinPacking: false 57 | FixNamespaceComments: true 58 | ForEachMacros: 59 | - foreach 60 | - Q_FOREACH 61 | - BOOST_FOREACH 62 | IncludeBlocks: Preserve 63 | IncludeCategories: 64 | - Regex: '^"(llvm|llvm-c|clang|clang-c)/' 65 | Priority: 2 66 | - Regex: '^(<|"(gtest|gmock|isl|json)/)' 67 | Priority: 3 68 | - Regex: '.*' 69 | Priority: 1 70 | IncludeIsMainRegex: '(Test)?$' 71 | IndentCaseLabels: false 72 | IndentPPDirectives: None 73 | IndentWidth: 2 74 | IndentWrappedFunctionNames: false 75 | JavaScriptQuotes: Leave 76 | JavaScriptWrapImports: true 77 | KeepEmptyLinesAtTheStartOfBlocks: true 78 | MacroBlockBegin: '' 79 | MacroBlockEnd: '' 80 | MaxEmptyLinesToKeep: 1 81 | NamespaceIndentation: All 82 | ObjCBinPackProtocolList: Auto 83 | ObjCBlockIndentWidth: 2 84 | ObjCSpaceAfterProperty: false 85 | ObjCSpaceBeforeProtocolList: true 86 | PenaltyBreakAssignment: 2 87 | PenaltyBreakBeforeFirstCallParameter: 19 88 | PenaltyBreakComment: 300 89 | PenaltyBreakFirstLessLess: 120 90 | PenaltyBreakString: 1000 91 | PenaltyBreakTemplateDeclaration: 10 92 | PenaltyExcessCharacter: 1000000 93 | PenaltyReturnTypeOnItsOwnLine: 60 94 | PointerAlignment: Right 95 | ReflowComments: true 96 | SortIncludes: true 97 | SortUsingDeclarations: true 98 | SpaceAfterCStyleCast: false 99 | SpaceAfterTemplateKeyword: true 100 | SpaceBeforeAssignmentOperators: true 101 | SpaceBeforeCpp11BracedList: false 102 | SpaceBeforeCtorInitializerColon: true 103 | SpaceBeforeInheritanceColon: true 104 | SpaceBeforeParens: ControlStatements 105 | SpaceBeforeRangeBasedForLoopColon: true 106 | SpaceInEmptyParentheses: false 107 | SpacesBeforeTrailingComments: 1 108 | SpacesInAngles: false 109 | SpacesInContainerLiterals: true 110 | SpacesInCStyleCastParentheses: false 111 | SpacesInParentheses: false 112 | SpacesInSquareBrackets: false 113 | Standard: Cpp11 114 | TabWidth: 2 115 | UseTab: Never -------------------------------------------------------------------------------- /.codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | ignore: 3 | - examples/**/* 4 | - vendor/**/* -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: cinemast 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vs/* 2 | *.vcxproj.user 3 | Debug/* 4 | ConsoleApplication1/Debug/* 5 | tests/Debug/* 6 | build/* 7 | .vscode/* 8 | build*/* 9 | cmake-build-*/* 10 | .idea/* 11 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## [0.3.2] - 2024-10-16 9 | 10 | ### Fixed 11 | - Positive numbers are not accepted in error codes (#44) 12 | - Using const member methods was not possible (#45) 13 | - `dirty_method` (#46) 14 | 15 | ## [0.3.1] - 2022-04-19 16 | ### Changed 17 | - Updated cpp-httplib to 0.10.6 18 | - Updated nlohmann/json to 3.10.5 19 | 20 | ### Fixed 21 | - Updated doctest to 2.4.8 (#31) 22 | 23 | ## [0.3.0] - 2021-03-13 24 | ### Changed 25 | - Updated cpp-httplib to v0.8.4 26 | - Migrated from Catch2 to doctest 27 | 28 | ### Added 29 | - Enum for specified JSON-RPC error codes (#17) 30 | 31 | ### Fixed 32 | - RPC methods expecting floats/doubles could be called with an integral type which would throw an exception (#18) 33 | 34 | ## [0.2.1] - 2020-10-21 35 | ### Changed 36 | - Updated Catch to version 2.13.2 37 | - Updated nlohmann_json to 3.9.1 38 | 39 | ### Fixed 40 | - Typemapper failed to convert enum parameters on top-level (#10) 41 | 42 | ## [0.2.0] - 2020-10-14 43 | 44 | ### Added 45 | - Support for `int64` (#9) 46 | - Support for registering `void` methods (#8) 47 | 48 | ### Changed 49 | - Differ between empty lists and calls with no params (#12) 50 | - Enable and fix compiler warnings (#11) 51 | 52 | ### Fixed 53 | - Remove `#include "common.h"` inside `"common.h"` 54 | - Allow strings as error object 55 | 56 | 57 | ## [0.1.0] - 2019-07-02 58 | 59 | ### Added 60 | - Initial implementation of 1.0 and 2.0 server 61 | - Initial implementation of 1.0 and 2.0 client 62 | - Test suite for server and client 63 | - Example Application with HTTP client and server connectors 64 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.12) 2 | set(CMAKE_CXX_STANDARD 17) 3 | project(json-rpc-cxx VERSION 0.0.1 LANGUAGES CXX) 4 | 5 | 6 | option(COMPILE_TESTS "Enable tests" ON) 7 | option(COMPILE_EXAMPLES "Enable examples" ON) 8 | option(CODE_COVERAGE "Enable coverage reporting" OFF) 9 | 10 | include(GNUInstallDirs) 11 | 12 | add_library(json-rpc-cxx INTERFACE) 13 | target_include_directories(json-rpc-cxx INTERFACE include) 14 | install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) 15 | 16 | add_library(coverage_config INTERFACE) 17 | 18 | # Warning options for the compiler 19 | string( 20 | APPEND _warning_opts 21 | "$<$,$,$>:-Wall;-Wextra;-Weffc++;-Werror;>" 22 | "$<$,$>:-Wthread-safety;-Wpedantic;>" 23 | "$<$:-pedantic;-pedantic-errors;>" 24 | ) 25 | 26 | 27 | if (COMPILE_TESTS) 28 | if (CODE_COVERAGE) 29 | message("Enabled coverage flags") 30 | target_compile_options(coverage_config INTERFACE -O0 -g --coverage) 31 | target_link_libraries(coverage_config INTERFACE --coverage) 32 | endif () 33 | add_executable(jsonrpccpp-test test/main.cpp test/client.cpp test/typemapper.cpp test/dispatcher.cpp test/server.cpp test/batchclient.cpp test/testclientconnector.hpp examples/warehouse/warehouseapp.cpp test/warehouseapp.cpp test/common.cpp) 34 | target_compile_options(jsonrpccpp-test PUBLIC "${_warning_opts}") 35 | target_include_directories(jsonrpccpp-test PRIVATE vendor examples) 36 | target_link_libraries(jsonrpccpp-test coverage_config json-rpc-cxx) 37 | enable_testing() 38 | add_test(NAME test COMMAND jsonrpccpp-test) 39 | endif () 40 | 41 | if (COMPILE_EXAMPLES) 42 | find_package(Threads) 43 | add_executable(example-warehouse examples/warehouse/main.cpp examples/warehouse/warehouseapp.cpp examples/warehouse/types.h examples/inmemoryconnector.hpp) 44 | target_compile_options(example-warehouse PUBLIC "${_warning_opts}") 45 | target_link_libraries(example-warehouse json-rpc-cxx Threads::Threads) 46 | target_include_directories(example-warehouse SYSTEM PRIVATE vendor) 47 | target_include_directories(example-warehouse PRIVATE examples) 48 | add_test(NAME example COMMAND example-warehouse) 49 | endif () 50 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Code style 2 | 3 | Please make sure your editor picks up the [.clang-format](.clang-format) file. 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2021 Peter Spiess-Knafl 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in the 5 | Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software is furnished to do so, 8 | subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 14 | INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 15 | PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 16 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 17 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE 18 | OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # json-rpc-cxx 2 | 3 | 4 | [![Build status](https://ci.appveyor.com/api/projects/status/c6rv869h984m1eo2?svg=true)](https://ci.appveyor.com/project/cinemast/json-rpc-cxx) 5 | [![CircleCI](https://circleci.com/gh/jsonrpcx/json-rpc-cxx.svg?style=svg)](https://circleci.com/gh/jsonrpcx/json-rpc-cxx) 6 | ![GitHub](https://img.shields.io/github/license/jsonrpcx/json-rpc-cxx.svg) 7 | [![codecov](https://codecov.io/gh/jsonrpcx/json-rpc-cxx/branch/master/graph/badge.svg)](https://codecov.io/gh/jsonrpcx/json-rpc-cxx) 8 | [![Language grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/jsonrpcx/json-rpc-cxx.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/jsonrpcx/json-rpc-cxx/context:cpp) 9 | [![Codacy Badge](https://api.codacy.com/project/badge/Grade/16b095ad49964288b524bc0b499c4efb)](https://www.codacy.com/app/cinemast/json-rpc-cxx?utm_source=github.com&utm_medium=referral&utm_content=jsonrpcx/json-rpc-cxx&utm_campaign=Badge_Grade) 10 | ![GitHub tag (latest SemVer)](https://img.shields.io/github/tag/jsonrpcx/json-rpc-cxx.svg) 11 | 12 | ![json-rpc-cxx-icon](doc/icon.png) 13 | 14 | A [JSON-RPC](https://www.jsonrpc.org/) 2.0 framework implemented in C++17 using the [nlohmann's json for modern C++](https://github.com/nlohmann/json). 15 | 16 | - JSON-RPC 2.0 compliant client 17 | - JSON-RPC 2.0 compliant server 18 | - Transport agnostic interfaces 19 | - Compile time type mapping (using [nlohmann's arbitrary type conversion](https://github.com/nlohmann/json#arbitrary-types-conversions)) 20 | - Runtime type checking 21 | - Cross-platform (Windows, Linux, OSX) 22 | 23 | ## Installation 24 | 25 | - Copy [include/jsonrpccxx](include) to your include path 26 | - Alternatively use CMake install mechanism 27 | 28 | ```bash 29 | mkdir build && cd build 30 | cmake .. 31 | sudo make install 32 | ``` 33 | 34 | ## Usage 35 | 36 | - [examples/warehouse/main.cpp](examples/warehouse/main.cpp) 37 | 38 | ## Design goals 39 | 40 | - Easy to use interface 41 | - Type safety where possible 42 | - Avoid errors at compile time where possible 43 | - Test driven development 44 | - Choose expressiveness over speed 45 | - Minimal dependencies 46 | 47 | ## License 48 | 49 | This framework is licensed under [MIT](LICENSE). 50 | 51 | ### Dependencies 52 | 53 | - [nlohmann's JSON for modern C++](https://github.com/nlohmann/json) is licensed under MIT. 54 | - Optional: [doctest](https://github.com/onqtam/doctest) is licensed under MIT. 55 | 56 | ## Developer information 57 | 58 | - [CONTRIBUTING.md](CONTRIBUTING.md) 59 | - [CHANGELOG.md](CHANGELOG.md) 60 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | os: Visual Studio 2017 2 | 3 | build_script: 4 | - call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat" 5 | - cmake --version 6 | - cmake -DCOMPILE_TESTS=ON -DCOMPILE_EXAMPLES=ON . 7 | - cmake --build . 8 | - Debug\jsonrpccpp-test.exe -s 9 | - Debug\example-warehouse.exe 10 | -------------------------------------------------------------------------------- /doc/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonrpcx/json-rpc-cxx/a0e195b575d62cb07016321ac9cd7e1b9e048fe5/doc/icon.png -------------------------------------------------------------------------------- /doc/icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | 24 | 43 | 45 | 46 | 48 | image/svg+xml 49 | 51 | 52 | 53 | 54 | 55 | 60 | { } 72 | 73 | 77 | rpccxx 93 | 94 | 98 | 99 | -------------------------------------------------------------------------------- /examples/cpphttplibconnector.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | class CppHttpLibClientConnector : public jsonrpccxx::IClientConnector { 9 | public: 10 | explicit CppHttpLibClientConnector(const std::string &host, int port) : httpClient(host.c_str(), port) {} 11 | std::string Send(const std::string &request) override { 12 | auto res = httpClient.Post("/jsonrpc", request, "application/json"); 13 | if (!res || res->status != 200) { 14 | throw jsonrpccxx::JsonRpcException(-32003, "client connector error, received status != 200"); 15 | } 16 | return res->body; 17 | } 18 | 19 | private: 20 | httplib::Client httpClient; 21 | }; 22 | 23 | class CppHttpLibServerConnector { 24 | public: 25 | explicit CppHttpLibServerConnector(jsonrpccxx::JsonRpcServer &server, int port) : 26 | thread(), 27 | server(server), 28 | httpServer(), 29 | port(port) { 30 | httpServer.Post("/jsonrpc", 31 | [this](const httplib::Request &req, httplib::Response &res) { 32 | this->PostAction(req, res); 33 | }); 34 | } 35 | 36 | virtual ~CppHttpLibServerConnector() { StopListening(); } 37 | 38 | bool StartListening() { 39 | if (httpServer.is_running()) 40 | return false; 41 | this->thread = std::thread([this]() { this->httpServer.listen("localhost", port); }); 42 | return true; 43 | } 44 | 45 | void StopListening() { 46 | if (httpServer.is_running()) { 47 | httpServer.stop(); 48 | this->thread.join(); 49 | } 50 | } 51 | 52 | private: 53 | std::thread thread; 54 | jsonrpccxx::JsonRpcServer &server; 55 | httplib::Server httpServer; 56 | int port; 57 | 58 | void PostAction(const httplib::Request &req, 59 | httplib::Response &res) { 60 | res.status = 200; 61 | res.set_content(this->server.HandleRequest(req.body), "application/json"); 62 | } 63 | }; 64 | -------------------------------------------------------------------------------- /examples/inmemoryconnector.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | //This class is server and client connector at the same time. 6 | class InMemoryConnector : public jsonrpccxx::IClientConnector { 7 | public: 8 | explicit InMemoryConnector(jsonrpccxx::JsonRpcServer &server) : server(server) {} 9 | std::string Send(const std::string &request) override { return server.HandleRequest(request); } 10 | private: 11 | jsonrpccxx::JsonRpcServer &server; 12 | }; -------------------------------------------------------------------------------- /examples/warehouse/main.cpp: -------------------------------------------------------------------------------- 1 | #include "inmemoryconnector.hpp" 2 | #include "cpphttplibconnector.hpp" 3 | #include "warehouseapp.hpp" 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace jsonrpccxx; 11 | using namespace std; 12 | 13 | class WareHouseClient { 14 | public: 15 | explicit WareHouseClient(JsonRpcClient &client) : client(client) {} 16 | bool AddProduct(const Product &p) { return client.CallMethod(1, "AddProduct", {p}); } 17 | Product GetProduct(const std::string &id) { return client.CallMethod(1, "GetProduct", {id}); } 18 | vector AllProducts() { return client.CallMethod>(1, "AllProducts", {}); } 19 | 20 | private: 21 | JsonRpcClient &client; 22 | }; 23 | 24 | void doWarehouseStuff(IClientConnector &clientConnector) { 25 | JsonRpcClient client(clientConnector, version::v2); 26 | WareHouseClient appClient(client); 27 | Product p; 28 | p.id = "0xff"; 29 | p.price = 22.4; 30 | p.name = "Product 1"; 31 | p.cat = category::cash_carry; 32 | cout << "Adding product: " << std::boolalpha << appClient.AddProduct(p) << "\n"; 33 | 34 | Product p2 = appClient.GetProduct("0xff"); 35 | cout << "Found product: " << p2.name << "\n"; 36 | try { 37 | appClient.GetProduct("0xff2"); 38 | } catch (JsonRpcException &e) { 39 | cerr << "Error finding product: " << e.what() << "\n"; 40 | } 41 | 42 | auto all = appClient.AllProducts(); 43 | for (const auto &p: all) { 44 | cout << p.name << endl; 45 | } 46 | } 47 | 48 | int main() { 49 | JsonRpc2Server rpcServer; 50 | 51 | // Bindings 52 | WarehouseServer app; 53 | rpcServer.Add("GetProduct", GetHandle(&WarehouseServer::GetProduct, app), {"id"}); 54 | rpcServer.Add("AddProduct", GetHandle(&WarehouseServer::AddProduct, app), {"product"}); 55 | rpcServer.Add("AllProducts", GetHandle(&WarehouseServer::AllProducts, app), {}); 56 | 57 | cout << "Running in-memory example" << "\n"; 58 | InMemoryConnector inMemoryConnector(rpcServer); 59 | doWarehouseStuff(inMemoryConnector); 60 | 61 | cout << "Running http example" << "\n"; 62 | CppHttpLibServerConnector httpServer(rpcServer, 8484); 63 | cout << "Starting http server: " << std::boolalpha << httpServer.StartListening() << "\n"; 64 | CppHttpLibClientConnector httpClient("localhost", 8484); 65 | std::this_thread::sleep_for(0.5s); 66 | doWarehouseStuff(httpClient); 67 | 68 | return 0; 69 | } 70 | -------------------------------------------------------------------------------- /examples/warehouse/types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | enum class category { order, cash_carry }; 5 | 6 | struct Product { 7 | public: 8 | Product() : id(), price(), name(), cat() {} 9 | std::string id; 10 | double price; 11 | std::string name; 12 | category cat; 13 | }; 14 | 15 | NLOHMANN_JSON_SERIALIZE_ENUM(category, {{category::order, "order"}, {category::cash_carry, "cc"}}) 16 | 17 | inline void to_json(nlohmann::json &j, const Product &p) { 18 | j = nlohmann::json{{"id", p.id}, 19 | {"price", p.price}, 20 | {"name", p.name}, 21 | {"category", p.cat}}; 22 | } 23 | 24 | inline void from_json(const nlohmann::json &j, Product &p) { 25 | j.at("name").get_to(p.name); 26 | j.at("id").get_to(p.id); 27 | j.at("price").get_to(p.price); 28 | j.at("category").get_to(p.cat); 29 | } 30 | -------------------------------------------------------------------------------- /examples/warehouse/warehouseapp.cpp: -------------------------------------------------------------------------------- 1 | #include "warehouseapp.hpp" 2 | #include 3 | 4 | using namespace jsonrpccxx; 5 | 6 | bool WarehouseServer::AddProduct(const Product &p) { 7 | if (products.find(p.id) != products.end()) 8 | return false; 9 | products[p.id] = p; 10 | return true; 11 | } 12 | 13 | const Product& WarehouseServer::GetProduct(const std::string &id) { 14 | if (products.find(id) == products.end()) 15 | throw JsonRpcException(-33000, "No product listed for id: " + id); 16 | return products[id]; 17 | } 18 | std::vector WarehouseServer::AllProducts() { 19 | std::vector result; 20 | for (const auto &p : products) 21 | result.push_back(p.second); 22 | return result; 23 | } 24 | -------------------------------------------------------------------------------- /examples/warehouse/warehouseapp.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include "types.h" 6 | 7 | class WarehouseServer { 8 | public: 9 | WarehouseServer() : 10 | products() {} 11 | 12 | bool AddProduct(const Product &p); 13 | const Product& GetProduct(const std::string& id); 14 | std::vector AllProducts(); 15 | 16 | private: 17 | std::map products; 18 | }; 19 | 20 | -------------------------------------------------------------------------------- /include/jsonrpccxx/batchclient.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "client.hpp" 4 | 5 | namespace jsonrpccxx { 6 | class BatchRequest { 7 | public: 8 | BatchRequest() : call(json::array()) {} 9 | BatchRequest &AddMethodCall(const id_type &id, const std::string &name, const positional_parameter ¶ms = {}) { 10 | json request = {{"method", name}, {"params", params}, {"jsonrpc", "2.0"}}; 11 | if (std::get_if(&id) != nullptr) { 12 | request["id"] = std::get(id); 13 | } else { 14 | request["id"] = std::get(id); 15 | } 16 | call.push_back(request); 17 | return *this; 18 | } 19 | 20 | BatchRequest &AddNamedMethodCall(const id_type &id, const std::string &name, const named_parameter ¶ms = {}) { 21 | json request = {{"method", name}, {"params", params}, {"jsonrpc", "2.0"}}; 22 | if (std::get_if(&id) != nullptr) { 23 | request["id"] = std::get(id); 24 | } else { 25 | request["id"] = std::get(id); 26 | } 27 | call.push_back(request); 28 | return *this; 29 | } 30 | 31 | BatchRequest &AddNotificationCall(const std::string &name, const positional_parameter ¶ms = {}) { 32 | call.push_back({{"method", name}, {"params", params}, {"jsonrpc", "2.0"}}); 33 | return *this; 34 | } 35 | 36 | BatchRequest &AddNamedNotificationCall(const std::string &name, const named_parameter ¶ms = {}) { 37 | call.push_back({{"method", name}, {"params", params}, {"jsonrpc", "2.0"}}); 38 | return *this; 39 | } 40 | 41 | const json &Build() const { return call; } 42 | 43 | private: 44 | json call; 45 | }; 46 | 47 | class BatchResponse { 48 | public: 49 | explicit BatchResponse(json &&response) : response(response), results(), errors(), nullIds() { 50 | for (auto &[key, value] : response.items()) { 51 | if (value.is_object() && valid_id_not_null(value) && has_key(value, "result")) { 52 | results[value["id"]] = std::stoi(key); 53 | } else if (value.is_object() && valid_id_not_null(value) && has_key(value, "error")) { 54 | errors[value["id"]] = std::stoi(key); 55 | } else { 56 | nullIds.push_back(std::stoi(key)); 57 | } 58 | } 59 | } 60 | 61 | template 62 | T Get(const json &id) { 63 | if (results.find(id) != results.end()) { 64 | try { 65 | return response[results[id]]["result"].get(); 66 | } catch (json::type_error &e) { 67 | throw JsonRpcException(parse_error, "invalid return type: " + std::string(e.what())); 68 | } 69 | } else if (errors.find(id) != errors.end()) { 70 | throw JsonRpcException::fromJson(response[errors[id]]["error"]); 71 | } 72 | throw JsonRpcException(parse_error, std::string("no result found for id ") + id.dump()); 73 | } 74 | 75 | bool HasErrors() { return !errors.empty() || !nullIds.empty(); } 76 | const std::vector GetInvalidIndexes() { return nullIds; } 77 | const json& GetResponse() { return response; } 78 | 79 | private: 80 | json response; 81 | std::map results; 82 | std::map errors; 83 | std::vector nullIds; 84 | }; 85 | 86 | class BatchClient : public JsonRpcClient { 87 | public: 88 | explicit BatchClient(IClientConnector &connector) : JsonRpcClient(connector, version::v2) {} 89 | BatchResponse BatchCall(const BatchRequest &request) { 90 | try { 91 | json response = json::parse(connector.Send(request.Build().dump())); 92 | if (!response.is_array()) { 93 | throw JsonRpcException(parse_error, std::string("invalid JSON response from server: expected array")); 94 | } 95 | return BatchResponse(std::move(response)); 96 | } catch (json::parse_error &e) { 97 | throw JsonRpcException(parse_error, std::string("invalid JSON response from server: ") + e.what()); 98 | } 99 | } 100 | }; 101 | } 102 | -------------------------------------------------------------------------------- /include/jsonrpccxx/client.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "common.hpp" 3 | #include "iclientconnector.hpp" 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace jsonrpccxx { 10 | enum class version { v1, v2 }; 11 | typedef std::vector positional_parameter; 12 | typedef std::map named_parameter; 13 | typedef std::variant id_type; 14 | 15 | struct JsonRpcResponse { 16 | id_type id; 17 | json result; 18 | }; 19 | 20 | class JsonRpcClient { 21 | public: 22 | JsonRpcClient(IClientConnector &connector, version v) : connector(connector), v(v) {} 23 | virtual ~JsonRpcClient() = default; 24 | 25 | template 26 | T CallMethod(const id_type &id, const std::string &name) { return call_method(id, name, json::object()).result.get(); } 27 | template 28 | T CallMethod(const id_type &id, const std::string &name, const positional_parameter ¶ms) { return call_method(id, name, params).result.get(); } 29 | template 30 | T CallMethodNamed(const id_type &id, const std::string &name, const named_parameter ¶ms = {}) { return call_method(id, name, params).result.get(); } 31 | 32 | void CallNotification(const std::string &name, const positional_parameter ¶ms = {}) { call_notification(name, params); } 33 | void CallNotificationNamed(const std::string &name, const named_parameter ¶ms = {}) { call_notification(name, params); } 34 | 35 | protected: 36 | IClientConnector &connector; 37 | 38 | private: 39 | version v; 40 | 41 | JsonRpcResponse call_method(const id_type &id, const std::string &name, const json ¶ms) { 42 | json j = {{"method", name}}; 43 | if (std::get_if(&id) != nullptr) { 44 | j["id"] = std::get(id); 45 | } else { 46 | j["id"] = std::get(id); 47 | } 48 | if (v == version::v2) { 49 | j["jsonrpc"] = "2.0"; 50 | } 51 | if (!params.empty() && !params.is_null()) { 52 | j["params"] = params; 53 | } else if (params.is_array()) { 54 | j["params"] = params; 55 | } else if (v == version::v1) { 56 | j["params"] = nullptr; 57 | } 58 | try { 59 | json response = json::parse(connector.Send(j.dump())); 60 | if (has_key_type(response, "error", json::value_t::object)) { 61 | throw JsonRpcException::fromJson(response["error"]); 62 | } else if (has_key_type(response, "error", json::value_t::string)) { 63 | throw JsonRpcException(internal_error, response["error"]); 64 | } 65 | if (has_key(response, "result") && has_key(response, "id")) { 66 | if (response["id"].type() == json::value_t::string) 67 | return JsonRpcResponse{response["id"].get(), response["result"].get()}; 68 | else 69 | return JsonRpcResponse{response["id"].get(), response["result"].get()}; 70 | } 71 | throw JsonRpcException(internal_error, R"(invalid server response: neither "result" nor "error" fields found)"); 72 | } catch (json::parse_error &e) { 73 | throw JsonRpcException(parse_error, std::string("invalid JSON response from server: ") + e.what()); 74 | } 75 | } 76 | 77 | void call_notification(const std::string &name, const nlohmann::json ¶ms) { 78 | nlohmann::json j = {{"method", name}}; 79 | if (v == version::v2) { 80 | j["jsonrpc"] = "2.0"; 81 | } else { 82 | j["id"] = nullptr; 83 | } 84 | if (!params.empty() && !params.is_null()) { 85 | j["params"] = params; 86 | } else if (v == version::v1) { 87 | j["params"] = nullptr; 88 | } 89 | connector.Send(j.dump()); 90 | } 91 | }; 92 | } // namespace jsonrpccxx 93 | -------------------------------------------------------------------------------- /include/jsonrpccxx/common.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "nlohmann/json.hpp" 3 | #include 4 | #include 5 | 6 | namespace jsonrpccxx { 7 | typedef nlohmann::json json; 8 | 9 | static inline bool has_key(const json &v, const std::string &key) { return v.find(key) != v.end(); } 10 | static inline bool has_key_type(const json &v, const std::string &key, json::value_t type) { return has_key(v, key) && v.at(key).type() == type; } 11 | static inline bool valid_id(const json &request) { 12 | return has_key(request, "id") && (request["id"].is_number() || request["id"].is_string() || request["id"].is_null()); 13 | } 14 | static inline bool valid_id_not_null(const json &request) { return has_key(request, "id") && (request["id"].is_number() || request["id"].is_string()); } 15 | 16 | enum error_type { 17 | parse_error = -32700, 18 | invalid_request = -32600, 19 | method_not_found = -32601, 20 | invalid_params = -32602, 21 | internal_error = -32603, 22 | server_error, 23 | invalid 24 | }; 25 | 26 | class JsonRpcException : public std::exception { 27 | public: 28 | JsonRpcException(int code, const std::string &message) noexcept : code(code), message(message), data(nullptr), err(std::to_string(code) + ": " + message) {} 29 | JsonRpcException(int code, const std::string &message, const json &data) noexcept 30 | : code(code), message(message), data(data), err(std::to_string(code) + ": " + message + ", data: " + data.dump()) {} 31 | 32 | error_type Type() const { 33 | if (code >= -32603 && code <= -32600) 34 | return static_cast(code); 35 | if (code >= -32099 && code <= -32000) 36 | return server_error; 37 | if (code == -32700) 38 | return parse_error; 39 | return invalid; 40 | } 41 | 42 | int Code() const { return code; } 43 | const std::string &Message() const { return message; } 44 | const json &Data() const { return data; } 45 | 46 | const char *what() const noexcept override { return err.c_str(); } 47 | 48 | static inline JsonRpcException fromJson(const json &value) { 49 | bool has_code = has_key_type(value, "code", json::value_t::number_integer) || has_key_type(value, "code", json::value_t::number_unsigned); 50 | bool has_message = has_key_type(value, "message", json::value_t::string); 51 | bool has_data = has_key(value, "data"); 52 | if (has_code && has_message) { 53 | if (has_data) { 54 | return JsonRpcException(value["code"], value["message"], value["data"].get()); 55 | } else { 56 | return JsonRpcException(value["code"], value["message"]); 57 | } 58 | } 59 | return JsonRpcException(internal_error, R"(invalid error response: "code" (integer number) and "message" (string) are required)"); 60 | } 61 | 62 | private: 63 | int code; 64 | std::string message; 65 | json data; 66 | std::string err; 67 | }; 68 | } // namespace jsonrpccxx 69 | -------------------------------------------------------------------------------- /include/jsonrpccxx/dispatcher.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "common.hpp" 4 | #include "typemapper.hpp" 5 | #include 6 | #include 7 | 8 | namespace jsonrpccxx { 9 | 10 | typedef std::vector NamedParamMapping; 11 | static NamedParamMapping NAMED_PARAM_MAPPING; 12 | 13 | class Dispatcher { 14 | public: 15 | Dispatcher() : 16 | methods(), 17 | notifications(), 18 | mapping() {} 19 | 20 | bool Add(const std::string &name, MethodHandle callback, const NamedParamMapping &mapping = NAMED_PARAM_MAPPING) { 21 | if (contains(name)) 22 | return false; 23 | methods[name] = std::move(callback); 24 | if (!mapping.empty()) { 25 | this->mapping[name] = mapping; 26 | } 27 | return true; 28 | } 29 | 30 | bool Add(const std::string &name, NotificationHandle callback, const NamedParamMapping &mapping = NAMED_PARAM_MAPPING) { 31 | if (contains(name)) 32 | return false; 33 | notifications[name] = std::move(callback); 34 | if (!mapping.empty()) { 35 | this->mapping[name] = mapping; 36 | } 37 | return true; 38 | } 39 | 40 | JsonRpcException process_type_error(const std::string &name, JsonRpcException &e) { 41 | if (e.Code() == -32602 && !e.Data().empty()) { 42 | std::string message = e.Message() + " for parameter "; 43 | if (this->mapping.find(name) != this->mapping.end()) { 44 | message += "\"" + mapping[name][e.Data().get()] + "\""; 45 | } else { 46 | message += std::to_string(e.Data().get()); 47 | } 48 | return JsonRpcException(e.Code(), message); 49 | } 50 | return e; 51 | } 52 | 53 | json InvokeMethod(const std::string &name, const json ¶ms) { 54 | auto method = methods.find(name); 55 | if (method == methods.end()) { 56 | throw JsonRpcException(method_not_found, "method not found: " + name); 57 | } 58 | try { 59 | return method->second(normalize_parameter(name, params)); 60 | } catch (json::type_error &e) { 61 | throw JsonRpcException(invalid_params, "invalid parameter: " + std::string(e.what())); 62 | } catch (JsonRpcException &e) { 63 | throw process_type_error(name, e); 64 | } 65 | } 66 | 67 | void InvokeNotification(const std::string &name, const json ¶ms) { 68 | auto notification = notifications.find(name); 69 | if (notification == notifications.end()) { 70 | throw JsonRpcException(method_not_found, "notification not found: " + name); 71 | } 72 | try { 73 | notification->second(normalize_parameter(name, params)); 74 | } catch (json::type_error &e) { 75 | throw JsonRpcException(invalid_params, "invalid parameter: " + std::string(e.what())); 76 | } catch (JsonRpcException &e) { 77 | throw process_type_error(name, e); 78 | } 79 | } 80 | 81 | private: 82 | std::map methods; 83 | std::map notifications; 84 | std::map mapping; 85 | 86 | inline bool contains(const std::string &name) { return (methods.find(name) != methods.end() || notifications.find(name) != notifications.end()); } 87 | inline json normalize_parameter(const std::string &name, const json ¶ms) { 88 | if (params.type() == json::value_t::array) { 89 | return params; 90 | } else if (params.type() == json::value_t::object) { 91 | if (mapping.find(name) == mapping.end()) { 92 | throw JsonRpcException(invalid_params, "invalid parameter: procedure doesn't support named parameter"); 93 | } 94 | json result; 95 | for (auto const &p : mapping[name]) { 96 | if (params.find(p) == params.end()) { 97 | throw JsonRpcException(invalid_params, "invalid parameter: missing named parameter \"" + p + "\""); 98 | } 99 | result.push_back(params[p]); 100 | } 101 | return result; 102 | } 103 | throw JsonRpcException(invalid_request, "invalid request: params field must be an array, object"); 104 | } 105 | }; 106 | } // namespace jsonrpccxx 107 | -------------------------------------------------------------------------------- /include/jsonrpccxx/iclientconnector.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace jsonrpccxx { 5 | class IClientConnector { 6 | public: 7 | virtual ~IClientConnector() = default; 8 | virtual std::string Send(const std::string &request) = 0; 9 | }; 10 | } -------------------------------------------------------------------------------- /include/jsonrpccxx/server.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "common.hpp" 4 | #include "dispatcher.hpp" 5 | #include 6 | 7 | namespace jsonrpccxx { 8 | class JsonRpcServer { 9 | public: 10 | JsonRpcServer() : dispatcher() {} 11 | virtual ~JsonRpcServer() = default; 12 | virtual std::string HandleRequest(const std::string &request) = 0; 13 | 14 | bool Add(const std::string &name, MethodHandle callback, const NamedParamMapping &mapping = NAMED_PARAM_MAPPING) { 15 | if (name.rfind("rpc.", 0) == 0) 16 | return false; 17 | return dispatcher.Add(name, callback, mapping); 18 | } 19 | bool Add(const std::string &name, NotificationHandle callback, const NamedParamMapping &mapping = NAMED_PARAM_MAPPING) { 20 | if (name.rfind("rpc.", 0) == 0) 21 | return false; 22 | return dispatcher.Add(name, callback, mapping); 23 | } 24 | 25 | protected: 26 | Dispatcher dispatcher; 27 | }; 28 | 29 | class JsonRpc2Server : public JsonRpcServer { 30 | public: 31 | JsonRpc2Server() = default; 32 | ~JsonRpc2Server() override = default; 33 | 34 | std::string HandleRequest(const std::string &requestString) override { 35 | try { 36 | json request = json::parse(requestString); 37 | if (request.is_array()) { 38 | json result = json::array(); 39 | for (json &r : request) { 40 | json res = this->HandleSingleRequest(r); 41 | if (!res.is_null()) { 42 | result.push_back(std::move(res)); 43 | } 44 | } 45 | return result.dump(); 46 | } else if (request.is_object()) { 47 | json res = HandleSingleRequest(request); 48 | if (!res.is_null()) { 49 | return res.dump(); 50 | } else { 51 | return ""; 52 | } 53 | } else { 54 | return json{{"id", nullptr}, {"error", {{"code", invalid_request}, {"message", "invalid request: expected array or object"}}}, {"jsonrpc", "2.0"}}.dump(); 55 | } 56 | } catch (json::parse_error &e) { 57 | return json{{"id", nullptr}, {"error", {{"code", parse_error}, {"message", std::string("parse error: ") + e.what()}}}, {"jsonrpc", "2.0"}}.dump(); 58 | } 59 | } 60 | 61 | private: 62 | json HandleSingleRequest(json &request) { 63 | json id = nullptr; 64 | if (valid_id(request)) { 65 | id = request["id"]; 66 | } 67 | try { 68 | return ProcessSingleRequest(request); 69 | } catch (JsonRpcException &e) { 70 | json error = {{"code", e.Code()}, {"message", e.Message()}}; 71 | if (!e.Data().is_null()) { 72 | error["data"] = e.Data(); 73 | } 74 | return json{{"id", id}, {"error", error}, {"jsonrpc", "2.0"}}; 75 | } catch (std::exception &e) { 76 | return json{{"id", id}, {"error", {{"code", internal_error}, {"message", std::string("internal server error: ") + e.what()}}}, {"jsonrpc", "2.0"}}; 77 | } catch (...) { 78 | return json{{"id", id}, {"error", {{"code", internal_error}, {"message", std::string("internal server error")}}}, {"jsonrpc", "2.0"}}; 79 | } 80 | } 81 | 82 | json ProcessSingleRequest(json &request) { 83 | if (!has_key_type(request, "jsonrpc", json::value_t::string) || request["jsonrpc"] != "2.0") { 84 | throw JsonRpcException(invalid_request, R"(invalid request: missing jsonrpc field set to "2.0")"); 85 | } 86 | if (!has_key_type(request, "method", json::value_t::string)) { 87 | throw JsonRpcException(invalid_request, "invalid request: method field must be a string"); 88 | } 89 | if (has_key(request, "id") && !valid_id(request)) { 90 | throw JsonRpcException(invalid_request, "invalid request: id field must be a number, string or null"); 91 | } 92 | if (has_key(request, "params") && !(request["params"].is_array() || request["params"].is_object() || request["params"].is_null())) { 93 | throw JsonRpcException(invalid_request, "invalid request: params field must be an array, object or null"); 94 | } 95 | if (!has_key(request, "params") || has_key_type(request, "params", json::value_t::null)) { 96 | request["params"] = json::array(); 97 | } 98 | if (!has_key(request, "id")) { 99 | try { 100 | dispatcher.InvokeNotification(request["method"], request["params"]); 101 | return json(); 102 | } catch (std::exception &) { 103 | return json(); 104 | } 105 | } else { 106 | return {{"jsonrpc", "2.0"}, {"id", request["id"]}, {"result", dispatcher.InvokeMethod(request["method"], request["params"])}}; 107 | } 108 | } 109 | }; 110 | } 111 | -------------------------------------------------------------------------------- /include/jsonrpccxx/typemapper.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "common.hpp" 4 | #include "nlohmann/json.hpp" 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace jsonrpccxx { 11 | typedef std::function MethodHandle; 12 | typedef std::function NotificationHandle; 13 | 14 | // Workaround due to forbidden partial template function specialisation 15 | template 16 | struct type {}; 17 | 18 | template 19 | constexpr json::value_t GetType(type>) { 20 | return json::value_t::array; 21 | } 22 | template 23 | constexpr json::value_t GetType(type) { 24 | if (std::is_enum::value) { 25 | return json::value_t::string; 26 | } 27 | return json::value_t::object; 28 | } 29 | constexpr json::value_t GetType(type) { return json::value_t::null; } 30 | constexpr json::value_t GetType(type) { return json::value_t::string; } 31 | constexpr json::value_t GetType(type) { return json::value_t::boolean; } 32 | constexpr json::value_t GetType(type) { return json::value_t::number_float; } 33 | constexpr json::value_t GetType(type) { return json::value_t::number_float; } 34 | constexpr json::value_t GetType(type) { return json::value_t::number_float; } 35 | constexpr json::value_t GetType(type) { return json::value_t::number_integer; } 36 | constexpr json::value_t GetType(type) { return json::value_t::number_integer; } 37 | constexpr json::value_t GetType(type) { return json::value_t::number_integer; } 38 | constexpr json::value_t GetType(type) { return json::value_t::number_integer; } 39 | constexpr json::value_t GetType(type) { return json::value_t::number_unsigned; } 40 | constexpr json::value_t GetType(type) { return json::value_t::number_unsigned; } 41 | constexpr json::value_t GetType(type) { return json::value_t::number_unsigned; } 42 | constexpr json::value_t GetType(type) { return json::value_t::number_unsigned; } 43 | 44 | inline std::string type_name(json::value_t t) { 45 | switch (t) { 46 | case json::value_t::number_integer: 47 | return "integer"; 48 | case json::value_t::boolean: 49 | return "boolean"; 50 | case json::value_t::number_float: 51 | return "float"; 52 | case json::value_t::number_unsigned: 53 | return "unsigned integer"; 54 | case json::value_t::object: 55 | return "object"; 56 | case json::value_t::array: 57 | return "array"; 58 | case json::value_t::string: 59 | return "string"; 60 | default: 61 | return "null"; 62 | } 63 | } 64 | 65 | template 66 | inline void check_param_type(size_t index, const json &x, json::value_t expectedType, typename std::enable_if::value>::type * = 0) { 67 | if (expectedType == json::value_t::number_unsigned && x.type() == json::value_t::number_integer) { 68 | if (x.get() < 0) 69 | throw JsonRpcException(invalid_params, "invalid parameter: must be " + type_name(expectedType) + ", but is " + type_name(x.type()), index); 70 | } else if (x.type() == json::value_t::number_unsigned && expectedType == json::value_t::number_integer) { 71 | if (x.get() > (long long unsigned)std::numeric_limits::max()) { 72 | throw JsonRpcException(invalid_params, "invalid parameter: exceeds value range of " + type_name(expectedType), index); 73 | } 74 | } 75 | else if ((x.type() == json::value_t::number_unsigned || x.type() == json::value_t::number_integer) && expectedType == json::value_t::number_float) { 76 | if (static_cast(x.get()) != x.get()) { 77 | throw JsonRpcException(invalid_params, "invalid parameter: exceeds value range of " + type_name(expectedType), index); 78 | } 79 | } else if (x.type() != expectedType) { 80 | throw JsonRpcException(invalid_params, "invalid parameter: must be " + type_name(expectedType) + ", but is " + type_name(x.type()), index); 81 | } 82 | } 83 | 84 | template 85 | inline void check_param_type(size_t index, const json &x, json::value_t expectedType, typename std::enable_if::value>::type * = 0) { 86 | if (x.type() != expectedType) { 87 | throw JsonRpcException(invalid_params, "invalid parameter: must be " + type_name(expectedType) + ", but is " + type_name(x.type()), index); 88 | } 89 | } 90 | 91 | template 92 | MethodHandle createMethodHandle(std::function method, std::index_sequence) { 93 | MethodHandle handle = [method](const json ¶ms) -> json { 94 | size_t actualSize = params.size(); 95 | size_t formalSize = sizeof...(ParamTypes); 96 | // TODO: add lenient mode for backwards compatible additional params 97 | if (actualSize != formalSize) { 98 | throw JsonRpcException(invalid_params, "invalid parameter: expected " + std::to_string(formalSize) + " argument(s), but found " + std::to_string(actualSize)); 99 | } 100 | (check_param_type::type>(index, params[index], GetType(type::type>())), ...); 101 | return method(params[index].get::type>()...); 102 | }; 103 | return handle; 104 | } 105 | 106 | template 107 | MethodHandle methodHandle(std::function method) { 108 | return createMethodHandle(method, std::index_sequence_for{}); 109 | } 110 | 111 | template 112 | MethodHandle GetHandle(std::function f) { 113 | return methodHandle(f); 114 | } 115 | // Mapping for c-style function pointers 116 | template 117 | MethodHandle GetHandle(ReturnType (*f)(ParamTypes...)) { 118 | return GetHandle(std::function(f)); 119 | } 120 | 121 | inline MethodHandle GetUncheckedHandle(std::function f) { 122 | MethodHandle handle = [f](const json ¶ms) -> json { 123 | return f(params); 124 | }; 125 | return handle; 126 | } 127 | 128 | // 129 | // Notification mapping 130 | // 131 | template 132 | NotificationHandle createNotificationHandle(std::function method, std::index_sequence) { 133 | NotificationHandle handle = [method](const json ¶ms) -> void { 134 | size_t actualSize = params.size(); 135 | size_t formalSize = sizeof...(ParamTypes); 136 | // TODO: add lenient mode for backwards compatible additional params 137 | // if ((!allow_unkown_params && actualSize != formalSize) || (allow_unkown_params && actualSize < formalSize)) { 138 | if (actualSize != formalSize) { 139 | throw JsonRpcException(invalid_params, "invalid parameter: expected " + std::to_string(formalSize) + " argument(s), but found " + std::to_string(actualSize)); 140 | } 141 | (check_param_type::type>(index, params[index], GetType(type::type>())), ...); 142 | method(params[index].get::type>()...); 143 | }; 144 | return handle; 145 | } 146 | 147 | template 148 | NotificationHandle notificationHandle(std::function method) { 149 | return createNotificationHandle(method, std::index_sequence_for{}); 150 | } 151 | 152 | template 153 | NotificationHandle GetHandle(std::function f) { 154 | return notificationHandle(f); 155 | } 156 | 157 | template 158 | NotificationHandle GetHandle(void (*f)(ParamTypes...)) { 159 | return GetHandle(std::function(f)); 160 | } 161 | 162 | inline NotificationHandle GetUncheckedNotificationHandle(std::function f) { 163 | NotificationHandle handle = [f](const json ¶ms) -> void { 164 | f(params); 165 | }; 166 | return handle; 167 | } 168 | 169 | template 170 | MethodHandle methodHandle(ReturnType (T::*method)(ParamTypes...), T &instance) { 171 | std::function function = [&instance, method](ParamTypes &&... params) -> ReturnType { 172 | return (instance.*method)(std::forward(params)...); 173 | }; 174 | return methodHandle(function); 175 | } 176 | 177 | template 178 | NotificationHandle notificationHandle(void (T::*method)(ParamTypes...), T &instance) { 179 | std::function function = [&instance, method](ParamTypes &&... params) -> void { 180 | return (instance.*method)(std::forward(params)...); 181 | }; 182 | return notificationHandle(function); 183 | } 184 | 185 | template 186 | MethodHandle GetHandle(ReturnType (T::*method)(ParamTypes...), T &instance) { 187 | std::function function = [&instance, method](ParamTypes &&... params) -> ReturnType { 188 | return (instance.*method)(std::forward(params)...); 189 | }; 190 | return GetHandle(function); 191 | } 192 | 193 | template 194 | NotificationHandle GetHandle(void (T::*method)(ParamTypes...), T &instance) { 195 | std::function function = [&instance, method](ParamTypes &&... params) -> void { 196 | return (instance.*method)(std::forward(params)...); 197 | }; 198 | return GetHandle(function); 199 | } 200 | 201 | template 202 | MethodHandle GetHandle(ReturnType (T::*method)(ParamTypes...) const, const T &instance) 203 | { 204 | std::function function = [&instance, method](ParamTypes &&...params) -> ReturnType { 205 | return (instance.*method)(std::forward(params)...); 206 | }; 207 | return GetHandle(function); 208 | } 209 | 210 | template 211 | NotificationHandle GetHandle(void (T::*method)(ParamTypes...) const, const T &instance) 212 | { 213 | std::function function = [&instance, method](ParamTypes &&...params) -> void { 214 | return (instance.*method)(std::forward(params)...); 215 | }; 216 | return GetHandle(function); 217 | } 218 | } 219 | -------------------------------------------------------------------------------- /test/batchclient.cpp: -------------------------------------------------------------------------------- 1 | #include "doctest/doctest.h" 2 | #include "testclientconnector.hpp" 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | using namespace jsonrpccxx; 8 | 9 | TEST_CASE("batchresponse") { 10 | BatchResponse br({{{"jsonrpc", "2.0"}, {"id", "1"}, {"result", "someresultstring"}}, 11 | {{"jsonrpc", "2.0"}, {"id", "2"}, {"result", 33}}, 12 | {{"jsonrpc", "2.0"}, {"id", "3"}, {"error", {{"code", -111}, {"message", "the error message"}}}}, 13 | {{"jsonrpc", "2.0"}, {"id", nullptr}, {"error", {{"code", -112}, {"message", "the error message"}}}}, 14 | 3}); 15 | 16 | CHECK(br.HasErrors()); 17 | CHECK(br.Get("1") == "someresultstring"); 18 | REQUIRE_THROWS_WITH(br.Get(1), "-32700: no result found for id 1"); 19 | CHECK(br.Get("2") == 33); 20 | CHECK(br.Get("2") == 33); 21 | REQUIRE_THROWS_WITH(br.Get("1"), "-32700: invalid return type: [json.exception.type_error.302] type must be number, but is string"); 22 | REQUIRE_THROWS_WITH(br.Get("3"), "-111: the error message"); 23 | REQUIRE_THROWS_WITH(br.Get(nullptr), "-32700: no result found for id null"); 24 | 25 | CHECK(br.GetInvalidIndexes().size() == 2); 26 | CHECK(br.GetResponse().size() == 5); 27 | CHECK(br.GetResponse()[br.GetInvalidIndexes()[0]]["error"]["code"] == -112); 28 | CHECK(br.GetResponse()[br.GetInvalidIndexes()[1]] == 3); 29 | } 30 | 31 | TEST_CASE("batchrequest") { 32 | BatchRequest br; 33 | TestClientConnector c; 34 | json request = br.AddMethodCall(1, "some_method1", {"value1"}) 35 | .AddMethodCall("1", "some_method1", {"value1"}) 36 | .AddNamedMethodCall(2, "some_method2", {{"param1", "value1"}}) 37 | .AddNamedMethodCall("2", "some_method2", {{"param1", "value1"}}) 38 | .AddNotificationCall("some_notification1", {"value2"}) 39 | .AddNamedNotificationCall("some_notification2", {{"param2", "value2"}}) 40 | .Build(); 41 | 42 | CHECK(request.is_array()); 43 | CHECK(request.size() == 6); 44 | c.Send(request[0].dump()); 45 | c.VerifyMethodRequest(version::v2, "some_method1", 1); 46 | c.Send(request[1].dump()); 47 | c.VerifyMethodRequest(version::v2, "some_method1", "1"); 48 | c.Send(request[2].dump()); 49 | c.VerifyMethodRequest(version::v2, "some_method2", 2); 50 | c.Send(request[3].dump()); 51 | c.VerifyMethodRequest(version::v2, "some_method2", "2"); 52 | c.Send(request[4].dump()); 53 | c.VerifyNotificationRequest(version::v2, "some_notification1"); 54 | c.Send(request[5].dump()); 55 | c.VerifyNotificationRequest(version::v2, "some_notification2"); 56 | } 57 | 58 | TEST_CASE("batchclient") { 59 | TestClientConnector c; 60 | BatchClient client(c); 61 | c.SetBatchResult({TestClientConnector::BuildResult("result1", 1), TestClientConnector::BuildResult(33, 2)}); 62 | 63 | BatchRequest r; 64 | r.AddMethodCall(1, "some_method", {"value1"}); 65 | r.AddMethodCall(2, "some_method", {"value2"}); 66 | BatchResponse response = client.BatchCall(r); 67 | CHECK(response.Get(1) == "result1"); 68 | CHECK(response.Get(2) == 33); 69 | 70 | c.SetBatchResult("{}"); 71 | CHECK_THROWS_WITH(client.BatchCall(r), "-32700: invalid JSON response from server: expected array"); 72 | c.raw_response = "somestring"; 73 | CHECK_THROWS_WITH(client.BatchCall(r), "-32700: invalid JSON response from server: [json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - invalid literal; last read: 's'"); 74 | } -------------------------------------------------------------------------------- /test/client.cpp: -------------------------------------------------------------------------------- 1 | #include "doctest/doctest.h" 2 | #include "testclientconnector.hpp" 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | using namespace jsonrpccxx; 8 | 9 | struct F { 10 | TestClientConnector c; 11 | JsonRpcClient clientV1; 12 | JsonRpcClient clientV2; 13 | F() : c(), clientV1(c, version::v1), clientV2(c, version::v2) {} 14 | }; 15 | 16 | TEST_CASE_FIXTURE(F, "v2_method_noparams") { 17 | c.SetResult(true); 18 | clientV2.CallMethod("000-000-000", "some.method_1"); 19 | c.VerifyMethodRequest(version::v2, "some.method_1", "000-000-000"); 20 | CHECK(!has_key(c.request, "params")); 21 | } 22 | 23 | TEST_CASE_FIXTURE(F, "v1_method_noparams") { 24 | c.SetResult(true); 25 | clientV1.CallMethod(37, "some.method_1"); 26 | c.VerifyMethodRequest(version::v1, "some.method_1", 37); 27 | CHECK(has_key_type(c.request, "params", json::value_t::null)); 28 | } 29 | 30 | TEST_CASE_FIXTURE(F, "v2_method_call_params_empty") { 31 | c.SetResult(true); 32 | clientV2.CallMethod("1", "some.method_1", {}); 33 | c.VerifyMethodRequest(version::v2, "some.method_1", "1"); 34 | CHECK(c.request["params"].is_array()); 35 | CHECK(c.request["params"].empty()); 36 | CHECK(c.request["params"].dump() == "[]"); 37 | 38 | c.SetResult(true); 39 | clientV2.CallMethod("1", "some.method_1", json::array()); 40 | c.VerifyMethodRequest(version::v2, "some.method_1", "1"); 41 | CHECK(c.request["params"].is_array()); 42 | CHECK(c.request["params"].empty()); 43 | CHECK(c.request["params"].dump() == "[]"); 44 | } 45 | 46 | TEST_CASE_FIXTURE(F, "v1_method_call_params_empty") { 47 | c.SetResult(true); 48 | clientV1.CallMethod("1", "some.method_1", {}); 49 | c.VerifyMethodRequest(version::v1, "some.method_1", "1"); 50 | CHECK(c.request["params"].is_array()); 51 | CHECK(c.request["params"].empty()); 52 | CHECK(c.request["params"].dump() == "[]"); 53 | 54 | c.SetResult(true); 55 | clientV1.CallMethod("1", "some.method_1", json::array()); 56 | c.VerifyMethodRequest(version::v1, "some.method_1", "1"); 57 | CHECK(c.request["params"].is_array()); 58 | CHECK(c.request["params"].empty()); 59 | CHECK(c.request["params"].dump() == "[]"); 60 | } 61 | 62 | TEST_CASE_FIXTURE(F, "v2_method_call_params_byname") { 63 | c.SetResult(true); 64 | clientV2.CallMethodNamed("1", "some.method_1", {{"a", "hello"}, {"b", 77}, {"c", true}}); 65 | c.VerifyMethodRequest(version::v2, "some.method_1", "1"); 66 | CHECK(c.request["params"]["a"] == "hello"); 67 | CHECK(c.request["params"]["b"] == 77); 68 | CHECK(c.request["params"]["c"] == true); 69 | } 70 | 71 | TEST_CASE_FIXTURE(F, "v1_method_call_params_byname") { 72 | c.SetResult(true); 73 | clientV1.CallMethodNamed("1", "some.method_1", {{"a", "hello"}, {"b", 77}, {"c", true}}); 74 | c.VerifyMethodRequest(version::v1, "some.method_1", "1"); 75 | CHECK(c.request["params"]["a"] == "hello"); 76 | CHECK(c.request["params"]["b"] == 77); 77 | CHECK(c.request["params"]["c"] == true); 78 | } 79 | 80 | TEST_CASE_FIXTURE(F, "v2_method_call_params_byposition") { 81 | c.SetResult(true); 82 | clientV2.CallMethod("1", "some.method_1", {"hello", 77, true}); 83 | c.VerifyMethodRequest(version::v2, "some.method_1", "1"); 84 | CHECK(c.request["params"][0] == "hello"); 85 | CHECK(c.request["params"][1] == 77); 86 | CHECK(c.request["params"][2] == true); 87 | } 88 | 89 | TEST_CASE_FIXTURE(F, "v1_method_call_params_byposition") { 90 | c.SetResult(true); 91 | clientV1.CallMethod("1", "some.method_1", {"hello", 77, true}); 92 | c.VerifyMethodRequest(version::v1, "some.method_1", "1"); 93 | CHECK(c.request["params"][0] == "hello"); 94 | CHECK(c.request["params"][1] == 77); 95 | CHECK(c.request["params"][2] == true); 96 | } 97 | 98 | TEST_CASE_FIXTURE(F, "v2_method_result_simple") { 99 | c.SetResult(23); 100 | int r = clientV2.CallMethod("1", "some.method_1", {}); 101 | c.VerifyMethodRequest(version::v2, "some.method_1", "1"); 102 | CHECK(23 == r); 103 | } 104 | 105 | TEST_CASE_FIXTURE(F, "v1_method_result_simple") { 106 | c.SetResult(23); 107 | int r = clientV1.CallMethod("1", "some.method_1", {}); 108 | c.VerifyMethodRequest(version::v1, "some.method_1", "1"); 109 | CHECK(23 == r); 110 | } 111 | 112 | TEST_CASE_FIXTURE(F, "v2_method_result_object") { 113 | c.SetResult({{"a", 3}, {"b", 4}}); 114 | json r = clientV2.CallMethod("1", "some.method_1", {}); 115 | c.VerifyMethodRequest(version::v2, "some.method_1", "1"); 116 | CHECK(r["a"] == 3); 117 | CHECK(r["b"] == 4); 118 | } 119 | 120 | TEST_CASE_FIXTURE(F, "v1_method_result_object") { 121 | c.SetResult({{"a", 3}, {"b", 4}}); 122 | json r = clientV1.CallMethod("1", "some.method_1", {}); 123 | c.VerifyMethodRequest(version::v1, "some.method_1", "1"); 124 | CHECK(r["a"] == 3); 125 | CHECK(r["b"] == 4); 126 | } 127 | 128 | TEST_CASE_FIXTURE(F, "v2_method_result_array") { 129 | c.SetResult({2, 3, 4}); 130 | json r = clientV2.CallMethod("1", "some.method_1", {}); 131 | c.VerifyMethodRequest(version::v2, "some.method_1", "1"); 132 | CHECK(r[0] == 2); 133 | CHECK(r[1] == 3); 134 | CHECK(r[2] == 4); 135 | } 136 | 137 | TEST_CASE_FIXTURE(F, "v1_method_result_array") { 138 | c.SetResult({2, 3, 4}); 139 | json r = clientV1.CallMethod("1", "some.method_1", {}); 140 | c.VerifyMethodRequest(version::v1, "some.method_1", "1"); 141 | CHECK(r[0] == 2); 142 | CHECK(r[1] == 3); 143 | CHECK(r[2] == 4); 144 | } 145 | 146 | TEST_CASE_FIXTURE(F, "v2_method_result_empty") { 147 | c.raw_response = "{}"; 148 | REQUIRE_THROWS_WITH(clientV2.CallMethod("1", "some.method_1", {}), "-32603: invalid server response: neither \"result\" nor \"error\" fields found"); 149 | c.VerifyMethodRequest(version::v2, "some.method_1", "1"); 150 | c.raw_response = "[]"; 151 | REQUIRE_THROWS_WITH(clientV2.CallMethod("1", "some.method_1", {}), "-32603: invalid server response: neither \"result\" nor \"error\" fields found"); 152 | c.VerifyMethodRequest(version::v2, "some.method_1", "1"); 153 | } 154 | 155 | /* 156 | TEST_CASE_FIXTURE(F, "v1_method_result_empty") { 157 | c.raw_response = "{}"; 158 | REQUIRE_THROWS_WITH(clientV1.CallMethod("1", "some.method_1", {}), 159 | Contains("result") && Contains("or") && Contains("error") && Contains("invalid server response")); 160 | c.VerifyMethodRequest(version::v1, "some.method_1", "1"); 161 | c.raw_response = "[]"; 162 | REQUIRE_THROWS_WITH(clientV1.CallMethod("1", "some.method_1", {}), 163 | Contains("result") && Contains("or") && Contains("error") && Contains("invalid server response")); 164 | c.VerifyMethodRequest(version::v1, "some.method_1", "1"); 165 | } 166 | 167 | TEST_CASE_FIXTURE(F, "v2_method_error") { 168 | c.SetError(JsonRpcException{-32602, "invalid method name"}); 169 | REQUIRE_THROWS_WITH(clientV2.CallMethod("1", "some.method_1", {}), Contains("-32602") && Contains("invalid method name") && !Contains("data")); 170 | c.VerifyMethodRequest(version::v2, "some.method_1", "1"); 171 | } 172 | 173 | TEST_CASE_FIXTURE(F, "v2_method_error_with_data") { 174 | c.SetError(JsonRpcException{-32602, "invalid method name", {1, 2}}); 175 | REQUIRE_THROWS_WITH(clientV2.CallMethod("1", "some.method_1", {}), 176 | Contains("-32602") && Contains("invalid method name") && Contains("data") && Contains("[1,2]")); 177 | c.VerifyMethodRequest(version::v2, "some.method_1", "1"); 178 | } 179 | 180 | TEST_CASE_FIXTURE(F, "v1_method_error") { 181 | c.SetError(JsonRpcException{-32602, "invalid method name"}); 182 | REQUIRE_THROWS_WITH(clientV1.CallMethod("1", "some.method_1", {}), Contains("-32602") && Contains("invalid method name") && !Contains("data")); 183 | c.VerifyMethodRequest(version::v1, "some.method_1", "1"); 184 | } 185 | 186 | TEST_CASE_FIXTURE(F, "v1_method_error_with_data") { 187 | c.SetError(JsonRpcException{-32602, "invalid method name", {1, 2}}); 188 | REQUIRE_THROWS_WITH(clientV1.CallMethod("1", "some.method_1", {}), 189 | Contains("-32602") && Contains("invalid method name") && Contains("data") && Contains("[1,2]")); 190 | c.VerifyMethodRequest(version::v1, "some.method_1", "1"); 191 | } 192 | 193 | TEST_CASE_FIXTURE(F, "v2_method_error_invalid_json") { 194 | c.raw_response = "{asdfasdf,[}"; 195 | REQUIRE_THROWS_WITH(clientV2.CallMethod("1", "some.method_1", {}), Contains("-32700") && Contains("invalid") && Contains("JSON") && Contains("server")); 196 | c.VerifyMethodRequest(version::v2, "some.method_1", "1"); 197 | c.raw_response = " "; 198 | REQUIRE_THROWS_WITH(clientV2.CallMethod("1", "some.method_1", {}), Contains("-32700") && Contains("invalid") && Contains("JSON") && Contains("server")); 199 | c.VerifyMethodRequest(version::v2, "some.method_1", "1"); 200 | c.raw_response = ""; 201 | REQUIRE_THROWS_WITH(clientV2.CallMethod("1", "some.method_1", {}), Contains("-32700") && Contains("invalid") && Contains("JSON") && Contains("server")); 202 | c.VerifyMethodRequest(version::v2, "some.method_1", "1"); 203 | } 204 | 205 | TEST_CASE_FIXTURE(F, "v1_method_error_invalid_json") { 206 | c.raw_response = "{asdfasdf,[}"; 207 | REQUIRE_THROWS_WITH(clientV1.CallMethod("1", "some.method_1", {}), Contains("-32700") && Contains("invalid") && Contains("JSON") && Contains("server")); 208 | c.VerifyMethodRequest(version::v1, "some.method_1", "1"); 209 | c.raw_response = " "; 210 | REQUIRE_THROWS_WITH(clientV1.CallMethod("1", "some.method_1", {}), Contains("-32700") && Contains("invalid") && Contains("JSON") && Contains("server")); 211 | c.VerifyMethodRequest(version::v1, "some.method_1", "1"); 212 | c.raw_response = ""; 213 | REQUIRE_THROWS_WITH(clientV1.CallMethod("1", "some.method_1", {}), Contains("-32700") && Contains("invalid") && Contains("JSON") && Contains("server")); 214 | c.VerifyMethodRequest(version::v1, "some.method_1", "1"); 215 | } 216 | 217 | TEST_CASE_FIXTURE(F, "v2_notification_call_no_params") { 218 | c.raw_response = ""; 219 | clientV2.CallNotification("some.notification_1", {}); 220 | c.VerifyNotificationRequest(version::v2, "some.notification_1"); 221 | CHECK(!has_key(c.request, "params")); 222 | 223 | c.raw_response = ""; 224 | clientV2.CallNotification("some.notification_1"); 225 | c.VerifyNotificationRequest(version::v2, "some.notification_1"); 226 | CHECK(!has_key(c.request, "params")); 227 | } 228 | 229 | TEST_CASE_FIXTURE(F, "v1_notification_call_no_params") { 230 | c.raw_response = ""; 231 | clientV1.CallNotification("some.notification_1", {}); 232 | c.VerifyNotificationRequest(version::v1, "some.notification_1"); 233 | CHECK(has_key_type(c.request, "params", json::value_t::null)); 234 | 235 | c.raw_response = ""; 236 | clientV1.CallNotification("some.notification_1"); 237 | c.VerifyNotificationRequest(version::v1, "some.notification_1"); 238 | CHECK(has_key_type(c.request, "params", json::value_t::null)); 239 | } 240 | 241 | TEST_CASE_FIXTURE(F, "v2_notification_call_params_byname") { 242 | c.raw_response = ""; 243 | clientV2.CallNotificationNamed("some.notification_1", {{"a", "hello"}, {"b", 77}, {"c", true}}); 244 | c.VerifyNotificationRequest(version::v2, "some.notification_1"); 245 | CHECK(c.request["params"]["a"] == "hello"); 246 | CHECK(c.request["params"]["b"] == 77); 247 | CHECK(c.request["params"]["c"] == true); 248 | } 249 | 250 | TEST_CASE_FIXTURE(F, "v1_notification_call_params_byname") { 251 | c.raw_response = ""; 252 | clientV1.CallNotificationNamed("some.notification_1", {{"a", "hello"}, {"b", 77}, {"c", true}}); 253 | c.VerifyNotificationRequest(version::v1, "some.notification_1"); 254 | CHECK(c.request["params"]["a"] == "hello"); 255 | CHECK(c.request["params"]["b"] == 77); 256 | CHECK(c.request["params"]["c"] == true); 257 | } 258 | 259 | TEST_CASE_FIXTURE(F, "v2_notification_call_params_byposition") { 260 | c.raw_response = ""; 261 | clientV2.CallNotification("some.notification_1", {"hello", 77, true}); 262 | c.VerifyNotificationRequest(version::v2, "some.notification_1"); 263 | CHECK(c.request["params"][0] == "hello"); 264 | CHECK(c.request["params"][1] == 77); 265 | CHECK(c.request["params"][2] == true); 266 | } 267 | 268 | TEST_CASE_FIXTURE(F, "v1_notification_call_params_byposition") { 269 | c.raw_response = ""; 270 | clientV1.CallNotification("some.notification_1", {"hello", 77, true}); 271 | c.VerifyNotificationRequest(version::v1, "some.notification_1"); 272 | CHECK(c.request["params"][0] == "hello"); 273 | CHECK(c.request["params"][1] == 77); 274 | CHECK(c.request["params"][2] == true); 275 | }*/ 276 | 277 | // TODO: test cases with return type mapping and param mapping for v1/v2 method and notification 278 | -------------------------------------------------------------------------------- /test/common.cpp: -------------------------------------------------------------------------------- 1 | #include "doctest/doctest.h" 2 | #include 3 | 4 | using namespace std; 5 | using namespace jsonrpccxx; 6 | 7 | TEST_CASE("exception error type") { 8 | CHECK(JsonRpcException(-32700, "").Type() == parse_error); 9 | CHECK(JsonRpcException(-32600, "").Type() == invalid_request); 10 | CHECK(JsonRpcException(-32601, "").Type() == method_not_found); 11 | CHECK(JsonRpcException(-32602, "").Type() == invalid_params); 12 | CHECK(JsonRpcException(-32603, "").Type() == internal_error); 13 | 14 | for(int c = -32000; c >= -32099; c--) 15 | CHECK(JsonRpcException(c, "").Type() == server_error); 16 | 17 | CHECK(JsonRpcException(0, "").Type() == invalid); 18 | CHECK(JsonRpcException(32700, "").Type() == invalid); 19 | CHECK(JsonRpcException(33000, "").Type() == invalid); 20 | } -------------------------------------------------------------------------------- /test/dispatcher.cpp: -------------------------------------------------------------------------------- 1 | #include "doctest/doctest.h" 2 | #include 3 | #include 4 | 5 | using namespace jsonrpccxx; 6 | using namespace std; 7 | 8 | static string procCache; 9 | unsigned int add_function(unsigned int a, unsigned int b) { return a + b; } 10 | void some_procedure(const string ¶m) { procCache = param; } 11 | 12 | TEST_CASE("add and invoke positional") { 13 | Dispatcher d; 14 | CHECK(d.Add("some method", GetHandle(&add_function))); 15 | CHECK(!d.Add("some method", GetHandle(&add_function))); 16 | CHECK(d.InvokeMethod("some method", {11, 22}) == 33); 17 | 18 | procCache = ""; 19 | CHECK(d.Add("some notification", GetHandle(&some_procedure))); 20 | CHECK(!d.Add("some notification", GetHandle(&some_procedure))); 21 | d.InvokeNotification("some notification", {"some string"}); 22 | CHECK(procCache == "some string"); 23 | } 24 | 25 | TEST_CASE("invoking supported named parameter") { 26 | Dispatcher d; 27 | CHECK(d.Add("some method", GetHandle(&add_function), {"a", "b"})); 28 | REQUIRE(d.InvokeMethod("some method", {{"a", 11}, {"b", 22}}) == 33); 29 | 30 | procCache = ""; 31 | CHECK(d.Add("some notification", GetHandle(&some_procedure), {"param"})); 32 | json p = {{"param", "some string"}}; 33 | d.InvokeNotification("some notification", p); 34 | CHECK(procCache == "some string"); 35 | } 36 | 37 | TEST_CASE("invoking missing named parameter") { 38 | Dispatcher d; 39 | CHECK(d.Add("some method", GetHandle(&add_function), {"a", "b"})); 40 | REQUIRE_THROWS_WITH(d.InvokeMethod("some method", {{"a", 11}, {"xx", 22}}), "-32602: invalid parameter: missing named parameter \"b\""); 41 | 42 | procCache = ""; 43 | CHECK(d.Add("some notification", GetHandle(&some_procedure), {"param"})); 44 | json p = {{"param2", "some string"}}; 45 | REQUIRE_THROWS_WITH(d.InvokeNotification("some notification", p), "-32602: invalid parameter: missing named parameter \"param\""); 46 | CHECK(procCache.empty()); 47 | } 48 | 49 | TEST_CASE("invoking wrong type namedparameter") { 50 | Dispatcher d; 51 | CHECK(d.Add("some method", GetHandle(&add_function), {"a", "b"})); 52 | REQUIRE_THROWS_WITH(d.InvokeMethod("some method", {{"a", "asdfasdf"}, {"b", -7}}), "-32602: invalid parameter: must be unsigned integer, but is string for parameter \"a\""); 53 | REQUIRE_THROWS_WITH(d.InvokeMethod("some method", {{"a", -10}, {"b", -7}}), "-32602: invalid parameter: must be unsigned integer, but is integer for parameter \"a\""); 54 | } 55 | 56 | TEST_CASE("error on invoking unsupported named parameter") { 57 | Dispatcher d; 58 | CHECK(d.Add("some method", GetHandle(&add_function))); 59 | REQUIRE_THROWS_WITH(d.InvokeMethod("some method", {{"a", 11}, {"b", 22}}), "-32602: invalid parameter: procedure doesn't support named parameter"); 60 | 61 | CHECK(d.Add("some notification", GetHandle(&some_procedure))); 62 | json p = {{"param", "some string"}}; 63 | REQUIRE_THROWS_WITH(d.InvokeNotification("some notification", p), "-32602: invalid parameter: procedure doesn't support named parameter"); 64 | } 65 | 66 | TEST_CASE("passing invalid literal as param") { 67 | Dispatcher d; 68 | CHECK(d.Add("some method", GetHandle(&add_function))); 69 | REQUIRE_THROWS_WITH(d.InvokeMethod("some method", true), "-32600: invalid request: params field must be an array, object"); 70 | } 71 | 72 | TEST_CASE("dispatching unknown procedures") { 73 | Dispatcher d; 74 | REQUIRE_THROWS_WITH(d.InvokeMethod("some method", {1}), "-32601: method not found: some method"); 75 | REQUIRE_THROWS_WITH(d.InvokeNotification("some notification", {1}), "-32601: notification not found: some notification"); 76 | } 77 | 78 | TEST_CASE("invalid param types") { 79 | Dispatcher d; 80 | CHECK(d.Add("some method", GetHandle(&add_function))); 81 | CHECK_THROWS_WITH(d.InvokeMethod("some method", {"string1", "string2"}), "-32602: invalid parameter: must be unsigned integer, but is string for parameter 0"); 82 | } 83 | 84 | // TODO: avoid signed, unsigned bool invocations -------------------------------------------------------------------------------- /test/integrationtest.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../examples/inmemoryconnector.hpp" 4 | #include 5 | #include 6 | 7 | using namespace jsonrpccxx; 8 | 9 | struct IntegrationTest { 10 | IntegrationTest() : rpcServer(), connector(rpcServer), client(connector, version::v2) {} 11 | JsonRpc2Server rpcServer; 12 | InMemoryConnector connector; 13 | JsonRpcClient client; 14 | }; 15 | -------------------------------------------------------------------------------- /test/main.cpp: -------------------------------------------------------------------------------- 1 | #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN 2 | #include "doctest/doctest.h" -------------------------------------------------------------------------------- /test/server.cpp: -------------------------------------------------------------------------------- 1 | #include "doctest/doctest.h" 2 | #include "testserverconnector.hpp" 3 | #include 4 | #include 5 | 6 | using namespace jsonrpccxx; 7 | using namespace std; 8 | 9 | struct Server2 { 10 | JsonRpc2Server server; 11 | TestServerConnector connector; 12 | 13 | Server2() : server(), connector(server) {} 14 | }; 15 | 16 | TEST_CASE_FIXTURE(Server2, "v2_method_not_found") { 17 | connector.CallMethod(1, "some_invalid_method", nullptr); 18 | connector.VerifyMethodError(-32601, "method not found: some_invalid_method", 1); 19 | } 20 | 21 | TEST_CASE_FIXTURE(Server2, "v2_malformed_requests") { 22 | string name = "some_method"; 23 | json params = nullptr; 24 | 25 | connector.SendRawRequest("dfasdf"); 26 | connector.VerifyMethodError(-32700, "parse error", nullptr); 27 | connector.SendRawRequest("true"); 28 | connector.VerifyMethodError(-32600, "invalid request: expected array or object", nullptr); 29 | 30 | connector.SendRequest({{"id", true}, {"method", name}, {"params", params}, {"jsonrpc", "2.0"}}); 31 | connector.VerifyMethodError(-32600, "invalid request: id field must be a number, string or null", nullptr); 32 | connector.SendRequest({{"id", {3}}, {"method", name}, {"params", params}, {"jsonrpc", "2.0"}}); 33 | connector.VerifyMethodError(-32600, "invalid request: id field must be a number, string or null", nullptr); 34 | connector.SendRequest({{"id", {{"a", "b"}}}, {"method", name}, {"params", params}, {"jsonrpc", "2.0"}}); 35 | connector.VerifyMethodError(-32600, "invalid request: id field must be a number, string or null", nullptr); 36 | connector.SendRequest({{"id", nullptr}, {"method", name}, {"params", params}, {"jsonrpc", "2.0"}}); 37 | connector.VerifyMethodError(-32601, "method not found: some_method", nullptr); 38 | 39 | connector.SendRequest({{"id", 1}, {"params", params}, {"jsonrpc", "2.0"}}); 40 | connector.VerifyMethodError(-32600, "invalid request: method field must be a string", 1); 41 | connector.SendRequest({{"id", 1}, {"method", 33}, {"params", params}, {"jsonrpc", "2.0"}}); 42 | connector.VerifyMethodError(-32600, "invalid request: method field must be a string", 1); 43 | connector.SendRequest({{"id", 1}, {"method", true}, {"params", params}, {"jsonrpc", "2.0"}}); 44 | connector.VerifyMethodError(-32600, "invalid request: method field must be a string", 1); 45 | 46 | connector.SendRequest({{"id", 1}, {"method", name}, {"params", params}, {"jsonrpc", "3.0"}}); 47 | connector.VerifyMethodError(-32600, R"(invalid request: missing jsonrpc field set to "2.0")", 1); 48 | connector.SendRequest({{"id", 1}, {"method", name}, {"params", params}, {"jsonrpc", nullptr}}); 49 | connector.VerifyMethodError(-32600, R"(invalid request: missing jsonrpc field set to "2.0")", 1); 50 | connector.SendRequest({{"id", 1}, {"method", name}, {"params", params}}); 51 | connector.VerifyMethodError(-32600, R"(invalid request: missing jsonrpc field set to "2.0")", 1); 52 | 53 | connector.SendRequest({{"id", 1}, {"method", name}, {"jsonrpc", "2.0"}}); 54 | connector.VerifyMethodError(-32601, "method not found: some_method", 1); 55 | connector.SendRequest({{"id", 1}, {"method", name}, {"params", true}, {"jsonrpc", "2.0"}}); 56 | connector.VerifyMethodError(-32600, "invalid request: params field must be an array, object or null", 1); 57 | } 58 | 59 | enum class category { ord, cc }; 60 | 61 | NLOHMANN_JSON_SERIALIZE_ENUM(category, {{category::ord, "order"}, {category::cc, "cc"}}) 62 | 63 | struct product { 64 | product() : id(), price(), name(), cat() {} 65 | int id; 66 | double price; 67 | string name; 68 | category cat; 69 | }; 70 | 71 | void to_json(json &j, const product &p); 72 | void from_json(const json &j, product &p); 73 | 74 | class TestServer { 75 | public: 76 | TestServer() : param_proc(), param_a(), param_b(), catalog() {} 77 | 78 | unsigned int add_function(unsigned int a, unsigned int b) { 79 | this->param_a = a; 80 | this->param_b = b; 81 | return a + b; 82 | } 83 | unsigned int div_function(unsigned int a, unsigned int b) { 84 | this->param_a = a; 85 | this->param_b = b; 86 | if (b != 0) 87 | return a / b; 88 | else 89 | throw JsonRpcException(-32602, "b must not be 0"); 90 | } 91 | void some_procedure(const string ¶m) { param_proc = param; } 92 | bool add_products(const vector &products) { 93 | std::copy(products.begin(), products.end(), std::back_inserter(catalog)); 94 | return true; 95 | }; 96 | 97 | void dirty_notification() { throw std::exception(); } 98 | int dirty_method(int a, int b) { auto _ = to_string(a+b); throw std::exception(); } 99 | int dirty_method2(int a, int b) { throw (a+b); } 100 | 101 | string param_proc; 102 | int param_a; 103 | int param_b; 104 | vector catalog; 105 | }; 106 | 107 | TEST_CASE_FIXTURE(Server2, "v2_invocations") { 108 | TestServer t; 109 | REQUIRE(server.Add("add_function", GetHandle(&TestServer::add_function, t), {"a", "b"})); 110 | REQUIRE(server.Add("div_function", GetHandle(&TestServer::div_function, t), {"a", "b"})); 111 | REQUIRE(server.Add("some_procedure", GetHandle(&TestServer::some_procedure, t), {"param"})); 112 | REQUIRE(server.Add("add_products", GetHandle(&TestServer::add_products, t), {"products"})); 113 | REQUIRE(server.Add("dirty_notification", GetHandle(&TestServer::dirty_notification, t), {"products"})); 114 | REQUIRE(server.Add("dirty_method", GetHandle(&TestServer::dirty_method, t), {"a", "b"})); 115 | REQUIRE(server.Add("dirty_method2", GetHandle(&TestServer::dirty_method2, t), {"a", "b"})); 116 | 117 | REQUIRE(!server.Add("dirty_method2", GetHandle(&TestServer::dirty_method2, t), {"a", "b"})); 118 | REQUIRE(!server.Add("rpc.something", GetHandle(&TestServer::dirty_method2, t), {"a", "b"})); 119 | REQUIRE(!server.Add("rpc.", GetHandle(&TestServer::dirty_method2, t), {"a", "b"})); 120 | REQUIRE(!server.Add("rpc.somenotification", GetHandle(&TestServer::dirty_notification, t), {"a", "b"})); 121 | REQUIRE(server.Add("rpc", GetHandle(&TestServer::dirty_method2, t), {"a", "b"})); 122 | 123 | connector.CallMethod(1, "add_function", {{"a", 3}, {"b", 4}}); 124 | CHECK(connector.VerifyMethodResult(1) == 7); 125 | CHECK(t.param_a == 3); 126 | CHECK(t.param_b == 4); 127 | 128 | connector.CallNotification("some_procedure", {{"param", "something set"}}); 129 | connector.VerifyNotificationResult(); 130 | CHECK(t.param_proc == "something set"); 131 | 132 | json params = json::parse( 133 | R"({"products": [{"id": 1, "price": 23.3, "name": "some product", "category": "cc"},{"id": 2, "price": 23.4, "name": "some product 2", "category": "order"}]})"); 134 | 135 | connector.CallMethod(1, "add_products", params); 136 | CHECK(connector.VerifyMethodResult(1) == true); 137 | CHECK(t.catalog.size() == 2); 138 | CHECK(t.catalog[0].id == 1); 139 | CHECK(t.catalog[0].name == "some product"); 140 | CHECK(t.catalog[0].price == 23.3); 141 | CHECK(t.catalog[0].cat == category::cc); 142 | CHECK(t.catalog[1].id == 2); 143 | CHECK(t.catalog[1].name == "some product 2"); 144 | CHECK(t.catalog[1].price == 23.4); 145 | CHECK(t.catalog[1].cat == category::ord); 146 | 147 | connector.CallNotification("dirty_notification", nullptr); 148 | connector.VerifyNotificationResult(); 149 | connector.CallMethod(1, "dirty_method", {{"a", 3}, {"b", 0}}); 150 | connector.VerifyMethodError(-32603, "internal server error", 1); 151 | connector.CallMethod(1, "div_function", {{"a", 3}, {"b", 0}}); 152 | connector.VerifyMethodError(-32602, "b must not be 0", 1); 153 | connector.CallMethod(1, "div_function", {{"a", 6}, {"b", 2}}); 154 | CHECK(connector.VerifyMethodResult(1) == 3); 155 | connector.CallMethod(1, "dirty_method2", {{"a", 3}, {"b", 0}}); 156 | connector.VerifyMethodError(-32603, "internal server error", 1); 157 | } 158 | 159 | TEST_CASE_FIXTURE(Server2, "v2_batch") { 160 | TestServer t; 161 | REQUIRE(server.Add("add_function", GetHandle(&TestServer::add_function, t), {"a", "b"})); 162 | 163 | json batchcall; 164 | 165 | batchcall.push_back(connector.BuildMethodCall(1, "add_function", {{"a", 3}, {"b", 4}})); 166 | batchcall.push_back(connector.BuildMethodCall(2, "add_function", {{"a", 300}, {"b", 4}})); 167 | batchcall.push_back(connector.BuildMethodCall(3, "add_function", {{"a", 300}})); 168 | batchcall.push_back(""); 169 | 170 | connector.SendRequest(batchcall); 171 | json batchresponse = connector.VerifyBatchResponse(); 172 | REQUIRE(batchresponse.size() == 4); 173 | 174 | REQUIRE(TestServerConnector::VerifyMethodResult(1, batchresponse[0]) == 7); 175 | REQUIRE(TestServerConnector::VerifyMethodResult(2, batchresponse[1]) == 304); 176 | TestServerConnector::VerifyMethodError(-32602, R"(missing named parameter "b")", 3, batchresponse[2]); 177 | TestServerConnector::VerifyMethodError(-32600, R"(invalid request)", nullptr, batchresponse[3]); 178 | 179 | connector.SendRawRequest("[]"); 180 | batchresponse = connector.VerifyBatchResponse(); 181 | REQUIRE(batchresponse.empty()); 182 | } 183 | -------------------------------------------------------------------------------- /test/testclientconnector.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "doctest/doctest.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | using namespace jsonrpccxx; 10 | using namespace std; 11 | 12 | class TestClientConnector : public IClientConnector { 13 | public: 14 | TestClientConnector() : request(), raw_response() {} 15 | 16 | json request; 17 | string raw_response; 18 | 19 | std::string Send(const std::string &r) override { 20 | this->request = json::parse(r); 21 | return raw_response; 22 | } 23 | 24 | void SetBatchResult(const json &result) { 25 | raw_response = result.dump(); 26 | } 27 | 28 | static json BuildResult(const json &result, int id) { 29 | return {{"jsonrpc", "2.0"}, {"id", id}, {"result", result}}; 30 | } 31 | 32 | void SetResult(const json &result) { 33 | json response = {{"jsonrpc", "2.0"}, {"id", "1"}, {"result", result}}; 34 | raw_response = response.dump(); 35 | } 36 | 37 | void SetError(const JsonRpcException &e) { 38 | json response = {{"jsonrpc", "2.0"}, {"id", "1"}}; 39 | if (!e.Data().empty()) { 40 | response["error"] = {{"code", e.Code()}, {"message", e.Message()}, {"data", e.Data()}}; 41 | } else { 42 | response["error"] = {{"code", e.Code()}, {"message", e.Message()}}; 43 | } 44 | raw_response = response.dump(); 45 | } 46 | 47 | void VerifyMethodRequest(version version, const string &name, json id) { 48 | CHECK(request["method"] == name); 49 | CHECK(request["id"] == id); 50 | if (version == version::v2) { 51 | CHECK(request["jsonrpc"] == "2.0"); 52 | } else { 53 | CHECK(!has_key(request, "jsonrpc")); 54 | CHECK(has_key(request, "params")); 55 | } 56 | } 57 | 58 | void VerifyNotificationRequest(version version, const string &name) { 59 | CHECK(request["method"] == name); 60 | if (version == version::v2) { 61 | CHECK(request["jsonrpc"] == "2.0"); 62 | CHECK(!has_key(request, "id")); 63 | } else { 64 | CHECK(!has_key(request, "jsonrpc")); 65 | CHECK(request["id"].is_null()); 66 | CHECK(has_key(request, "params")); 67 | } 68 | } 69 | }; 70 | -------------------------------------------------------------------------------- /test/testserverconnector.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "doctest/doctest.h" 3 | #include 4 | 5 | using namespace jsonrpccxx; 6 | using namespace std; 7 | 8 | class TestServerConnector { 9 | public: 10 | explicit TestServerConnector(JsonRpcServer &handler) : handler(handler), raw_response() {} 11 | 12 | void SendRawRequest(const string &request) { this->raw_response = handler.HandleRequest(request); } 13 | void SendRequest(const json &request) { SendRawRequest(request.dump()); } 14 | static json BuildMethodCall(const json &id, const string &name, const json ¶ms) { return {{"id", id}, {"method", name}, {"params", params}, {"jsonrpc", "2.0"}}; } 15 | void CallMethod(const json &id, const string &name, const json ¶ms) { SendRequest(BuildMethodCall(id, name, params)); } 16 | static json BuildNotificationCall(const string &name, const json ¶ms) { return {{"method", name}, {"params", params}, {"jsonrpc", "2.0"}}; } 17 | void CallNotification(const string &name, const json ¶ms) { SendRequest(BuildNotificationCall(name, params)); } 18 | 19 | json VerifyMethodResult(const json &id) { 20 | json result = json::parse(this->raw_response); 21 | return VerifyMethodResult(id, result); 22 | } 23 | 24 | static json VerifyMethodResult(const json &id, json &result) { 25 | REQUIRE(!has_key(result, "error")); 26 | REQUIRE(result["jsonrpc"] == "2.0"); 27 | REQUIRE(result["id"] == id); 28 | REQUIRE(has_key(result, "result")); 29 | return result["result"]; 30 | } 31 | 32 | json VerifyBatchResponse() { 33 | json result = json::parse(raw_response); 34 | REQUIRE(result.is_array()); 35 | return result; 36 | } 37 | 38 | void VerifyNotificationResult() { VerifyNotificationResult(this->raw_response); } 39 | 40 | static void VerifyNotificationResult(string &raw_response) { REQUIRE(raw_response.empty()); } 41 | 42 | json VerifyMethodError(int code, const string &message, const json &id) { 43 | json error = json::parse(this->raw_response); 44 | return VerifyMethodError(code, message, id, error); 45 | } 46 | 47 | static json VerifyMethodError(int code, const string &message, const json &id, json &result) { 48 | REQUIRE(!has_key(result, "result")); 49 | REQUIRE(result["jsonrpc"] == "2.0"); 50 | REQUIRE(result["id"] == id); 51 | REQUIRE(has_key_type(result, "error", json::value_t::object)); 52 | REQUIRE(has_key_type(result["error"], "code", json::value_t::number_integer)); 53 | REQUIRE(result["error"]["code"] == code); 54 | REQUIRE(has_key_type(result["error"], "message", json::value_t::string)); 55 | REQUIRE(result["error"]["message"].get().find(message) != std::string::npos); 56 | 57 | return result["error"]; 58 | } 59 | 60 | private: 61 | JsonRpcServer &handler; 62 | string raw_response; 63 | }; 64 | -------------------------------------------------------------------------------- /test/typemapper.cpp: -------------------------------------------------------------------------------- 1 | #include "doctest/doctest.h" 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace jsonrpccxx; 7 | using namespace std; 8 | 9 | static string notifyResult = ""; 10 | 11 | int add(int a, int b) { return a + b; } 12 | void notify(const std::string &hello) { notifyResult = string("Hello world: ") + hello; } 13 | 14 | class SomeClass { 15 | public: 16 | int add(int a, int b) { return a + b; } 17 | void notify(const std::string &hello) { notifyResult = string("Hello world: ") + hello; } 18 | }; 19 | 20 | class SomeClassConst { 21 | public: 22 | int add(int a, int b) const { return a + b; } 23 | void notify(const std::string &hello) { notifyResult = string("Hello world: ") + hello; } 24 | }; 25 | 26 | 27 | TEST_CASE("test function binding") { 28 | MethodHandle mh = GetHandle(&add); 29 | CHECK(mh(R"([3, 4])"_json) == 7); 30 | 31 | notifyResult = ""; 32 | NotificationHandle mh2 = GetHandle(¬ify); 33 | CHECK(notifyResult.empty()); 34 | mh2(R"(["someone"])"_json); 35 | CHECK(notifyResult == "Hello world: someone"); 36 | } 37 | 38 | TEST_CASE("test class member binding") { 39 | SomeClass instance; 40 | MethodHandle mh = GetHandle(&SomeClass::add, instance); 41 | CHECK(mh(R"([3, 4])"_json) == 7); 42 | 43 | notifyResult = ""; 44 | NotificationHandle mh2 = GetHandle(&SomeClass::notify, instance); 45 | CHECK(notifyResult.empty()); 46 | mh2(R"(["someone"])"_json); 47 | CHECK(notifyResult == "Hello world: someone"); 48 | } 49 | 50 | TEST_CASE("test const class member binding") { 51 | SomeClassConst instance; 52 | MethodHandle mh = GetHandle(&SomeClassConst::add, instance); 53 | CHECK(mh(R"([3, 4])"_json) == 7); 54 | } 55 | 56 | TEST_CASE("test class member explicit binding") { 57 | SomeClass instance; 58 | MethodHandle mh = methodHandle(&SomeClass::add, instance); 59 | CHECK(mh(R"([3, 4])"_json) == 7); 60 | 61 | notifyResult = ""; 62 | NotificationHandle mh2 = notificationHandle(&SomeClass::notify, instance); 63 | CHECK(notifyResult.empty()); 64 | mh2(R"(["someone"])"_json); 65 | CHECK(notifyResult == "Hello world: someone"); 66 | } 67 | 68 | TEST_CASE("test incorrect params") { 69 | SomeClass instance; 70 | MethodHandle mh = GetHandle(&SomeClass::add, instance); 71 | REQUIRE_THROWS_WITH(mh(R"(["3", "4"])"_json), "-32602: invalid parameter: must be integer, but is string, data: 0"); 72 | REQUIRE_THROWS_WITH(mh(R"([true, true])"_json), "-32602: invalid parameter: must be integer, but is boolean, data: 0"); 73 | REQUIRE_THROWS_WITH(mh(R"([null, 3])"_json), "-32602: invalid parameter: must be integer, but is null, data: 0"); 74 | REQUIRE_THROWS_WITH(mh(R"([{"a": true}, 3])"_json), "-32602: invalid parameter: must be integer, but is object, data: 0"); 75 | REQUIRE_THROWS_WITH(mh(R"([[2,3], 3])"_json), "-32602: invalid parameter: must be integer, but is array, data: 0"); 76 | REQUIRE_THROWS_WITH(mh(R"([3.4, 3])"_json), "-32602: invalid parameter: must be integer, but is float, data: 0"); 77 | REQUIRE_THROWS_WITH(mh(R"([4])"_json), "-32602: invalid parameter: expected 2 argument(s), but found 1"); 78 | REQUIRE_THROWS_WITH(mh(R"([5, 6, 5])"_json), "-32602: invalid parameter: expected 2 argument(s), but found 3"); 79 | 80 | notifyResult = ""; 81 | NotificationHandle mh2 = GetHandle(&SomeClass::notify, instance); 82 | REQUIRE_THROWS_WITH(mh2(R"([33])"_json), "-32602: invalid parameter: must be string, but is unsigned integer, data: 0"); 83 | REQUIRE_THROWS_WITH(mh2(R"([-33])"_json), "-32602: invalid parameter: must be string, but is integer, data: 0"); 84 | REQUIRE_THROWS_WITH(mh2(R"(["someone", "anotherone"])"_json), "-32602: invalid parameter: expected 1 argument(s), but found 2"); 85 | REQUIRE_THROWS_WITH(mh2(R"([])"_json), "-32602: invalid parameter: expected 1 argument(s), but found 0"); 86 | REQUIRE_THROWS_WITH(mh2(R"([true])"_json), "-32602: invalid parameter: must be string, but is boolean, data: 0"); 87 | REQUIRE_THROWS_WITH(mh2(R"([null])"_json), "-32602: invalid parameter: must be string, but is null, data: 0"); 88 | REQUIRE_THROWS_WITH(mh2(R"([3.4])"_json), "-32602: invalid parameter: must be string, but is float, data: 0"); 89 | REQUIRE_THROWS_WITH(mh2(R"([{"a": true}])"_json), "-32602: invalid parameter: must be string, but is object, data: 0"); 90 | REQUIRE_THROWS_WITH(mh2(R"([["some string"]])"_json), "-32602: invalid parameter: must be string, but is array, data: 0"); 91 | 92 | CHECK(notifyResult.empty()); 93 | } 94 | 95 | enum class category { order, cash_carry }; 96 | 97 | struct product { 98 | product() : id(), price(), name(), cat() {} 99 | int id; 100 | double price; 101 | string name; 102 | category cat; 103 | }; 104 | 105 | NLOHMANN_JSON_SERIALIZE_ENUM(category, {{category::order, "order"}, {category::cash_carry, "cc"}}) 106 | 107 | void to_json(json &j, const product &p) { j = json{{"id", p.id}, {"price", p.price}, {"name", p.name}, {"category", p.cat}}; } 108 | 109 | product get_product(int id) { 110 | if (id == 1) { 111 | product p; 112 | p.id = 1; 113 | p.price = 22.50; 114 | p.name = "some product"; 115 | p.cat = category::order; 116 | return p; 117 | } 118 | else if (id == 2) { 119 | product p; 120 | p.id = 2; 121 | p.price = 55.50; 122 | p.name = "some product 2"; 123 | p.cat = category::cash_carry; 124 | return p; 125 | } 126 | throw JsonRpcException(-50000, "product not found"); 127 | } 128 | 129 | TEST_CASE("test with custom struct return") { 130 | MethodHandle mh = GetHandle(&get_product); 131 | json j = mh(R"([1])"_json); 132 | CHECK(j["id"] == 1); 133 | CHECK(j["name"] == "some product"); 134 | CHECK(j["price"] == 22.5); 135 | CHECK(j["category"] == category::order); 136 | 137 | j = mh(R"([2])"_json); 138 | CHECK(j["id"] == 2); 139 | CHECK(j["name"] == "some product 2"); 140 | CHECK(j["price"] == 55.5); 141 | CHECK(j["category"] == category::cash_carry); 142 | 143 | REQUIRE_THROWS_WITH(mh(R"([444])"_json), "-50000: product not found"); 144 | } 145 | 146 | void from_json(const json &j, product &p) { 147 | j.at("name").get_to(p.name); 148 | j.at("id").get_to(p.id); 149 | j.at("price").get_to(p.price); 150 | j.at("category").get_to(p.cat); 151 | } 152 | 153 | static vector catalog; 154 | bool add_products(const vector &products) { 155 | std::copy(products.begin(), products.end(), std::back_inserter(catalog)); 156 | return true; 157 | } 158 | 159 | string enumToString(const category& category) { 160 | switch (category) { 161 | case category::cash_carry: return "cash&carry"; 162 | case category::order: return "online-order"; 163 | default: return "unknown category"; 164 | } 165 | } 166 | 167 | TEST_CASE("test with enum as top level parameter") { 168 | MethodHandle mh = GetHandle(&enumToString); 169 | 170 | json params = R"(["cc"])"_json; 171 | CHECK(mh(params) == "cash&carry"); 172 | } 173 | 174 | TEST_CASE("test with custom params") { 175 | MethodHandle mh = GetHandle(&add_products); 176 | catalog.clear(); 177 | json params = 178 | R"([[{"id": 1, "price": 22.50, "name": "some product", "category": "order"}, {"id": 2, "price": 55.50, "name": "some product 2", "category": "cc"}]])"_json; 179 | 180 | CHECK(mh(params) == true); 181 | REQUIRE(catalog.size() == 2); 182 | 183 | CHECK(catalog[0].id == 1); 184 | CHECK(catalog[0].name == "some product"); 185 | CHECK(catalog[0].price == 22.5); 186 | CHECK(catalog[0].cat == category::order); 187 | CHECK(catalog[1].id == 2); 188 | CHECK(catalog[1].name == "some product 2"); 189 | CHECK(catalog[1].price == 55.5); 190 | CHECK(catalog[1].cat == category::cash_carry); 191 | 192 | REQUIRE_THROWS_WITH(mh(R"([[{"id": 1, "price": 22.50}]])"_json), "[json.exception.out_of_range.403] key 'name' not found"); 193 | REQUIRE_THROWS_WITH(mh(R"([{"id": 1, "price": 22.50}])"_json), "-32602: invalid parameter: must be array, but is object, data: 0"); 194 | } 195 | 196 | unsigned long unsigned_add(unsigned int a, int b) { return a + b; } 197 | unsigned long unsigned_add2(unsigned short a, short b) { return a + b; } 198 | float float_add(float a, float b) { return a+b; } 199 | 200 | TEST_CASE("test number range checking") { 201 | MethodHandle mh = GetHandle(&unsigned_add); 202 | 203 | REQUIRE_THROWS_WITH(mh(R"([-3,3])"_json), "-32602: invalid parameter: must be unsigned integer, but is integer, data: 0"); 204 | REQUIRE_THROWS_WITH(mh(R"([null,3])"_json), "-32602: invalid parameter: must be unsigned integer, but is null, data: 0"); 205 | 206 | unsigned int max_us = numeric_limits::max(); 207 | unsigned int max_s = numeric_limits::max(); 208 | CHECK(mh({max_us, max_s}) == max_us + max_s); 209 | REQUIRE_THROWS_WITH(mh({max_us, max_us}), "-32602: invalid parameter: exceeds value range of integer, data: 1"); 210 | 211 | MethodHandle mh2 = GetHandle(&unsigned_add2); 212 | unsigned short max_su = numeric_limits::max(); 213 | unsigned short max_ss = numeric_limits::max(); 214 | CHECK(mh2({max_su, max_ss}) == max_su + max_ss); 215 | REQUIRE_THROWS_WITH(mh2({max_su, max_su}), "-32602: invalid parameter: exceeds value range of integer, data: 1"); 216 | } 217 | 218 | TEST_CASE("test auto conversion of float to int passed to float method") { 219 | MethodHandle mh = GetHandle(&float_add); 220 | CHECK(mh(R"([3,3])"_json) == 6.0); 221 | CHECK(mh(R"([3.0,3.0])"_json) == 6.0); 222 | CHECK(mh(R"([3.1,3.2])"_json) == doctest::Approx(6.3)); 223 | } 224 | 225 | json arbitrary_json(const json& value) { 226 | return value; 227 | } 228 | 229 | void arbitrary_json_notification(const json& value) { 230 | to_string(value); 231 | } 232 | 233 | TEST_CASE("test json method handles without specific types") { 234 | MethodHandle mh = GetUncheckedHandle(&arbitrary_json); 235 | CHECK(mh(R"([3,"string"])"_json) == R"([3,"string"])"_json); 236 | auto param = R"({"a": "string"})"_json; 237 | CHECK(mh(param) == param); 238 | 239 | NotificationHandle nh = GetUncheckedNotificationHandle(&arbitrary_json_notification); 240 | nh(R"([3,"string"])"_json); 241 | nh(R"({"3": "string"})"_json); 242 | } -------------------------------------------------------------------------------- /test/warehouseapp.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "../examples/warehouse/warehouseapp.hpp" 3 | #include "doctest/doctest.h" 4 | #include "integrationtest.hpp" 5 | 6 | TEST_CASE_FIXTURE(IntegrationTest, "warehouse_test") { 7 | WarehouseServer app; 8 | rpcServer.Add("GetProduct", GetHandle(&WarehouseServer::GetProduct, app)); 9 | rpcServer.Add("AddProduct", GetHandle(&WarehouseServer::AddProduct, app)); 10 | 11 | Product p; 12 | p.id = "0xff"; 13 | p.price = 22.4; 14 | p.name = "Product 1"; 15 | p.cat = category::cash_carry; 16 | CHECK(client.CallMethod(1, "AddProduct", {p})); 17 | 18 | Product p2 = client.CallMethod(1, "GetProduct", {"0xff"}); 19 | CHECK((p2.id == p.id && p2.name == p.name && p2.price == p.price && p2.cat == p.cat)); 20 | } 21 | -------------------------------------------------------------------------------- /vendor/cpp-httplib/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 yhirose 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /vendor/nlohmann/adl_serializer.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace nlohmann 12 | { 13 | 14 | /// @sa https://json.nlohmann.me/api/adl_serializer/ 15 | template 16 | struct adl_serializer 17 | { 18 | /// @brief convert a JSON value to any value type 19 | /// @sa https://json.nlohmann.me/api/adl_serializer/from_json/ 20 | template 21 | static auto from_json(BasicJsonType && j, TargetType& val) noexcept( 22 | noexcept(::nlohmann::from_json(std::forward(j), val))) 23 | -> decltype(::nlohmann::from_json(std::forward(j), val), void()) 24 | { 25 | ::nlohmann::from_json(std::forward(j), val); 26 | } 27 | 28 | /// @brief convert a JSON value to any value type 29 | /// @sa https://json.nlohmann.me/api/adl_serializer/from_json/ 30 | template 31 | static auto from_json(BasicJsonType && j) noexcept( 32 | noexcept(::nlohmann::from_json(std::forward(j), detail::identity_tag {}))) 33 | -> decltype(::nlohmann::from_json(std::forward(j), detail::identity_tag {})) 34 | { 35 | return ::nlohmann::from_json(std::forward(j), detail::identity_tag {}); 36 | } 37 | 38 | /// @brief convert any value type to a JSON value 39 | /// @sa https://json.nlohmann.me/api/adl_serializer/to_json/ 40 | template 41 | static auto to_json(BasicJsonType& j, TargetType && val) noexcept( 42 | noexcept(::nlohmann::to_json(j, std::forward(val)))) 43 | -> decltype(::nlohmann::to_json(j, std::forward(val)), void()) 44 | { 45 | ::nlohmann::to_json(j, std::forward(val)); 46 | } 47 | }; 48 | } // namespace nlohmann 49 | -------------------------------------------------------------------------------- /vendor/nlohmann/byte_container_with_subtype.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // uint8_t, uint64_t 4 | #include // tie 5 | #include // move 6 | 7 | namespace nlohmann 8 | { 9 | 10 | /// @brief an internal type for a backed binary type 11 | /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/ 12 | template 13 | class byte_container_with_subtype : public BinaryType 14 | { 15 | public: 16 | using container_type = BinaryType; 17 | using subtype_type = std::uint64_t; 18 | 19 | /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/ 20 | byte_container_with_subtype() noexcept(noexcept(container_type())) 21 | : container_type() 22 | {} 23 | 24 | /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/ 25 | byte_container_with_subtype(const container_type& b) noexcept(noexcept(container_type(b))) 26 | : container_type(b) 27 | {} 28 | 29 | /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/ 30 | byte_container_with_subtype(container_type&& b) noexcept(noexcept(container_type(std::move(b)))) 31 | : container_type(std::move(b)) 32 | {} 33 | 34 | /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/ 35 | byte_container_with_subtype(const container_type& b, subtype_type subtype_) noexcept(noexcept(container_type(b))) 36 | : container_type(b) 37 | , m_subtype(subtype_) 38 | , m_has_subtype(true) 39 | {} 40 | 41 | /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/ 42 | byte_container_with_subtype(container_type&& b, subtype_type subtype_) noexcept(noexcept(container_type(std::move(b)))) 43 | : container_type(std::move(b)) 44 | , m_subtype(subtype_) 45 | , m_has_subtype(true) 46 | {} 47 | 48 | bool operator==(const byte_container_with_subtype& rhs) const 49 | { 50 | return std::tie(static_cast(*this), m_subtype, m_has_subtype) == 51 | std::tie(static_cast(rhs), rhs.m_subtype, rhs.m_has_subtype); 52 | } 53 | 54 | bool operator!=(const byte_container_with_subtype& rhs) const 55 | { 56 | return !(rhs == *this); 57 | } 58 | 59 | /// @brief sets the binary subtype 60 | /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/set_subtype/ 61 | void set_subtype(subtype_type subtype_) noexcept 62 | { 63 | m_subtype = subtype_; 64 | m_has_subtype = true; 65 | } 66 | 67 | /// @brief return the binary subtype 68 | /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/subtype/ 69 | constexpr subtype_type subtype() const noexcept 70 | { 71 | return m_has_subtype ? m_subtype : static_cast(-1); 72 | } 73 | 74 | /// @brief return whether the value has a subtype 75 | /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/has_subtype/ 76 | constexpr bool has_subtype() const noexcept 77 | { 78 | return m_has_subtype; 79 | } 80 | 81 | /// @brief clears the binary subtype 82 | /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/clear_subtype/ 83 | void clear_subtype() noexcept 84 | { 85 | m_subtype = 0; 86 | m_has_subtype = false; 87 | } 88 | 89 | private: 90 | subtype_type m_subtype = 0; 91 | bool m_has_subtype = false; 92 | }; 93 | 94 | } // namespace nlohmann 95 | -------------------------------------------------------------------------------- /vendor/nlohmann/detail/conversions/to_json.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // copy 4 | #include // begin, end 5 | #include // string 6 | #include // tuple, get 7 | #include // is_same, is_constructible, is_floating_point, is_enum, underlying_type 8 | #include // move, forward, declval, pair 9 | #include // valarray 10 | #include // vector 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #if JSON_HAS_EXPERIMENTAL_FILESYSTEM 19 | #include 20 | namespace nlohmann::detail 21 | { 22 | namespace std_fs = std::experimental::filesystem; 23 | } // namespace nlohmann::detail 24 | #elif JSON_HAS_FILESYSTEM 25 | #include 26 | namespace nlohmann::detail 27 | { 28 | namespace std_fs = std::filesystem; 29 | } // namespace nlohmann::detail 30 | #endif 31 | 32 | namespace nlohmann 33 | { 34 | namespace detail 35 | { 36 | ////////////////// 37 | // constructors // 38 | ////////////////// 39 | 40 | /* 41 | * Note all external_constructor<>::construct functions need to call 42 | * j.m_value.destroy(j.m_type) to avoid a memory leak in case j contains an 43 | * allocated value (e.g., a string). See bug issue 44 | * https://github.com/nlohmann/json/issues/2865 for more information. 45 | */ 46 | 47 | template struct external_constructor; 48 | 49 | template<> 50 | struct external_constructor 51 | { 52 | template 53 | static void construct(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept 54 | { 55 | j.m_value.destroy(j.m_type); 56 | j.m_type = value_t::boolean; 57 | j.m_value = b; 58 | j.assert_invariant(); 59 | } 60 | }; 61 | 62 | template<> 63 | struct external_constructor 64 | { 65 | template 66 | static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s) 67 | { 68 | j.m_value.destroy(j.m_type); 69 | j.m_type = value_t::string; 70 | j.m_value = s; 71 | j.assert_invariant(); 72 | } 73 | 74 | template 75 | static void construct(BasicJsonType& j, typename BasicJsonType::string_t&& s) 76 | { 77 | j.m_value.destroy(j.m_type); 78 | j.m_type = value_t::string; 79 | j.m_value = std::move(s); 80 | j.assert_invariant(); 81 | } 82 | 83 | template < typename BasicJsonType, typename CompatibleStringType, 84 | enable_if_t < !std::is_same::value, 85 | int > = 0 > 86 | static void construct(BasicJsonType& j, const CompatibleStringType& str) 87 | { 88 | j.m_value.destroy(j.m_type); 89 | j.m_type = value_t::string; 90 | j.m_value.string = j.template create(str); 91 | j.assert_invariant(); 92 | } 93 | }; 94 | 95 | template<> 96 | struct external_constructor 97 | { 98 | template 99 | static void construct(BasicJsonType& j, const typename BasicJsonType::binary_t& b) 100 | { 101 | j.m_value.destroy(j.m_type); 102 | j.m_type = value_t::binary; 103 | j.m_value = typename BasicJsonType::binary_t(b); 104 | j.assert_invariant(); 105 | } 106 | 107 | template 108 | static void construct(BasicJsonType& j, typename BasicJsonType::binary_t&& b) 109 | { 110 | j.m_value.destroy(j.m_type); 111 | j.m_type = value_t::binary; 112 | j.m_value = typename BasicJsonType::binary_t(std::move(b)); 113 | j.assert_invariant(); 114 | } 115 | }; 116 | 117 | template<> 118 | struct external_constructor 119 | { 120 | template 121 | static void construct(BasicJsonType& j, typename BasicJsonType::number_float_t val) noexcept 122 | { 123 | j.m_value.destroy(j.m_type); 124 | j.m_type = value_t::number_float; 125 | j.m_value = val; 126 | j.assert_invariant(); 127 | } 128 | }; 129 | 130 | template<> 131 | struct external_constructor 132 | { 133 | template 134 | static void construct(BasicJsonType& j, typename BasicJsonType::number_unsigned_t val) noexcept 135 | { 136 | j.m_value.destroy(j.m_type); 137 | j.m_type = value_t::number_unsigned; 138 | j.m_value = val; 139 | j.assert_invariant(); 140 | } 141 | }; 142 | 143 | template<> 144 | struct external_constructor 145 | { 146 | template 147 | static void construct(BasicJsonType& j, typename BasicJsonType::number_integer_t val) noexcept 148 | { 149 | j.m_value.destroy(j.m_type); 150 | j.m_type = value_t::number_integer; 151 | j.m_value = val; 152 | j.assert_invariant(); 153 | } 154 | }; 155 | 156 | template<> 157 | struct external_constructor 158 | { 159 | template 160 | static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr) 161 | { 162 | j.m_value.destroy(j.m_type); 163 | j.m_type = value_t::array; 164 | j.m_value = arr; 165 | j.set_parents(); 166 | j.assert_invariant(); 167 | } 168 | 169 | template 170 | static void construct(BasicJsonType& j, typename BasicJsonType::array_t&& arr) 171 | { 172 | j.m_value.destroy(j.m_type); 173 | j.m_type = value_t::array; 174 | j.m_value = std::move(arr); 175 | j.set_parents(); 176 | j.assert_invariant(); 177 | } 178 | 179 | template < typename BasicJsonType, typename CompatibleArrayType, 180 | enable_if_t < !std::is_same::value, 181 | int > = 0 > 182 | static void construct(BasicJsonType& j, const CompatibleArrayType& arr) 183 | { 184 | using std::begin; 185 | using std::end; 186 | 187 | j.m_value.destroy(j.m_type); 188 | j.m_type = value_t::array; 189 | j.m_value.array = j.template create(begin(arr), end(arr)); 190 | j.set_parents(); 191 | j.assert_invariant(); 192 | } 193 | 194 | template 195 | static void construct(BasicJsonType& j, const std::vector& arr) 196 | { 197 | j.m_value.destroy(j.m_type); 198 | j.m_type = value_t::array; 199 | j.m_value = value_t::array; 200 | j.m_value.array->reserve(arr.size()); 201 | for (const bool x : arr) 202 | { 203 | j.m_value.array->push_back(x); 204 | j.set_parent(j.m_value.array->back()); 205 | } 206 | j.assert_invariant(); 207 | } 208 | 209 | template::value, int> = 0> 211 | static void construct(BasicJsonType& j, const std::valarray& arr) 212 | { 213 | j.m_value.destroy(j.m_type); 214 | j.m_type = value_t::array; 215 | j.m_value = value_t::array; 216 | j.m_value.array->resize(arr.size()); 217 | if (arr.size() > 0) 218 | { 219 | std::copy(std::begin(arr), std::end(arr), j.m_value.array->begin()); 220 | } 221 | j.set_parents(); 222 | j.assert_invariant(); 223 | } 224 | }; 225 | 226 | template<> 227 | struct external_constructor 228 | { 229 | template 230 | static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj) 231 | { 232 | j.m_value.destroy(j.m_type); 233 | j.m_type = value_t::object; 234 | j.m_value = obj; 235 | j.set_parents(); 236 | j.assert_invariant(); 237 | } 238 | 239 | template 240 | static void construct(BasicJsonType& j, typename BasicJsonType::object_t&& obj) 241 | { 242 | j.m_value.destroy(j.m_type); 243 | j.m_type = value_t::object; 244 | j.m_value = std::move(obj); 245 | j.set_parents(); 246 | j.assert_invariant(); 247 | } 248 | 249 | template < typename BasicJsonType, typename CompatibleObjectType, 250 | enable_if_t < !std::is_same::value, int > = 0 > 251 | static void construct(BasicJsonType& j, const CompatibleObjectType& obj) 252 | { 253 | using std::begin; 254 | using std::end; 255 | 256 | j.m_value.destroy(j.m_type); 257 | j.m_type = value_t::object; 258 | j.m_value.object = j.template create(begin(obj), end(obj)); 259 | j.set_parents(); 260 | j.assert_invariant(); 261 | } 262 | }; 263 | 264 | ///////////// 265 | // to_json // 266 | ///////////// 267 | 268 | template::value, int> = 0> 270 | void to_json(BasicJsonType& j, T b) noexcept 271 | { 272 | external_constructor::construct(j, b); 273 | } 274 | 275 | template::value, int> = 0> 277 | void to_json(BasicJsonType& j, const CompatibleString& s) 278 | { 279 | external_constructor::construct(j, s); 280 | } 281 | 282 | template 283 | void to_json(BasicJsonType& j, typename BasicJsonType::string_t&& s) 284 | { 285 | external_constructor::construct(j, std::move(s)); 286 | } 287 | 288 | template::value, int> = 0> 290 | void to_json(BasicJsonType& j, FloatType val) noexcept 291 | { 292 | external_constructor::construct(j, static_cast(val)); 293 | } 294 | 295 | template::value, int> = 0> 297 | void to_json(BasicJsonType& j, CompatibleNumberUnsignedType val) noexcept 298 | { 299 | external_constructor::construct(j, static_cast(val)); 300 | } 301 | 302 | template::value, int> = 0> 304 | void to_json(BasicJsonType& j, CompatibleNumberIntegerType val) noexcept 305 | { 306 | external_constructor::construct(j, static_cast(val)); 307 | } 308 | 309 | template::value, int> = 0> 311 | void to_json(BasicJsonType& j, EnumType e) noexcept 312 | { 313 | using underlying_type = typename std::underlying_type::type; 314 | external_constructor::construct(j, static_cast(e)); 315 | } 316 | 317 | template 318 | void to_json(BasicJsonType& j, const std::vector& e) 319 | { 320 | external_constructor::construct(j, e); 321 | } 322 | 323 | template < typename BasicJsonType, typename CompatibleArrayType, 324 | enable_if_t < is_compatible_array_type::value&& 326 | !is_compatible_object_type::value&& 327 | !is_compatible_string_type::value&& 328 | !std::is_same::value&& 329 | !is_basic_json::value, 330 | int > = 0 > 331 | void to_json(BasicJsonType& j, const CompatibleArrayType& arr) 332 | { 333 | external_constructor::construct(j, arr); 334 | } 335 | 336 | template 337 | void to_json(BasicJsonType& j, const typename BasicJsonType::binary_t& bin) 338 | { 339 | external_constructor::construct(j, bin); 340 | } 341 | 342 | template::value, int> = 0> 344 | void to_json(BasicJsonType& j, const std::valarray& arr) 345 | { 346 | external_constructor::construct(j, std::move(arr)); 347 | } 348 | 349 | template 350 | void to_json(BasicJsonType& j, typename BasicJsonType::array_t&& arr) 351 | { 352 | external_constructor::construct(j, std::move(arr)); 353 | } 354 | 355 | template < typename BasicJsonType, typename CompatibleObjectType, 356 | enable_if_t < is_compatible_object_type::value&& !is_basic_json::value, int > = 0 > 357 | void to_json(BasicJsonType& j, const CompatibleObjectType& obj) 358 | { 359 | external_constructor::construct(j, obj); 360 | } 361 | 362 | template 363 | void to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj) 364 | { 365 | external_constructor::construct(j, std::move(obj)); 366 | } 367 | 368 | template < 369 | typename BasicJsonType, typename T, std::size_t N, 370 | enable_if_t < !std::is_constructible::value, // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) 372 | int > = 0 > 373 | void to_json(BasicJsonType& j, const T(&arr)[N]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) 374 | { 375 | external_constructor::construct(j, arr); 376 | } 377 | 378 | template < typename BasicJsonType, typename T1, typename T2, enable_if_t < std::is_constructible::value&& std::is_constructible::value, int > = 0 > 379 | void to_json(BasicJsonType& j, const std::pair& p) 380 | { 381 | j = { p.first, p.second }; 382 | } 383 | 384 | // for https://github.com/nlohmann/json/pull/1134 385 | template>::value, int> = 0> 387 | void to_json(BasicJsonType& j, const T& b) 388 | { 389 | j = { {b.key(), b.value()} }; 390 | } 391 | 392 | template 393 | void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence /*unused*/) 394 | { 395 | j = { std::get(t)... }; 396 | } 397 | 398 | template::value, int > = 0> 399 | void to_json(BasicJsonType& j, const T& t) 400 | { 401 | to_json_tuple_impl(j, t, make_index_sequence::value> {}); 402 | } 403 | 404 | #if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM 405 | template 406 | void to_json(BasicJsonType& j, const std_fs::path& p) 407 | { 408 | j = p.string(); 409 | } 410 | #endif 411 | 412 | struct to_json_fn 413 | { 414 | template 415 | auto operator()(BasicJsonType& j, T&& val) const noexcept(noexcept(to_json(j, std::forward(val)))) 416 | -> decltype(to_json(j, std::forward(val)), void()) 417 | { 418 | return to_json(j, std::forward(val)); 419 | } 420 | }; 421 | } // namespace detail 422 | 423 | /// namespace to hold default `to_json` function 424 | /// to see why this is required: 425 | /// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html 426 | namespace // NOLINT(cert-dcl59-cpp,fuchsia-header-anon-namespaces,google-build-namespaces) 427 | { 428 | constexpr const auto& to_json = detail::static_const::value; // NOLINT(misc-definitions-in-headers) 429 | } // namespace 430 | } // namespace nlohmann 431 | -------------------------------------------------------------------------------- /vendor/nlohmann/detail/exceptions.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // exception 4 | #include // runtime_error 5 | #include // to_string 6 | #include // vector 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | namespace nlohmann 14 | { 15 | namespace detail 16 | { 17 | //////////////// 18 | // exceptions // 19 | //////////////// 20 | 21 | /// @brief general exception of the @ref basic_json class 22 | /// @sa https://json.nlohmann.me/api/basic_json/exception/ 23 | class exception : public std::exception 24 | { 25 | public: 26 | /// returns the explanatory string 27 | const char* what() const noexcept override 28 | { 29 | return m.what(); 30 | } 31 | 32 | /// the id of the exception 33 | const int id; // NOLINT(cppcoreguidelines-non-private-member-variables-in-classes) 34 | 35 | protected: 36 | JSON_HEDLEY_NON_NULL(3) 37 | exception(int id_, const char* what_arg) : id(id_), m(what_arg) {} // NOLINT(bugprone-throw-keyword-missing) 38 | 39 | static std::string name(const std::string& ename, int id_) 40 | { 41 | return "[json.exception." + ename + "." + std::to_string(id_) + "] "; 42 | } 43 | 44 | template 45 | static std::string diagnostics(const BasicJsonType& leaf_element) 46 | { 47 | #if JSON_DIAGNOSTICS 48 | std::vector tokens; 49 | for (const auto* current = &leaf_element; current->m_parent != nullptr; current = current->m_parent) 50 | { 51 | switch (current->m_parent->type()) 52 | { 53 | case value_t::array: 54 | { 55 | for (std::size_t i = 0; i < current->m_parent->m_value.array->size(); ++i) 56 | { 57 | if (¤t->m_parent->m_value.array->operator[](i) == current) 58 | { 59 | tokens.emplace_back(std::to_string(i)); 60 | break; 61 | } 62 | } 63 | break; 64 | } 65 | 66 | case value_t::object: 67 | { 68 | for (const auto& element : *current->m_parent->m_value.object) 69 | { 70 | if (&element.second == current) 71 | { 72 | tokens.emplace_back(element.first.c_str()); 73 | break; 74 | } 75 | } 76 | break; 77 | } 78 | 79 | case value_t::null: // LCOV_EXCL_LINE 80 | case value_t::string: // LCOV_EXCL_LINE 81 | case value_t::boolean: // LCOV_EXCL_LINE 82 | case value_t::number_integer: // LCOV_EXCL_LINE 83 | case value_t::number_unsigned: // LCOV_EXCL_LINE 84 | case value_t::number_float: // LCOV_EXCL_LINE 85 | case value_t::binary: // LCOV_EXCL_LINE 86 | case value_t::discarded: // LCOV_EXCL_LINE 87 | default: // LCOV_EXCL_LINE 88 | break; // LCOV_EXCL_LINE 89 | } 90 | } 91 | 92 | if (tokens.empty()) 93 | { 94 | return ""; 95 | } 96 | 97 | return "(" + std::accumulate(tokens.rbegin(), tokens.rend(), std::string{}, 98 | [](const std::string & a, const std::string & b) 99 | { 100 | return a + "/" + detail::escape(b); 101 | }) + ") "; 102 | #else 103 | static_cast(leaf_element); 104 | return ""; 105 | #endif 106 | } 107 | 108 | private: 109 | /// an exception object as storage for error messages 110 | std::runtime_error m; 111 | }; 112 | 113 | /// @brief exception indicating a parse error 114 | /// @sa https://json.nlohmann.me/api/basic_json/parse_error/ 115 | class parse_error : public exception 116 | { 117 | public: 118 | /*! 119 | @brief create a parse error exception 120 | @param[in] id_ the id of the exception 121 | @param[in] pos the position where the error occurred (or with 122 | chars_read_total=0 if the position cannot be 123 | determined) 124 | @param[in] what_arg the explanatory string 125 | @return parse_error object 126 | */ 127 | template 128 | static parse_error create(int id_, const position_t& pos, const std::string& what_arg, const BasicJsonType& context) 129 | { 130 | std::string w = exception::name("parse_error", id_) + "parse error" + 131 | position_string(pos) + ": " + exception::diagnostics(context) + what_arg; 132 | return {id_, pos.chars_read_total, w.c_str()}; 133 | } 134 | 135 | template 136 | static parse_error create(int id_, std::size_t byte_, const std::string& what_arg, const BasicJsonType& context) 137 | { 138 | std::string w = exception::name("parse_error", id_) + "parse error" + 139 | (byte_ != 0 ? (" at byte " + std::to_string(byte_)) : "") + 140 | ": " + exception::diagnostics(context) + what_arg; 141 | return {id_, byte_, w.c_str()}; 142 | } 143 | 144 | /*! 145 | @brief byte index of the parse error 146 | 147 | The byte index of the last read character in the input file. 148 | 149 | @note For an input with n bytes, 1 is the index of the first character and 150 | n+1 is the index of the terminating null byte or the end of file. 151 | This also holds true when reading a byte vector (CBOR or MessagePack). 152 | */ 153 | const std::size_t byte; 154 | 155 | private: 156 | parse_error(int id_, std::size_t byte_, const char* what_arg) 157 | : exception(id_, what_arg), byte(byte_) {} 158 | 159 | static std::string position_string(const position_t& pos) 160 | { 161 | return " at line " + std::to_string(pos.lines_read + 1) + 162 | ", column " + std::to_string(pos.chars_read_current_line); 163 | } 164 | }; 165 | 166 | /// @brief exception indicating errors with iterators 167 | /// @sa https://json.nlohmann.me/api/basic_json/invalid_iterator/ 168 | class invalid_iterator : public exception 169 | { 170 | public: 171 | template 172 | static invalid_iterator create(int id_, const std::string& what_arg, const BasicJsonType& context) 173 | { 174 | std::string w = exception::name("invalid_iterator", id_) + exception::diagnostics(context) + what_arg; 175 | return {id_, w.c_str()}; 176 | } 177 | 178 | private: 179 | JSON_HEDLEY_NON_NULL(3) 180 | invalid_iterator(int id_, const char* what_arg) 181 | : exception(id_, what_arg) {} 182 | }; 183 | 184 | /// @brief exception indicating executing a member function with a wrong type 185 | /// @sa https://json.nlohmann.me/api/basic_json/type_error/ 186 | class type_error : public exception 187 | { 188 | public: 189 | template 190 | static type_error create(int id_, const std::string& what_arg, const BasicJsonType& context) 191 | { 192 | std::string w = exception::name("type_error", id_) + exception::diagnostics(context) + what_arg; 193 | return {id_, w.c_str()}; 194 | } 195 | 196 | private: 197 | JSON_HEDLEY_NON_NULL(3) 198 | type_error(int id_, const char* what_arg) : exception(id_, what_arg) {} 199 | }; 200 | 201 | /// @brief exception indicating access out of the defined range 202 | /// @sa https://json.nlohmann.me/api/basic_json/out_of_range/ 203 | class out_of_range : public exception 204 | { 205 | public: 206 | template 207 | static out_of_range create(int id_, const std::string& what_arg, const BasicJsonType& context) 208 | { 209 | std::string w = exception::name("out_of_range", id_) + exception::diagnostics(context) + what_arg; 210 | return {id_, w.c_str()}; 211 | } 212 | 213 | private: 214 | JSON_HEDLEY_NON_NULL(3) 215 | out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {} 216 | }; 217 | 218 | /// @brief exception indicating other library errors 219 | /// @sa https://json.nlohmann.me/api/basic_json/other_error/ 220 | class other_error : public exception 221 | { 222 | public: 223 | template 224 | static other_error create(int id_, const std::string& what_arg, const BasicJsonType& context) 225 | { 226 | std::string w = exception::name("other_error", id_) + exception::diagnostics(context) + what_arg; 227 | return {id_, w.c_str()}; 228 | } 229 | 230 | private: 231 | JSON_HEDLEY_NON_NULL(3) 232 | other_error(int id_, const char* what_arg) : exception(id_, what_arg) {} 233 | }; 234 | 235 | } // namespace detail 236 | } // namespace nlohmann 237 | -------------------------------------------------------------------------------- /vendor/nlohmann/detail/hash.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // uint8_t 4 | #include // size_t 5 | #include // hash 6 | 7 | #include 8 | #include 9 | 10 | namespace nlohmann 11 | { 12 | namespace detail 13 | { 14 | 15 | // boost::hash_combine 16 | inline std::size_t combine(std::size_t seed, std::size_t h) noexcept 17 | { 18 | seed ^= h + 0x9e3779b9 + (seed << 6U) + (seed >> 2U); 19 | return seed; 20 | } 21 | 22 | /*! 23 | @brief hash a JSON value 24 | 25 | The hash function tries to rely on std::hash where possible. Furthermore, the 26 | type of the JSON value is taken into account to have different hash values for 27 | null, 0, 0U, and false, etc. 28 | 29 | @tparam BasicJsonType basic_json specialization 30 | @param j JSON value to hash 31 | @return hash value of j 32 | */ 33 | template 34 | std::size_t hash(const BasicJsonType& j) 35 | { 36 | using string_t = typename BasicJsonType::string_t; 37 | using number_integer_t = typename BasicJsonType::number_integer_t; 38 | using number_unsigned_t = typename BasicJsonType::number_unsigned_t; 39 | using number_float_t = typename BasicJsonType::number_float_t; 40 | 41 | const auto type = static_cast(j.type()); 42 | switch (j.type()) 43 | { 44 | case BasicJsonType::value_t::null: 45 | case BasicJsonType::value_t::discarded: 46 | { 47 | return combine(type, 0); 48 | } 49 | 50 | case BasicJsonType::value_t::object: 51 | { 52 | auto seed = combine(type, j.size()); 53 | for (const auto& element : j.items()) 54 | { 55 | const auto h = std::hash {}(element.key()); 56 | seed = combine(seed, h); 57 | seed = combine(seed, hash(element.value())); 58 | } 59 | return seed; 60 | } 61 | 62 | case BasicJsonType::value_t::array: 63 | { 64 | auto seed = combine(type, j.size()); 65 | for (const auto& element : j) 66 | { 67 | seed = combine(seed, hash(element)); 68 | } 69 | return seed; 70 | } 71 | 72 | case BasicJsonType::value_t::string: 73 | { 74 | const auto h = std::hash {}(j.template get_ref()); 75 | return combine(type, h); 76 | } 77 | 78 | case BasicJsonType::value_t::boolean: 79 | { 80 | const auto h = std::hash {}(j.template get()); 81 | return combine(type, h); 82 | } 83 | 84 | case BasicJsonType::value_t::number_integer: 85 | { 86 | const auto h = std::hash {}(j.template get()); 87 | return combine(type, h); 88 | } 89 | 90 | case BasicJsonType::value_t::number_unsigned: 91 | { 92 | const auto h = std::hash {}(j.template get()); 93 | return combine(type, h); 94 | } 95 | 96 | case BasicJsonType::value_t::number_float: 97 | { 98 | const auto h = std::hash {}(j.template get()); 99 | return combine(type, h); 100 | } 101 | 102 | case BasicJsonType::value_t::binary: 103 | { 104 | auto seed = combine(type, j.get_binary().size()); 105 | const auto h = std::hash {}(j.get_binary().has_subtype()); 106 | seed = combine(seed, h); 107 | seed = combine(seed, static_cast(j.get_binary().subtype())); 108 | for (const auto byte : j.get_binary()) 109 | { 110 | seed = combine(seed, std::hash {}(byte)); 111 | } 112 | return seed; 113 | } 114 | 115 | default: // LCOV_EXCL_LINE 116 | JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE 117 | return 0; // LCOV_EXCL_LINE 118 | } 119 | } 120 | 121 | } // namespace detail 122 | } // namespace nlohmann 123 | -------------------------------------------------------------------------------- /vendor/nlohmann/detail/input/input_adapters.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // array 4 | #include // size_t 5 | #include // strlen 6 | #include // begin, end, iterator_traits, random_access_iterator_tag, distance, next 7 | #include // shared_ptr, make_shared, addressof 8 | #include // accumulate 9 | #include // string, char_traits 10 | #include // enable_if, is_base_of, is_pointer, is_integral, remove_pointer 11 | #include // pair, declval 12 | 13 | #ifndef JSON_NO_IO 14 | #include // FILE * 15 | #include // istream 16 | #endif // JSON_NO_IO 17 | 18 | #include 19 | #include 20 | 21 | namespace nlohmann 22 | { 23 | namespace detail 24 | { 25 | /// the supported input formats 26 | enum class input_format_t { json, cbor, msgpack, ubjson, bson }; 27 | 28 | //////////////////// 29 | // input adapters // 30 | //////////////////// 31 | 32 | #ifndef JSON_NO_IO 33 | /*! 34 | Input adapter for stdio file access. This adapter read only 1 byte and do not use any 35 | buffer. This adapter is a very low level adapter. 36 | */ 37 | class file_input_adapter 38 | { 39 | public: 40 | using char_type = char; 41 | 42 | JSON_HEDLEY_NON_NULL(2) 43 | explicit file_input_adapter(std::FILE* f) noexcept 44 | : m_file(f) 45 | {} 46 | 47 | // make class move-only 48 | file_input_adapter(const file_input_adapter&) = delete; 49 | file_input_adapter(file_input_adapter&&) noexcept = default; 50 | file_input_adapter& operator=(const file_input_adapter&) = delete; 51 | file_input_adapter& operator=(file_input_adapter&&) = delete; 52 | ~file_input_adapter() = default; 53 | 54 | std::char_traits::int_type get_character() noexcept 55 | { 56 | return std::fgetc(m_file); 57 | } 58 | 59 | private: 60 | /// the file pointer to read from 61 | std::FILE* m_file; 62 | }; 63 | 64 | 65 | /*! 66 | Input adapter for a (caching) istream. Ignores a UFT Byte Order Mark at 67 | beginning of input. Does not support changing the underlying std::streambuf 68 | in mid-input. Maintains underlying std::istream and std::streambuf to support 69 | subsequent use of standard std::istream operations to process any input 70 | characters following those used in parsing the JSON input. Clears the 71 | std::istream flags; any input errors (e.g., EOF) will be detected by the first 72 | subsequent call for input from the std::istream. 73 | */ 74 | class input_stream_adapter 75 | { 76 | public: 77 | using char_type = char; 78 | 79 | ~input_stream_adapter() 80 | { 81 | // clear stream flags; we use underlying streambuf I/O, do not 82 | // maintain ifstream flags, except eof 83 | if (is != nullptr) 84 | { 85 | is->clear(is->rdstate() & std::ios::eofbit); 86 | } 87 | } 88 | 89 | explicit input_stream_adapter(std::istream& i) 90 | : is(&i), sb(i.rdbuf()) 91 | {} 92 | 93 | // delete because of pointer members 94 | input_stream_adapter(const input_stream_adapter&) = delete; 95 | input_stream_adapter& operator=(input_stream_adapter&) = delete; 96 | input_stream_adapter& operator=(input_stream_adapter&&) = delete; 97 | 98 | input_stream_adapter(input_stream_adapter&& rhs) noexcept 99 | : is(rhs.is), sb(rhs.sb) 100 | { 101 | rhs.is = nullptr; 102 | rhs.sb = nullptr; 103 | } 104 | 105 | // std::istream/std::streambuf use std::char_traits::to_int_type, to 106 | // ensure that std::char_traits::eof() and the character 0xFF do not 107 | // end up as the same value, e.g. 0xFFFFFFFF. 108 | std::char_traits::int_type get_character() 109 | { 110 | auto res = sb->sbumpc(); 111 | // set eof manually, as we don't use the istream interface. 112 | if (JSON_HEDLEY_UNLIKELY(res == std::char_traits::eof())) 113 | { 114 | is->clear(is->rdstate() | std::ios::eofbit); 115 | } 116 | return res; 117 | } 118 | 119 | private: 120 | /// the associated input stream 121 | std::istream* is = nullptr; 122 | std::streambuf* sb = nullptr; 123 | }; 124 | #endif // JSON_NO_IO 125 | 126 | // General-purpose iterator-based adapter. It might not be as fast as 127 | // theoretically possible for some containers, but it is extremely versatile. 128 | template 129 | class iterator_input_adapter 130 | { 131 | public: 132 | using char_type = typename std::iterator_traits::value_type; 133 | 134 | iterator_input_adapter(IteratorType first, IteratorType last) 135 | : current(std::move(first)), end(std::move(last)) 136 | {} 137 | 138 | typename std::char_traits::int_type get_character() 139 | { 140 | if (JSON_HEDLEY_LIKELY(current != end)) 141 | { 142 | auto result = std::char_traits::to_int_type(*current); 143 | std::advance(current, 1); 144 | return result; 145 | } 146 | 147 | return std::char_traits::eof(); 148 | } 149 | 150 | private: 151 | IteratorType current; 152 | IteratorType end; 153 | 154 | template 155 | friend struct wide_string_input_helper; 156 | 157 | bool empty() const 158 | { 159 | return current == end; 160 | } 161 | }; 162 | 163 | 164 | template 165 | struct wide_string_input_helper; 166 | 167 | template 168 | struct wide_string_input_helper 169 | { 170 | // UTF-32 171 | static void fill_buffer(BaseInputAdapter& input, 172 | std::array::int_type, 4>& utf8_bytes, 173 | size_t& utf8_bytes_index, 174 | size_t& utf8_bytes_filled) 175 | { 176 | utf8_bytes_index = 0; 177 | 178 | if (JSON_HEDLEY_UNLIKELY(input.empty())) 179 | { 180 | utf8_bytes[0] = std::char_traits::eof(); 181 | utf8_bytes_filled = 1; 182 | } 183 | else 184 | { 185 | // get the current character 186 | const auto wc = input.get_character(); 187 | 188 | // UTF-32 to UTF-8 encoding 189 | if (wc < 0x80) 190 | { 191 | utf8_bytes[0] = static_cast::int_type>(wc); 192 | utf8_bytes_filled = 1; 193 | } 194 | else if (wc <= 0x7FF) 195 | { 196 | utf8_bytes[0] = static_cast::int_type>(0xC0u | ((static_cast(wc) >> 6u) & 0x1Fu)); 197 | utf8_bytes[1] = static_cast::int_type>(0x80u | (static_cast(wc) & 0x3Fu)); 198 | utf8_bytes_filled = 2; 199 | } 200 | else if (wc <= 0xFFFF) 201 | { 202 | utf8_bytes[0] = static_cast::int_type>(0xE0u | ((static_cast(wc) >> 12u) & 0x0Fu)); 203 | utf8_bytes[1] = static_cast::int_type>(0x80u | ((static_cast(wc) >> 6u) & 0x3Fu)); 204 | utf8_bytes[2] = static_cast::int_type>(0x80u | (static_cast(wc) & 0x3Fu)); 205 | utf8_bytes_filled = 3; 206 | } 207 | else if (wc <= 0x10FFFF) 208 | { 209 | utf8_bytes[0] = static_cast::int_type>(0xF0u | ((static_cast(wc) >> 18u) & 0x07u)); 210 | utf8_bytes[1] = static_cast::int_type>(0x80u | ((static_cast(wc) >> 12u) & 0x3Fu)); 211 | utf8_bytes[2] = static_cast::int_type>(0x80u | ((static_cast(wc) >> 6u) & 0x3Fu)); 212 | utf8_bytes[3] = static_cast::int_type>(0x80u | (static_cast(wc) & 0x3Fu)); 213 | utf8_bytes_filled = 4; 214 | } 215 | else 216 | { 217 | // unknown character 218 | utf8_bytes[0] = static_cast::int_type>(wc); 219 | utf8_bytes_filled = 1; 220 | } 221 | } 222 | } 223 | }; 224 | 225 | template 226 | struct wide_string_input_helper 227 | { 228 | // UTF-16 229 | static void fill_buffer(BaseInputAdapter& input, 230 | std::array::int_type, 4>& utf8_bytes, 231 | size_t& utf8_bytes_index, 232 | size_t& utf8_bytes_filled) 233 | { 234 | utf8_bytes_index = 0; 235 | 236 | if (JSON_HEDLEY_UNLIKELY(input.empty())) 237 | { 238 | utf8_bytes[0] = std::char_traits::eof(); 239 | utf8_bytes_filled = 1; 240 | } 241 | else 242 | { 243 | // get the current character 244 | const auto wc = input.get_character(); 245 | 246 | // UTF-16 to UTF-8 encoding 247 | if (wc < 0x80) 248 | { 249 | utf8_bytes[0] = static_cast::int_type>(wc); 250 | utf8_bytes_filled = 1; 251 | } 252 | else if (wc <= 0x7FF) 253 | { 254 | utf8_bytes[0] = static_cast::int_type>(0xC0u | ((static_cast(wc) >> 6u))); 255 | utf8_bytes[1] = static_cast::int_type>(0x80u | (static_cast(wc) & 0x3Fu)); 256 | utf8_bytes_filled = 2; 257 | } 258 | else if (0xD800 > wc || wc >= 0xE000) 259 | { 260 | utf8_bytes[0] = static_cast::int_type>(0xE0u | ((static_cast(wc) >> 12u))); 261 | utf8_bytes[1] = static_cast::int_type>(0x80u | ((static_cast(wc) >> 6u) & 0x3Fu)); 262 | utf8_bytes[2] = static_cast::int_type>(0x80u | (static_cast(wc) & 0x3Fu)); 263 | utf8_bytes_filled = 3; 264 | } 265 | else 266 | { 267 | if (JSON_HEDLEY_UNLIKELY(!input.empty())) 268 | { 269 | const auto wc2 = static_cast(input.get_character()); 270 | const auto charcode = 0x10000u + (((static_cast(wc) & 0x3FFu) << 10u) | (wc2 & 0x3FFu)); 271 | utf8_bytes[0] = static_cast::int_type>(0xF0u | (charcode >> 18u)); 272 | utf8_bytes[1] = static_cast::int_type>(0x80u | ((charcode >> 12u) & 0x3Fu)); 273 | utf8_bytes[2] = static_cast::int_type>(0x80u | ((charcode >> 6u) & 0x3Fu)); 274 | utf8_bytes[3] = static_cast::int_type>(0x80u | (charcode & 0x3Fu)); 275 | utf8_bytes_filled = 4; 276 | } 277 | else 278 | { 279 | utf8_bytes[0] = static_cast::int_type>(wc); 280 | utf8_bytes_filled = 1; 281 | } 282 | } 283 | } 284 | } 285 | }; 286 | 287 | // Wraps another input apdater to convert wide character types into individual bytes. 288 | template 289 | class wide_string_input_adapter 290 | { 291 | public: 292 | using char_type = char; 293 | 294 | wide_string_input_adapter(BaseInputAdapter base) 295 | : base_adapter(base) {} 296 | 297 | typename std::char_traits::int_type get_character() noexcept 298 | { 299 | // check if buffer needs to be filled 300 | if (utf8_bytes_index == utf8_bytes_filled) 301 | { 302 | fill_buffer(); 303 | 304 | JSON_ASSERT(utf8_bytes_filled > 0); 305 | JSON_ASSERT(utf8_bytes_index == 0); 306 | } 307 | 308 | // use buffer 309 | JSON_ASSERT(utf8_bytes_filled > 0); 310 | JSON_ASSERT(utf8_bytes_index < utf8_bytes_filled); 311 | return utf8_bytes[utf8_bytes_index++]; 312 | } 313 | 314 | private: 315 | BaseInputAdapter base_adapter; 316 | 317 | template 318 | void fill_buffer() 319 | { 320 | wide_string_input_helper::fill_buffer(base_adapter, utf8_bytes, utf8_bytes_index, utf8_bytes_filled); 321 | } 322 | 323 | /// a buffer for UTF-8 bytes 324 | std::array::int_type, 4> utf8_bytes = {{0, 0, 0, 0}}; 325 | 326 | /// index to the utf8_codes array for the next valid byte 327 | std::size_t utf8_bytes_index = 0; 328 | /// number of valid bytes in the utf8_codes array 329 | std::size_t utf8_bytes_filled = 0; 330 | }; 331 | 332 | 333 | template 334 | struct iterator_input_adapter_factory 335 | { 336 | using iterator_type = IteratorType; 337 | using char_type = typename std::iterator_traits::value_type; 338 | using adapter_type = iterator_input_adapter; 339 | 340 | static adapter_type create(IteratorType first, IteratorType last) 341 | { 342 | return adapter_type(std::move(first), std::move(last)); 343 | } 344 | }; 345 | 346 | template 347 | struct is_iterator_of_multibyte 348 | { 349 | using value_type = typename std::iterator_traits::value_type; 350 | enum 351 | { 352 | value = sizeof(value_type) > 1 353 | }; 354 | }; 355 | 356 | template 357 | struct iterator_input_adapter_factory::value>> 358 | { 359 | using iterator_type = IteratorType; 360 | using char_type = typename std::iterator_traits::value_type; 361 | using base_adapter_type = iterator_input_adapter; 362 | using adapter_type = wide_string_input_adapter; 363 | 364 | static adapter_type create(IteratorType first, IteratorType last) 365 | { 366 | return adapter_type(base_adapter_type(std::move(first), std::move(last))); 367 | } 368 | }; 369 | 370 | // General purpose iterator-based input 371 | template 372 | typename iterator_input_adapter_factory::adapter_type input_adapter(IteratorType first, IteratorType last) 373 | { 374 | using factory_type = iterator_input_adapter_factory; 375 | return factory_type::create(first, last); 376 | } 377 | 378 | // Convenience shorthand from container to iterator 379 | // Enables ADL on begin(container) and end(container) 380 | // Encloses the using declarations in namespace for not to leak them to outside scope 381 | 382 | namespace container_input_adapter_factory_impl 383 | { 384 | 385 | using std::begin; 386 | using std::end; 387 | 388 | template 389 | struct container_input_adapter_factory {}; 390 | 391 | template 392 | struct container_input_adapter_factory< ContainerType, 393 | void_t()), end(std::declval()))>> 394 | { 395 | using adapter_type = decltype(input_adapter(begin(std::declval()), end(std::declval()))); 396 | 397 | static adapter_type create(const ContainerType& container) 398 | { 399 | return input_adapter(begin(container), end(container)); 400 | } 401 | }; 402 | 403 | } // namespace container_input_adapter_factory_impl 404 | 405 | template 406 | typename container_input_adapter_factory_impl::container_input_adapter_factory::adapter_type input_adapter(const ContainerType& container) 407 | { 408 | return container_input_adapter_factory_impl::container_input_adapter_factory::create(container); 409 | } 410 | 411 | #ifndef JSON_NO_IO 412 | // Special cases with fast paths 413 | inline file_input_adapter input_adapter(std::FILE* file) 414 | { 415 | return file_input_adapter(file); 416 | } 417 | 418 | inline input_stream_adapter input_adapter(std::istream& stream) 419 | { 420 | return input_stream_adapter(stream); 421 | } 422 | 423 | inline input_stream_adapter input_adapter(std::istream&& stream) 424 | { 425 | return input_stream_adapter(stream); 426 | } 427 | #endif // JSON_NO_IO 428 | 429 | using contiguous_bytes_input_adapter = decltype(input_adapter(std::declval(), std::declval())); 430 | 431 | // Null-delimited strings, and the like. 432 | template < typename CharT, 433 | typename std::enable_if < 434 | std::is_pointer::value&& 435 | !std::is_array::value&& 436 | std::is_integral::type>::value&& 437 | sizeof(typename std::remove_pointer::type) == 1, 438 | int >::type = 0 > 439 | contiguous_bytes_input_adapter input_adapter(CharT b) 440 | { 441 | auto length = std::strlen(reinterpret_cast(b)); 442 | const auto* ptr = reinterpret_cast(b); 443 | return input_adapter(ptr, ptr + length); 444 | } 445 | 446 | template 447 | auto input_adapter(T (&array)[N]) -> decltype(input_adapter(array, array + N)) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) 448 | { 449 | return input_adapter(array, array + N); 450 | } 451 | 452 | // This class only handles inputs of input_buffer_adapter type. 453 | // It's required so that expressions like {ptr, len} can be implicitly cast 454 | // to the correct adapter. 455 | class span_input_adapter 456 | { 457 | public: 458 | template < typename CharT, 459 | typename std::enable_if < 460 | std::is_pointer::value&& 461 | std::is_integral::type>::value&& 462 | sizeof(typename std::remove_pointer::type) == 1, 463 | int >::type = 0 > 464 | span_input_adapter(CharT b, std::size_t l) 465 | : ia(reinterpret_cast(b), reinterpret_cast(b) + l) {} 466 | 467 | template::iterator_category, std::random_access_iterator_tag>::value, 470 | int>::type = 0> 471 | span_input_adapter(IteratorType first, IteratorType last) 472 | : ia(input_adapter(first, last)) {} 473 | 474 | contiguous_bytes_input_adapter&& get() 475 | { 476 | return std::move(ia); // NOLINT(hicpp-move-const-arg,performance-move-const-arg) 477 | } 478 | 479 | private: 480 | contiguous_bytes_input_adapter ia; 481 | }; 482 | } // namespace detail 483 | } // namespace nlohmann 484 | -------------------------------------------------------------------------------- /vendor/nlohmann/detail/input/position_t.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // size_t 4 | 5 | namespace nlohmann 6 | { 7 | namespace detail 8 | { 9 | /// struct to capture the start position of the current token 10 | struct position_t 11 | { 12 | /// the total number of characters read 13 | std::size_t chars_read_total = 0; 14 | /// the number of characters read in the current line 15 | std::size_t chars_read_current_line = 0; 16 | /// the number of lines read 17 | std::size_t lines_read = 0; 18 | 19 | /// conversion to size_t to preserve SAX interface 20 | constexpr operator size_t() const 21 | { 22 | return chars_read_total; 23 | } 24 | }; 25 | 26 | } // namespace detail 27 | } // namespace nlohmann 28 | -------------------------------------------------------------------------------- /vendor/nlohmann/detail/iterators/internal_iterator.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace nlohmann 6 | { 7 | namespace detail 8 | { 9 | /*! 10 | @brief an iterator value 11 | 12 | @note This structure could easily be a union, but MSVC currently does not allow 13 | unions members with complex constructors, see https://github.com/nlohmann/json/pull/105. 14 | */ 15 | template struct internal_iterator 16 | { 17 | /// iterator for JSON objects 18 | typename BasicJsonType::object_t::iterator object_iterator {}; 19 | /// iterator for JSON arrays 20 | typename BasicJsonType::array_t::iterator array_iterator {}; 21 | /// generic iterator for all other types 22 | primitive_iterator_t primitive_iterator {}; 23 | }; 24 | } // namespace detail 25 | } // namespace nlohmann 26 | -------------------------------------------------------------------------------- /vendor/nlohmann/detail/iterators/iteration_proxy.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // size_t 4 | #include // input_iterator_tag 5 | #include // string, to_string 6 | #include // tuple_size, get, tuple_element 7 | #include // move 8 | 9 | #include 10 | #include 11 | 12 | namespace nlohmann 13 | { 14 | namespace detail 15 | { 16 | template 17 | void int_to_string( string_type& target, std::size_t value ) 18 | { 19 | // For ADL 20 | using std::to_string; 21 | target = to_string(value); 22 | } 23 | template class iteration_proxy_value 24 | { 25 | public: 26 | using difference_type = std::ptrdiff_t; 27 | using value_type = iteration_proxy_value; 28 | using pointer = value_type * ; 29 | using reference = value_type & ; 30 | using iterator_category = std::input_iterator_tag; 31 | using string_type = typename std::remove_cv< typename std::remove_reference().key() ) >::type >::type; 32 | 33 | private: 34 | /// the iterator 35 | IteratorType anchor; 36 | /// an index for arrays (used to create key names) 37 | std::size_t array_index = 0; 38 | /// last stringified array index 39 | mutable std::size_t array_index_last = 0; 40 | /// a string representation of the array index 41 | mutable string_type array_index_str = "0"; 42 | /// an empty string (to return a reference for primitive values) 43 | const string_type empty_str{}; 44 | 45 | public: 46 | explicit iteration_proxy_value(IteratorType it) noexcept 47 | : anchor(std::move(it)) 48 | {} 49 | 50 | /// dereference operator (needed for range-based for) 51 | iteration_proxy_value& operator*() 52 | { 53 | return *this; 54 | } 55 | 56 | /// increment operator (needed for range-based for) 57 | iteration_proxy_value& operator++() 58 | { 59 | ++anchor; 60 | ++array_index; 61 | 62 | return *this; 63 | } 64 | 65 | /// equality operator (needed for InputIterator) 66 | bool operator==(const iteration_proxy_value& o) const 67 | { 68 | return anchor == o.anchor; 69 | } 70 | 71 | /// inequality operator (needed for range-based for) 72 | bool operator!=(const iteration_proxy_value& o) const 73 | { 74 | return anchor != o.anchor; 75 | } 76 | 77 | /// return key of the iterator 78 | const string_type& key() const 79 | { 80 | JSON_ASSERT(anchor.m_object != nullptr); 81 | 82 | switch (anchor.m_object->type()) 83 | { 84 | // use integer array index as key 85 | case value_t::array: 86 | { 87 | if (array_index != array_index_last) 88 | { 89 | int_to_string( array_index_str, array_index ); 90 | array_index_last = array_index; 91 | } 92 | return array_index_str; 93 | } 94 | 95 | // use key from the object 96 | case value_t::object: 97 | return anchor.key(); 98 | 99 | // use an empty key for all primitive types 100 | case value_t::null: 101 | case value_t::string: 102 | case value_t::boolean: 103 | case value_t::number_integer: 104 | case value_t::number_unsigned: 105 | case value_t::number_float: 106 | case value_t::binary: 107 | case value_t::discarded: 108 | default: 109 | return empty_str; 110 | } 111 | } 112 | 113 | /// return value of the iterator 114 | typename IteratorType::reference value() const 115 | { 116 | return anchor.value(); 117 | } 118 | }; 119 | 120 | /// proxy class for the items() function 121 | template class iteration_proxy 122 | { 123 | private: 124 | /// the container to iterate 125 | typename IteratorType::reference container; 126 | 127 | public: 128 | /// construct iteration proxy from a container 129 | explicit iteration_proxy(typename IteratorType::reference cont) noexcept 130 | : container(cont) {} 131 | 132 | /// return iterator begin (needed for range-based for) 133 | iteration_proxy_value begin() noexcept 134 | { 135 | return iteration_proxy_value(container.begin()); 136 | } 137 | 138 | /// return iterator end (needed for range-based for) 139 | iteration_proxy_value end() noexcept 140 | { 141 | return iteration_proxy_value(container.end()); 142 | } 143 | }; 144 | // Structured Bindings Support 145 | // For further reference see https://blog.tartanllama.xyz/structured-bindings/ 146 | // And see https://github.com/nlohmann/json/pull/1391 147 | template = 0> 148 | auto get(const nlohmann::detail::iteration_proxy_value& i) -> decltype(i.key()) 149 | { 150 | return i.key(); 151 | } 152 | // Structured Bindings Support 153 | // For further reference see https://blog.tartanllama.xyz/structured-bindings/ 154 | // And see https://github.com/nlohmann/json/pull/1391 155 | template = 0> 156 | auto get(const nlohmann::detail::iteration_proxy_value& i) -> decltype(i.value()) 157 | { 158 | return i.value(); 159 | } 160 | } // namespace detail 161 | } // namespace nlohmann 162 | 163 | // The Addition to the STD Namespace is required to add 164 | // Structured Bindings Support to the iteration_proxy_value class 165 | // For further reference see https://blog.tartanllama.xyz/structured-bindings/ 166 | // And see https://github.com/nlohmann/json/pull/1391 167 | namespace std 168 | { 169 | #if defined(__clang__) 170 | // Fix: https://github.com/nlohmann/json/issues/1401 171 | #pragma clang diagnostic push 172 | #pragma clang diagnostic ignored "-Wmismatched-tags" 173 | #endif 174 | template 175 | class tuple_size<::nlohmann::detail::iteration_proxy_value> 176 | : public std::integral_constant {}; 177 | 178 | template 179 | class tuple_element> 180 | { 181 | public: 182 | using type = decltype( 183 | get(std::declval < 184 | ::nlohmann::detail::iteration_proxy_value> ())); 185 | }; 186 | #if defined(__clang__) 187 | #pragma clang diagnostic pop 188 | #endif 189 | } // namespace std 190 | -------------------------------------------------------------------------------- /vendor/nlohmann/detail/iterators/iterator_traits.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // random_access_iterator_tag 4 | 5 | #include 6 | #include 7 | 8 | namespace nlohmann 9 | { 10 | namespace detail 11 | { 12 | template 13 | struct iterator_types {}; 14 | 15 | template 16 | struct iterator_types < 17 | It, 18 | void_t> 20 | { 21 | using difference_type = typename It::difference_type; 22 | using value_type = typename It::value_type; 23 | using pointer = typename It::pointer; 24 | using reference = typename It::reference; 25 | using iterator_category = typename It::iterator_category; 26 | }; 27 | 28 | // This is required as some compilers implement std::iterator_traits in a way that 29 | // doesn't work with SFINAE. See https://github.com/nlohmann/json/issues/1341. 30 | template 31 | struct iterator_traits 32 | { 33 | }; 34 | 35 | template 36 | struct iterator_traits < T, enable_if_t < !std::is_pointer::value >> 37 | : iterator_types 38 | { 39 | }; 40 | 41 | template 42 | struct iterator_traits::value>> 43 | { 44 | using iterator_category = std::random_access_iterator_tag; 45 | using value_type = T; 46 | using difference_type = ptrdiff_t; 47 | using pointer = T*; 48 | using reference = T&; 49 | }; 50 | } // namespace detail 51 | } // namespace nlohmann 52 | -------------------------------------------------------------------------------- /vendor/nlohmann/detail/iterators/json_reverse_iterator.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // ptrdiff_t 4 | #include // reverse_iterator 5 | #include // declval 6 | 7 | namespace nlohmann 8 | { 9 | namespace detail 10 | { 11 | ////////////////////// 12 | // reverse_iterator // 13 | ////////////////////// 14 | 15 | /*! 16 | @brief a template for a reverse iterator class 17 | 18 | @tparam Base the base iterator type to reverse. Valid types are @ref 19 | iterator (to create @ref reverse_iterator) and @ref const_iterator (to 20 | create @ref const_reverse_iterator). 21 | 22 | @requirement The class satisfies the following concept requirements: 23 | - 24 | [BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator): 25 | The iterator that can be moved can be moved in both directions (i.e. 26 | incremented and decremented). 27 | - [OutputIterator](https://en.cppreference.com/w/cpp/named_req/OutputIterator): 28 | It is possible to write to the pointed-to element (only if @a Base is 29 | @ref iterator). 30 | 31 | @since version 1.0.0 32 | */ 33 | template 34 | class json_reverse_iterator : public std::reverse_iterator 35 | { 36 | public: 37 | using difference_type = std::ptrdiff_t; 38 | /// shortcut to the reverse iterator adapter 39 | using base_iterator = std::reverse_iterator; 40 | /// the reference type for the pointed-to element 41 | using reference = typename Base::reference; 42 | 43 | /// create reverse iterator from iterator 44 | explicit json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept 45 | : base_iterator(it) {} 46 | 47 | /// create reverse iterator from base class 48 | explicit json_reverse_iterator(const base_iterator& it) noexcept : base_iterator(it) {} 49 | 50 | /// post-increment (it++) 51 | json_reverse_iterator const operator++(int) // NOLINT(readability-const-return-type) 52 | { 53 | return static_cast(base_iterator::operator++(1)); 54 | } 55 | 56 | /// pre-increment (++it) 57 | json_reverse_iterator& operator++() 58 | { 59 | return static_cast(base_iterator::operator++()); 60 | } 61 | 62 | /// post-decrement (it--) 63 | json_reverse_iterator const operator--(int) // NOLINT(readability-const-return-type) 64 | { 65 | return static_cast(base_iterator::operator--(1)); 66 | } 67 | 68 | /// pre-decrement (--it) 69 | json_reverse_iterator& operator--() 70 | { 71 | return static_cast(base_iterator::operator--()); 72 | } 73 | 74 | /// add to iterator 75 | json_reverse_iterator& operator+=(difference_type i) 76 | { 77 | return static_cast(base_iterator::operator+=(i)); 78 | } 79 | 80 | /// add to iterator 81 | json_reverse_iterator operator+(difference_type i) const 82 | { 83 | return static_cast(base_iterator::operator+(i)); 84 | } 85 | 86 | /// subtract from iterator 87 | json_reverse_iterator operator-(difference_type i) const 88 | { 89 | return static_cast(base_iterator::operator-(i)); 90 | } 91 | 92 | /// return difference 93 | difference_type operator-(const json_reverse_iterator& other) const 94 | { 95 | return base_iterator(*this) - base_iterator(other); 96 | } 97 | 98 | /// access to successor 99 | reference operator[](difference_type n) const 100 | { 101 | return *(this->operator+(n)); 102 | } 103 | 104 | /// return the key of an object iterator 105 | auto key() const -> decltype(std::declval().key()) 106 | { 107 | auto it = --this->base(); 108 | return it.key(); 109 | } 110 | 111 | /// return the value of an iterator 112 | reference value() const 113 | { 114 | auto it = --this->base(); 115 | return it.operator * (); 116 | } 117 | }; 118 | } // namespace detail 119 | } // namespace nlohmann 120 | -------------------------------------------------------------------------------- /vendor/nlohmann/detail/iterators/primitive_iterator.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // ptrdiff_t 4 | #include // numeric_limits 5 | 6 | #include 7 | 8 | namespace nlohmann 9 | { 10 | namespace detail 11 | { 12 | /* 13 | @brief an iterator for primitive JSON types 14 | 15 | This class models an iterator for primitive JSON types (boolean, number, 16 | string). It's only purpose is to allow the iterator/const_iterator classes 17 | to "iterate" over primitive values. Internally, the iterator is modeled by 18 | a `difference_type` variable. Value begin_value (`0`) models the begin, 19 | end_value (`1`) models past the end. 20 | */ 21 | class primitive_iterator_t 22 | { 23 | private: 24 | using difference_type = std::ptrdiff_t; 25 | static constexpr difference_type begin_value = 0; 26 | static constexpr difference_type end_value = begin_value + 1; 27 | 28 | JSON_PRIVATE_UNLESS_TESTED: 29 | /// iterator as signed integer type 30 | difference_type m_it = (std::numeric_limits::min)(); 31 | 32 | public: 33 | constexpr difference_type get_value() const noexcept 34 | { 35 | return m_it; 36 | } 37 | 38 | /// set iterator to a defined beginning 39 | void set_begin() noexcept 40 | { 41 | m_it = begin_value; 42 | } 43 | 44 | /// set iterator to a defined past the end 45 | void set_end() noexcept 46 | { 47 | m_it = end_value; 48 | } 49 | 50 | /// return whether the iterator can be dereferenced 51 | constexpr bool is_begin() const noexcept 52 | { 53 | return m_it == begin_value; 54 | } 55 | 56 | /// return whether the iterator is at end 57 | constexpr bool is_end() const noexcept 58 | { 59 | return m_it == end_value; 60 | } 61 | 62 | friend constexpr bool operator==(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept 63 | { 64 | return lhs.m_it == rhs.m_it; 65 | } 66 | 67 | friend constexpr bool operator<(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept 68 | { 69 | return lhs.m_it < rhs.m_it; 70 | } 71 | 72 | primitive_iterator_t operator+(difference_type n) noexcept 73 | { 74 | auto result = *this; 75 | result += n; 76 | return result; 77 | } 78 | 79 | friend constexpr difference_type operator-(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept 80 | { 81 | return lhs.m_it - rhs.m_it; 82 | } 83 | 84 | primitive_iterator_t& operator++() noexcept 85 | { 86 | ++m_it; 87 | return *this; 88 | } 89 | 90 | primitive_iterator_t const operator++(int) noexcept // NOLINT(readability-const-return-type) 91 | { 92 | auto result = *this; 93 | ++m_it; 94 | return result; 95 | } 96 | 97 | primitive_iterator_t& operator--() noexcept 98 | { 99 | --m_it; 100 | return *this; 101 | } 102 | 103 | primitive_iterator_t const operator--(int) noexcept // NOLINT(readability-const-return-type) 104 | { 105 | auto result = *this; 106 | --m_it; 107 | return result; 108 | } 109 | 110 | primitive_iterator_t& operator+=(difference_type n) noexcept 111 | { 112 | m_it += n; 113 | return *this; 114 | } 115 | 116 | primitive_iterator_t& operator-=(difference_type n) noexcept 117 | { 118 | m_it -= n; 119 | return *this; 120 | } 121 | }; 122 | } // namespace detail 123 | } // namespace nlohmann 124 | -------------------------------------------------------------------------------- /vendor/nlohmann/detail/json_ref.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | namespace nlohmann 9 | { 10 | namespace detail 11 | { 12 | template 13 | class json_ref 14 | { 15 | public: 16 | using value_type = BasicJsonType; 17 | 18 | json_ref(value_type&& value) 19 | : owned_value(std::move(value)) 20 | {} 21 | 22 | json_ref(const value_type& value) 23 | : value_ref(&value) 24 | {} 25 | 26 | json_ref(std::initializer_list init) 27 | : owned_value(init) 28 | {} 29 | 30 | template < 31 | class... Args, 32 | enable_if_t::value, int> = 0 > 33 | json_ref(Args && ... args) 34 | : owned_value(std::forward(args)...) 35 | {} 36 | 37 | // class should be movable only 38 | json_ref(json_ref&&) noexcept = default; 39 | json_ref(const json_ref&) = delete; 40 | json_ref& operator=(const json_ref&) = delete; 41 | json_ref& operator=(json_ref&&) = delete; 42 | ~json_ref() = default; 43 | 44 | value_type moved_or_copied() const 45 | { 46 | if (value_ref == nullptr) 47 | { 48 | return std::move(owned_value); 49 | } 50 | return *value_ref; 51 | } 52 | 53 | value_type const& operator*() const 54 | { 55 | return value_ref ? *value_ref : owned_value; 56 | } 57 | 58 | value_type const* operator->() const 59 | { 60 | return &** this; 61 | } 62 | 63 | private: 64 | mutable value_type owned_value = nullptr; 65 | value_type const* value_ref = nullptr; 66 | }; 67 | } // namespace detail 68 | } // namespace nlohmann 69 | -------------------------------------------------------------------------------- /vendor/nlohmann/detail/macro_unscope.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // restore clang diagnostic settings 4 | #if defined(__clang__) 5 | #pragma clang diagnostic pop 6 | #endif 7 | 8 | // clean up 9 | #undef JSON_ASSERT 10 | #undef JSON_INTERNAL_CATCH 11 | #undef JSON_CATCH 12 | #undef JSON_THROW 13 | #undef JSON_TRY 14 | #undef JSON_PRIVATE_UNLESS_TESTED 15 | #undef JSON_HAS_CPP_11 16 | #undef JSON_HAS_CPP_14 17 | #undef JSON_HAS_CPP_17 18 | #undef JSON_HAS_CPP_20 19 | #undef JSON_HAS_FILESYSTEM 20 | #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM 21 | #undef NLOHMANN_BASIC_JSON_TPL_DECLARATION 22 | #undef NLOHMANN_BASIC_JSON_TPL 23 | #undef JSON_EXPLICIT 24 | #undef NLOHMANN_CAN_CALL_STD_FUNC_IMPL 25 | 26 | #include 27 | -------------------------------------------------------------------------------- /vendor/nlohmann/detail/meta/call_std/begin.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace nlohmann 6 | { 7 | NLOHMANN_CAN_CALL_STD_FUNC_IMPL(begin); 8 | } // namespace nlohmann 9 | -------------------------------------------------------------------------------- /vendor/nlohmann/detail/meta/call_std/end.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace nlohmann 6 | { 7 | NLOHMANN_CAN_CALL_STD_FUNC_IMPL(end); 8 | } // namespace nlohmann 9 | -------------------------------------------------------------------------------- /vendor/nlohmann/detail/meta/cpp_future.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // size_t 4 | #include // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type 5 | #include // index_sequence, make_index_sequence, index_sequence_for 6 | 7 | #include 8 | 9 | namespace nlohmann 10 | { 11 | namespace detail 12 | { 13 | 14 | template 15 | using uncvref_t = typename std::remove_cv::type>::type; 16 | 17 | #ifdef JSON_HAS_CPP_14 18 | 19 | // the following utilities are natively available in C++14 20 | using std::enable_if_t; 21 | using std::index_sequence; 22 | using std::make_index_sequence; 23 | using std::index_sequence_for; 24 | 25 | #else 26 | 27 | // alias templates to reduce boilerplate 28 | template 29 | using enable_if_t = typename std::enable_if::type; 30 | 31 | // The following code is taken from https://github.com/abseil/abseil-cpp/blob/10cb35e459f5ecca5b2ff107635da0bfa41011b4/absl/utility/utility.h 32 | // which is part of Google Abseil (https://github.com/abseil/abseil-cpp), licensed under the Apache License 2.0. 33 | 34 | //// START OF CODE FROM GOOGLE ABSEIL 35 | 36 | // integer_sequence 37 | // 38 | // Class template representing a compile-time integer sequence. An instantiation 39 | // of `integer_sequence` has a sequence of integers encoded in its 40 | // type through its template arguments (which is a common need when 41 | // working with C++11 variadic templates). `absl::integer_sequence` is designed 42 | // to be a drop-in replacement for C++14's `std::integer_sequence`. 43 | // 44 | // Example: 45 | // 46 | // template< class T, T... Ints > 47 | // void user_function(integer_sequence); 48 | // 49 | // int main() 50 | // { 51 | // // user_function's `T` will be deduced to `int` and `Ints...` 52 | // // will be deduced to `0, 1, 2, 3, 4`. 53 | // user_function(make_integer_sequence()); 54 | // } 55 | template 56 | struct integer_sequence 57 | { 58 | using value_type = T; 59 | static constexpr std::size_t size() noexcept 60 | { 61 | return sizeof...(Ints); 62 | } 63 | }; 64 | 65 | // index_sequence 66 | // 67 | // A helper template for an `integer_sequence` of `size_t`, 68 | // `absl::index_sequence` is designed to be a drop-in replacement for C++14's 69 | // `std::index_sequence`. 70 | template 71 | using index_sequence = integer_sequence; 72 | 73 | namespace utility_internal 74 | { 75 | 76 | template 77 | struct Extend; 78 | 79 | // Note that SeqSize == sizeof...(Ints). It's passed explicitly for efficiency. 80 | template 81 | struct Extend, SeqSize, 0> 82 | { 83 | using type = integer_sequence < T, Ints..., (Ints + SeqSize)... >; 84 | }; 85 | 86 | template 87 | struct Extend, SeqSize, 1> 88 | { 89 | using type = integer_sequence < T, Ints..., (Ints + SeqSize)..., 2 * SeqSize >; 90 | }; 91 | 92 | // Recursion helper for 'make_integer_sequence'. 93 | // 'Gen::type' is an alias for 'integer_sequence'. 94 | template 95 | struct Gen 96 | { 97 | using type = 98 | typename Extend < typename Gen < T, N / 2 >::type, N / 2, N % 2 >::type; 99 | }; 100 | 101 | template 102 | struct Gen 103 | { 104 | using type = integer_sequence; 105 | }; 106 | 107 | } // namespace utility_internal 108 | 109 | // Compile-time sequences of integers 110 | 111 | // make_integer_sequence 112 | // 113 | // This template alias is equivalent to 114 | // `integer_sequence`, and is designed to be a drop-in 115 | // replacement for C++14's `std::make_integer_sequence`. 116 | template 117 | using make_integer_sequence = typename utility_internal::Gen::type; 118 | 119 | // make_index_sequence 120 | // 121 | // This template alias is equivalent to `index_sequence<0, 1, ..., N-1>`, 122 | // and is designed to be a drop-in replacement for C++14's 123 | // `std::make_index_sequence`. 124 | template 125 | using make_index_sequence = make_integer_sequence; 126 | 127 | // index_sequence_for 128 | // 129 | // Converts a typename pack into an index sequence of the same length, and 130 | // is designed to be a drop-in replacement for C++14's 131 | // `std::index_sequence_for()` 132 | template 133 | using index_sequence_for = make_index_sequence; 134 | 135 | //// END OF CODE FROM GOOGLE ABSEIL 136 | 137 | #endif 138 | 139 | // dispatch utility (taken from ranges-v3) 140 | template struct priority_tag : priority_tag < N - 1 > {}; 141 | template<> struct priority_tag<0> {}; 142 | 143 | // taken from ranges-v3 144 | template 145 | struct static_const 146 | { 147 | static constexpr T value{}; 148 | }; 149 | 150 | template 151 | constexpr T static_const::value; // NOLINT(readability-redundant-declaration) 152 | 153 | } // namespace detail 154 | } // namespace nlohmann 155 | -------------------------------------------------------------------------------- /vendor/nlohmann/detail/meta/detected.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | // https://en.cppreference.com/w/cpp/experimental/is_detected 8 | namespace nlohmann 9 | { 10 | namespace detail 11 | { 12 | struct nonesuch 13 | { 14 | nonesuch() = delete; 15 | ~nonesuch() = delete; 16 | nonesuch(nonesuch const&) = delete; 17 | nonesuch(nonesuch const&&) = delete; 18 | void operator=(nonesuch const&) = delete; 19 | void operator=(nonesuch&&) = delete; 20 | }; 21 | 22 | template class Op, 25 | class... Args> 26 | struct detector 27 | { 28 | using value_t = std::false_type; 29 | using type = Default; 30 | }; 31 | 32 | template class Op, class... Args> 33 | struct detector>, Op, Args...> 34 | { 35 | using value_t = std::true_type; 36 | using type = Op; 37 | }; 38 | 39 | template class Op, class... Args> 40 | using is_detected = typename detector::value_t; 41 | 42 | template class Op, class... Args> 43 | struct is_detected_lazy : is_detected { }; 44 | 45 | template class Op, class... Args> 46 | using detected_t = typename detector::type; 47 | 48 | template class Op, class... Args> 49 | using detected_or = detector; 50 | 51 | template class Op, class... Args> 52 | using detected_or_t = typename detected_or::type; 53 | 54 | template class Op, class... Args> 55 | using is_detected_exact = std::is_same>; 56 | 57 | template class Op, class... Args> 58 | using is_detected_convertible = 59 | std::is_convertible, To>; 60 | } // namespace detail 61 | } // namespace nlohmann 62 | -------------------------------------------------------------------------------- /vendor/nlohmann/detail/meta/identity_tag.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nlohmann 4 | { 5 | namespace detail 6 | { 7 | // dispatching helper struct 8 | template struct identity_tag {}; 9 | } // namespace detail 10 | } // namespace nlohmann 11 | -------------------------------------------------------------------------------- /vendor/nlohmann/detail/meta/is_sax.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // size_t 4 | #include // declval 5 | #include // string 6 | 7 | #include 8 | #include 9 | 10 | namespace nlohmann 11 | { 12 | namespace detail 13 | { 14 | template 15 | using null_function_t = decltype(std::declval().null()); 16 | 17 | template 18 | using boolean_function_t = 19 | decltype(std::declval().boolean(std::declval())); 20 | 21 | template 22 | using number_integer_function_t = 23 | decltype(std::declval().number_integer(std::declval())); 24 | 25 | template 26 | using number_unsigned_function_t = 27 | decltype(std::declval().number_unsigned(std::declval())); 28 | 29 | template 30 | using number_float_function_t = decltype(std::declval().number_float( 31 | std::declval(), std::declval())); 32 | 33 | template 34 | using string_function_t = 35 | decltype(std::declval().string(std::declval())); 36 | 37 | template 38 | using binary_function_t = 39 | decltype(std::declval().binary(std::declval())); 40 | 41 | template 42 | using start_object_function_t = 43 | decltype(std::declval().start_object(std::declval())); 44 | 45 | template 46 | using key_function_t = 47 | decltype(std::declval().key(std::declval())); 48 | 49 | template 50 | using end_object_function_t = decltype(std::declval().end_object()); 51 | 52 | template 53 | using start_array_function_t = 54 | decltype(std::declval().start_array(std::declval())); 55 | 56 | template 57 | using end_array_function_t = decltype(std::declval().end_array()); 58 | 59 | template 60 | using parse_error_function_t = decltype(std::declval().parse_error( 61 | std::declval(), std::declval(), 62 | std::declval())); 63 | 64 | template 65 | struct is_sax 66 | { 67 | private: 68 | static_assert(is_basic_json::value, 69 | "BasicJsonType must be of type basic_json<...>"); 70 | 71 | using number_integer_t = typename BasicJsonType::number_integer_t; 72 | using number_unsigned_t = typename BasicJsonType::number_unsigned_t; 73 | using number_float_t = typename BasicJsonType::number_float_t; 74 | using string_t = typename BasicJsonType::string_t; 75 | using binary_t = typename BasicJsonType::binary_t; 76 | using exception_t = typename BasicJsonType::exception; 77 | 78 | public: 79 | static constexpr bool value = 80 | is_detected_exact::value && 81 | is_detected_exact::value && 82 | is_detected_exact::value && 83 | is_detected_exact::value && 84 | is_detected_exact::value && 85 | is_detected_exact::value && 86 | is_detected_exact::value && 87 | is_detected_exact::value && 88 | is_detected_exact::value && 89 | is_detected_exact::value && 90 | is_detected_exact::value && 91 | is_detected_exact::value && 92 | is_detected_exact::value; 93 | }; 94 | 95 | template 96 | struct is_sax_static_asserts 97 | { 98 | private: 99 | static_assert(is_basic_json::value, 100 | "BasicJsonType must be of type basic_json<...>"); 101 | 102 | using number_integer_t = typename BasicJsonType::number_integer_t; 103 | using number_unsigned_t = typename BasicJsonType::number_unsigned_t; 104 | using number_float_t = typename BasicJsonType::number_float_t; 105 | using string_t = typename BasicJsonType::string_t; 106 | using binary_t = typename BasicJsonType::binary_t; 107 | using exception_t = typename BasicJsonType::exception; 108 | 109 | public: 110 | static_assert(is_detected_exact::value, 111 | "Missing/invalid function: bool null()"); 112 | static_assert(is_detected_exact::value, 113 | "Missing/invalid function: bool boolean(bool)"); 114 | static_assert(is_detected_exact::value, 115 | "Missing/invalid function: bool boolean(bool)"); 116 | static_assert( 117 | is_detected_exact::value, 119 | "Missing/invalid function: bool number_integer(number_integer_t)"); 120 | static_assert( 121 | is_detected_exact::value, 123 | "Missing/invalid function: bool number_unsigned(number_unsigned_t)"); 124 | static_assert(is_detected_exact::value, 126 | "Missing/invalid function: bool number_float(number_float_t, const string_t&)"); 127 | static_assert( 128 | is_detected_exact::value, 129 | "Missing/invalid function: bool string(string_t&)"); 130 | static_assert( 131 | is_detected_exact::value, 132 | "Missing/invalid function: bool binary(binary_t&)"); 133 | static_assert(is_detected_exact::value, 134 | "Missing/invalid function: bool start_object(std::size_t)"); 135 | static_assert(is_detected_exact::value, 136 | "Missing/invalid function: bool key(string_t&)"); 137 | static_assert(is_detected_exact::value, 138 | "Missing/invalid function: bool end_object()"); 139 | static_assert(is_detected_exact::value, 140 | "Missing/invalid function: bool start_array(std::size_t)"); 141 | static_assert(is_detected_exact::value, 142 | "Missing/invalid function: bool end_array()"); 143 | static_assert( 144 | is_detected_exact::value, 145 | "Missing/invalid function: bool parse_error(std::size_t, const " 146 | "std::string&, const exception&)"); 147 | }; 148 | } // namespace detail 149 | } // namespace nlohmann 150 | -------------------------------------------------------------------------------- /vendor/nlohmann/detail/meta/void_t.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nlohmann 4 | { 5 | namespace detail 6 | { 7 | template struct make_void 8 | { 9 | using type = void; 10 | }; 11 | template using void_t = typename make_void::type; 12 | } // namespace detail 13 | } // namespace nlohmann 14 | -------------------------------------------------------------------------------- /vendor/nlohmann/detail/output/output_adapters.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // copy 4 | #include // size_t 5 | #include // back_inserter 6 | #include // shared_ptr, make_shared 7 | #include // basic_string 8 | #include // vector 9 | 10 | #ifndef JSON_NO_IO 11 | #include // streamsize 12 | #include // basic_ostream 13 | #endif // JSON_NO_IO 14 | 15 | #include 16 | 17 | namespace nlohmann 18 | { 19 | namespace detail 20 | { 21 | /// abstract output adapter interface 22 | template struct output_adapter_protocol 23 | { 24 | virtual void write_character(CharType c) = 0; 25 | virtual void write_characters(const CharType* s, std::size_t length) = 0; 26 | virtual ~output_adapter_protocol() = default; 27 | 28 | output_adapter_protocol() = default; 29 | output_adapter_protocol(const output_adapter_protocol&) = default; 30 | output_adapter_protocol(output_adapter_protocol&&) noexcept = default; 31 | output_adapter_protocol& operator=(const output_adapter_protocol&) = default; 32 | output_adapter_protocol& operator=(output_adapter_protocol&&) noexcept = default; 33 | }; 34 | 35 | /// a type to simplify interfaces 36 | template 37 | using output_adapter_t = std::shared_ptr>; 38 | 39 | /// output adapter for byte vectors 40 | template> 41 | class output_vector_adapter : public output_adapter_protocol 42 | { 43 | public: 44 | explicit output_vector_adapter(std::vector& vec) noexcept 45 | : v(vec) 46 | {} 47 | 48 | void write_character(CharType c) override 49 | { 50 | v.push_back(c); 51 | } 52 | 53 | JSON_HEDLEY_NON_NULL(2) 54 | void write_characters(const CharType* s, std::size_t length) override 55 | { 56 | std::copy(s, s + length, std::back_inserter(v)); 57 | } 58 | 59 | private: 60 | std::vector& v; 61 | }; 62 | 63 | #ifndef JSON_NO_IO 64 | /// output adapter for output streams 65 | template 66 | class output_stream_adapter : public output_adapter_protocol 67 | { 68 | public: 69 | explicit output_stream_adapter(std::basic_ostream& s) noexcept 70 | : stream(s) 71 | {} 72 | 73 | void write_character(CharType c) override 74 | { 75 | stream.put(c); 76 | } 77 | 78 | JSON_HEDLEY_NON_NULL(2) 79 | void write_characters(const CharType* s, std::size_t length) override 80 | { 81 | stream.write(s, static_cast(length)); 82 | } 83 | 84 | private: 85 | std::basic_ostream& stream; 86 | }; 87 | #endif // JSON_NO_IO 88 | 89 | /// output adapter for basic_string 90 | template> 91 | class output_string_adapter : public output_adapter_protocol 92 | { 93 | public: 94 | explicit output_string_adapter(StringType& s) noexcept 95 | : str(s) 96 | {} 97 | 98 | void write_character(CharType c) override 99 | { 100 | str.push_back(c); 101 | } 102 | 103 | JSON_HEDLEY_NON_NULL(2) 104 | void write_characters(const CharType* s, std::size_t length) override 105 | { 106 | str.append(s, length); 107 | } 108 | 109 | private: 110 | StringType& str; 111 | }; 112 | 113 | template> 114 | class output_adapter 115 | { 116 | public: 117 | template> 118 | output_adapter(std::vector& vec) 119 | : oa(std::make_shared>(vec)) {} 120 | 121 | #ifndef JSON_NO_IO 122 | output_adapter(std::basic_ostream& s) 123 | : oa(std::make_shared>(s)) {} 124 | #endif // JSON_NO_IO 125 | 126 | output_adapter(StringType& s) 127 | : oa(std::make_shared>(s)) {} 128 | 129 | operator output_adapter_t() 130 | { 131 | return oa; 132 | } 133 | 134 | private: 135 | output_adapter_t oa = nullptr; 136 | }; 137 | } // namespace detail 138 | } // namespace nlohmann 139 | -------------------------------------------------------------------------------- /vendor/nlohmann/detail/string_escape.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace nlohmann 7 | { 8 | namespace detail 9 | { 10 | 11 | /*! 12 | @brief replace all occurrences of a substring by another string 13 | 14 | @param[in,out] s the string to manipulate; changed so that all 15 | occurrences of @a f are replaced with @a t 16 | @param[in] f the substring to replace with @a t 17 | @param[in] t the string to replace @a f 18 | 19 | @pre The search string @a f must not be empty. **This precondition is 20 | enforced with an assertion.** 21 | 22 | @since version 2.0.0 23 | */ 24 | inline void replace_substring(std::string& s, const std::string& f, 25 | const std::string& t) 26 | { 27 | JSON_ASSERT(!f.empty()); 28 | for (auto pos = s.find(f); // find first occurrence of f 29 | pos != std::string::npos; // make sure f was found 30 | s.replace(pos, f.size(), t), // replace with t, and 31 | pos = s.find(f, pos + t.size())) // find next occurrence of f 32 | {} 33 | } 34 | 35 | /*! 36 | * @brief string escaping as described in RFC 6901 (Sect. 4) 37 | * @param[in] s string to escape 38 | * @return escaped string 39 | * 40 | * Note the order of escaping "~" to "~0" and "/" to "~1" is important. 41 | */ 42 | inline std::string escape(std::string s) 43 | { 44 | replace_substring(s, "~", "~0"); 45 | replace_substring(s, "/", "~1"); 46 | return s; 47 | } 48 | 49 | /*! 50 | * @brief string unescaping as described in RFC 6901 (Sect. 4) 51 | * @param[in] s string to unescape 52 | * @return unescaped string 53 | * 54 | * Note the order of escaping "~1" to "/" and "~0" to "~" is important. 55 | */ 56 | static void unescape(std::string& s) 57 | { 58 | replace_substring(s, "~1", "/"); 59 | replace_substring(s, "~0", "~"); 60 | } 61 | 62 | } // namespace detail 63 | } // namespace nlohmann 64 | -------------------------------------------------------------------------------- /vendor/nlohmann/detail/value_t.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // array 4 | #include // size_t 5 | #include // uint8_t 6 | #include // string 7 | 8 | namespace nlohmann 9 | { 10 | namespace detail 11 | { 12 | /////////////////////////// 13 | // JSON type enumeration // 14 | /////////////////////////// 15 | 16 | /*! 17 | @brief the JSON type enumeration 18 | 19 | This enumeration collects the different JSON types. It is internally used to 20 | distinguish the stored values, and the functions @ref basic_json::is_null(), 21 | @ref basic_json::is_object(), @ref basic_json::is_array(), 22 | @ref basic_json::is_string(), @ref basic_json::is_boolean(), 23 | @ref basic_json::is_number() (with @ref basic_json::is_number_integer(), 24 | @ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()), 25 | @ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and 26 | @ref basic_json::is_structured() rely on it. 27 | 28 | @note There are three enumeration entries (number_integer, number_unsigned, and 29 | number_float), because the library distinguishes these three types for numbers: 30 | @ref basic_json::number_unsigned_t is used for unsigned integers, 31 | @ref basic_json::number_integer_t is used for signed integers, and 32 | @ref basic_json::number_float_t is used for floating-point numbers or to 33 | approximate integers which do not fit in the limits of their respective type. 34 | 35 | @sa see @ref basic_json::basic_json(const value_t value_type) -- create a JSON 36 | value with the default value for a given type 37 | 38 | @since version 1.0.0 39 | */ 40 | enum class value_t : std::uint8_t 41 | { 42 | null, ///< null value 43 | object, ///< object (unordered set of name/value pairs) 44 | array, ///< array (ordered collection of values) 45 | string, ///< string value 46 | boolean, ///< boolean value 47 | number_integer, ///< number value (signed integer) 48 | number_unsigned, ///< number value (unsigned integer) 49 | number_float, ///< number value (floating-point) 50 | binary, ///< binary array (ordered collection of bytes) 51 | discarded ///< discarded by the parser callback function 52 | }; 53 | 54 | /*! 55 | @brief comparison operator for JSON types 56 | 57 | Returns an ordering that is similar to Python: 58 | - order: null < boolean < number < object < array < string < binary 59 | - furthermore, each type is not smaller than itself 60 | - discarded values are not comparable 61 | - binary is represented as a b"" string in python and directly comparable to a 62 | string; however, making a binary array directly comparable with a string would 63 | be surprising behavior in a JSON file. 64 | 65 | @since version 1.0.0 66 | */ 67 | inline bool operator<(const value_t lhs, const value_t rhs) noexcept 68 | { 69 | static constexpr std::array order = {{ 70 | 0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */, 71 | 1 /* boolean */, 2 /* integer */, 2 /* unsigned */, 2 /* float */, 72 | 6 /* binary */ 73 | } 74 | }; 75 | 76 | const auto l_index = static_cast(lhs); 77 | const auto r_index = static_cast(rhs); 78 | return l_index < order.size() && r_index < order.size() && order[l_index] < order[r_index]; 79 | } 80 | } // namespace detail 81 | } // namespace nlohmann 82 | -------------------------------------------------------------------------------- /vendor/nlohmann/json_fwd.hpp: -------------------------------------------------------------------------------- 1 | #ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_ 2 | #define INCLUDE_NLOHMANN_JSON_FWD_HPP_ 3 | 4 | #include // int64_t, uint64_t 5 | #include // map 6 | #include // allocator 7 | #include // string 8 | #include // vector 9 | 10 | /*! 11 | @brief namespace for Niels Lohmann 12 | @see https://github.com/nlohmann 13 | @since version 1.0.0 14 | */ 15 | namespace nlohmann 16 | { 17 | /*! 18 | @brief default JSONSerializer template argument 19 | 20 | This serializer ignores the template arguments and uses ADL 21 | ([argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl)) 22 | for serialization. 23 | */ 24 | template 25 | struct adl_serializer; 26 | 27 | /// a class to store JSON values 28 | /// @sa https://json.nlohmann.me/api/basic_json/ 29 | template class ObjectType = 30 | std::map, 31 | template class ArrayType = std::vector, 32 | class StringType = std::string, class BooleanType = bool, 33 | class NumberIntegerType = std::int64_t, 34 | class NumberUnsignedType = std::uint64_t, 35 | class NumberFloatType = double, 36 | template class AllocatorType = std::allocator, 37 | template class JSONSerializer = 38 | adl_serializer, 39 | class BinaryType = std::vector> 40 | class basic_json; 41 | 42 | /// @brief JSON Pointer defines a string syntax for identifying a specific value within a JSON document 43 | /// @sa https://json.nlohmann.me/api/json_pointer/ 44 | template 45 | class json_pointer; 46 | 47 | /*! 48 | @brief default specialization 49 | @sa https://json.nlohmann.me/api/json/ 50 | */ 51 | using json = basic_json<>; 52 | 53 | /// @brief a minimal map-like container that preserves insertion order 54 | /// @sa https://json.nlohmann.me/api/ordered_map/ 55 | template 56 | struct ordered_map; 57 | 58 | /// @brief specialization that maintains the insertion order of object keys 59 | /// @sa https://json.nlohmann.me/api/ordered_json/ 60 | using ordered_json = basic_json; 61 | 62 | } // namespace nlohmann 63 | 64 | #endif // INCLUDE_NLOHMANN_JSON_FWD_HPP_ 65 | -------------------------------------------------------------------------------- /vendor/nlohmann/ordered_map.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // less 4 | #include // initializer_list 5 | #include // input_iterator_tag, iterator_traits 6 | #include // allocator 7 | #include // for out_of_range 8 | #include // enable_if, is_convertible 9 | #include // pair 10 | #include // vector 11 | 12 | #include 13 | 14 | namespace nlohmann 15 | { 16 | 17 | /// ordered_map: a minimal map-like container that preserves insertion order 18 | /// for use within nlohmann::basic_json 19 | template , 20 | class Allocator = std::allocator>> 21 | struct ordered_map : std::vector, Allocator> 22 | { 23 | using key_type = Key; 24 | using mapped_type = T; 25 | using Container = std::vector, Allocator>; 26 | using iterator = typename Container::iterator; 27 | using const_iterator = typename Container::const_iterator; 28 | using size_type = typename Container::size_type; 29 | using value_type = typename Container::value_type; 30 | 31 | // Explicit constructors instead of `using Container::Container` 32 | // otherwise older compilers choke on it (GCC <= 5.5, xcode <= 9.4) 33 | ordered_map(const Allocator& alloc = Allocator()) : Container{alloc} {} 34 | template 35 | ordered_map(It first, It last, const Allocator& alloc = Allocator()) 36 | : Container{first, last, alloc} {} 37 | ordered_map(std::initializer_list init, const Allocator& alloc = Allocator() ) 38 | : Container{init, alloc} {} 39 | 40 | std::pair emplace(const key_type& key, T&& t) 41 | { 42 | for (auto it = this->begin(); it != this->end(); ++it) 43 | { 44 | if (it->first == key) 45 | { 46 | return {it, false}; 47 | } 48 | } 49 | Container::emplace_back(key, t); 50 | return {--this->end(), true}; 51 | } 52 | 53 | T& operator[](const Key& key) 54 | { 55 | return emplace(key, T{}).first->second; 56 | } 57 | 58 | const T& operator[](const Key& key) const 59 | { 60 | return at(key); 61 | } 62 | 63 | T& at(const Key& key) 64 | { 65 | for (auto it = this->begin(); it != this->end(); ++it) 66 | { 67 | if (it->first == key) 68 | { 69 | return it->second; 70 | } 71 | } 72 | 73 | JSON_THROW(std::out_of_range("key not found")); 74 | } 75 | 76 | const T& at(const Key& key) const 77 | { 78 | for (auto it = this->begin(); it != this->end(); ++it) 79 | { 80 | if (it->first == key) 81 | { 82 | return it->second; 83 | } 84 | } 85 | 86 | JSON_THROW(std::out_of_range("key not found")); 87 | } 88 | 89 | size_type erase(const Key& key) 90 | { 91 | for (auto it = this->begin(); it != this->end(); ++it) 92 | { 93 | if (it->first == key) 94 | { 95 | // Since we cannot move const Keys, re-construct them in place 96 | for (auto next = it; ++next != this->end(); ++it) 97 | { 98 | it->~value_type(); // Destroy but keep allocation 99 | new (&*it) value_type{std::move(*next)}; 100 | } 101 | Container::pop_back(); 102 | return 1; 103 | } 104 | } 105 | return 0; 106 | } 107 | 108 | iterator erase(iterator pos) 109 | { 110 | return erase(pos, std::next(pos)); 111 | } 112 | 113 | iterator erase(iterator first, iterator last) 114 | { 115 | const auto elements_affected = std::distance(first, last); 116 | const auto offset = std::distance(Container::begin(), first); 117 | 118 | // This is the start situation. We need to delete elements_affected 119 | // elements (3 in this example: e, f, g), and need to return an 120 | // iterator past the last deleted element (h in this example). 121 | // Note that offset is the distance from the start of the vector 122 | // to first. We will need this later. 123 | 124 | // [ a, b, c, d, e, f, g, h, i, j ] 125 | // ^ ^ 126 | // first last 127 | 128 | // Since we cannot move const Keys, we re-construct them in place. 129 | // We start at first and re-construct (viz. copy) the elements from 130 | // the back of the vector. Example for first iteration: 131 | 132 | // ,--------. 133 | // v | destroy e and re-construct with h 134 | // [ a, b, c, d, e, f, g, h, i, j ] 135 | // ^ ^ 136 | // it it + elements_affected 137 | 138 | for (auto it = first; std::next(it, elements_affected) != Container::end(); ++it) 139 | { 140 | it->~value_type(); // destroy but keep allocation 141 | new (&*it) value_type{std::move(*std::next(it, elements_affected))}; // "move" next element to it 142 | } 143 | 144 | // [ a, b, c, d, h, i, j, h, i, j ] 145 | // ^ ^ 146 | // first last 147 | 148 | // remove the unneeded elements at the end of the vector 149 | Container::resize(this->size() - static_cast(elements_affected)); 150 | 151 | // [ a, b, c, d, h, i, j ] 152 | // ^ ^ 153 | // first last 154 | 155 | // first is now pointing past the last deleted element, but we cannot 156 | // use this iterator, because it may have been invalidated by the 157 | // resize call. Instead, we can return begin() + offset. 158 | return Container::begin() + offset; 159 | } 160 | 161 | size_type count(const Key& key) const 162 | { 163 | for (auto it = this->begin(); it != this->end(); ++it) 164 | { 165 | if (it->first == key) 166 | { 167 | return 1; 168 | } 169 | } 170 | return 0; 171 | } 172 | 173 | iterator find(const Key& key) 174 | { 175 | for (auto it = this->begin(); it != this->end(); ++it) 176 | { 177 | if (it->first == key) 178 | { 179 | return it; 180 | } 181 | } 182 | return Container::end(); 183 | } 184 | 185 | const_iterator find(const Key& key) const 186 | { 187 | for (auto it = this->begin(); it != this->end(); ++it) 188 | { 189 | if (it->first == key) 190 | { 191 | return it; 192 | } 193 | } 194 | return Container::end(); 195 | } 196 | 197 | std::pair insert( value_type&& value ) 198 | { 199 | return emplace(value.first, std::move(value.second)); 200 | } 201 | 202 | std::pair insert( const value_type& value ) 203 | { 204 | for (auto it = this->begin(); it != this->end(); ++it) 205 | { 206 | if (it->first == value.first) 207 | { 208 | return {it, false}; 209 | } 210 | } 211 | Container::push_back(value); 212 | return {--this->end(), true}; 213 | } 214 | 215 | template 216 | using require_input_iter = typename std::enable_if::iterator_category, 217 | std::input_iterator_tag>::value>::type; 218 | 219 | template> 220 | void insert(InputIt first, InputIt last) 221 | { 222 | for (auto it = first; it != last; ++it) 223 | { 224 | insert(*it); 225 | } 226 | } 227 | }; 228 | 229 | } // namespace nlohmann 230 | -------------------------------------------------------------------------------- /vendor/nlohmann/thirdparty/hedley/hedley_undef.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #undef JSON_HEDLEY_ALWAYS_INLINE 4 | #undef JSON_HEDLEY_ARM_VERSION 5 | #undef JSON_HEDLEY_ARM_VERSION_CHECK 6 | #undef JSON_HEDLEY_ARRAY_PARAM 7 | #undef JSON_HEDLEY_ASSUME 8 | #undef JSON_HEDLEY_BEGIN_C_DECLS 9 | #undef JSON_HEDLEY_CLANG_HAS_ATTRIBUTE 10 | #undef JSON_HEDLEY_CLANG_HAS_BUILTIN 11 | #undef JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE 12 | #undef JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE 13 | #undef JSON_HEDLEY_CLANG_HAS_EXTENSION 14 | #undef JSON_HEDLEY_CLANG_HAS_FEATURE 15 | #undef JSON_HEDLEY_CLANG_HAS_WARNING 16 | #undef JSON_HEDLEY_COMPCERT_VERSION 17 | #undef JSON_HEDLEY_COMPCERT_VERSION_CHECK 18 | #undef JSON_HEDLEY_CONCAT 19 | #undef JSON_HEDLEY_CONCAT3 20 | #undef JSON_HEDLEY_CONCAT3_EX 21 | #undef JSON_HEDLEY_CONCAT_EX 22 | #undef JSON_HEDLEY_CONST 23 | #undef JSON_HEDLEY_CONSTEXPR 24 | #undef JSON_HEDLEY_CONST_CAST 25 | #undef JSON_HEDLEY_CPP_CAST 26 | #undef JSON_HEDLEY_CRAY_VERSION 27 | #undef JSON_HEDLEY_CRAY_VERSION_CHECK 28 | #undef JSON_HEDLEY_C_DECL 29 | #undef JSON_HEDLEY_DEPRECATED 30 | #undef JSON_HEDLEY_DEPRECATED_FOR 31 | #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL 32 | #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ 33 | #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED 34 | #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES 35 | #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS 36 | #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION 37 | #undef JSON_HEDLEY_DIAGNOSTIC_POP 38 | #undef JSON_HEDLEY_DIAGNOSTIC_PUSH 39 | #undef JSON_HEDLEY_DMC_VERSION 40 | #undef JSON_HEDLEY_DMC_VERSION_CHECK 41 | #undef JSON_HEDLEY_EMPTY_BASES 42 | #undef JSON_HEDLEY_EMSCRIPTEN_VERSION 43 | #undef JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK 44 | #undef JSON_HEDLEY_END_C_DECLS 45 | #undef JSON_HEDLEY_FLAGS 46 | #undef JSON_HEDLEY_FLAGS_CAST 47 | #undef JSON_HEDLEY_GCC_HAS_ATTRIBUTE 48 | #undef JSON_HEDLEY_GCC_HAS_BUILTIN 49 | #undef JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE 50 | #undef JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE 51 | #undef JSON_HEDLEY_GCC_HAS_EXTENSION 52 | #undef JSON_HEDLEY_GCC_HAS_FEATURE 53 | #undef JSON_HEDLEY_GCC_HAS_WARNING 54 | #undef JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK 55 | #undef JSON_HEDLEY_GCC_VERSION 56 | #undef JSON_HEDLEY_GCC_VERSION_CHECK 57 | #undef JSON_HEDLEY_GNUC_HAS_ATTRIBUTE 58 | #undef JSON_HEDLEY_GNUC_HAS_BUILTIN 59 | #undef JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE 60 | #undef JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE 61 | #undef JSON_HEDLEY_GNUC_HAS_EXTENSION 62 | #undef JSON_HEDLEY_GNUC_HAS_FEATURE 63 | #undef JSON_HEDLEY_GNUC_HAS_WARNING 64 | #undef JSON_HEDLEY_GNUC_VERSION 65 | #undef JSON_HEDLEY_GNUC_VERSION_CHECK 66 | #undef JSON_HEDLEY_HAS_ATTRIBUTE 67 | #undef JSON_HEDLEY_HAS_BUILTIN 68 | #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE 69 | #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS 70 | #undef JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE 71 | #undef JSON_HEDLEY_HAS_EXTENSION 72 | #undef JSON_HEDLEY_HAS_FEATURE 73 | #undef JSON_HEDLEY_HAS_WARNING 74 | #undef JSON_HEDLEY_IAR_VERSION 75 | #undef JSON_HEDLEY_IAR_VERSION_CHECK 76 | #undef JSON_HEDLEY_IBM_VERSION 77 | #undef JSON_HEDLEY_IBM_VERSION_CHECK 78 | #undef JSON_HEDLEY_IMPORT 79 | #undef JSON_HEDLEY_INLINE 80 | #undef JSON_HEDLEY_INTEL_CL_VERSION 81 | #undef JSON_HEDLEY_INTEL_CL_VERSION_CHECK 82 | #undef JSON_HEDLEY_INTEL_VERSION 83 | #undef JSON_HEDLEY_INTEL_VERSION_CHECK 84 | #undef JSON_HEDLEY_IS_CONSTANT 85 | #undef JSON_HEDLEY_IS_CONSTEXPR_ 86 | #undef JSON_HEDLEY_LIKELY 87 | #undef JSON_HEDLEY_MALLOC 88 | #undef JSON_HEDLEY_MCST_LCC_VERSION 89 | #undef JSON_HEDLEY_MCST_LCC_VERSION_CHECK 90 | #undef JSON_HEDLEY_MESSAGE 91 | #undef JSON_HEDLEY_MSVC_VERSION 92 | #undef JSON_HEDLEY_MSVC_VERSION_CHECK 93 | #undef JSON_HEDLEY_NEVER_INLINE 94 | #undef JSON_HEDLEY_NON_NULL 95 | #undef JSON_HEDLEY_NO_ESCAPE 96 | #undef JSON_HEDLEY_NO_RETURN 97 | #undef JSON_HEDLEY_NO_THROW 98 | #undef JSON_HEDLEY_NULL 99 | #undef JSON_HEDLEY_PELLES_VERSION 100 | #undef JSON_HEDLEY_PELLES_VERSION_CHECK 101 | #undef JSON_HEDLEY_PGI_VERSION 102 | #undef JSON_HEDLEY_PGI_VERSION_CHECK 103 | #undef JSON_HEDLEY_PREDICT 104 | #undef JSON_HEDLEY_PRINTF_FORMAT 105 | #undef JSON_HEDLEY_PRIVATE 106 | #undef JSON_HEDLEY_PUBLIC 107 | #undef JSON_HEDLEY_PURE 108 | #undef JSON_HEDLEY_REINTERPRET_CAST 109 | #undef JSON_HEDLEY_REQUIRE 110 | #undef JSON_HEDLEY_REQUIRE_CONSTEXPR 111 | #undef JSON_HEDLEY_REQUIRE_MSG 112 | #undef JSON_HEDLEY_RESTRICT 113 | #undef JSON_HEDLEY_RETURNS_NON_NULL 114 | #undef JSON_HEDLEY_SENTINEL 115 | #undef JSON_HEDLEY_STATIC_ASSERT 116 | #undef JSON_HEDLEY_STATIC_CAST 117 | #undef JSON_HEDLEY_STRINGIFY 118 | #undef JSON_HEDLEY_STRINGIFY_EX 119 | #undef JSON_HEDLEY_SUNPRO_VERSION 120 | #undef JSON_HEDLEY_SUNPRO_VERSION_CHECK 121 | #undef JSON_HEDLEY_TINYC_VERSION 122 | #undef JSON_HEDLEY_TINYC_VERSION_CHECK 123 | #undef JSON_HEDLEY_TI_ARMCL_VERSION 124 | #undef JSON_HEDLEY_TI_ARMCL_VERSION_CHECK 125 | #undef JSON_HEDLEY_TI_CL2000_VERSION 126 | #undef JSON_HEDLEY_TI_CL2000_VERSION_CHECK 127 | #undef JSON_HEDLEY_TI_CL430_VERSION 128 | #undef JSON_HEDLEY_TI_CL430_VERSION_CHECK 129 | #undef JSON_HEDLEY_TI_CL6X_VERSION 130 | #undef JSON_HEDLEY_TI_CL6X_VERSION_CHECK 131 | #undef JSON_HEDLEY_TI_CL7X_VERSION 132 | #undef JSON_HEDLEY_TI_CL7X_VERSION_CHECK 133 | #undef JSON_HEDLEY_TI_CLPRU_VERSION 134 | #undef JSON_HEDLEY_TI_CLPRU_VERSION_CHECK 135 | #undef JSON_HEDLEY_TI_VERSION 136 | #undef JSON_HEDLEY_TI_VERSION_CHECK 137 | #undef JSON_HEDLEY_UNAVAILABLE 138 | #undef JSON_HEDLEY_UNLIKELY 139 | #undef JSON_HEDLEY_UNPREDICTABLE 140 | #undef JSON_HEDLEY_UNREACHABLE 141 | #undef JSON_HEDLEY_UNREACHABLE_RETURN 142 | #undef JSON_HEDLEY_VERSION 143 | #undef JSON_HEDLEY_VERSION_DECODE_MAJOR 144 | #undef JSON_HEDLEY_VERSION_DECODE_MINOR 145 | #undef JSON_HEDLEY_VERSION_DECODE_REVISION 146 | #undef JSON_HEDLEY_VERSION_ENCODE 147 | #undef JSON_HEDLEY_WARNING 148 | #undef JSON_HEDLEY_WARN_UNUSED_RESULT 149 | #undef JSON_HEDLEY_WARN_UNUSED_RESULT_MSG 150 | #undef JSON_HEDLEY_FALL_THROUGH 151 | --------------------------------------------------------------------------------