From c3b5a29da20f1376785c7c78e8aef1d309234a2b Mon Sep 17 00:00:00 2001 From: tqcq <99722391+tqcq@users.noreply.github.com> Date: Sun, 21 Jan 2024 16:05:01 +0800 Subject: [PATCH] feat add rpc_core --- 3party/rpc_core/.clang-format | 5 + 3party/rpc_core/.github/workflows/build.yml | 29 + 3party/rpc_core/.gitignore | 14 + 3party/rpc_core/CMakeLists.txt | 54 ++ 3party/rpc_core/README.md | 148 +++++ 3party/rpc_core/include/rpc_core.hpp | 10 + 3party/rpc_core/include/rpc_core/config.hpp | 3 + .../rpc_core/include/rpc_core/connection.hpp | 86 +++ .../rpc_core/detail/callable/callable.hpp | 58 ++ .../rpc_core/detail/callable/function.hpp | 40 ++ .../rpc_core/detail/callable/functor.hpp | 25 + .../rpc_core/detail/callable/helpers.hpp | 58 ++ .../detail/callable/member_function.hpp | 139 +++++ .../include/rpc_core/detail/coder.hpp | 56 ++ .../include/rpc_core/detail/copyable.hpp | 17 + .../include/rpc_core/detail/data_packer.hpp | 120 ++++ 3party/rpc_core/include/rpc_core/detail/log.h | 272 ++++++++ .../rpc_core/detail/msg_dispatcher.hpp | 168 +++++ .../include/rpc_core/detail/msg_wrapper.hpp | 59 ++ .../include/rpc_core/detail/noncopyable.hpp | 17 + .../include/rpc_core/detail/string_view.hpp | 26 + .../include/rpc_core/detail/type_traits.hpp | 24 + 3party/rpc_core/include/rpc_core/dispose.hpp | 61 ++ .../include/rpc_core/plugin/flatbuffers.hpp | 35 ++ .../rpc_core/include/rpc_core/plugin/json.hpp | 26 + .../include/rpc_core/plugin/json_msg.hpp | 26 + 3party/rpc_core/include/rpc_core/request.hpp | 384 ++++++++++++ 3party/rpc_core/include/rpc_core/rpc.hpp | 165 +++++ .../rpc_core/include/rpc_core/serialize.hpp | 34 + .../rpc_core/serialize/binary_wrap.hpp | 38 ++ .../rpc_core/serialize/detail/auto_size.hpp | 73 +++ .../include/rpc_core/serialize/std_array.hpp | 57 ++ .../rpc_core/serialize/std_basic_string.hpp | 42 ++ .../include/rpc_core/serialize/std_bitset.hpp | 33 + .../include/rpc_core/serialize/std_chrono.hpp | 53 ++ .../rpc_core/serialize/std_complex.hpp | 52 ++ .../serialize/std_container_adaptors.hpp | 36 ++ .../rpc_core/serialize/std_forward_list.hpp | 58 ++ .../rpc_core/serialize/std_list_like.hpp | 63 ++ .../include/rpc_core/serialize/std_map.hpp | 57 ++ .../include/rpc_core/serialize/std_pair.hpp | 34 + .../include/rpc_core/serialize/std_set.hpp | 65 ++ .../rpc_core/serialize/std_shared_ptr.hpp | 40 ++ .../include/rpc_core/serialize/std_tuple.hpp | 147 +++++ .../rpc_core/serialize/std_unique_ptr.hpp | 40 ++ .../include/rpc_core/serialize/type_enum.hpp | 20 + .../include/rpc_core/serialize/type_ptr.hpp | 22 + .../include/rpc_core/serialize/type_raw.hpp | 54 ++ .../rpc_core/serialize/type_struct.hpp | 200 ++++++ .../include/rpc_core/serialize/type_void.hpp | 17 + .../include/rpc_core/serialize_type.hpp | 82 +++ 3party/rpc_core/include/rpc_core/type.hpp | 25 + 3party/rpc_core/include/rpc_core/version.hpp | 8 + 3party/rpc_core/library.json | 20 + 3party/rpc_core/test/assert_def.h | 12 + 3party/rpc_core/test/main.cpp | 31 + 3party/rpc_core/test/plugin/JsonType.h | 11 + 3party/rpc_core/test/plugin/RawType.h | 10 + 3party/rpc_core/test/plugin/fb/.clang-format | 1 + 3party/rpc_core/test/plugin/fb/FbMsg.fbs | 9 + .../rpc_core/test/plugin/fb/FbMsg_generated.h | 186 ++++++ 3party/rpc_core/test/serialize/CustomType.h | 65 ++ 3party/rpc_core/test/serialize/TestStruct.h | 10 + 3party/rpc_core/test/test.h | 13 + 3party/rpc_core/test/test_data_packer.cpp | 95 +++ 3party/rpc_core/test/test_plugin.cpp | 86 +++ 3party/rpc_core/test/test_rpc.cpp | 318 ++++++++++ 3party/rpc_core/test/test_serialize.cpp | 586 ++++++++++++++++++ CMakeLists.txt | 1 + tests/3party/rpc_core/rpc_core_unittest.cpp | 40 ++ tests/CMakeLists.txt | 1 + 71 files changed, 4970 insertions(+) create mode 100644 3party/rpc_core/.clang-format create mode 100644 3party/rpc_core/.github/workflows/build.yml create mode 100644 3party/rpc_core/.gitignore create mode 100644 3party/rpc_core/CMakeLists.txt create mode 100644 3party/rpc_core/README.md create mode 100644 3party/rpc_core/include/rpc_core.hpp create mode 100644 3party/rpc_core/include/rpc_core/config.hpp create mode 100644 3party/rpc_core/include/rpc_core/connection.hpp create mode 100644 3party/rpc_core/include/rpc_core/detail/callable/callable.hpp create mode 100644 3party/rpc_core/include/rpc_core/detail/callable/function.hpp create mode 100644 3party/rpc_core/include/rpc_core/detail/callable/functor.hpp create mode 100644 3party/rpc_core/include/rpc_core/detail/callable/helpers.hpp create mode 100644 3party/rpc_core/include/rpc_core/detail/callable/member_function.hpp create mode 100644 3party/rpc_core/include/rpc_core/detail/coder.hpp create mode 100644 3party/rpc_core/include/rpc_core/detail/copyable.hpp create mode 100644 3party/rpc_core/include/rpc_core/detail/data_packer.hpp create mode 100644 3party/rpc_core/include/rpc_core/detail/log.h create mode 100644 3party/rpc_core/include/rpc_core/detail/msg_dispatcher.hpp create mode 100644 3party/rpc_core/include/rpc_core/detail/msg_wrapper.hpp create mode 100644 3party/rpc_core/include/rpc_core/detail/noncopyable.hpp create mode 100644 3party/rpc_core/include/rpc_core/detail/string_view.hpp create mode 100644 3party/rpc_core/include/rpc_core/detail/type_traits.hpp create mode 100644 3party/rpc_core/include/rpc_core/dispose.hpp create mode 100644 3party/rpc_core/include/rpc_core/plugin/flatbuffers.hpp create mode 100644 3party/rpc_core/include/rpc_core/plugin/json.hpp create mode 100644 3party/rpc_core/include/rpc_core/plugin/json_msg.hpp create mode 100644 3party/rpc_core/include/rpc_core/request.hpp create mode 100644 3party/rpc_core/include/rpc_core/rpc.hpp create mode 100644 3party/rpc_core/include/rpc_core/serialize.hpp create mode 100644 3party/rpc_core/include/rpc_core/serialize/binary_wrap.hpp create mode 100644 3party/rpc_core/include/rpc_core/serialize/detail/auto_size.hpp create mode 100644 3party/rpc_core/include/rpc_core/serialize/std_array.hpp create mode 100644 3party/rpc_core/include/rpc_core/serialize/std_basic_string.hpp create mode 100644 3party/rpc_core/include/rpc_core/serialize/std_bitset.hpp create mode 100644 3party/rpc_core/include/rpc_core/serialize/std_chrono.hpp create mode 100644 3party/rpc_core/include/rpc_core/serialize/std_complex.hpp create mode 100644 3party/rpc_core/include/rpc_core/serialize/std_container_adaptors.hpp create mode 100644 3party/rpc_core/include/rpc_core/serialize/std_forward_list.hpp create mode 100644 3party/rpc_core/include/rpc_core/serialize/std_list_like.hpp create mode 100644 3party/rpc_core/include/rpc_core/serialize/std_map.hpp create mode 100644 3party/rpc_core/include/rpc_core/serialize/std_pair.hpp create mode 100644 3party/rpc_core/include/rpc_core/serialize/std_set.hpp create mode 100644 3party/rpc_core/include/rpc_core/serialize/std_shared_ptr.hpp create mode 100644 3party/rpc_core/include/rpc_core/serialize/std_tuple.hpp create mode 100644 3party/rpc_core/include/rpc_core/serialize/std_unique_ptr.hpp create mode 100644 3party/rpc_core/include/rpc_core/serialize/type_enum.hpp create mode 100644 3party/rpc_core/include/rpc_core/serialize/type_ptr.hpp create mode 100644 3party/rpc_core/include/rpc_core/serialize/type_raw.hpp create mode 100644 3party/rpc_core/include/rpc_core/serialize/type_struct.hpp create mode 100644 3party/rpc_core/include/rpc_core/serialize/type_void.hpp create mode 100644 3party/rpc_core/include/rpc_core/serialize_type.hpp create mode 100644 3party/rpc_core/include/rpc_core/type.hpp create mode 100644 3party/rpc_core/include/rpc_core/version.hpp create mode 100644 3party/rpc_core/library.json create mode 100644 3party/rpc_core/test/assert_def.h create mode 100644 3party/rpc_core/test/main.cpp create mode 100644 3party/rpc_core/test/plugin/JsonType.h create mode 100644 3party/rpc_core/test/plugin/RawType.h create mode 100644 3party/rpc_core/test/plugin/fb/.clang-format create mode 100644 3party/rpc_core/test/plugin/fb/FbMsg.fbs create mode 100644 3party/rpc_core/test/plugin/fb/FbMsg_generated.h create mode 100644 3party/rpc_core/test/serialize/CustomType.h create mode 100644 3party/rpc_core/test/serialize/TestStruct.h create mode 100644 3party/rpc_core/test/test.h create mode 100644 3party/rpc_core/test/test_data_packer.cpp create mode 100644 3party/rpc_core/test/test_plugin.cpp create mode 100644 3party/rpc_core/test/test_rpc.cpp create mode 100644 3party/rpc_core/test/test_serialize.cpp create mode 100644 tests/3party/rpc_core/rpc_core_unittest.cpp diff --git a/3party/rpc_core/.clang-format b/3party/rpc_core/.clang-format new file mode 100644 index 0000000..d907df7 --- /dev/null +++ b/3party/rpc_core/.clang-format @@ -0,0 +1,5 @@ +Language: Cpp +BasedOnStyle: Google +ColumnLimit: 150 +AllowShortFunctionsOnASingleLine: Empty +AllowShortLambdasOnASingleLine: Empty diff --git a/3party/rpc_core/.github/workflows/build.yml b/3party/rpc_core/.github/workflows/build.yml new file mode 100644 index 0000000..df4f506 --- /dev/null +++ b/3party/rpc_core/.github/workflows/build.yml @@ -0,0 +1,29 @@ +name: build + +on: + push: + paths-ignore: + - '**.md' + pull_request: + paths-ignore: + - '**.md' + +jobs: + Linux: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: CMake + run: | + mkdir build && cd build + cmake -DCMAKE_BUILD_TYPE=Debug -DRPC_CORE_TEST_PLUGIN=ON .. + + - name: Init thirdparty + run: cd build && make rpc_core_test_init + + - name: Build + run: cd build && make -j2 + + - name: Run + run: cd build && ./rpc_core_test diff --git a/3party/rpc_core/.gitignore b/3party/rpc_core/.gitignore new file mode 100644 index 0000000..4e24b5d --- /dev/null +++ b/3party/rpc_core/.gitignore @@ -0,0 +1,14 @@ +build/ + +# clion +.idea/ +cmake-build-*/ + +# qt creator +CMakeLists.txt.user + +# vscode +.vscode/ + +# thirdparty +/thirdparty/ diff --git a/3party/rpc_core/CMakeLists.txt b/3party/rpc_core/CMakeLists.txt new file mode 100644 index 0000000..0887699 --- /dev/null +++ b/3party/rpc_core/CMakeLists.txt @@ -0,0 +1,54 @@ +cmake_minimum_required(VERSION 3.5) + +project(rpc_core CXX) + +option(RPC_CORE_BUILD_TEST "" OFF) +option(RPC_CORE_TEST_PLUGIN "" OFF) +option(RPC_CORE_TEST_LINK_PTHREAD "" OFF) + +if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) + set(RPC_CORE_BUILD_TEST ON) +endif () + +set(CMAKE_CXX_STANDARD 11) +add_compile_options(-Wall -Wunused-parameter) + +add_library(${PROJECT_NAME} INTERFACE) +target_include_directories(${PROJECT_NAME} INTERFACE include) + +if (RPC_CORE_BUILD_TEST) + set(EXAMPLE_COMPILE_DEFINE + ANDROID_STANDALONE + RPC_CORE_LOG_SHOW_DEBUG + # RPC_CORE_LOG_SHOW_VERBOSE + ) + + set(TARGET_NAME ${PROJECT_NAME}_test) + file(GLOB SRCS test/main.cpp test/test_rpc.cpp test/test_serialize.cpp test/test_data_packer.cpp) + add_executable(${TARGET_NAME}) + if (RPC_CORE_TEST_LINK_PTHREAD) + # some linux platform need link -pthread for std::future api + set(LIBRARIES -pthread) + endif () + target_link_libraries(${TARGET_NAME} ${PROJECT_NAME} ${LIBRARIES}) + target_compile_definitions(${TARGET_NAME} PRIVATE ${EXAMPLE_COMPILE_DEFINE}) + + if (RPC_CORE_TEST_PLUGIN) + list(APPEND SRCS test/test_plugin.cpp) + target_compile_definitions(${TARGET_NAME} PRIVATE "RPC_CORE_TEST_PLUGIN") + add_custom_target(${TARGET_NAME}_init + # clear dir + COMMAND rm -rf ${CMAKE_CURRENT_LIST_DIR}/thirdparty + # json + COMMAND mkdir -p ${CMAKE_CURRENT_LIST_DIR}/thirdparty/nlohmann + COMMAND curl -L -o ${CMAKE_CURRENT_LIST_DIR}/thirdparty/nlohmann/json.hpp https://github.com/nlohmann/json/releases/download/v3.11.2/json.hpp + # flatbuffers + COMMAND git clone https://github.com/google/flatbuffers.git --depth=1 --branch=v23.1.21 ${CMAKE_CURRENT_LIST_DIR}/thirdparty/flatbuffers + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} + ) + + target_include_directories(${TARGET_NAME} PRIVATE thirdparty) + target_include_directories(${TARGET_NAME} PRIVATE thirdparty/flatbuffers/include) + endif () + target_sources(${TARGET_NAME} PRIVATE ${SRCS}) +endif () diff --git a/3party/rpc_core/README.md b/3party/rpc_core/README.md new file mode 100644 index 0000000..a0deb0b --- /dev/null +++ b/3party/rpc_core/README.md @@ -0,0 +1,148 @@ +# rpc_core + +[![Build Status](https://github.com/shuai132/rpc_core/workflows/build/badge.svg)](https://github.com/shuai132/rpc_core/actions?workflow=build) + +a tiny c++11 rpc library, supports all platforms (macOS, Linux, Windows, iOS, Android, etc.) and most microchips ( +Arduino, STM32, ESP32/ESP8266, etc.) + +## Introduction + +The complete rpc frameworks (such as `gRPC` and `brpc`) have complex functions +and are not practical on embedded platforms. + +This project offers a lightweight and user-friendly rpc library that is better suited for one-to-one rpc calls. +It supports all platforms and a wide range of microchips, including Arduino, STM32, ESP32/ESP8266, and more. + +Note: +This project solely offers the protocol layer and API, +and `does not include the implementation of the transport layer`. +For TCP-based implementations: [asio_net](https://github.com/shuai132/asio_net) + +## Features + +* Header-Only +* No-Schema +* Support performance-limited platforms including microchips +* Support any connection type (`tcp socket`, `serial port`, etc.) +* High Performance Serialization, support most STL containers and user type +* Serialization plugins implementations for `flatbuffers` and `nlohmann::json` +* RAII-based `dispose` for automatic cancel request +* Timeout and Retry API +* Support `std::future` interface + +## Requirements + +* C++11 +* Provide your connection implementation: [connection](include/rpc_core/connection.hpp) + NOTICE: complete data packets are required for data transmission, such as `websocket`. + If using `tcp socket`, `serial port`, etc., message pack and unpack need to be implemented. + Or you can use [stream_connection](include/rpc_core/connection.hpp). + +## Usage + +```c++ +// The Receiver +rpc->subscribe("cmd", [](const std::string& msg) -> std::string { + assert(msg == "hello"); + return "world"; +}); + +// The Sender +rpc->cmd("cmd") + ->msg(std::string("hello")) + ->rsp([](const std::string& rsp) { + assert(rsp == "world"); + }) + ->call(); +``` + +`msg` and `rsp` support any serializable type, see [Serialization](#Serialization). + +Detailed usages and unittests can be found here: [rpc_test.cpp](test/test_rpc.cpp) + +## Serialization + +High-performance and memory-saving binary serialization. + +For example, user data: + +```c++ +struct Type { + uint8_t id = 1; + uint8_t age = 18; + std::string name = "test"; +}; +``` + +json: `{"id":1,"age":18,"name":"test"}` + +| library | bytes | +|-------------|:-----:| +| json | 31 | +| flatbuffers | 44 | +| protobuf | 10 | +| msgpack | 8 | +| rpc_core | 8 | + +- [x] [std::string](https://en.cppreference.com/w/cpp/string/basic_string) +- [x] [std::wstring](https://en.cppreference.com/w/cpp/string/basic_string) +- [x] [std::array](https://en.cppreference.com/w/cpp/container/array) +- [x] [std::vector](https://en.cppreference.com/w/cpp/container/vector) +- [x] [std::list](https://en.cppreference.com/w/cpp/container/list) +- [x] [std::forward_list](https://en.cppreference.com/w/cpp/container/forward_list) +- [x] [std::deque](https://en.cppreference.com/w/cpp/container/deque) +- [x] [std::pair](https://en.cppreference.com/w/cpp/utility/pair) +- [x] [std::tuple](https://en.cppreference.com/w/cpp/utility/tuple) +- [x] [std::map](https://en.cppreference.com/w/cpp/container/map) +- [x] [std::unordered_map](https://en.cppreference.com/w/cpp/container/unordered_map) +- [x] [std::multimap](https://en.cppreference.com/w/cpp/container/multimap) +- [x] [std::unordered_multimap](https://en.cppreference.com/w/cpp/container/unordered_multimap) +- [x] [std::set](https://en.cppreference.com/w/cpp/container/set) +- [x] [std::unordered_set](https://en.cppreference.com/w/cpp/container/unordered_set) +- [x] [std::multiset](https://en.cppreference.com/w/cpp/container/multiset) +- [x] [std::unordered_multiset](https://en.cppreference.com/w/cpp/container/unordered_multiset) +- [x] [std::stack](https://en.cppreference.com/w/cpp/container/stack) +- [x] [std::queue](https://en.cppreference.com/w/cpp/container/queue) +- [x] [std::priority_queue](https://en.cppreference.com/w/cpp/container/priority_queue) +- [x] [std::bitset](https://en.cppreference.com/w/cpp/utility/bitset) +- [x] [std::complex](https://en.cppreference.com/w/cpp/numeric/complex) +- [x] [std::chrono::duration](https://en.cppreference.com/w/cpp/chrono/duration) +- [x] [std::chrono::time_point](https://en.cppreference.com/w/cpp/chrono/time_point) +- [x] [std::unique_ptr](https://en.cppreference.com/w/cpp/memory/unique_ptr) +- [x] [std::shared_ptr](https://en.cppreference.com/w/cpp/memory/shared_ptr) +- [x] [rpc_core::binary_wrap](include/rpc_core/serialize/binary_wrap.hpp) +- [x] [custom struct/class](test/serialize/CustomType.h) + ```c++ + #include "rpc_core/serialize.hpp" + struct TestStruct { + uint8_t a; + std::string b; + OtherType c + // RPC_CORE_DEFINE_TYPE_INNER(a, b, c); + }; + RPC_CORE_DEFINE_TYPE(TestStruct, a, b, c); + ``` + choose `RPC_CORE_DEFINE_TYPE` or `RPC_CORE_DEFINE_TYPE_INNER` for private member variable. + +## Serialization Plugins + +* [flatbuffers.hpp](include/rpc_core/plugin/flatbuffers.hpp) + Supports using types generated by `flatbuffers` directly as message + (add the option `--gen-object-api` when using `flatc`) + + +* [json_msg.hpp](include/rpc_core/plugin/json_msg.hpp) + Supports using types supported by [nlohmann/json](https://github.com/nlohmann/json) directly as message + (the `to_json/from_json` rules in `nlohmann/json` need to be satisfied, and use `DEFINE_JSON_CLASS`). + + +* [json.hpp](include/rpc_core/plugin/json.hpp) + A flexible way to use `nlohmann/json` + +## Links + +* Implementation based on asio: [asio_net](https://github.com/shuai132/asio_net) + support macOS, Linux, Windows, iOS, Android, etc. and can be used on MCUs that support asio, such as ESP32. + + +* Implementation suitable for ESP8266: [esp_rpc](https://github.com/shuai132/esp_rpc) diff --git a/3party/rpc_core/include/rpc_core.hpp b/3party/rpc_core/include/rpc_core.hpp new file mode 100644 index 0000000..99ceba0 --- /dev/null +++ b/3party/rpc_core/include/rpc_core.hpp @@ -0,0 +1,10 @@ +#pragma once + +// first include +#include "rpc_core/serialize.hpp" + +// other include +#include "rpc_core/connection.hpp" +#include "rpc_core/dispose.hpp" +#include "rpc_core/request.hpp" +#include "rpc_core/rpc.hpp" diff --git a/3party/rpc_core/include/rpc_core/config.hpp b/3party/rpc_core/include/rpc_core/config.hpp new file mode 100644 index 0000000..0892918 --- /dev/null +++ b/3party/rpc_core/include/rpc_core/config.hpp @@ -0,0 +1,3 @@ +#pragma once + +#include "version.hpp" diff --git a/3party/rpc_core/include/rpc_core/connection.hpp b/3party/rpc_core/include/rpc_core/connection.hpp new file mode 100644 index 0000000..34ebd1c --- /dev/null +++ b/3party/rpc_core/include/rpc_core/connection.hpp @@ -0,0 +1,86 @@ +#pragma once + +#include +#include +#include + +// config +#include "config.hpp" + +// include +#include "detail/data_packer.hpp" +#include "detail/noncopyable.hpp" + +namespace rpc_core { + +/** + * Defines interfaces for sending and receiving messages + * Usage: + * 1. Both sending and receiving should ensure that a complete package of data is sent/received. + * 2. Call on_recv_package when a package of data is actually received. + * 3. Provide the implementation of sending data, send_package_impl. + */ +struct connection : detail::noncopyable { + std::function send_package_impl; + std::function on_recv_package; +}; + +/** + * Default connection avoid crash + */ +struct default_connection : connection { + default_connection() { + send_package_impl = [](const std::string &payload) { + RPC_CORE_LOGE("need send_package_impl: %zu", payload.size()); + }; + on_recv_package = [](const std::string &payload) { + RPC_CORE_LOGE("need on_recv_package: %zu", payload.size()); + }; + } +}; + +/** + * Loopback connection for testing + */ +struct loopback_connection : public connection { + loopback_connection() { + send_package_impl = [this](std::string payload) { + on_recv_package(std::move(payload)); + }; + } +}; + +/** + * Stream connection + * for bytes stream: tcp socket, serial port, etc. + */ +struct stream_connection : public connection { + explicit stream_connection(uint32_t max_body_size = UINT32_MAX) : data_packer_(max_body_size) { + send_package_impl = [this](const std::string &package) { + auto payload = data_packer_.pack(package); + send_bytes_impl(std::move(payload)); + }; + data_packer_.on_data = [this](std::string payload) { + on_recv_package(std::move(payload)); + }; + on_recv_bytes = [this](const void *data, size_t size) { + data_packer_.feed(data, size); + }; + } + + /** + * should call on connected or disconnected + */ + void reset() { + data_packer_.reset(); + } + + public: + std::function send_bytes_impl; + std::function on_recv_bytes; + + private: + detail::data_packer data_packer_; +}; + +} // namespace rpc_core diff --git a/3party/rpc_core/include/rpc_core/detail/callable/callable.hpp b/3party/rpc_core/include/rpc_core/detail/callable/callable.hpp new file mode 100644 index 0000000..fc3a5c2 --- /dev/null +++ b/3party/rpc_core/include/rpc_core/detail/callable/callable.hpp @@ -0,0 +1,58 @@ +#pragma once + +#include +#include + +#include "function.hpp" +#include "functor.hpp" +#include "helpers.hpp" +#include "member_function.hpp" + +namespace rpc_core { + +// There are three basic kinds of callable types +// function types +struct function_tag {}; +// function pointer types +struct function_ptr_tag {}; +// classes with operator() +struct functor_tag {}; + +namespace detail { + +/** Define traits for a operator() member function pointer type */ + +// classes with operator() +template +struct callable_traits : functor_traits { + typedef functor_tag callable_category; +}; + +// functions +template +struct callable_traits : function_traits { + typedef function_tag callable_category; +}; + +// function pointers +template +struct callable_traits : function_traits { + typedef function_ptr_tag callable_category; +}; + +} // namespace detail + +// Main template + +/** Traits for a callable (function/functor/lambda/...) */ +template +struct callable_traits : detail::callable_traits> {}; + +/** Convert a callable to a std::function<> */ +template +std::function::function_type> to_stdfunction(Callable fun) { + std::function::function_type> stdfun(std::forward(fun)); + return stdfun; +} + +} // namespace rpc_core diff --git a/3party/rpc_core/include/rpc_core/detail/callable/function.hpp b/3party/rpc_core/include/rpc_core/detail/callable/function.hpp new file mode 100644 index 0000000..2acd242 --- /dev/null +++ b/3party/rpc_core/include/rpc_core/detail/callable/function.hpp @@ -0,0 +1,40 @@ +#pragma once + +#include + +#include "helpers.hpp" + +namespace rpc_core { + +namespace detail { + +namespace { + +/** Define traits for a function type */ +template +struct function_traits; + +template +struct function_traits { + typedef Ret function_type(Args...); + typedef Ret return_type; + static constexpr std::size_t argc = types_count::value; + + template + using argument_type = typename types_n::type; +}; + +template +const std::size_t function_traits::argc; + +} // namespace + +} // namespace detail + +template +struct function_traits : detail::function_traits> {}; + +template +struct function_traits : detail::function_traits> {}; + +} // namespace rpc_core diff --git a/3party/rpc_core/include/rpc_core/detail/callable/functor.hpp b/3party/rpc_core/include/rpc_core/detail/callable/functor.hpp new file mode 100644 index 0000000..2a0f32b --- /dev/null +++ b/3party/rpc_core/include/rpc_core/detail/callable/functor.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include "function.hpp" +#include "helpers.hpp" +#include "member_function.hpp" + +namespace rpc_core { + +namespace detail { + +template +using call_operator_traits = member_function_traits; + +// classes with operator() +template +struct functor_traits : function_traits::function_type> { + typedef call_operator_traits call_operator; +}; + +} // namespace detail + +template +struct functor_traits : detail::functor_traits> {}; + +} // namespace rpc_core diff --git a/3party/rpc_core/include/rpc_core/detail/callable/helpers.hpp b/3party/rpc_core/include/rpc_core/detail/callable/helpers.hpp new file mode 100644 index 0000000..5b5b4f8 --- /dev/null +++ b/3party/rpc_core/include/rpc_core/detail/callable/helpers.hpp @@ -0,0 +1,58 @@ +#pragma once + +#include + +namespace rpc_core { + +namespace detail { + +/** Remove reference and cv qualification */ +template +using remove_cvref_t = typename std::remove_cv::type>::type; + +/** Count the number of types given to the template */ +template +struct types_count; + +template <> +struct types_count<> { + static constexpr std::size_t value = 0; +}; + +template +struct types_count { + static constexpr std::size_t value = types_count::value + 1; +}; + +/** Get the nth type given to the template */ +template +struct types_n; + +template +struct types_n : types_n {}; + +template +struct types_n<0, Type, Types...> { + typedef Type type; +}; + +/** Test if a type is in a list given types */ +template +struct types_has; + +template +struct types_has { + static constexpr bool value = false; +}; + +template +struct types_has { + static constexpr bool value = true; +}; + +template +struct types_has : types_has {}; + +} // namespace detail + +} // namespace rpc_core diff --git a/3party/rpc_core/include/rpc_core/detail/callable/member_function.hpp b/3party/rpc_core/include/rpc_core/detail/callable/member_function.hpp new file mode 100644 index 0000000..6d5aed6 --- /dev/null +++ b/3party/rpc_core/include/rpc_core/detail/callable/member_function.hpp @@ -0,0 +1,139 @@ +#pragma once + +#include "helpers.hpp" + +namespace rpc_core { + +namespace detail { + +// Tags for member function qualifiers +struct const_tag {}; +struct volatile_tag {}; +struct lref_tag {}; +struct rref_tag {}; +struct noexcept_tag {}; + +namespace { + +template +struct member_function_traits_q : function_traits { + typedef Class class_type; + static constexpr bool is_const = types_has::value; + static constexpr bool is_volatile = types_has::value; + static constexpr bool is_lref = types_has::value; + static constexpr bool is_rref = types_has::value; +#if __cpp_noexcept_function_type + static constexpr bool is_noexcept = types_has::value; +#endif +}; + +// We need these until C++17 in case someone takes the address of one +// of those static variables or passses it by reference to a function +template +const bool member_function_traits_q::is_const; +template +const bool member_function_traits_q::is_volatile; +template +const bool member_function_traits_q::is_lref; +template +const bool member_function_traits_q::is_rref; +#if __cpp_noexcept_function_type +template +const bool member_function_traits_q::is_noexcept; +#endif + +} // namespace + +template +struct member_function_traits; + +template +struct member_function_traits : member_function_traits_q {}; + +template +struct member_function_traits : member_function_traits_q {}; + +template +struct member_function_traits : member_function_traits_q {}; + +template +struct member_function_traits : member_function_traits_q {}; + +template +struct member_function_traits : member_function_traits_q {}; + +template +struct member_function_traits : member_function_traits_q {}; + +template +struct member_function_traits : member_function_traits_q {}; + +template +struct member_function_traits + : member_function_traits_q {}; + +template +struct member_function_traits : member_function_traits_q {}; + +template +struct member_function_traits : member_function_traits_q {}; + +template +struct member_function_traits : member_function_traits_q {}; + +template +struct member_function_traits + : member_function_traits_q {}; + +#if __cpp_noexcept_function_type +template +struct member_function_traits : member_function_traits_q {}; + +template +struct member_function_traits : member_function_traits_q {}; + +template +struct member_function_traits : member_function_traits_q { +}; + +template +struct member_function_traits + : member_function_traits_q {}; + +template +struct member_function_traits : member_function_traits_q {}; + +template +struct member_function_traits + : member_function_traits_q {}; + +template +struct member_function_traits + : member_function_traits_q {}; + +template +struct member_function_traits + : member_function_traits_q {}; + +template +struct member_function_traits : member_function_traits_q {}; + +template +struct member_function_traits + : member_function_traits_q {}; + +template +struct member_function_traits + : member_function_traits_q {}; + +template +struct member_function_traits + : member_function_traits_q {}; +#endif // __cpp_noexcept_function_type + +} // namespace detail + +template +struct member_function_traits : detail::member_function_traits> {}; + +} // namespace rpc_core diff --git a/3party/rpc_core/include/rpc_core/detail/coder.hpp b/3party/rpc_core/include/rpc_core/detail/coder.hpp new file mode 100644 index 0000000..6b4c2fe --- /dev/null +++ b/3party/rpc_core/include/rpc_core/detail/coder.hpp @@ -0,0 +1,56 @@ +#pragma once + +#include "msg_wrapper.hpp" + +namespace rpc_core { +namespace detail { + +class coder { + public: + static std::string serialize(const msg_wrapper& msg) { + std::string payload; + payload.reserve(PayloadMinLen + msg.cmd.size() + msg.data.size()); + payload.append((char*)&msg.seq, 4); + uint16_t cmdLen = msg.cmd.length(); + payload.append((char*)&cmdLen, 2); + payload.append((char*)msg.cmd.data(), cmdLen); + payload.append((char*)&msg.type, 1); + if (msg.request_payload) { + payload.append(*msg.request_payload); + } else { + payload.append(msg.data); + } + return payload; + } + + static msg_wrapper deserialize(const std::string& payload, bool& ok) { + msg_wrapper msg; + if (payload.size() < PayloadMinLen) { + ok = false; + return msg; + } + char* p = (char*)payload.data(); + const char* pend = payload.data() + payload.size(); + msg.seq = *(seq_type*)p; + p += 4; + uint16_t cmdLen = *(uint16_t*)p; + p += 2; + if (p + cmdLen + 1 > pend) { + ok = false; + return msg; + } + msg.cmd.append(p, cmdLen); + p += cmdLen; + msg.type = *(msg_wrapper::msg_type*)(p); + p += 1; + msg.data.append(p, pend - p); + ok = true; + return msg; + } + + private: + static const uint8_t PayloadMinLen = 4 /*seq*/ + 2 /*cmdLen*/ + 1 /*type*/; +}; + +} // namespace detail +} // namespace rpc_core diff --git a/3party/rpc_core/include/rpc_core/detail/copyable.hpp b/3party/rpc_core/include/rpc_core/detail/copyable.hpp new file mode 100644 index 0000000..2284b8a --- /dev/null +++ b/3party/rpc_core/include/rpc_core/detail/copyable.hpp @@ -0,0 +1,17 @@ +#pragma once + +namespace rpc_core { +namespace detail { + +class copyable { + public: + copyable(const copyable&) = default; + copyable& operator=(const copyable&) = default; + + protected: + copyable() = default; + ~copyable() = default; +}; + +} // namespace detail +} // namespace rpc_core diff --git a/3party/rpc_core/include/rpc_core/detail/data_packer.hpp b/3party/rpc_core/include/rpc_core/detail/data_packer.hpp new file mode 100644 index 0000000..ea2bd6f --- /dev/null +++ b/3party/rpc_core/include/rpc_core/detail/data_packer.hpp @@ -0,0 +1,120 @@ +#pragma once + +#include +#include +#include + +// #define RPC_CORE_LOG_SHOW_VERBOSE +#include "log.h" +#include "noncopyable.hpp" + +namespace rpc_core { +namespace detail { + +class data_packer : detail::noncopyable { + public: + explicit data_packer(uint32_t max_body_size = UINT32_MAX) : max_body_size_(max_body_size) {} + + public: + bool pack(const void *data, size_t size, const std::function &cb) const { + if (size > max_body_size_) { + return false; + } + auto ret = cb(&size, 4); + if (!ret) return false; + ret = cb(data, size); + if (!ret) return false; + + return true; + } + + std::string pack(const void *data, size_t size) const { + std::string payload; + if (size > max_body_size_) { + RPC_CORE_LOGW("size > max_body_size: %zu > %u", size, max_body_size_); + return payload; + } + payload.insert(0, (char *)&size, 4); + payload.insert(payload.size(), (char *)data, size); + return payload; + } + + std::string pack(const std::string &data) const { + return pack(data.data(), data.size()); + } + + public: + bool feed(const void *data, size_t size) { // NOLINT(misc-no-recursion) + if (body_size_ != 0) { + feed_body(data, size); + return true; + } + + /// wait header(4 bytes) + if (header_len_now_ + size < 4) { + buffer_.insert(buffer_.size(), (char *)data, size); + header_len_now_ += size; + return true; + } + + /// herder data ready, start read body + // 1. read header, aka: body size + uint8_t header_len = 4 - header_len_now_; + size_t body_len = size - header_len; + for (int i = 0; i < header_len; ++i) { + buffer_.push_back(((char *)data)[i]); + } + body_size_ = *(uint32_t *)(buffer_.data()); + buffer_.clear(); + RPC_CORE_LOGV("feed: wait body_size: %u", body_size_); + if (body_size_ > max_body_size_) { + RPC_CORE_LOGW("body_size > max_body_size: %u > %u", body_size_, max_body_size_); + reset(); + return false; + } + + // 2. feed body + if (body_len != 0) { + feed_body((char *)data + header_len, body_len); + } + return true; + } + + void reset() { + buffer_.clear(); + buffer_.shrink_to_fit(); + header_len_now_ = 0; + body_size_ = 0; + } + + private: + void feed_body(const void *data, size_t size) { // NOLINT(misc-no-recursion) + if (buffer_.size() + size < body_size_) { + buffer_.insert(buffer_.size(), (char *)data, size); + } else { + size_t body_need = body_size_ - buffer_.size(); + size_t body_left = size - body_need; + buffer_.insert(buffer_.size(), (char *)data, body_need); + if (on_data) on_data(std::move(buffer_)); + + reset(); + + if (body_left != 0) { + feed((char *)data + body_need, body_left); + } + } + } + + public: + std::function on_data; + + private: + uint32_t max_body_size_; + std::string buffer_; + + uint32_t header_len_now_ = 0; + uint32_t body_size_ = 0; +}; + +} // namespace detail +} // namespace rpc_core diff --git a/3party/rpc_core/include/rpc_core/detail/log.h b/3party/rpc_core/include/rpc_core/detail/log.h new file mode 100644 index 0000000..048ee5b --- /dev/null +++ b/3party/rpc_core/include/rpc_core/detail/log.h @@ -0,0 +1,272 @@ +// 1. 全局控制 +// L_O_G_NDEBUG 关闭DEBUG日志(默认依据NDEBUG自动判断) +// L_O_G_SHOW_DEBUG 强制开启DEBUG日志 +// L_O_G_DISABLE_ALL 关闭所有日志 +// L_O_G_DISABLE_COLOR 禁用颜色显示 +// L_O_G_LINE_END_CRLF 默认是\n结尾 添加此宏将以\r\n结尾 +// L_O_G_FOR_MCU 更适用于MCU环境 +// L_O_G_NOT_EXIT_ON_FATAL FATAL默认退出程序 添加此宏将不退出 +// L_O_G_SHOW_FULL_PATH 显示文件绝对路径 +// +// c++11环境默认打开以下内容 +// L_O_G_ENABLE_THREAD_SAFE 线程安全 +// L_O_G_ENABLE_THREAD_ID 显示线程ID +// L_O_G_ENABLE_DATE_TIME 显示日期 +// 分别可通过下列禁用 +// L_O_G_DISABLE_THREAD_SAFE +// L_O_G_DISABLE_THREAD_ID +// L_O_G_DISABLE_DATE_TIME +// 可通过`L_O_G_GET_TID_CUSTOM`自定义获取线程ID的实现 +// +// 2. 自定义实现 +// L_O_G_PRINTF_CUSTOM 自定义输出实现 +// 并添加实现`int L_O_G_PRINTF_CUSTOM(const char *fmt, ...)` +// +// 3. 在库中使用时 +// 3.1. 替换`RPC_CORE_LOG`为库名 +// 3.2. 定义`RPC_CORE_LOG_IN_LIB` +// 3.3. 可配置项 +// RPC_CORE_LOG_SHOW_DEBUG 开启RPC_CORE_LOGD的输出 +// RPC_CORE_LOG_SHOW_VERBOSE 显示RPC_CORE_LOGV的输出 +// RPC_CORE_LOG_DISABLE_ALL 关闭所有日志 + +#pragma once + +// clang-format off + +#define RPC_CORE_LOG_IN_LIB + +#if defined(RPC_CORE_LOG_DISABLE_ALL) || defined(L_O_G_DISABLE_ALL) + +#define RPC_CORE_LOG(fmt, ...) ((void)0) +#define RPC_CORE_LOGT(tag, fmt, ...) ((void)0) +#define RPC_CORE_LOGI(fmt, ...) ((void)0) +#define RPC_CORE_LOGW(fmt, ...) ((void)0) +#define RPC_CORE_LOGE(fmt, ...) ((void)0) +#define RPC_CORE_LOGF(fmt, ...) ((void)0) +#define RPC_CORE_LOGD(fmt, ...) ((void)0) +#define RPC_CORE_LOGV(fmt, ...) ((void)0) + +#else + +#ifdef __cplusplus +#include +#include +#if __cplusplus >= 201103L + +#if !defined(L_O_G_DISABLE_THREAD_SAFE) && !defined(L_O_G_ENABLE_THREAD_SAFE) +#define L_O_G_ENABLE_THREAD_SAFE +#endif + +#if !defined(L_O_G_DISABLE_THREAD_ID) && !defined(L_O_G_ENABLE_THREAD_ID) +#define L_O_G_ENABLE_THREAD_ID +#endif + +#if !defined(L_O_G_DISABLE_DATE_TIME) && !defined(L_O_G_ENABLE_DATE_TIME) +#define L_O_G_ENABLE_DATE_TIME +#endif + +#endif +#else +#include +#include +#endif + +#ifdef L_O_G_LINE_END_CRLF +#define RPC_CORE_LOG_LINE_END "\r\n" +#else +#define RPC_CORE_LOG_LINE_END "\n" +#endif + +#ifdef L_O_G_NOT_EXIT_ON_FATAL +#define RPC_CORE_LOG_EXIT_PROGRAM() +#else +#ifdef L_O_G_FOR_MCU +#define RPC_CORE_LOG_EXIT_PROGRAM() do{ for(;;); } while(0) +#else +#define RPC_CORE_LOG_EXIT_PROGRAM() exit(EXIT_FAILURE) +#endif +#endif + +#ifdef L_O_G_SHOW_FULL_PATH +#define RPC_CORE_LOG_BASE_FILENAME (__FILE__) +#else +#ifdef __FILE_NAME__ +#define RPC_CORE_LOG_BASE_FILENAME (__FILE_NAME__) +#else +#define RPC_CORE_LOG_BASE_FILENAME (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__) +#endif +#endif + +#define RPC_CORE_LOG_WITH_COLOR + +#if defined(_WIN32) || (defined(__ANDROID__) && !defined(ANDROID_STANDALONE)) || defined(L_O_G_FOR_MCU) +#undef RPC_CORE_LOG_WITH_COLOR +#endif + +#ifdef L_O_G_DISABLE_COLOR +#undef RPC_CORE_LOG_WITH_COLOR +#endif + +#ifdef RPC_CORE_LOG_WITH_COLOR +#define RPC_CORE_LOG_COLOR_RED "\033[31m" +#define RPC_CORE_LOG_COLOR_GREEN "\033[32m" +#define RPC_CORE_LOG_COLOR_YELLOW "\033[33m" +#define RPC_CORE_LOG_COLOR_BLUE "\033[34m" +#define RPC_CORE_LOG_COLOR_CARMINE "\033[35m" +#define RPC_CORE_LOG_COLOR_CYAN "\033[36m" +#define RPC_CORE_LOG_COLOR_DEFAULT +#define RPC_CORE_LOG_COLOR_END "\033[m" +#else +#define RPC_CORE_LOG_COLOR_RED +#define RPC_CORE_LOG_COLOR_GREEN +#define RPC_CORE_LOG_COLOR_YELLOW +#define RPC_CORE_LOG_COLOR_BLUE +#define RPC_CORE_LOG_COLOR_CARMINE +#define RPC_CORE_LOG_COLOR_CYAN +#define RPC_CORE_LOG_COLOR_DEFAULT +#define RPC_CORE_LOG_COLOR_END +#endif + +#define RPC_CORE_LOG_END RPC_CORE_LOG_COLOR_END RPC_CORE_LOG_LINE_END + +#ifndef L_O_G_PRINTF +#ifndef RPC_CORE_LOG_PRINTF_DEFAULT +#if defined(__ANDROID__) && !defined(ANDROID_STANDALONE) +#include +#define RPC_CORE_LOG_PRINTF_DEFAULT(...) __android_log_print(ANDROID_L##OG_DEBUG, "RPC_CORE_LOG", __VA_ARGS__) +#else +#define RPC_CORE_LOG_PRINTF_DEFAULT(...) printf(__VA_ARGS__) +#endif +#endif + +#ifndef L_O_G_PRINTF_CUSTOM +#ifdef __cplusplus +#include +#else +#include +#endif +#ifdef L_O_G_ENABLE_THREAD_SAFE +#ifndef L_O_G_NS_MUTEX +#define L_O_G_NS_MUTEX L_O_G_NS_MUTEX +#include +// 1. struct instead of namespace, ensure single instance +struct L_O_G_NS_MUTEX { +static std::mutex& mutex() { + // 2. never delete, avoid destroy before user log + // 3. static memory, avoid memory fragmentation + static char memory[sizeof(std::mutex)]; + static std::mutex& mutex = *(new (memory) std::mutex()); + return mutex; +} +}; +#endif +#define L_O_G_PRINTF(...) { \ + std::lock_guard lock(L_O_G_NS_MUTEX::mutex()); \ + RPC_CORE_LOG_PRINTF_DEFAULT(__VA_ARGS__); \ +} +#else +#define L_O_G_PRINTF(...) RPC_CORE_LOG_PRINTF_DEFAULT(__VA_ARGS__) +#endif +#else +extern int L_O_G_PRINTF_CUSTOM(const char *fmt, ...); +#define L_O_G_PRINTF(...) L_O_G_PRINTF_CUSTOM(__VA_ARGS__) +#endif +#endif + +#ifdef L_O_G_ENABLE_THREAD_ID +#ifndef L_O_G_NS_GET_TID +#define L_O_G_NS_GET_TID L_O_G_NS_GET_TID +#include +#ifdef L_O_G_GET_TID_CUSTOM +extern uint32_t L_O_G_GET_TID_CUSTOM(); +#elif defined(_WIN32) +#include +struct L_O_G_NS_GET_TID { +static inline uint32_t get_tid() { + return GetCurrentThreadId(); +} +}; +#elif defined(__linux__) +#include +#include +struct L_O_G_NS_GET_TID { +static inline uint32_t get_tid() { + return syscall(SYS_gettid); +} +}; +#else /* for mac, bsd.. */ +#include +struct L_O_G_NS_GET_TID { +static inline uint32_t get_tid() { + uint64_t x; + pthread_threadid_np(nullptr, &x); + return (uint32_t)x; +} +}; +#endif +#endif +#ifdef L_O_G_GET_TID_CUSTOM +#define RPC_CORE_LOG_THREAD_LABEL "%u " +#define RPC_CORE_LOG_THREAD_VALUE ,L_O_G_GET_TID_CUSTOM() +#else +#define RPC_CORE_LOG_THREAD_LABEL "%u " +#define RPC_CORE_LOG_THREAD_VALUE ,L_O_G_NS_GET_TID::get_tid() +#endif +#else +#define RPC_CORE_LOG_THREAD_LABEL +#define RPC_CORE_LOG_THREAD_VALUE +#endif + +#ifdef L_O_G_ENABLE_DATE_TIME +#include +#include +#include // std::put_time +#ifndef L_O_G_NS_GET_TIME +#define L_O_G_NS_GET_TIME L_O_G_NS_GET_TIME +struct L_O_G_NS_GET_TIME { +static inline std::string get_time() { + auto now = std::chrono::system_clock::now(); + std::time_t time = std::chrono::system_clock::to_time_t(now); + auto ms = std::chrono::duration_cast(now.time_since_epoch()) % 1000; + std::stringstream ss; + ss << std::put_time(std::localtime(&time), "%Y-%m-%d %H:%M:%S") << '.' << std::setw(3) << std::setfill('0') << ms.count(); + return ss.str(); +} +}; +#endif +#define RPC_CORE_LOG_TIME_LABEL "%s " +#define RPC_CORE_LOG_TIME_VALUE ,L_O_G_NS_GET_TIME::get_time().c_str() +#else +#define RPC_CORE_LOG_TIME_LABEL +#define RPC_CORE_LOG_TIME_VALUE +#endif + +#define RPC_CORE_LOG(fmt, ...) do{ L_O_G_PRINTF(RPC_CORE_LOG_COLOR_GREEN RPC_CORE_LOG_TIME_LABEL RPC_CORE_LOG_THREAD_LABEL "[*]: %s:%d " fmt RPC_CORE_LOG_END RPC_CORE_LOG_TIME_VALUE RPC_CORE_LOG_THREAD_VALUE, RPC_CORE_LOG_BASE_FILENAME, __LINE__, ##__VA_ARGS__); } while(0) +#define RPC_CORE_LOGT(tag, fmt, ...) do{ L_O_G_PRINTF(RPC_CORE_LOG_COLOR_BLUE RPC_CORE_LOG_TIME_LABEL RPC_CORE_LOG_THREAD_LABEL "[" tag "]: %s:%d " fmt RPC_CORE_LOG_END RPC_CORE_LOG_TIME_VALUE RPC_CORE_LOG_THREAD_VALUE, RPC_CORE_LOG_BASE_FILENAME, __LINE__, ##__VA_ARGS__); } while(0) +#define RPC_CORE_LOGI(fmt, ...) do{ L_O_G_PRINTF(RPC_CORE_LOG_COLOR_YELLOW RPC_CORE_LOG_TIME_LABEL RPC_CORE_LOG_THREAD_LABEL "[I]: %s:%d " fmt RPC_CORE_LOG_END RPC_CORE_LOG_TIME_VALUE RPC_CORE_LOG_THREAD_VALUE, RPC_CORE_LOG_BASE_FILENAME, __LINE__, ##__VA_ARGS__); } while(0) +#define RPC_CORE_LOGW(fmt, ...) do{ L_O_G_PRINTF(RPC_CORE_LOG_COLOR_CARMINE RPC_CORE_LOG_TIME_LABEL RPC_CORE_LOG_THREAD_LABEL "[W]: %s:%d [%s] " fmt RPC_CORE_LOG_END RPC_CORE_LOG_TIME_VALUE RPC_CORE_LOG_THREAD_VALUE, RPC_CORE_LOG_BASE_FILENAME, __LINE__, __func__, ##__VA_ARGS__); } while(0) // NOLINT(bugprone-lambda-function-name) +#define RPC_CORE_LOGE(fmt, ...) do{ L_O_G_PRINTF(RPC_CORE_LOG_COLOR_RED RPC_CORE_LOG_TIME_LABEL RPC_CORE_LOG_THREAD_LABEL "[E]: %s:%d [%s] " fmt RPC_CORE_LOG_END RPC_CORE_LOG_TIME_VALUE RPC_CORE_LOG_THREAD_VALUE, RPC_CORE_LOG_BASE_FILENAME, __LINE__, __func__, ##__VA_ARGS__); } while(0) // NOLINT(bugprone-lambda-function-name) +#define RPC_CORE_LOGF(fmt, ...) do{ L_O_G_PRINTF(RPC_CORE_LOG_COLOR_CYAN RPC_CORE_LOG_TIME_LABEL RPC_CORE_LOG_THREAD_LABEL "[!]: %s:%d [%s] " fmt RPC_CORE_LOG_END RPC_CORE_LOG_TIME_VALUE RPC_CORE_LOG_THREAD_VALUE, RPC_CORE_LOG_BASE_FILENAME, __LINE__, __func__, ##__VA_ARGS__); RPC_CORE_LOG_EXIT_PROGRAM(); } while(0) // NOLINT(bugprone-lambda-function-name) + +#if defined(RPC_CORE_LOG_IN_LIB) && !defined(RPC_CORE_LOG_SHOW_DEBUG) && !defined(L_O_G_NDEBUG) +#define RPC_CORE_LOG_NDEBUG +#endif + +#if defined(L_O_G_NDEBUG) && !defined(RPC_CORE_LOG_NDEBUG) +#define RPC_CORE_LOG_NDEBUG +#endif + +#if (defined(NDEBUG) || defined(RPC_CORE_LOG_NDEBUG)) && !defined(L_O_G_SHOW_DEBUG) +#define RPC_CORE_LOGD(fmt, ...) ((void)0) +#else +#define RPC_CORE_LOGD(fmt, ...) do{ L_O_G_PRINTF(RPC_CORE_LOG_COLOR_DEFAULT RPC_CORE_LOG_TIME_LABEL RPC_CORE_LOG_THREAD_LABEL "[D]: %s:%d " fmt RPC_CORE_LOG_END RPC_CORE_LOG_TIME_VALUE RPC_CORE_LOG_THREAD_VALUE, RPC_CORE_LOG_BASE_FILENAME, __LINE__, ##__VA_ARGS__); } while(0) +#endif + +#if defined(RPC_CORE_LOG_SHOW_VERBOSE) +#define RPC_CORE_LOGV(fmt, ...) do{ L_O_G_PRINTF(RPC_CORE_LOG_COLOR_DEFAULT RPC_CORE_LOG_TIME_LABEL RPC_CORE_LOG_THREAD_LABEL "[V]: %s:%d " fmt RPC_CORE_LOG_END RPC_CORE_LOG_TIME_VALUE RPC_CORE_LOG_THREAD_VALUE, RPC_CORE_LOG_BASE_FILENAME, __LINE__, ##__VA_ARGS__); } while(0) +#else +#define RPC_CORE_LOGV(fmt, ...) ((void)0) +#endif + +#endif diff --git a/3party/rpc_core/include/rpc_core/detail/msg_dispatcher.hpp b/3party/rpc_core/include/rpc_core/detail/msg_dispatcher.hpp new file mode 100644 index 0000000..a5e2ebf --- /dev/null +++ b/3party/rpc_core/include/rpc_core/detail/msg_dispatcher.hpp @@ -0,0 +1,168 @@ +#pragma once + +#include +#include +#include + +#include "../connection.hpp" +#include "coder.hpp" +#include "log.h" +#include "noncopyable.hpp" + +namespace rpc_core { +namespace detail { + +class msg_dispatcher : noncopyable { + public: + using cmd_handle = std::function(msg_wrapper)>; + using rsp_handle = std::function; + + using timeout_cb = std::function; + using timer_impl = std::function; + + public: + explicit msg_dispatcher(std::shared_ptr conn) : conn_(std::move(conn)) { + auto alive = std::weak_ptr(is_alive_); + conn_->on_recv_package = ([this, RPC_CORE_MOVE_LAMBDA(alive)](const std::string& payload) { + if (alive.expired()) { + RPC_CORE_LOGD("msg_dispatcher expired"); + return; + } + bool success; + auto msg = coder::deserialize(payload, success); + if (success) { + this->dispatch(std::move(msg)); + } else { + RPC_CORE_LOGE("payload deserialize error"); + } + }); + } + + private: + void dispatch(msg_wrapper msg) { + switch (msg.type & (msg_wrapper::command | msg_wrapper::response)) { + case msg_wrapper::command: { + // ping + const bool is_ping = msg.type & msg_wrapper::ping; + if (is_ping) { + RPC_CORE_LOGD("<= seq:%u type:ping", msg.seq); + msg.type = static_cast(msg_wrapper::response | msg_wrapper::pong); + RPC_CORE_LOGD("=> seq:%u type:pong", msg.seq); + conn_->send_package_impl(coder::serialize(msg)); + return; + } + + // command + RPC_CORE_LOGD("<= seq:%u cmd:%s", msg.seq, msg.cmd.c_str()); + const auto& cmd = msg.cmd; + auto it = cmd_handle_map_.find(cmd); + if (it == cmd_handle_map_.cend()) { + RPC_CORE_LOGD("not subscribe cmd for: %s", cmd.c_str()); + const bool need_rsp = msg.type & msg_wrapper::need_rsp; + if (need_rsp) { + RPC_CORE_LOGD("=> seq:%u type:rsp", msg.seq); + msg_wrapper rsp; + rsp.seq = msg.seq; + rsp.type = static_cast(msg_wrapper::msg_type::response | msg_wrapper::msg_type::no_such_cmd); + conn_->send_package_impl(coder::serialize(rsp)); + } + return; + } + const auto& fn = it->second; + const bool need_rsp = msg.type & msg_wrapper::need_rsp; + auto resp = fn(msg); + if (need_rsp && resp.first) { + RPC_CORE_LOGD("=> seq:%u type:rsp", msg.seq); + conn_->send_package_impl(coder::serialize(resp.second)); + } + } break; + + case msg_wrapper::response: { + // pong or response + const bool isPong = msg.type & msg_wrapper::pong; + const auto handleMap = isPong ? &pong_handle_map_ : &rsp_handle_map_; + + RPC_CORE_LOGD("<= seq:%u type:%s", msg.seq, (msg.type & detail::msg_wrapper::msg_type::pong) ? "pong" : "rsp"); + auto it = handleMap->find(msg.seq); + if (it == handleMap->cend()) { + RPC_CORE_LOGD("no rsp for seq:%u", msg.seq); + break; + } + const auto& cb = it->second; + if (not cb) { + RPC_CORE_LOGE("rsp can not be null"); + return; + } + if (cb(std::move(msg))) { + handleMap->erase(it); + RPC_CORE_LOGV("handleMap->size=%zu", handleMap->size()); + } else { + RPC_CORE_LOGE("may deserialize error"); + } + } break; + + default: + RPC_CORE_LOGE("unknown type"); + } + } + + public: + inline void subscribe_cmd(const cmd_type& cmd, cmd_handle handle) { + RPC_CORE_LOGD("subscribe cmd:%s", cmd.c_str()); + cmd_handle_map_[cmd] = std::move(handle); + } + + void unsubscribe_cmd(const cmd_type& cmd) { + auto it = cmd_handle_map_.find(cmd); + if (it != cmd_handle_map_.cend()) { + RPC_CORE_LOGD("erase cmd:%s", cmd.c_str()); + cmd_handle_map_.erase(it); + } else { + RPC_CORE_LOGD("not subscribe cmd for: %s", cmd.c_str()); + } + } + + void subscribe_rsp(seq_type seq, rsp_handle handle, RPC_CORE_MOVE_PARAM(timeout_cb) timeout_cb, uint32_t timeout_ms, bool is_ping) { + RPC_CORE_LOGD("subscribe_rsp seq:%u", seq); + if (handle == nullptr) return; + const auto handleMap = is_ping ? &pong_handle_map_ : &rsp_handle_map_; + + (*handleMap)[seq] = std::move(handle); + + if (timer_impl_ == nullptr) { + RPC_CORE_LOGW("no timeout will cause memory leak!"); + return; + } + + auto alive = std::weak_ptr(is_alive_); + timer_impl_(timeout_ms, [handleMap, seq, RPC_CORE_MOVE_LAMBDA(timeout_cb), RPC_CORE_MOVE_LAMBDA(alive)] { + if (alive.expired()) { + RPC_CORE_LOGD("seq:%u timeout after destroy", seq); + return; + } + auto it = handleMap->find(seq); + if (it != handleMap->cend()) { + if (timeout_cb) { + timeout_cb(); + } + handleMap->erase(seq); + RPC_CORE_LOGV("Timeout seq=%d, handleMap.size=%zu", seq, handleMap->size()); + } + }); + } + + inline void set_timer_impl(timer_impl timer_impl) { + timer_impl_ = std::move(timer_impl); + } + + private: + std::shared_ptr conn_; + std::map cmd_handle_map_; + std::map rsp_handle_map_; + std::map pong_handle_map_; + timer_impl timer_impl_; + std::shared_ptr is_alive_ = std::make_shared(); +}; + +} // namespace detail +} // namespace rpc_core diff --git a/3party/rpc_core/include/rpc_core/detail/msg_wrapper.hpp b/3party/rpc_core/include/rpc_core/detail/msg_wrapper.hpp new file mode 100644 index 0000000..abbcaa6 --- /dev/null +++ b/3party/rpc_core/include/rpc_core/detail/msg_wrapper.hpp @@ -0,0 +1,59 @@ +#pragma once + +#include +#include + +#include "../type.hpp" +#include "copyable.hpp" +#include "log.h" +#include "msg_wrapper.hpp" + +namespace rpc_core { +namespace detail { + +struct msg_wrapper : copyable { // NOLINT + enum msg_type : uint8_t { + command = 1 << 0, + response = 1 << 1, + need_rsp = 1 << 2, + ping = 1 << 3, + pong = 1 << 4, + no_such_cmd = 1 << 5, + }; + + seq_type seq; + cmd_type cmd; + msg_type type; + std::string data; + std::string* request_payload = nullptr; + + std::string dump() const { + char tmp[100]; + snprintf(tmp, 100, "seq:%u, type:%u, cmd:%s", seq, type, cmd.c_str()); + return tmp; + } + + template + std::pair unpack_as() const { + T message; + bool ok = deserialize(data, message); + if (not ok) { + RPC_CORE_LOGE("deserialize error, msg info:%s", dump().c_str()); + } + return std::make_pair(ok, std::move(message)); + } + + template + static std::pair make_rsp(seq_type seq, T* t = nullptr, bool success = true) { + msg_wrapper msg; + msg.type = msg_wrapper::response; + msg.seq = seq; + if (success && t != nullptr) { + msg.data = serialize(*t); + } + return std::make_pair(success, std::move(msg)); + } +}; + +} // namespace detail +} // namespace rpc_core diff --git a/3party/rpc_core/include/rpc_core/detail/noncopyable.hpp b/3party/rpc_core/include/rpc_core/detail/noncopyable.hpp new file mode 100644 index 0000000..3dcff71 --- /dev/null +++ b/3party/rpc_core/include/rpc_core/detail/noncopyable.hpp @@ -0,0 +1,17 @@ +#pragma once + +namespace rpc_core { +namespace detail { + +class noncopyable { + public: + noncopyable(const noncopyable&) = delete; + noncopyable& operator=(const noncopyable&) = delete; + + protected: + noncopyable() = default; + ~noncopyable() = default; +}; + +} // namespace detail +} // namespace rpc_core diff --git a/3party/rpc_core/include/rpc_core/detail/string_view.hpp b/3party/rpc_core/include/rpc_core/detail/string_view.hpp new file mode 100644 index 0000000..1630db0 --- /dev/null +++ b/3party/rpc_core/include/rpc_core/detail/string_view.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include +#include + +namespace rpc_core { +namespace detail { + +class string_view { + public: + string_view(const char* data, size_t size) : data_(data), size_(size) {} + string_view(const std::string& data) : data_(data.data()), size_(data.size()) {} // NOLINT + const char* data() const { + return data_; + } + size_t size() const { + return size_; + } + + private: + const char* data_; + size_t size_; +}; + +} // namespace detail +} // namespace rpc_core diff --git a/3party/rpc_core/include/rpc_core/detail/type_traits.hpp b/3party/rpc_core/include/rpc_core/detail/type_traits.hpp new file mode 100644 index 0000000..036a929 --- /dev/null +++ b/3party/rpc_core/include/rpc_core/detail/type_traits.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include + +namespace rpc_core { +namespace detail { + +template +struct all_base_of { + static constexpr bool value = std::is_base_of::value && all_base_of::value; +}; + +template +struct all_base_of { + static constexpr bool value = std::is_base_of::value; +}; + +template +constexpr const T& min(const T& a, const T& b) { + return a < b ? a : b; +} + +} // namespace detail +} // namespace rpc_core diff --git a/3party/rpc_core/include/rpc_core/dispose.hpp b/3party/rpc_core/include/rpc_core/dispose.hpp new file mode 100644 index 0000000..f6a3526 --- /dev/null +++ b/3party/rpc_core/include/rpc_core/dispose.hpp @@ -0,0 +1,61 @@ +#pragma once + +#include +#include +#include + +// #define RPC_CORE_LOG_SHOW_VERBOSE + +// config +#include "config.hpp" + +// include +#include "detail/noncopyable.hpp" +#include "request.hpp" + +namespace rpc_core { + +class dispose : detail::noncopyable, public request::dispose_proto { + public: + static std::shared_ptr create() { + return std::make_shared(); + } + + public: + void add(const request_s& request) override { + RPC_CORE_LOGV("add: ptr:%p", request.get()); + requests_.push_back(request_w{request}); + } + + void remove(const request_s& request) override { + RPC_CORE_LOGV("remove: ptr:%p", request.get()); + auto iter = std::remove_if(requests_.begin(), requests_.end(), [&](request_w& param) { + auto r = param.lock(); + if (!r) return true; + return r == request; + }); + requests_.erase(iter); + } + + void dismiss() { + for (const auto& item : requests_) { + auto r = item.lock(); + if (r) { + r->cancel(); + } + } + requests_.clear(); + } + + ~dispose() override { + RPC_CORE_LOGD("~dispose: size:%zu", requests_.size()); + dismiss(); + } + + private: + std::vector requests_; +}; + +using dispose_s = std::shared_ptr; + +} // namespace rpc_core diff --git a/3party/rpc_core/include/rpc_core/plugin/flatbuffers.hpp b/3party/rpc_core/include/rpc_core/plugin/flatbuffers.hpp new file mode 100644 index 0000000..6b19768 --- /dev/null +++ b/3party/rpc_core/include/rpc_core/plugin/flatbuffers.hpp @@ -0,0 +1,35 @@ +#pragma once + +#include "flatbuffers/flatbuffers.h" +#include "rpc_core/serialize.hpp" + +namespace rpc_core { + +template ::value, int>::type = 0> +serialize_oarchive& operator>>(const T& t, serialize_oarchive& oa) { + using TableType = typename T::TableType; + + flatbuffers::FlatBufferBuilder fbb(1024); + auto offset = TableType::Pack(fbb, &t); + fbb.Finish(offset); + auto data = fbb.GetBufferPointer(); + auto size = fbb.GetSize(); + oa.data.append((char*)data, size); + return oa; +} + +template ::value, int>::type = 0> +serialize_iarchive& operator<<(T& t, serialize_iarchive& ia) { + using TableType = typename T::TableType; + + flatbuffers::Verifier verifier((uint8_t*)ia.data, ia.size); + bool ok = verifier.VerifyBuffer(); + if (!ok) { + ia.error = true; + return ia; + } + flatbuffers::GetRoot(ia.data)->UnPackTo(&t); + return ia; +} + +} // namespace rpc_core diff --git a/3party/rpc_core/include/rpc_core/plugin/json.hpp b/3party/rpc_core/include/rpc_core/plugin/json.hpp new file mode 100644 index 0000000..312dcea --- /dev/null +++ b/3party/rpc_core/include/rpc_core/plugin/json.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include "nlohmann/json.hpp" +#include "rpc_core/detail/log.h" +#include "rpc_core/serialize.hpp" + +namespace rpc_core { + +template ::value, int>::type = 0> +serialize_oarchive& operator>>(const T& t, serialize_oarchive& oa) { + t.dump() >> oa; + return oa; +} + +template ::value, int>::type = 0> +serialize_iarchive& operator<<(T& t, serialize_iarchive& ia) { + try { + nlohmann::json::parse(ia.data, ia.data + ia.size).swap(t); + } catch (std::exception& e) { + RPC_CORE_LOGE("deserialize: %s", e.what()); + ia.error = true; + } + return ia; +} + +} // namespace rpc_core diff --git a/3party/rpc_core/include/rpc_core/plugin/json_msg.hpp b/3party/rpc_core/include/rpc_core/plugin/json_msg.hpp new file mode 100644 index 0000000..4aa99c4 --- /dev/null +++ b/3party/rpc_core/include/rpc_core/plugin/json_msg.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include "nlohmann/json.hpp" +#include "rpc_core/detail/log.h" +#include "rpc_core/serialize.hpp" + +#define RPC_CORE_DEFINE_TYPE_NLOHMANN_JSON(CLASS) \ + template ::value, int>::type = 0> \ + ::rpc_core::serialize_oarchive& operator>>(const T& t, ::rpc_core::serialize_oarchive& oa) { \ + oa.data.append(nlohmann::json(t).dump(-1)); \ + return oa; \ + } \ + template ::value, int>::type = 0> \ + ::rpc_core::serialize_iarchive& operator<<(T& t, ::rpc_core::serialize_iarchive& ia) { \ + try { \ + t = nlohmann::json::parse(ia.data, ia.data + ia.size).get(); \ + } catch (std::exception & e) { \ + RPC_CORE_LOGE("deserialize: %s", e.what()); \ + ia.error = true; \ + } \ + return ia; \ + } + +#define RPC_CORE_DEFINE_TYPE_JSON(Type, ...) \ + NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Type, __VA_ARGS__) \ + RPC_CORE_DEFINE_TYPE_NLOHMANN_JSON(Type); diff --git a/3party/rpc_core/include/rpc_core/request.hpp b/3party/rpc_core/include/rpc_core/request.hpp new file mode 100644 index 0000000..4398b13 --- /dev/null +++ b/3party/rpc_core/include/rpc_core/request.hpp @@ -0,0 +1,384 @@ +#pragma once + +#include +#include +#include + +#ifndef RPC_CORE_FEATURE_DISABLE_FUTURE +#include +#endif + +// config +#include "config.hpp" + +// include +#include "detail/callable/callable.hpp" +#include "detail/msg_wrapper.hpp" +#include "detail/noncopyable.hpp" +#include "serialize.hpp" + +namespace rpc_core { + +class request : detail::noncopyable, public std::enable_shared_from_this { + friend class rpc; + + public: + using request_s = std::shared_ptr; + using request_w = std::weak_ptr; + + struct rpc_proto { + virtual ~rpc_proto() = default; + virtual seq_type make_seq() = 0; + virtual void send_request(const request_s&) = 0; + virtual bool is_ready() const = 0; + }; + using send_proto_s = std::shared_ptr; + using send_proto_w = std::weak_ptr; + + struct dispose_proto { + virtual ~dispose_proto() = default; + virtual void add(const request_s& request) = 0; + virtual void remove(const request_s& request) = 0; + }; + + enum class finally_t : int { + normal = 0, + no_need_rsp = 1, + timeout = 2, + canceled = 3, + rpc_expired = 4, + rpc_not_ready = 5, + rsp_serialize_error = 6, + no_such_cmd = 7, + }; + static inline const char* finally_t_str(finally_t t) { + switch (t) { + case finally_t::normal: + return "normal"; + case finally_t::no_need_rsp: + return "no_need_rsp"; + case finally_t::timeout: + return "timeout"; + case finally_t::canceled: + return "canceled"; + case finally_t::rpc_expired: + return "rpc_expired"; + case finally_t::rpc_not_ready: + return "rpc_not_ready"; + case finally_t::rsp_serialize_error: + return "rsp_serialize_error"; + case finally_t::no_such_cmd: + return "no_such_cmd"; + default: + return "unknown"; + } + } + + public: + template + static request_s create(Args&&... args) { + auto r = std::shared_ptr(new request(std::forward(args)...), [](request* p) { + delete p; + }); + r->init(); + return r; + } + + public: + std::shared_ptr cmd(cmd_type cmd) { + cmd_ = std::move(cmd); + return shared_from_this(); + } + + template + request_s msg(T&& message) { + this->payload_ = serialize(std::forward(message)); + return shared_from_this(); + } + + template ::argc, int>::type = 0> + request_s rsp(RPC_CORE_MOVE_PARAM(F) cb) { + using T = detail::remove_cvref_t::template argument_type<0>>; + + need_rsp_ = true; + auto self = shared_from_this(); + this->rsp_handle_ = [this, RPC_CORE_MOVE_LAMBDA(cb)](detail::msg_wrapper msg) { + if (canceled_) { + on_finish(finally_t::canceled); + return true; + } + + if (msg.type & detail::msg_wrapper::msg_type::no_such_cmd) { + on_finish(finally_t::no_such_cmd); + return true; + } + + auto rsp = msg.unpack_as(); + if (rsp.first) { + cb(std::move(rsp.second)); + on_finish(finally_t::normal); + return true; + } else { + on_finish(finally_t::rsp_serialize_error); + return false; + } + }; + return self; + } + + template ::argc, int>::type = 0> + request_s rsp(RPC_CORE_MOVE_PARAM(F) cb) { + need_rsp_ = true; + auto self = shared_from_this(); + this->rsp_handle_ = [this, RPC_CORE_MOVE_LAMBDA(cb)](const detail::msg_wrapper& msg) { + RPC_CORE_UNUSED(msg); + if (canceled_) { + on_finish(finally_t::canceled); + return true; + } + + if (msg.type & detail::msg_wrapper::msg_type::no_such_cmd) { + on_finish(finally_t::no_such_cmd); + return true; + } + + cb(); + on_finish(finally_t::normal); + return true; + }; + return self; + } + + /** + * one call, one finally + * @param finally + * @return + */ + std::shared_ptr finally(std::function finally) { + finally_ = std::move(finally); + return shared_from_this(); + } + + std::shared_ptr finally(RPC_CORE_MOVE_PARAM(std::function) finally) { + finally_ = [RPC_CORE_MOVE_LAMBDA(finally)](finally_t t) { + RPC_CORE_UNUSED(t); + finally(); + }; + return shared_from_this(); + } + + void call(const send_proto_s& rpc = nullptr) { + waiting_rsp_ = true; + + if (canceled_) { + on_finish(finally_t::canceled); + return; + } + + self_keeper_ = shared_from_this(); + if (rpc) { + rpc_ = rpc; + } else if (rpc_.expired()) { + on_finish(finally_t::rpc_expired); + return; + } + + auto r = rpc_.lock(); + if (!r->is_ready()) { + on_finish(finally_t::rpc_not_ready); + return; + } + seq_ = r->make_seq(); + r->send_request(self_keeper_); + if (!need_rsp_) { + on_finish(finally_t::no_need_rsp); + } + } + + request_s ping() { + is_ping_ = true; + return shared_from_this(); + } + + std::shared_ptr timeout_ms(uint32_t timeout_ms) { + timeout_ms_ = timeout_ms; + return shared_from_this(); + } + + /** + * timeout callback for wait `rsp` + */ + std::shared_ptr timeout(RPC_CORE_MOVE_PARAM(std::function) timeout_cb) { + timeout_cb_ = [this, RPC_CORE_MOVE_LAMBDA(timeout_cb)] { + if (timeout_cb) { + timeout_cb(); + } + if (retry_count_ == -1) { + call(); + } else if (retry_count_ > 0) { + retry_count_--; + call(); + } else { + on_finish(finally_t::timeout); + } + }; + return shared_from_this(); + } + + request_s add_to(dispose_proto& dispose) { + auto self = shared_from_this(); + dispose.add(self); + return self; + } + + request_s cancel() { + canceled(true); + on_finish(finally_t::canceled); + return shared_from_this(); + } + + request_s reset_cancel() { + canceled(false); + return shared_from_this(); + } + + /** + * Automatic retry times after timeout + * -1 means retry indefinitely, 0 means no retry, >0 means the number of retries. + */ + request_s retry(int count) { + retry_count_ = count; + return shared_from_this(); + } + + /** + * Force to ignore `rsp` callback. + */ + request_s disable_rsp() { + need_rsp_ = false; + return shared_from_this(); + } + + std::shared_ptr rpc(send_proto_w rpc) { + rpc_ = std::move(rpc); + return shared_from_this(); + } + + send_proto_w rpc() { + return rpc_; + } + + bool canceled() const { + return canceled_; + } + + std::shared_ptr canceled(bool canceled) { + canceled_ = canceled; + return shared_from_this(); + } + +#ifndef RPC_CORE_FEATURE_DISABLE_FUTURE + /** + * Future pattern + * It is not recommended to use blocking interfaces unless you are very clear about what you are doing, as it is easy to cause deadlock. + */ + template + struct future_ret; + + template ::value, int>::type = 0> + std::future> future(const send_proto_s& rpc = nullptr); + + template ::value, int>::type = 0> + std::future> future(const send_proto_s& rpc = nullptr); +#endif + + private: + explicit request(const send_proto_s& rpc = nullptr) : rpc_(rpc) { + RPC_CORE_LOGD("request: %p", this); + } + ~request() { + RPC_CORE_LOGD("~request: %p", this); + } + + private: + void init() { + timeout(nullptr); + } + + void on_finish(finally_t type) { + if (!waiting_rsp_) return; + waiting_rsp_ = false; + RPC_CORE_LOGD("on_finish: cmd:%s type:%s", cmd_.c_str(), finally_t_str(type)); + finally_type_ = type; + if (finally_) { + finally_(finally_type_); + } + self_keeper_ = nullptr; + } + + private: + send_proto_w rpc_; + request_s self_keeper_; + seq_type seq_{}; + cmd_type cmd_; + std::string payload_; + bool need_rsp_ = false; + bool canceled_ = false; + std::function rsp_handle_; + uint32_t timeout_ms_ = 3000; + std::function timeout_cb_; + finally_t finally_type_ = finally_t::no_need_rsp; + std::function finally_; + int retry_count_ = 0; + bool waiting_rsp_ = false; + bool is_ping_ = false; +}; + +#ifndef RPC_CORE_FEATURE_DISABLE_FUTURE +template +struct request::future_ret { + finally_t type; + T data; +}; + +template <> +struct request::future_ret { + finally_t type; +}; + +template ::value, int>::type> +std::future> request::future(const request::send_proto_s& rpc) { + auto promise = std::make_shared>>(); + rsp([promise](R r) { + promise->set_value({finally_t::normal, std::move(r)}); + }); + finally([promise](finally_t type) { + if (type != finally_t::normal) { + promise->set_value({type, {}}); + } + }); + call(rpc); + return promise->get_future(); +} + +template ::value, int>::type> +std::future> request::future(const request::send_proto_s& rpc) { + auto promise = std::make_shared>>(); + rsp([promise] { + promise->set_value({request::finally_t::normal}); + }); + finally([promise](request::finally_t type) { + if (type != request::finally_t::normal) { + promise->set_value({type}); + } + }); + call(rpc); + return promise->get_future(); +} +#endif + +using request_s = request::request_s; +using request_w = request::request_w; +using finally_t = request::finally_t; + +} // namespace rpc_core diff --git a/3party/rpc_core/include/rpc_core/rpc.hpp b/3party/rpc_core/include/rpc_core/rpc.hpp new file mode 100644 index 0000000..86ce038 --- /dev/null +++ b/3party/rpc_core/include/rpc_core/rpc.hpp @@ -0,0 +1,165 @@ +#pragma once + +#include +#include + +// config +#include "config.hpp" + +// include +#include "connection.hpp" +#include "detail/callable/callable.hpp" +#include "detail/msg_dispatcher.hpp" +#include "detail/noncopyable.hpp" +#include "request.hpp" + +namespace rpc_core { + +class rpc : detail::noncopyable, public std::enable_shared_from_this, public request::rpc_proto { + public: + using timeout_cb = detail::msg_dispatcher::timeout_cb; + + public: + template + static std::shared_ptr create(Args&&... args) { + return std::shared_ptr(new rpc(std::forward(args)...), [](rpc* p) { + delete p; + }); + } + + private: + explicit rpc(std::shared_ptr conn = std::make_shared()) : conn_(conn), dispatcher_(std::move(conn)) { + RPC_CORE_LOGD("rpc: %p", this); + } + + ~rpc() override { + RPC_CORE_LOGD("~rpc: %p", this); + }; + + public: + inline std::shared_ptr get_connection() const { + return conn_; + } + + inline void set_timer(detail::msg_dispatcher::timer_impl timer_impl) { + dispatcher_.set_timer_impl(std::move(timer_impl)); + } + + inline void set_ready(bool ready) { + is_ready_ = ready; + } + + public: + template + void subscribe(const cmd_type& cmd, RPC_CORE_MOVE_PARAM(F) handle) { + constexpr bool F_ReturnIsEmpty = std::is_void::return_type>::value; + constexpr bool F_ParamIsEmpty = detail::callable_traits::argc == 0; + subscribe_helper()(cmd, std::move(handle), &dispatcher_); + } + + inline void unsubscribe(const cmd_type& cmd) { + dispatcher_.unsubscribe_cmd(cmd); + } + + public: + inline request_s create_request() { + return request::create(shared_from_this()); + } + + inline request_s cmd(cmd_type cmd) { + return create_request()->cmd(std::move(cmd)); + } + + inline request_s ping(std::string payload = {}) { // NOLINT + return create_request()->ping()->msg(std::move(payload)); + } + + public: + seq_type make_seq() override { + return seq_++; + } + + void send_request(const request_s& request) override { + if (request->need_rsp_) { + dispatcher_.subscribe_rsp(request->seq_, request->rsp_handle_, request->timeout_cb_, request->timeout_ms_, request->is_ping_); + } + detail::msg_wrapper msg; + msg.type = static_cast(detail::msg_wrapper::command | (request->is_ping_ ? detail::msg_wrapper::ping : 0) | + (request->need_rsp_ ? detail::msg_wrapper::need_rsp : 0)); + msg.cmd = request->cmd_; + msg.seq = request->seq_; + msg.request_payload = &request->payload_; + RPC_CORE_LOGD("=> seq:%u type:%s %s", msg.seq, (msg.type & detail::msg_wrapper::msg_type::ping) ? "ping" : "cmd", msg.cmd.c_str()); + conn_->send_package_impl(detail::coder::serialize(msg)); + } + + inline bool is_ready() const override { + return is_ready_; + } + + private: + template + struct subscribe_helper; + + template + struct subscribe_helper { + void operator()(const cmd_type& cmd, RPC_CORE_MOVE_PARAM(F) handle, detail::msg_dispatcher* dispatcher) { + dispatcher->subscribe_cmd(cmd, [RPC_CORE_MOVE_LAMBDA(handle)](const detail::msg_wrapper& msg) { + using F_Param = detail::remove_cvref_t::template argument_type<0>>; + using F_Return = detail::remove_cvref_t::return_type>; + + auto r = msg.unpack_as(); + F_Return ret; + if (r.first) { + ret = handle(std::move(r.second)); + } + return detail::msg_wrapper::make_rsp(msg.seq, &ret, r.first); + }); + } + }; + + template + struct subscribe_helper { + void operator()(const cmd_type& cmd, RPC_CORE_MOVE_PARAM(F) handle, detail::msg_dispatcher* dispatcher) { + dispatcher->subscribe_cmd(cmd, [RPC_CORE_MOVE_LAMBDA(handle)](const detail::msg_wrapper& msg) { + using F_Param = detail::remove_cvref_t::template argument_type<0>>; + + auto r = msg.unpack_as(); + if (r.first) { + handle(std::move(r.second)); + } + return detail::msg_wrapper::make_rsp(msg.seq, nullptr, r.first); + }); + } + }; + + template + struct subscribe_helper { + void operator()(const cmd_type& cmd, RPC_CORE_MOVE_PARAM(F) handle, detail::msg_dispatcher* dispatcher) { + dispatcher->subscribe_cmd(cmd, [RPC_CORE_MOVE_LAMBDA(handle)](const detail::msg_wrapper& msg) { + using F_Return = typename detail::callable_traits::return_type; + + F_Return ret = handle(); + return detail::msg_wrapper::make_rsp(msg.seq, &ret, true); + }); + } + }; + + template + struct subscribe_helper { + void operator()(const cmd_type& cmd, RPC_CORE_MOVE_PARAM(F) handle, detail::msg_dispatcher* dispatcher) { + dispatcher->subscribe_cmd(cmd, [RPC_CORE_MOVE_LAMBDA(handle)](const detail::msg_wrapper& msg) { + handle(); + return detail::msg_wrapper::make_rsp(msg.seq, nullptr, true); + }); + } + }; + + private: + std::shared_ptr conn_; + detail::msg_dispatcher dispatcher_; + seq_type seq_{0}; + bool is_ready_ = false; +}; + +} // namespace rpc_core diff --git a/3party/rpc_core/include/rpc_core/serialize.hpp b/3party/rpc_core/include/rpc_core/serialize.hpp new file mode 100644 index 0000000..dfd0266 --- /dev/null +++ b/3party/rpc_core/include/rpc_core/serialize.hpp @@ -0,0 +1,34 @@ +#pragma once + +// config +#include "config.hpp" + +// type traits +#include "detail/type_traits.hpp" + +// serialize type +#include "serialize_type.hpp" + +// raw type +#include "serialize/type_raw.hpp" + +// other types +#include "serialize/binary_wrap.hpp" +#include "serialize/std_array.hpp" +#include "serialize/std_basic_string.hpp" +#include "serialize/std_bitset.hpp" +#include "serialize/std_chrono.hpp" +#include "serialize/std_complex.hpp" +#include "serialize/std_container_adaptors.hpp" +#include "serialize/std_forward_list.hpp" +#include "serialize/std_list_like.hpp" +#include "serialize/std_map.hpp" +#include "serialize/std_pair.hpp" +#include "serialize/std_set.hpp" +#include "serialize/std_shared_ptr.hpp" +#include "serialize/std_tuple.hpp" +#include "serialize/std_unique_ptr.hpp" +#include "serialize/type_enum.hpp" +#include "serialize/type_ptr.hpp" +#include "serialize/type_struct.hpp" +#include "serialize/type_void.hpp" diff --git a/3party/rpc_core/include/rpc_core/serialize/binary_wrap.hpp b/3party/rpc_core/include/rpc_core/serialize/binary_wrap.hpp new file mode 100644 index 0000000..fdc270e --- /dev/null +++ b/3party/rpc_core/include/rpc_core/serialize/binary_wrap.hpp @@ -0,0 +1,38 @@ +#pragma once + +#include +#include + +namespace rpc_core { + +struct binary_wrap { + binary_wrap() = default; + binary_wrap(void* data, size_t size) : data(data), size(size) {} + void* data = nullptr; + size_t size = 0; + + // private: + std::shared_ptr _data_; +}; + +template ::value, int>::type = 0> +inline serialize_oarchive& operator>>(const T& t, serialize_oarchive& oa) { + t.size >> oa; + oa.data.append((char*)t.data, t.size); + return oa; +} + +template ::value, int>::type = 0> +inline serialize_iarchive& operator<<(T& t, serialize_iarchive& ia) { + t.size << ia; + t._data_ = std::shared_ptr(new uint8_t[t.size], [](const uint8_t* p) { + delete[] p; + }); + t.data = t._data_.get(); + memcpy(t.data, ia.data, t.size); + ia.data += t.size; + ia.size -= t.size; + return ia; +} + +} // namespace rpc_core diff --git a/3party/rpc_core/include/rpc_core/serialize/detail/auto_size.hpp b/3party/rpc_core/include/rpc_core/serialize/detail/auto_size.hpp new file mode 100644 index 0000000..8bc26ca --- /dev/null +++ b/3party/rpc_core/include/rpc_core/serialize/detail/auto_size.hpp @@ -0,0 +1,73 @@ +#pragma once + +#include +#include +#include +#include + +namespace rpc_core { +namespace detail { + +template +struct auto_size_type { + explicit auto_size_type(int_impl_t value = 0) : value(value) {} + + std::string serialize() const { + if (value == 0) { + return {(char*)&value, 1}; + } + + uint8_t effective_bytes = sizeof(int_impl_t); + auto value_tmp = value; + if (value_tmp < 0) { + value_tmp = -value_tmp; + } + for (int i = sizeof(int_impl_t) - 1; i >= 0; --i) { + if ((value_tmp >> (i * 8)) & 0xff) { + break; + } else { + --effective_bytes; + } + } + + std::string ret; + ret.resize(1 + effective_bytes); + auto data = (uint8_t*)ret.data(); + data[0] = effective_bytes; + memcpy(data + 1, &value_tmp, effective_bytes); + if (value < 0) { + data[0] |= 0x80; + } + return ret; + } + + int deserialize(const void* data) { + auto p = (uint8_t*)data; + uint8_t size_bytes = p[0]; + bool negative = false; + if (size_bytes & 0x80) { + negative = true; + size_bytes &= 0x7f; + } + memcpy(&value, p + 1, size_bytes); + if (negative) { + value = -value; + } + return size_bytes + 1; + } + + int_impl_t value; +}; + +using auto_size = auto_size_type; +using auto_intmax = auto_size_type; +using auto_uintmax = auto_size_type; + +template +struct is_auto_size_type : std::false_type {}; + +template +struct is_auto_size_type> : std::true_type {}; + +} // namespace detail +} // namespace rpc_core diff --git a/3party/rpc_core/include/rpc_core/serialize/std_array.hpp b/3party/rpc_core/include/rpc_core/serialize/std_array.hpp new file mode 100644 index 0000000..8d7c03a --- /dev/null +++ b/3party/rpc_core/include/rpc_core/serialize/std_array.hpp @@ -0,0 +1,57 @@ +#pragma once + +#include + +#include "../detail/callable/helpers.hpp" + +namespace rpc_core { + +namespace detail { + +template +struct is_std_array : std::false_type {}; + +template +struct is_std_array> : std::true_type {}; + +} // namespace detail + +template ::value, int>::type = 0> +serialize_oarchive& operator>>(const T& t, serialize_oarchive& oa) { + detail::auto_size size(t.size()); + size >> oa; + for (auto& item : t) { + if (std::is_fundamental>::value) { + item >> oa; + } else { + serialize_oarchive tmp; + item >> tmp; + tmp >> oa; + } + } + return oa; +} + +template ::value, int>::type = 0> +serialize_iarchive& operator<<(T& t, serialize_iarchive& ia) { + detail::auto_size size; + size << ia; + for (size_t i = 0; i < size.value; ++i) { + typename T::value_type item; + if (std::is_fundamental>::value) { + item << ia; + } else { + serialize_iarchive tmp; + tmp << ia; + item << tmp; + if (tmp.error) { + ia.error = true; + break; + } + } + t[i] = std::move(item); + } + return ia; +} + +} // namespace rpc_core diff --git a/3party/rpc_core/include/rpc_core/serialize/std_basic_string.hpp b/3party/rpc_core/include/rpc_core/serialize/std_basic_string.hpp new file mode 100644 index 0000000..5a00e0c --- /dev/null +++ b/3party/rpc_core/include/rpc_core/serialize/std_basic_string.hpp @@ -0,0 +1,42 @@ +#pragma once + +#include + +namespace rpc_core { + +namespace detail { + +template +struct is_std_basic_string : std::false_type {}; + +template +struct is_std_basic_string> : std::true_type {}; + +} // namespace detail + +template ::value, int>::type = 0> +inline serialize_oarchive& operator>>(const T& t, serialize_oarchive& oa) { + using VT = typename T::value_type; + oa.data.append((char*)t.data(), t.size() * sizeof(VT)); + return oa; +} + +template ::value, int>::type = 0> +inline serialize_oarchive& operator>>(T&& t, serialize_oarchive& oa) { + using VT = typename T::value_type; + if (oa.data.empty()) { + oa.data = std::forward(t); + } else { + oa.data.append((char*)t.data(), t.size() * sizeof(VT)); + } + return oa; +} + +template ::value, int>::type = 0> +inline serialize_iarchive& operator<<(T& t, serialize_iarchive& ia) { + using VT = typename T::value_type; + t = T((VT*)(ia.data), ia.size / sizeof(VT)); + return ia; +} + +} // namespace rpc_core diff --git a/3party/rpc_core/include/rpc_core/serialize/std_bitset.hpp b/3party/rpc_core/include/rpc_core/serialize/std_bitset.hpp new file mode 100644 index 0000000..f5b530b --- /dev/null +++ b/3party/rpc_core/include/rpc_core/serialize/std_bitset.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include +#include +#include + +namespace rpc_core { + +namespace detail { + +template +struct is_std_bitset : std::false_type {}; + +template +struct is_std_bitset> : std::true_type {}; + +} // namespace detail + +template ::value, int>::type = 0> +serialize_oarchive& operator>>(const T& t, serialize_oarchive& oa) { + oa.data.append(t.to_string()); + return oa; +} + +template ::value, int>::type = 0> +serialize_iarchive& operator<<(T& t, serialize_iarchive& ia) { + std::string tmp; + tmp << ia; + t = T(std::move(tmp)); + return ia; +} + +} // namespace rpc_core diff --git a/3party/rpc_core/include/rpc_core/serialize/std_chrono.hpp b/3party/rpc_core/include/rpc_core/serialize/std_chrono.hpp new file mode 100644 index 0000000..57e7e19 --- /dev/null +++ b/3party/rpc_core/include/rpc_core/serialize/std_chrono.hpp @@ -0,0 +1,53 @@ +#pragma once + +#include +#include + +namespace rpc_core { + +namespace detail { + +template +struct is_std_chrono_duration : std::false_type {}; + +template +struct is_std_chrono_duration> : std::true_type {}; + +template +struct is_std_chrono_time_point : std::false_type {}; + +template +struct is_std_chrono_time_point> : std::true_type {}; + +} // namespace detail + +template ::value, int>::type = 0> +serialize_oarchive& operator>>(const T& t, serialize_oarchive& oa) { + detail::auto_intmax count(t.count()); + count >> oa; + return oa; +} + +template ::value, int>::type = 0> +serialize_iarchive& operator<<(T& t, serialize_iarchive& ia) { + detail::auto_intmax rep; + rep << ia; + t = T(rep.value); + return ia; +} + +template ::value, int>::type = 0> +serialize_oarchive& operator>>(const T& t, serialize_oarchive& oa) { + t.time_since_epoch() >> oa; + return oa; +} + +template ::value, int>::type = 0> +serialize_iarchive& operator<<(T& t, serialize_iarchive& ia) { + typename T::duration duration; + duration << ia; + t = T(duration); + return ia; +} + +} // namespace rpc_core diff --git a/3party/rpc_core/include/rpc_core/serialize/std_complex.hpp b/3party/rpc_core/include/rpc_core/serialize/std_complex.hpp new file mode 100644 index 0000000..18e574c --- /dev/null +++ b/3party/rpc_core/include/rpc_core/serialize/std_complex.hpp @@ -0,0 +1,52 @@ +#pragma once + +#include +#include + +namespace rpc_core { + +namespace detail { + +template +struct is_std_complex : std::false_type {}; + +template +struct is_std_complex> : std::true_type {}; + +} // namespace detail + +template ::value, int>::type = 0> +serialize_oarchive& operator>>(const T& t, serialize_oarchive& oa) { + using VT = typename T::value_type; + if (std::is_fundamental::value) { + t.real() >> oa; + t.imag() >> oa; + } else { + oa & t.real(); + oa & t.imag(); + } + return oa; +} + +template ::value, int>::type = 0> +serialize_iarchive& operator<<(T& t, serialize_iarchive& ia) { + using VT = typename T::value_type; + if (std::is_fundamental::value) { + VT real; + real << ia; + t.real(real); + VT imag; + imag << ia; + t.imag(imag); + } else { + VT real; + ia & real; + t.real(std::move(real)); + VT imag; + ia & imag; + t.imag(std::move(imag)); + } + return ia; +} + +} // namespace rpc_core diff --git a/3party/rpc_core/include/rpc_core/serialize/std_container_adaptors.hpp b/3party/rpc_core/include/rpc_core/serialize/std_container_adaptors.hpp new file mode 100644 index 0000000..2077b4b --- /dev/null +++ b/3party/rpc_core/include/rpc_core/serialize/std_container_adaptors.hpp @@ -0,0 +1,36 @@ +#pragma once + +#include +#include + +namespace rpc_core { + +namespace detail { + +template +struct is_std_stack : std::false_type {}; + +template +struct is_std_stack> : std::true_type {}; + +template +struct is_std_stack> : std::true_type {}; + +template +struct is_std_stack> : std::true_type {}; + +} // namespace detail + +template ::value, int>::type = 0> +serialize_oarchive& operator>>(const T& t, serialize_oarchive& oa) { + (typename T::container_type&)t >> oa; + return oa; +} + +template ::value, int>::type = 0> +serialize_iarchive& operator<<(T& t, serialize_iarchive& ia) { + (typename T::container_type&)t << ia; + return ia; +} + +} // namespace rpc_core diff --git a/3party/rpc_core/include/rpc_core/serialize/std_forward_list.hpp b/3party/rpc_core/include/rpc_core/serialize/std_forward_list.hpp new file mode 100644 index 0000000..ce11067 --- /dev/null +++ b/3party/rpc_core/include/rpc_core/serialize/std_forward_list.hpp @@ -0,0 +1,58 @@ +#pragma once + +#include + +#include "../detail/callable/helpers.hpp" + +namespace rpc_core { + +namespace detail { + +template +struct is_std_forward_list : std::false_type {}; + +template +struct is_std_forward_list> : std::true_type {}; + +} // namespace detail + +template ::value, int>::type = 0> +serialize_oarchive& operator>>(const T& t, serialize_oarchive& oa) { + detail::auto_size size(std::distance(t.cbegin(), t.cend())); + size >> oa; + for (auto& item : t) { + if (std::is_fundamental>::value) { + item >> oa; + } else { + serialize_oarchive tmp; + item >> tmp; + tmp >> oa; + } + } + return oa; +} + +template ::value, int>::type = 0> +serialize_iarchive& operator<<(T& t, serialize_iarchive& ia) { + detail::auto_size size; + size << ia; + for (size_t i = 0; i < size.value; ++i) { + typename T::value_type item; + if (std::is_fundamental>::value) { + item << ia; + } else { + serialize_iarchive tmp; + tmp << ia; + item << tmp; + if (tmp.error) { + ia.error = true; + break; + } + } + t.emplace_front(std::move(item)); + } + t.reverse(); + return ia; +} + +} // namespace rpc_core diff --git a/3party/rpc_core/include/rpc_core/serialize/std_list_like.hpp b/3party/rpc_core/include/rpc_core/serialize/std_list_like.hpp new file mode 100644 index 0000000..5ab2dbc --- /dev/null +++ b/3party/rpc_core/include/rpc_core/serialize/std_list_like.hpp @@ -0,0 +1,63 @@ +#pragma once + +#include +#include +#include + +namespace rpc_core { + +namespace detail { + +template +struct is_std_list_like : std::false_type {}; + +template +struct is_std_list_like> : std::true_type {}; + +template +struct is_std_list_like> : std::true_type {}; + +template +struct is_std_list_like> : std::true_type {}; + +} // namespace detail + +template ::value, int>::type = 0> +serialize_oarchive& operator>>(const T& t, serialize_oarchive& oa) { + detail::auto_size size(t.size()); + size >> oa; + for (auto& item : t) { + if (std::is_fundamental>::value) { + item >> oa; + } else { + serialize_oarchive tmp; + item >> tmp; + tmp >> oa; + } + } + return oa; +} + +template ::value, int>::type = 0> +serialize_iarchive& operator<<(T& t, serialize_iarchive& ia) { + detail::auto_size size; + size << ia; + for (size_t i = 0; i < size.value; ++i) { + typename T::value_type item; + if (std::is_fundamental>::value) { + item << ia; + } else { + serialize_iarchive tmp; + tmp << ia; + item << tmp; + if (tmp.error) { + ia.error = true; + break; + } + } + t.emplace_back(std::move(item)); + } + return ia; +} + +} // namespace rpc_core diff --git a/3party/rpc_core/include/rpc_core/serialize/std_map.hpp b/3party/rpc_core/include/rpc_core/serialize/std_map.hpp new file mode 100644 index 0000000..825f9eb --- /dev/null +++ b/3party/rpc_core/include/rpc_core/serialize/std_map.hpp @@ -0,0 +1,57 @@ +#pragma once + +#include +#include + +namespace rpc_core { + +namespace detail { + +template +struct is_std_map_like : std::false_type {}; + +template +struct is_std_map_like> : std::true_type {}; + +template +struct is_std_map_like> : std::true_type {}; + +template +struct is_std_map_like> : std::true_type {}; + +template +struct is_std_map_like> : std::true_type {}; + +} // namespace detail + +template ::value, int>::type = 0> +serialize_oarchive& operator>>(const T& t, serialize_oarchive& oa) { + detail::auto_size size(t.size()); + size >> oa; + for (auto& item : t) { + serialize_oarchive tmp; + item >> tmp; + tmp >> oa; + } + return oa; +} + +template ::value, int>::type = 0> +serialize_iarchive& operator<<(T& t, serialize_iarchive& ia) { + detail::auto_size size; + size << ia; + for (size_t i = 0; i < size.value; ++i) { + typename T::value_type item; + serialize_iarchive tmp; + tmp << ia; + item << tmp; + if (tmp.error) { + ia.error = true; + break; + } + t.emplace(std::move(item)); + } + return ia; +} + +} // namespace rpc_core diff --git a/3party/rpc_core/include/rpc_core/serialize/std_pair.hpp b/3party/rpc_core/include/rpc_core/serialize/std_pair.hpp new file mode 100644 index 0000000..d8870c5 --- /dev/null +++ b/3party/rpc_core/include/rpc_core/serialize/std_pair.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include + +namespace rpc_core { + +namespace detail { + +template +struct is_std_pair : std::false_type {}; + +template +struct is_std_pair> : std::true_type {}; + +} // namespace detail + +template ::value, int>::type = 0> +inline serialize_oarchive& operator>>(const T& t, serialize_oarchive& oa) { + std::tie(t.first, t.second) >> oa; + return oa; +} + +template ::value, int>::type = 0> +serialize_iarchive& operator<<(T& t, serialize_iarchive& ia) { + using first_type = detail::remove_cvref_t; + using second_type = detail::remove_cvref_t; + auto& tt = (std::pair&)t; + std::tuple tup; + tup << ia; + std::tie(tt.first, tt.second) = std::move(tup); + return ia; +} + +} // namespace rpc_core diff --git a/3party/rpc_core/include/rpc_core/serialize/std_set.hpp b/3party/rpc_core/include/rpc_core/serialize/std_set.hpp new file mode 100644 index 0000000..76b3f64 --- /dev/null +++ b/3party/rpc_core/include/rpc_core/serialize/std_set.hpp @@ -0,0 +1,65 @@ +#pragma once + +#include +#include + +namespace rpc_core { + +namespace detail { + +template +struct is_std_set_like : std::false_type {}; + +template +struct is_std_set_like> : std::true_type {}; + +template +struct is_std_set_like> : std::true_type {}; + +template +struct is_std_set_like> : std::true_type {}; + +template +struct is_std_set_like> : std::true_type {}; + +} // namespace detail + +template ::value, int>::type = 0> +serialize_oarchive& operator>>(const T& t, serialize_oarchive& oa) { + detail::auto_size size(t.size()); + size >> oa; + for (auto& item : t) { + if (std::is_fundamental>::value) { + item >> oa; + } else { + serialize_oarchive tmp; + item >> tmp; + tmp >> oa; + } + } + return oa; +} + +template ::value, int>::type = 0> +serialize_iarchive& operator<<(T& t, serialize_iarchive& ia) { + detail::auto_size size; + size << ia; + for (size_t i = 0; i < size.value; ++i) { + typename T::value_type item; + if (std::is_fundamental>::value) { + item << ia; + } else { + serialize_iarchive tmp; + tmp << ia; + item << tmp; + if (tmp.error) { + ia.error = true; + break; + } + } + t.emplace(std::move(item)); + } + return ia; +} + +} // namespace rpc_core diff --git a/3party/rpc_core/include/rpc_core/serialize/std_shared_ptr.hpp b/3party/rpc_core/include/rpc_core/serialize/std_shared_ptr.hpp new file mode 100644 index 0000000..af983c3 --- /dev/null +++ b/3party/rpc_core/include/rpc_core/serialize/std_shared_ptr.hpp @@ -0,0 +1,40 @@ +#pragma once + +#include + +namespace rpc_core { + +namespace detail { + +template +struct is_std_shared_ptr : std::false_type {}; + +template +struct is_std_shared_ptr> : std::true_type {}; + +} // namespace detail + +template ::value, int>::type = 0> +inline serialize_oarchive& operator>>(const T& t, serialize_oarchive& oa) { + if (t != nullptr) { + true >> oa; + *t >> oa; + } else { + false >> oa; + } + return oa; +} + +template ::value, int>::type = 0> +inline serialize_iarchive& operator<<(T& t, serialize_iarchive& ia) { + bool notnull; + notnull << ia; + if (notnull) { + using Type = typename T::element_type; + t = std::make_shared(); + *t << ia; + } + return ia; +} + +} // namespace rpc_core diff --git a/3party/rpc_core/include/rpc_core/serialize/std_tuple.hpp b/3party/rpc_core/include/rpc_core/serialize/std_tuple.hpp new file mode 100644 index 0000000..f0f7187 --- /dev/null +++ b/3party/rpc_core/include/rpc_core/serialize/std_tuple.hpp @@ -0,0 +1,147 @@ +#pragma once + +#include + +#include "../detail/callable/helpers.hpp" + +namespace rpc_core { + +namespace detail { + +template +using tuple_element_t = detail::remove_cvref_t>::type>; + +template +struct is_tuple : std::false_type {}; + +template +struct is_tuple> : std::true_type {}; + +template +struct is_std_ignore { + static const bool value = std::is_same, T>::value; +}; + +enum class tuple_serialize_type { + Ignore, + RawType, + Normal, +}; + +template +struct tuple_serialize_type_check { + static constexpr tuple_serialize_type value = std::is_fundamental::value ? tuple_serialize_type::RawType + : is_std_ignore::value ? tuple_serialize_type::Ignore + : tuple_serialize_type::Normal; +}; + +template +struct tuple_serialize_helper_impl; + +template +struct tuple_serialize_helper_impl { + static void serialize(const Tuple& t, serialize_oarchive& oa) { + serialize_oarchive tmp; + std::get(t) >> tmp; + tmp >> oa; + } +}; + +template +struct tuple_serialize_helper_impl { + static void serialize(const Tuple& t, serialize_oarchive& oa) { + std::get(t) >> oa; + } +}; + +template +struct tuple_serialize_helper_impl { + static void serialize(const Tuple& t, serialize_oarchive& oa) { + RPC_CORE_UNUSED(t); + RPC_CORE_UNUSED(oa); + } +}; + +template +struct tuple_serialize_helper { + static void serialize(const Tuple& t, serialize_oarchive& oa) { + tuple_serialize_helper::serialize(t, oa); + tuple_serialize_helper_impl>::value>::serialize(t, oa); + } +}; + +template +struct tuple_serialize_helper { + static void serialize(const Tuple& t, serialize_oarchive& oa) { + tuple_serialize_helper_impl>::value>::serialize(t, oa); + } +}; + +template +void tuple_serialize(const std::tuple& t, serialize_oarchive& oa) { + tuple_serialize_helper::serialize(t, oa); +} + +template +struct tuple_de_serialize_helper_impl; + +template +struct tuple_de_serialize_helper_impl { + static void de_serialize(Tuple& t, serialize_iarchive& ia) { + serialize_iarchive tmp; + tmp << ia; + std::get(t) << tmp; + } +}; + +template +struct tuple_de_serialize_helper_impl { + static void de_serialize(Tuple& t, serialize_iarchive& ia) { + std::get(t) << ia; + } +}; + +template +struct tuple_de_serialize_helper_impl { + static void de_serialize(Tuple& t, serialize_iarchive& ia) { + RPC_CORE_UNUSED(t); + RPC_CORE_UNUSED(ia); + } +}; + +template +struct tuple_de_serialize_helper { + static void de_serialize(Tuple& t, serialize_iarchive& ia) { + tuple_de_serialize_helper::de_serialize(t, ia); + if (ia.error) return; + tuple_de_serialize_helper_impl>::value>::de_serialize(t, ia); + } +}; + +template +struct tuple_de_serialize_helper { + static void de_serialize(Tuple& t, serialize_iarchive& ia) { + tuple_de_serialize_helper_impl>::value>::de_serialize(t, ia); + } +}; + +template +void tuple_de_serialize(std::tuple& t, serialize_iarchive& ia) { + tuple_de_serialize_helper::de_serialize(t, ia); +} + +} // namespace detail + +template ::value, int>::type = 0> +serialize_oarchive& operator>>(const T& t, serialize_oarchive& oa) { + detail::tuple_serialize(t, oa); + return oa; +} + +template ::value, int>::type = 0> +serialize_iarchive& operator<<(T& t, serialize_iarchive& ia) { + detail::tuple_de_serialize(t, ia); + return ia; +} + +} // namespace rpc_core diff --git a/3party/rpc_core/include/rpc_core/serialize/std_unique_ptr.hpp b/3party/rpc_core/include/rpc_core/serialize/std_unique_ptr.hpp new file mode 100644 index 0000000..b3e5558 --- /dev/null +++ b/3party/rpc_core/include/rpc_core/serialize/std_unique_ptr.hpp @@ -0,0 +1,40 @@ +#pragma once + +#include + +namespace rpc_core { + +namespace detail { + +template +struct is_std_unique_ptr : std::false_type {}; + +template +struct is_std_unique_ptr> : std::true_type {}; + +} // namespace detail + +template ::value, int>::type = 0> +inline serialize_oarchive& operator>>(const T& t, serialize_oarchive& oa) { + if (t != nullptr) { + true >> oa; + *t >> oa; + } else { + false >> oa; + } + return oa; +} + +template ::value, int>::type = 0> +inline serialize_iarchive& operator<<(T& t, serialize_iarchive& ia) { + bool notnull; + notnull << ia; + if (notnull) { + using Type = typename T::element_type; + t = std::unique_ptr(new Type); + *t << ia; + } + return ia; +} + +} // namespace rpc_core diff --git a/3party/rpc_core/include/rpc_core/serialize/type_enum.hpp b/3party/rpc_core/include/rpc_core/serialize/type_enum.hpp new file mode 100644 index 0000000..21895b3 --- /dev/null +++ b/3party/rpc_core/include/rpc_core/serialize/type_enum.hpp @@ -0,0 +1,20 @@ +#pragma once + +namespace rpc_core { + +template ::value, int>::type = 0> +inline serialize_oarchive& operator>>(const T& t, serialize_oarchive& oa) { + detail::auto_uintmax impl((uintmax_t)t); + impl >> oa; + return oa; +} + +template ::value, int>::type = 0> +inline serialize_iarchive& operator<<(T& t, serialize_iarchive& ia) { + detail::auto_uintmax impl; + impl << ia; + t = (T)impl.value; + return ia; +} + +} // namespace rpc_core diff --git a/3party/rpc_core/include/rpc_core/serialize/type_ptr.hpp b/3party/rpc_core/include/rpc_core/serialize/type_ptr.hpp new file mode 100644 index 0000000..f9f937b --- /dev/null +++ b/3party/rpc_core/include/rpc_core/serialize/type_ptr.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include + +namespace rpc_core { + +template ::value, int>::type = 0> +inline serialize_oarchive& operator>>(const T& t, serialize_oarchive& oa) { + auto ptr = (intptr_t)t; + ptr >> oa; + return oa; +} + +template ::value, int>::type = 0> +inline serialize_iarchive& operator<<(T& t, serialize_iarchive& ia) { + intptr_t ptr; + ptr << ia; + t = (T)ptr; + return ia; +} + +} // namespace rpc_core diff --git a/3party/rpc_core/include/rpc_core/serialize/type_raw.hpp b/3party/rpc_core/include/rpc_core/serialize/type_raw.hpp new file mode 100644 index 0000000..64dca63 --- /dev/null +++ b/3party/rpc_core/include/rpc_core/serialize/type_raw.hpp @@ -0,0 +1,54 @@ +#pragma once + +#include +#include + +#include "detail/auto_size.hpp" + +#define RPC_CORE_DETAIL_DEFINE_RAW_TYPE(type_raw, type_size) \ + static_assert(sizeof(type_raw) <= type_size, ""); \ + inline serialize_oarchive& operator>>(const type_raw& t, serialize_oarchive& oa) { \ + oa.data.append((char*)&t, type_size); \ + return oa; \ + } \ + inline serialize_iarchive& operator<<(type_raw& t, serialize_iarchive& ia) { \ + t = {}; \ + memcpy(&t, ia.data, detail::min(sizeof(t), type_size)); \ + ia.data += type_size; \ + ia.size -= type_size; \ + return ia; \ + } + +#define RPC_CORE_DETAIL_DEFINE_RAW_TYPE_AUTO_SIZE(type_raw, type_auto) \ + inline serialize_oarchive& operator>>(const type_raw& t, serialize_oarchive& oa) { \ + type_auto impl(t); \ + impl >> oa; \ + return oa; \ + } \ + inline serialize_iarchive& operator<<(type_raw& t, serialize_iarchive& ia) { \ + type_auto impl; \ + impl << ia; \ + t = impl.value; \ + return ia; \ + } + +namespace rpc_core { + +RPC_CORE_DETAIL_DEFINE_RAW_TYPE(bool, 1); +RPC_CORE_DETAIL_DEFINE_RAW_TYPE(char, 1); +RPC_CORE_DETAIL_DEFINE_RAW_TYPE(signed char, 1); +RPC_CORE_DETAIL_DEFINE_RAW_TYPE(unsigned char, 1); +RPC_CORE_DETAIL_DEFINE_RAW_TYPE(short, 2); +RPC_CORE_DETAIL_DEFINE_RAW_TYPE(unsigned short, 2); +RPC_CORE_DETAIL_DEFINE_RAW_TYPE_AUTO_SIZE(int, detail::auto_intmax); +RPC_CORE_DETAIL_DEFINE_RAW_TYPE_AUTO_SIZE(unsigned int, detail::auto_uintmax); +RPC_CORE_DETAIL_DEFINE_RAW_TYPE_AUTO_SIZE(long, detail::auto_intmax); +RPC_CORE_DETAIL_DEFINE_RAW_TYPE_AUTO_SIZE(unsigned long, detail::auto_uintmax); +RPC_CORE_DETAIL_DEFINE_RAW_TYPE_AUTO_SIZE(long long, detail::auto_intmax); +RPC_CORE_DETAIL_DEFINE_RAW_TYPE_AUTO_SIZE(unsigned long long, detail::auto_uintmax); + +RPC_CORE_DETAIL_DEFINE_RAW_TYPE(float, 4); +RPC_CORE_DETAIL_DEFINE_RAW_TYPE(double, 8); +RPC_CORE_DETAIL_DEFINE_RAW_TYPE(long double, 16); + +} // namespace rpc_core diff --git a/3party/rpc_core/include/rpc_core/serialize/type_struct.hpp b/3party/rpc_core/include/rpc_core/serialize/type_struct.hpp new file mode 100644 index 0000000..9bb79c0 --- /dev/null +++ b/3party/rpc_core/include/rpc_core/serialize/type_struct.hpp @@ -0,0 +1,200 @@ +#pragma once + +// clang-format off +#define RPC_CORE_DETAIL_SERIALIZE_GET_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, NAME,...) NAME +#define RPC_CORE_DETAIL_SERIALIZE_PASTE(...) RPC_CORE_DETAIL_SERIALIZE_GET_MACRO(__VA_ARGS__, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE64, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE63, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE62, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE61, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE60, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE59, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE58, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE57, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE56, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE55, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE54, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE53, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE52, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE51, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE50, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE49, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE48, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE47, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE46, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE45, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE44, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE43, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE42, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE41, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE40, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE39, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE38, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE37, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE36, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE35, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE34, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE33, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE32, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE31, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE30, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE29, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE28, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE27, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE26, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE25, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE24, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE23, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE22, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE21, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE20, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE19, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE18, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE17, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE16, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE15, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE14, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE13, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE12, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE11, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE10, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE9, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE8, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE7, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE6, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE5, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE4, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE3, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE2, \ + RPC_CORE_DETAIL_SERIALIZE_PASTE1)(__VA_ARGS__) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) func(v1) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE3(func, v1, v2) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v2) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE4(func, v1, v2, v3) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE3(func, v2, v3) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE5(func, v1, v2, v3, v4) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE4(func, v2, v3, v4) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE6(func, v1, v2, v3, v4, v5) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE5(func, v2, v3, v4, v5) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE7(func, v1, v2, v3, v4, v5, v6) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE6(func, v2, v3, v4, v5, v6) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE8(func, v1, v2, v3, v4, v5, v6, v7) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE7(func, v2, v3, v4, v5, v6, v7) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE9(func, v1, v2, v3, v4, v5, v6, v7, v8) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE8(func, v2, v3, v4, v5, v6, v7, v8) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE10(func, v1, v2, v3, v4, v5, v6, v7, v8, v9) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE9(func, v2, v3, v4, v5, v6, v7, v8, v9) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE11(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE10(func, v2, v3, v4, v5, v6, v7, v8, v9, v10) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE12(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE11(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE13(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE12(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE14(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE13(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE15(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE14(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE16(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE15(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE17(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE16(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE18(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE17(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE19(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE18(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE20(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE19(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE21(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE20(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE22(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE21(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE23(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE22(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE24(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE23(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE25(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE24(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE26(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE25(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE27(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE26(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE28(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE27(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE29(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE28(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE30(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE29(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE31(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE30(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE32(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE31(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE33(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE32(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE34(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE33(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE35(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE34(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE36(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE35(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE37(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE36(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE38(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE37(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE39(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE38(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE40(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE39(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE41(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE40(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE42(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE41(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE43(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE42(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE44(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE43(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE45(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE44(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE46(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE45(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE47(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE46(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE48(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE47(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE49(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE48(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE50(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE49(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE51(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE50(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE52(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE51(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE53(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE52(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE54(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE53(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE55(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE54(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE56(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE55(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE57(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE56(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE58(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE57(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE59(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE58(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE60(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE59(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE61(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE60(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE62(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE61(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE63(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE62(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62) +#define RPC_CORE_DETAIL_SERIALIZE_PASTE64(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63) RPC_CORE_DETAIL_SERIALIZE_PASTE2(func, v1) RPC_CORE_DETAIL_SERIALIZE_PASTE63(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63) + +#define RPC_CORE_DETAIL_SERIALIZE_FIELD(v1) ar & t.v1; +#define RPC_CORE_DETAIL_SERIALIZE_FIELD_INNER(v1) ar & this->v1; +// clang-format on + +#include +#include + +#include "../detail/noncopyable.hpp" +#include "../detail/string_view.hpp" + +namespace rpc_core { + +template ::value, int>::type = 0> +inline serialize_oarchive& operator&(serialize_oarchive& oa, const T& t) { + t >> oa; + return oa; +} + +template ::value, int>::type = 0> +inline serialize_oarchive& operator&(serialize_oarchive& oa, const T& t) { + serialize_oarchive tmp; + t >> tmp; + tmp >> oa; + return oa; +} + +template ::value, int>::type = 0> +inline serialize_iarchive& operator&(serialize_iarchive& ia, T& t) { + if (ia.error) return ia; + t << ia; + return ia; +} + +template ::value, int>::type = 0> +serialize_iarchive& operator&(serialize_iarchive& ia, T& t) { + if (ia.error) return ia; + detail::auto_size auto_size; + int cost = auto_size.deserialize(ia.data); + uint32_t size = auto_size.value; + ia.data += cost; + + serialize_iarchive tmp(detail::string_view(ia.data, size)); + t << tmp; + ia.error = tmp.error; + + ia.data += size; + return ia; +} + +} // namespace rpc_core + +#define RPC_CORE_DEFINE_TYPE(Type, ...) \ + inline void operator>>(const Type& t, ::rpc_core::serialize_oarchive& ar) { \ + RPC_CORE_DETAIL_SERIALIZE_PASTE(RPC_CORE_DETAIL_SERIALIZE_FIELD, __VA_ARGS__) \ + } \ + inline void operator<<(Type& t, ::rpc_core::serialize_iarchive& ar) { \ + RPC_CORE_DETAIL_SERIALIZE_PASTE(RPC_CORE_DETAIL_SERIALIZE_FIELD, __VA_ARGS__) \ + } + +#define RPC_CORE_DEFINE_TYPE_INNER(...) \ + public: \ + void operator>>(::rpc_core::serialize_oarchive& ar) const { \ + RPC_CORE_DETAIL_SERIALIZE_PASTE(RPC_CORE_DETAIL_SERIALIZE_FIELD_INNER, __VA_ARGS__) \ + } \ + void operator<<(::rpc_core::serialize_iarchive& ar) { \ + RPC_CORE_DETAIL_SERIALIZE_PASTE(RPC_CORE_DETAIL_SERIALIZE_FIELD_INNER, __VA_ARGS__) \ + } diff --git a/3party/rpc_core/include/rpc_core/serialize/type_void.hpp b/3party/rpc_core/include/rpc_core/serialize/type_void.hpp new file mode 100644 index 0000000..b6bb0d3 --- /dev/null +++ b/3party/rpc_core/include/rpc_core/serialize/type_void.hpp @@ -0,0 +1,17 @@ +#pragma once + +namespace rpc_core { + +template ::value, int>::type = 0> +inline serialize_oarchive& operator>>(const T& t, serialize_oarchive& oa) { + RPC_CORE_UNUSED(t); + return oa; +} + +template ::value, int>::type = 0> +inline serialize_iarchive& operator<<(T& t, serialize_iarchive& ia) { + RPC_CORE_UNUSED(t); + return ia; +} + +} // namespace rpc_core diff --git a/3party/rpc_core/include/rpc_core/serialize_type.hpp b/3party/rpc_core/include/rpc_core/serialize_type.hpp new file mode 100644 index 0000000..6b04e05 --- /dev/null +++ b/3party/rpc_core/include/rpc_core/serialize_type.hpp @@ -0,0 +1,82 @@ +#pragma once + +// config +#include "config.hpp" + +// include +#include "detail/noncopyable.hpp" +#include "detail/string_view.hpp" +#include "serialize/detail/auto_size.hpp" +#include "type.hpp" + +namespace rpc_core { + +struct serialize_oarchive : detail::noncopyable { + std::string data; +}; + +inline serialize_oarchive& operator>>(const serialize_oarchive& t, serialize_oarchive& oa) { + oa.data.append(detail::auto_size(t.data.size()).serialize()); + oa.data.append(t.data); + return oa; +} + +inline serialize_oarchive& operator>>(serialize_oarchive&& t, serialize_oarchive& oa) { + if (oa.data.empty()) { + oa.data = std::move(t.data); + return oa; + } + oa.data.append(detail::auto_size(t.data.size()).serialize()); + oa.data.append(t.data); + return oa; +} + +struct serialize_iarchive : detail::noncopyable { + serialize_iarchive() = default; + serialize_iarchive(detail::string_view sv) : data((char*)sv.data()), size(sv.size()) {} // NOLINT(google-explicit-constructor) + serialize_iarchive(const char* data, size_t size) : data((char*)data), size(size) {} + char* data = nullptr; + size_t size = 0; + bool error = false; +}; + +inline serialize_iarchive& operator<<(serialize_iarchive& t, serialize_iarchive& ia) { + detail::auto_size size; + int cost = size.deserialize(ia.data); + ia.data += cost; + t.data = ia.data; + t.size = size.value; + ia.data += size.value; + ia.size -= cost + size.value; + return ia; +} + +template +inline std::string serialize(T&& t) { + serialize_oarchive ar; + std::forward(t) >> ar; + return std::move(ar.data); +} + +template +inline bool deserialize(const detail::string_view& data, T& t) { + serialize_iarchive ar(data); + t << ar; + return !ar.error; +} + +template ::value, int>::type = 0> +inline serialize_oarchive& operator>>(const T& t, serialize_oarchive& oa) { + oa.data.append(t.serialize()); + return oa; +} + +template ::value, int>::type = 0> +inline serialize_iarchive& operator<<(T& t, serialize_iarchive& ia) { + int cost = t.deserialize((uint8_t*)ia.data); + ia.data += cost; + ia.size -= cost; + return ia; +} + +} // namespace rpc_core diff --git a/3party/rpc_core/include/rpc_core/type.hpp b/3party/rpc_core/include/rpc_core/type.hpp new file mode 100644 index 0000000..8792112 --- /dev/null +++ b/3party/rpc_core/include/rpc_core/type.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include +#include + +// config +#include "config.hpp" + +namespace rpc_core { + +#if __cplusplus >= 201402L +#define RPC_CORE_MOVE_LAMBDA(arg) arg = std::move(arg) +#define RPC_CORE_MOVE_PARAM(arg) arg +#else +#define RPC_CORE_MOVE_LAMBDA(arg) arg +#define RPC_CORE_MOVE_PARAM(arg) const arg& +#endif + +#define RPC_CORE_UNUSED(x) (void)x + +using cmd_type = std::string; + +using seq_type = uint32_t; + +} // namespace rpc_core diff --git a/3party/rpc_core/include/rpc_core/version.hpp b/3party/rpc_core/include/rpc_core/version.hpp new file mode 100644 index 0000000..7d8f042 --- /dev/null +++ b/3party/rpc_core/include/rpc_core/version.hpp @@ -0,0 +1,8 @@ +#pragma once + +#define RPC_CORE_VER_MAJOR 2 +#define RPC_CORE_VER_MINOR 0 +#define RPC_CORE_VER_PATCH 1 + +#define RPC_CORE_TO_VERSION(major, minor, patch) (major * 10000 + minor * 100 + patch) +#define RPC_CORE_VERSION RPC_CORE_TO_VERSION(RPC_CORE_VER_MAJOR, RPC_CORE_VER_MINOR, RPC_CORE_VER_PATCH) diff --git a/3party/rpc_core/library.json b/3party/rpc_core/library.json new file mode 100644 index 0000000..39733ea --- /dev/null +++ b/3party/rpc_core/library.json @@ -0,0 +1,20 @@ +{ + "name": "rpc_core", + "description": "a tiny c++11 rpc library, supports all platforms (macOS, Linux, Windows, iOS, Android, etc.) and most microchips (Arduino, STM32, ESP32/ESP8266, etc.)", + "keywords": "rpc", + "authors": { + "name": "shuai132", + "maintainer": true + }, + "repository": { + "type": "git", + "url": "https://github.com/shuai132/rpc_core.git" + }, + "version": "2.0.1", + "build": { + "srcDir": "_", + "flags": [ + "-I include" + ] + } +} diff --git a/3party/rpc_core/test/assert_def.h b/3party/rpc_core/test/assert_def.h new file mode 100644 index 0000000..c707334 --- /dev/null +++ b/3party/rpc_core/test/assert_def.h @@ -0,0 +1,12 @@ +#pragma once + +#include +#include + +// clang-format off + +#define __ASSERT(e, file, line) \ + ((void)printf ("%s:%d: failed assertion `%s'\n", file, line, e), abort()) + +#define ASSERT(e) \ + ((void) ((e) ? ((void)0) : __ASSERT (#e, __FILE__, __LINE__))) diff --git a/3party/rpc_core/test/main.cpp b/3party/rpc_core/test/main.cpp new file mode 100644 index 0000000..103950b --- /dev/null +++ b/3party/rpc_core/test/main.cpp @@ -0,0 +1,31 @@ +#include + +#include "rpc_core.hpp" +#include "rpc_core/detail/log.h" +#include "test.h" + +using namespace rpc_core_test; + +int main() { + RPC_CORE_LOG("version: %d", RPC_CORE_VERSION); + + printf("\n"); + RPC_CORE_LOG("test_serialize..."); + test_serialize(); + + printf("\n"); + RPC_CORE_LOG("test_data_packer..."); + test_data_packer(); + +#ifdef RPC_CORE_TEST_PLUGIN + printf("\n"); + RPC_CORE_LOG("test_plugin..."); + test_plugin(); +#endif + + printf("\n"); + RPC_CORE_LOG("test_rpc..."); + test_rpc(); + + return 0; +} diff --git a/3party/rpc_core/test/plugin/JsonType.h b/3party/rpc_core/test/plugin/JsonType.h new file mode 100644 index 0000000..5d9fa9f --- /dev/null +++ b/3party/rpc_core/test/plugin/JsonType.h @@ -0,0 +1,11 @@ +#pragma once + +#include "nlohmann/json.hpp" +#include "rpc_core/plugin/json_msg.hpp" + +struct JsonType { + int id = 0; + std::string name; + uint8_t age = 0; +}; +RPC_CORE_DEFINE_TYPE_JSON(JsonType, id, name, age); diff --git a/3party/rpc_core/test/plugin/RawType.h b/3party/rpc_core/test/plugin/RawType.h new file mode 100644 index 0000000..10b6813 --- /dev/null +++ b/3party/rpc_core/test/plugin/RawType.h @@ -0,0 +1,10 @@ +#pragma once + +#include "rpc_core/serialize.hpp" + +struct RawType { + uint8_t id = 0; + std::string name; + uint8_t age = 0; +}; +RPC_CORE_DEFINE_TYPE(RawType, id, name, age); diff --git a/3party/rpc_core/test/plugin/fb/.clang-format b/3party/rpc_core/test/plugin/fb/.clang-format new file mode 100644 index 0000000..e384528 --- /dev/null +++ b/3party/rpc_core/test/plugin/fb/.clang-format @@ -0,0 +1 @@ +DisableFormat: true diff --git a/3party/rpc_core/test/plugin/fb/FbMsg.fbs b/3party/rpc_core/test/plugin/fb/FbMsg.fbs new file mode 100644 index 0000000..f59a489 --- /dev/null +++ b/3party/rpc_core/test/plugin/fb/FbMsg.fbs @@ -0,0 +1,9 @@ +namespace msg; + +table FbMsg { + id: int; + age: uint8; + name: string; +} + +root_type FbMsg; diff --git a/3party/rpc_core/test/plugin/fb/FbMsg_generated.h b/3party/rpc_core/test/plugin/fb/FbMsg_generated.h new file mode 100644 index 0000000..8ff5f9c --- /dev/null +++ b/3party/rpc_core/test/plugin/fb/FbMsg_generated.h @@ -0,0 +1,186 @@ +// automatically generated by the FlatBuffers compiler, do not modify + + +#ifndef FLATBUFFERS_GENERATED_FBMSG_MSG_H_ +#define FLATBUFFERS_GENERATED_FBMSG_MSG_H_ + +#include "flatbuffers/flatbuffers.h" + +// Ensure the included flatbuffers.h is the same version as when this file was +// generated, otherwise it may not be compatible. +static_assert(FLATBUFFERS_VERSION_MAJOR == 23 && + FLATBUFFERS_VERSION_MINOR == 1 && + FLATBUFFERS_VERSION_REVISION == 21, + "Non-compatible flatbuffers version included"); + +namespace msg { + +struct FbMsg; +struct FbMsgBuilder; +struct FbMsgT; + +struct FbMsgT : public ::flatbuffers::NativeTable { + typedef FbMsg TableType; + int32_t id = 0; + uint8_t age = 0; + std::string name{}; +}; + +struct FbMsg FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef FbMsgT NativeTableType; + typedef FbMsgBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_ID = 4, + VT_AGE = 6, + VT_NAME = 8 + }; + int32_t id() const { + return GetField(VT_ID, 0); + } + uint8_t age() const { + return GetField(VT_AGE, 0); + } + const ::flatbuffers::String *name() const { + return GetPointer(VT_NAME); + } + bool Verify(::flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_ID, 4) && + VerifyField(verifier, VT_AGE, 1) && + VerifyOffset(verifier, VT_NAME) && + verifier.VerifyString(name()) && + verifier.EndTable(); + } + FbMsgT *UnPack(const ::flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(FbMsgT *_o, const ::flatbuffers::resolver_function_t *_resolver = nullptr) const; + static ::flatbuffers::Offset Pack(::flatbuffers::FlatBufferBuilder &_fbb, const FbMsgT* _o, const ::flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct FbMsgBuilder { + typedef FbMsg Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_id(int32_t id) { + fbb_.AddElement(FbMsg::VT_ID, id, 0); + } + void add_age(uint8_t age) { + fbb_.AddElement(FbMsg::VT_AGE, age, 0); + } + void add_name(::flatbuffers::Offset<::flatbuffers::String> name) { + fbb_.AddOffset(FbMsg::VT_NAME, name); + } + explicit FbMsgBuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = ::flatbuffers::Offset(end); + return o; + } +}; + +inline ::flatbuffers::Offset CreateFbMsg( + ::flatbuffers::FlatBufferBuilder &_fbb, + int32_t id = 0, + uint8_t age = 0, + ::flatbuffers::Offset<::flatbuffers::String> name = 0) { + FbMsgBuilder builder_(_fbb); + builder_.add_name(name); + builder_.add_id(id); + builder_.add_age(age); + return builder_.Finish(); +} + +inline ::flatbuffers::Offset CreateFbMsgDirect( + ::flatbuffers::FlatBufferBuilder &_fbb, + int32_t id = 0, + uint8_t age = 0, + const char *name = nullptr) { + auto name__ = name ? _fbb.CreateString(name) : 0; + return msg::CreateFbMsg( + _fbb, + id, + age, + name__); +} + +::flatbuffers::Offset CreateFbMsg(::flatbuffers::FlatBufferBuilder &_fbb, const FbMsgT *_o, const ::flatbuffers::rehasher_function_t *_rehasher = nullptr); + +inline FbMsgT *FbMsg::UnPack(const ::flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new FbMsgT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void FbMsg::UnPackTo(FbMsgT *_o, const ::flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = id(); _o->id = _e; } + { auto _e = age(); _o->age = _e; } + { auto _e = name(); if (_e) _o->name = _e->str(); } +} + +inline ::flatbuffers::Offset FbMsg::Pack(::flatbuffers::FlatBufferBuilder &_fbb, const FbMsgT* _o, const ::flatbuffers::rehasher_function_t *_rehasher) { + return CreateFbMsg(_fbb, _o, _rehasher); +} + +inline ::flatbuffers::Offset CreateFbMsg(::flatbuffers::FlatBufferBuilder &_fbb, const FbMsgT *_o, const ::flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { ::flatbuffers::FlatBufferBuilder *__fbb; const FbMsgT* __o; const ::flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _id = _o->id; + auto _age = _o->age; + auto _name = _o->name.empty() ? 0 : _fbb.CreateString(_o->name); + return msg::CreateFbMsg( + _fbb, + _id, + _age, + _name); +} + +inline const msg::FbMsg *GetFbMsg(const void *buf) { + return ::flatbuffers::GetRoot(buf); +} + +inline const msg::FbMsg *GetSizePrefixedFbMsg(const void *buf) { + return ::flatbuffers::GetSizePrefixedRoot(buf); +} + +inline bool VerifyFbMsgBuffer( + ::flatbuffers::Verifier &verifier) { + return verifier.VerifyBuffer(nullptr); +} + +inline bool VerifySizePrefixedFbMsgBuffer( + ::flatbuffers::Verifier &verifier) { + return verifier.VerifySizePrefixedBuffer(nullptr); +} + +inline void FinishFbMsgBuffer( + ::flatbuffers::FlatBufferBuilder &fbb, + ::flatbuffers::Offset root) { + fbb.Finish(root); +} + +inline void FinishSizePrefixedFbMsgBuffer( + ::flatbuffers::FlatBufferBuilder &fbb, + ::flatbuffers::Offset root) { + fbb.FinishSizePrefixed(root); +} + +inline std::unique_ptr UnPackFbMsg( + const void *buf, + const ::flatbuffers::resolver_function_t *res = nullptr) { + return std::unique_ptr(GetFbMsg(buf)->UnPack(res)); +} + +inline std::unique_ptr UnPackSizePrefixedFbMsg( + const void *buf, + const ::flatbuffers::resolver_function_t *res = nullptr) { + return std::unique_ptr(GetSizePrefixedFbMsg(buf)->UnPack(res)); +} + +} // namespace msg + +#endif // FLATBUFFERS_GENERATED_FBMSG_MSG_H_ diff --git a/3party/rpc_core/test/serialize/CustomType.h b/3party/rpc_core/test/serialize/CustomType.h new file mode 100644 index 0000000..b9b65a8 --- /dev/null +++ b/3party/rpc_core/test/serialize/CustomType.h @@ -0,0 +1,65 @@ +#pragma once + +#include "rpc_core/serialize.hpp" + +struct CustomType { + uint32_t id = 0; + std::vector ids; + std::string name; + bool operator==(const CustomType& t) const { + return std::tie(id, ids, name) == std::tie(t.id, t.ids, t.name); + } + bool operator<(const CustomType& t) const { + return std::tie(id, ids, name) < std::tie(t.id, t.ids, t.name); + } +}; +RPC_CORE_DEFINE_TYPE(CustomType, id, ids, name); + +// 指针 +struct CustomTypePtr { + int32_t* int_n; + int32_t* int_v; + std::unique_ptr unique_ptr_n; + std::unique_ptr unique_ptr_v; + std::shared_ptr shared_ptr_n; + std::shared_ptr shared_ptr_v; +}; +RPC_CORE_DEFINE_TYPE(CustomTypePtr, int_n, int_v, unique_ptr_n, unique_ptr_v, shared_ptr_n, shared_ptr_v); + +#pragma pack(push, 1) +struct CustomType2 { + uint8_t id1{}; + uint8_t id2{}; + uint32_t id3{}; +}; +#pragma pack(pop) +RPC_CORE_DEFINE_TYPE(CustomType2, id1, id2, id3); + +#pragma pack(push, 4) +struct CustomType3 { + uint8_t id1{}; + uint8_t id2{}; + uint32_t id3{}; +}; +#pragma pack(pop) +RPC_CORE_DEFINE_TYPE(CustomType3, id1, id2, id3); + +namespace test { +// 嵌套定义 +struct CustomTypeNest { + CustomType2 c2{}; + CustomType3 c3{}; + CustomTypeNest* ptr{}; +}; +RPC_CORE_DEFINE_TYPE(test::CustomTypeNest, c2, c3, ptr); + +// 内部定义 +struct CustomTypeNest2 { + // can be private + CustomType2 c2{}; + CustomType3 c3{}; + CustomTypeNest* ptr{}; + RPC_CORE_DEFINE_TYPE_INNER(c2, c3, ptr); +}; + +} // namespace test diff --git a/3party/rpc_core/test/serialize/TestStruct.h b/3party/rpc_core/test/serialize/TestStruct.h new file mode 100644 index 0000000..58d6ccb --- /dev/null +++ b/3party/rpc_core/test/serialize/TestStruct.h @@ -0,0 +1,10 @@ +#pragma once + +#include "rpc_core/serialize.hpp" + +struct TestStruct { + uint8_t a; + uint16_t b; + uint32_t c; +}; +RPC_CORE_DEFINE_TYPE(TestStruct, a, b, c); diff --git a/3party/rpc_core/test/test.h b/3party/rpc_core/test/test.h new file mode 100644 index 0000000..82c0638 --- /dev/null +++ b/3party/rpc_core/test/test.h @@ -0,0 +1,13 @@ +#pragma once + +namespace rpc_core_test { + +void test_serialize(); + +void test_data_packer(); + +void test_rpc(); + +void test_plugin(); + +} // namespace rpc_core_test diff --git a/3party/rpc_core/test/test_data_packer.cpp b/3party/rpc_core/test/test_data_packer.cpp new file mode 100644 index 0000000..4f6ec40 --- /dev/null +++ b/3party/rpc_core/test/test_data_packer.cpp @@ -0,0 +1,95 @@ +#include +#include + +#include "assert_def.h" +#include "rpc_core.hpp" +#include "test.h" + +static void test_simple() { + RPC_CORE_LOGI(); + RPC_CORE_LOGI("test_simple..."); + rpc_core::detail::data_packer packer; + std::string testData = "hello world"; + std::string packedData; + + packer.pack(testData.data(), testData.size(), [&](const void *data, size_t size) { + packedData.insert(packedData.size(), (char *)data, size); + return true; + }); + ASSERT(packedData.size() == testData.size() + 4); + + std::string feedRecData; + packer.on_data = [&](std::string data) { + feedRecData = std::move(data); + }; + packer.feed(packedData.data(), packedData.size()); + ASSERT(testData == feedRecData); + RPC_CORE_LOGI("packedData PASS"); + + std::string packedData2 = packer.pack(testData); + ASSERT(packedData2 == packedData); + RPC_CORE_LOGI("packedData2 PASS"); + + RPC_CORE_LOGI("feed again..."); + feedRecData.clear(); + ASSERT(testData != feedRecData); + packer.feed(packedData.data(), packedData.size()); + ASSERT(testData == feedRecData); +} + +static void test_random() { + RPC_CORE_LOGI(); + RPC_CORE_LOGI("test_random..."); + RPC_CORE_LOGI("generate big data..."); + bool pass = false; + std::string TEST_PAYLOAD; + size_t TestAddCount = 1000; + for (size_t i = 0; i < TestAddCount; i++) { + TEST_PAYLOAD += "helloworld"; // 10bytes + } + RPC_CORE_LOGI("data generated, size:%zu", TEST_PAYLOAD.size()); + ASSERT(TEST_PAYLOAD.size() == TestAddCount * 10); + + rpc_core::detail::data_packer packer; + packer.on_data = [&](const std::string &data) { + size_t size = data.size(); + RPC_CORE_LOGI("get payload size:%zu", size); + if (data == TEST_PAYLOAD) { + pass = true; + } + }; + + RPC_CORE_LOGI("packing..."); + auto payload = packer.pack(TEST_PAYLOAD); + const uint32_t payloadSize = payload.size(); + RPC_CORE_LOGI("payloadSize:%u", payloadSize); + ASSERT(payloadSize == TestAddCount * 10 + 4); + + RPC_CORE_LOGI("******test normal******"); + packer.feed(payload.data(), payloadSize); + ASSERT(pass); + pass = false; + + RPC_CORE_LOGI("******test random******"); + uint32_t sendLeft = payloadSize; + std::default_random_engine generator(time(nullptr)); // NOLINT + std::uniform_int_distribution dis(1, 10); + auto random = std::bind(dis, generator); // NOLINT + while (sendLeft > 0) { + uint32_t randomSize = random(); + // RPC_CORE_LOGI("random: %u, %u", randomSize, sendLeft); + size_t needSend = std::min(randomSize, sendLeft); + packer.feed(payload.data() + (payloadSize - sendLeft), needSend); + sendLeft -= needSend; + } + ASSERT(pass); +} + +namespace rpc_core_test { + +void test_data_packer() { + test_simple(); + test_random(); +} + +} // namespace rpc_core_test diff --git a/3party/rpc_core/test/test_plugin.cpp b/3party/rpc_core/test/test_plugin.cpp new file mode 100644 index 0000000..72187c0 --- /dev/null +++ b/3party/rpc_core/test/test_plugin.cpp @@ -0,0 +1,86 @@ +#include "assert_def.h" +#include "plugin/JsonType.h" +#include "plugin/RawType.h" +#include "plugin/fb/FbMsg_generated.h" +#include "rpc_core/plugin/flatbuffers.hpp" +#include "rpc_core/plugin/json.hpp" +#include "test.h" + +namespace rpc_core_test { + +void test_plugin() { + using namespace rpc_core; + { + RPC_CORE_LOGI("RawType..."); + RawType a; + a.id = 1; + a.name = "test"; + a.age = 18; + + auto payload = serialize(a); + // payload is not readable + RPC_CORE_LOGI("RawType: size: %zu", payload.size()); + + RawType b; + deserialize(payload, b); + ASSERT(a.id == b.id); + ASSERT(a.name == b.name); + ASSERT(a.age == b.age); + } + + { + RPC_CORE_LOGI("json..."); + nlohmann::json a; + a["id"] = 1; + a["name"] = "test"; + a["age"] = 18; + + auto payload = serialize(a); + RPC_CORE_LOGI("json: %s", payload.c_str()); + RPC_CORE_LOGI("json: size: %zu", payload.size()); + + nlohmann::json b; + deserialize(payload, b); + ASSERT(b["id"] == a["id"]); + ASSERT(b["name"] == a["name"]); + ASSERT(b["age"] == a["age"]); + } + + { + RPC_CORE_LOGI("JsonType..."); + JsonType a; + a.id = 1; + a.name = "test"; + a.age = 18; + + auto payload = serialize(a); + RPC_CORE_LOGI("JsonType: %s", payload.c_str()); + RPC_CORE_LOGI("JsonType: size: %zu", payload.size()); + + JsonType b; + deserialize(payload, b); + ASSERT(b.id == a.id); + ASSERT(b.name == a.name); + ASSERT(b.age == a.age); + } + + { + RPC_CORE_LOGI("flatbuffers..."); + msg::FbMsgT a; + a.id = 1; + a.name = "test"; + a.age = 18; + + auto payload = serialize(a); + // flatbuffers payload is not readable + RPC_CORE_LOGI("flatbuffers: size: %zu", payload.size()); + + msg::FbMsgT b; + deserialize(payload, b); + ASSERT(b.id == a.id); + ASSERT(b.name == a.name); + ASSERT(b.age == a.age); + } +} + +} // namespace rpc_core_test diff --git a/3party/rpc_core/test/test_rpc.cpp b/3party/rpc_core/test/test_rpc.cpp new file mode 100644 index 0000000..6f181d3 --- /dev/null +++ b/3party/rpc_core/test/test_rpc.cpp @@ -0,0 +1,318 @@ +#include "assert_def.h" +#include "rpc_core.hpp" +#include "serialize/CustomType.h" +#include "test.h" + +namespace rpc_core_test { + +void test_rpc() { + using namespace rpc_core; + + // 此示例使用回环连接 实际使用时需自定义连接 + auto connection = std::make_shared(); + + // 创建rpc 收发消息 + auto rpc = rpc::create(connection); + + // 定时器实现 应配合当前应用的事件循环 以确保消息收发和超时回调在同一个线程 + // 此示例使用回环连接 不做超时测试 + rpc->set_timer([](uint32_t ms, const rpc::timeout_cb& cb) { + RPC_CORE_UNUSED(ms); + RPC_CORE_UNUSED(cb); + }); + + // 已连接时设置ready + rpc->set_ready(true); + + /** + * 简单示例 + * 以收发`std::string`为例,支持结构体和绝大多数STL容器(见序列化章节)。 + */ + { + // The Receiver + rpc->subscribe("cmd", [](const std::string& msg) -> std::string { + assert(msg == "hello"); + return "world"; + }); + + // The Sender + rpc->cmd("cmd") + ->msg(std::string("hello")) + ->rsp([](const std::string& rsp) { + assert(rsp == "world"); + }) + ->call(); + } + + /** + * 详细测试 + * 根据使用场景不同 提供以下几种方式 + */ + { + RPC_CORE_LOG("1. 收发消息完整测试"); + // 注册监听 + rpc->subscribe("cmd1", [&](const std::string& msg) -> std::string { + RPC_CORE_LOGI("get cmd1: %s", msg.c_str()); + ASSERT(msg == "test"); + return "ok"; + }); + + // 请求支持很多方法 可根据需求使用所需部分 + bool pass = false; + auto request = rpc->cmd("cmd1") + ->msg(std::string("test")) + ->rsp([&](const std::string& rsp) { + RPC_CORE_LOGI("get rsp from cmd1: %s", rsp.c_str()); + ASSERT(rsp == "ok"); + pass = true; + }) + ->timeout([] { + RPC_CORE_LOGI("timeout"); + }) + ->finally([](finally_t type) { + RPC_CORE_LOGI("finally: type:%s", rpc_core::request::finally_t_str(type)); + }); + RPC_CORE_LOGI("执行请求"); + ASSERT(!pass); + request->call(); + ASSERT(pass); + + /// 其他功能测试 + RPC_CORE_LOGI("多次调用"); + pass = false; + request->call(); + ASSERT(pass); + + RPC_CORE_LOGI("测试取消"); + pass = false; + request->cancel(); + request->call(); + ASSERT(!pass); + + RPC_CORE_LOGI("恢复取消"); + request->reset_cancel(); + request->call(); + ASSERT(pass); + + RPC_CORE_LOGI("添加到dispose"); + pass = false; + { // RAII dispose + dispose dispose; + request->add_to(dispose); + } + request->call(); + ASSERT(!pass); + + RPC_CORE_LOGI("先创建request"); + pass = false; + request::create() + ->cmd("cmd1") + ->msg(std::string("test")) + ->rsp([&](const std::string& rsp) { + ASSERT(rsp == "ok"); + pass = true; + }) + ->call(rpc); + ASSERT(pass); + + RPC_CORE_LOGI("no_such_cmd"); + pass = false; + request::create() + ->cmd("cmd_xx") + ->msg(std::string("test")) + ->rsp([] { + ASSERT(false); + }) + ->finally([&](finally_t type) { + ASSERT(type == finally_t::no_such_cmd); + pass = true; + }) + ->call(rpc); + ASSERT(pass); + } + + RPC_CORE_LOG("2. 复杂结构体类型测试(包含STL容器)"); + { + bool pass = false; + CustomType customType; + customType.id = 1; + customType.ids = {1, 2, 3}; + customType.name = "test"; + + rpc->subscribe("cmd2", [&](const CustomType& msg) -> CustomType { + RPC_CORE_LOGI("get cmd2"); + ASSERT(msg == customType); + return customType; + }); + rpc->cmd("cmd2") + ->msg(customType) + ->rsp([&](const CustomType& rsp) { + RPC_CORE_LOGI("get rsp from cmd2"); + ASSERT(rsp == customType); + pass = true; + }) + ->call(); + ASSERT(pass); + } + + RPC_CORE_LOG("3. finally测试"); + { + bool pass = false; + bool pass_finally = false; + rpc->subscribe("cmd3", [&](const std::string& msg) { + return msg; + }); + rpc->cmd("cmd3") + ->msg(std::string("test")) + ->rsp([&](const std::string& rsp) { + ASSERT(rsp == "test"); + pass = true; + }) + ->finally([&](finally_t type) { + ASSERT(type == finally_t::normal); + ASSERT(!pass_finally); + pass_finally = true; + }) + ->call(); + ASSERT(pass); + ASSERT(pass_finally); + + pass_finally = false; + rpc->cmd("cmd3") + ->msg(std::string("test")) + ->finally([&](finally_t type) { + ASSERT(type == finally_t::no_need_rsp); + ASSERT(!pass_finally); + pass_finally = true; + }) + ->call(); + ASSERT(pass_finally); + } + + RPC_CORE_LOG("4. 多种使用场景测试"); + { + RPC_CORE_LOG("4.1 有参数 有返回"); + { + bool pass_cmd = false; + bool pass_rsp = false; + rpc->subscribe("cmd4", [&](const std::string& msg) -> std::string { + ASSERT(msg == "test"); + pass_cmd = true; + return "test"; + }); + rpc->cmd("cmd4") + ->msg(std::string("test")) + ->rsp([&](const std::string& msg) { + ASSERT(msg == "test"); + pass_rsp = true; + }) + ->call(); + ASSERT(pass_cmd); + ASSERT(pass_rsp); + } + + RPC_CORE_LOG("4.2 有参数 无返回"); + { + bool pass_cmd = false; + rpc->subscribe("cmd4", [&](const std::string& msg) { + ASSERT(msg == "test"); + pass_cmd = true; + }); + rpc->cmd("cmd4")->msg(std::string("test"))->call(); + ASSERT(pass_cmd); + } + + RPC_CORE_LOG("4.3 无参数 有返回"); + { + bool pass_cmd = false; + bool pass_rsp = false; + rpc->subscribe("cmd4", [&]() -> std::string { + pass_cmd = true; + return "test"; + }); + rpc->cmd("cmd4") + ->rsp([&](const std::string& msg) { + pass_rsp = true; + ASSERT(msg == "test"); + }) + ->call(); + ASSERT(pass_cmd); + ASSERT(pass_rsp); + } + + RPC_CORE_LOG("4.4 无参数 无返回"); + { + bool pass_cmd = false; + rpc->subscribe("cmd4", [&]() { + pass_cmd = true; + }); + rpc->cmd("cmd4")->call(); + ASSERT(pass_cmd); + } + } + + RPC_CORE_LOG("5. ping pong测试"); + { + bool pass = false; + rpc->ping("test") + ->rsp([&](const std::string& payload) { + RPC_CORE_LOGI("get rsp from ping: %s", payload.c_str()); + ASSERT(payload == "test"); + pass = true; + }) + ->call(); + ASSERT(pass); + } + + RPC_CORE_LOG("6. dispose测试"); + { + bool pass = false; + auto request = rpc->ping("test") + ->rsp([&](const std::string& payload) { + RPC_CORE_UNUSED(payload); + ASSERT(false); + }) + ->finally([&](finally_t type) { + ASSERT(type == finally_t::canceled); + pass = true; + }); + { + dispose dispose; + request->add_to(dispose); + } + request->call(); + ASSERT(pass); + } + +#ifndef RPC_CORE_FEATURE_DISABLE_FUTURE + RPC_CORE_LOG("7. future模式测试"); + { + { + auto result = rpc->ping("test")->future().get(); + ASSERT(result.type == finally_t::normal); + ASSERT(result.data == "test"); + } + { + auto result = rpc->ping()->future().get(); + ASSERT(result.type == finally_t::normal); + } + } +#endif + + RPC_CORE_LOG("8. 未ready的rpc对象"); + { + bool pass = false; + auto rpc_tmp = rpc::create(connection); + rpc_tmp->cmd("cmd")->call(); // should not crash + rpc_tmp->cmd("cmd") + ->finally([&](finally_t type) { + RPC_CORE_LOG("finally: %d", (int)type); + ASSERT(type == finally_t::rpc_not_ready); + pass = true; + }) + ->call(); + ASSERT(pass); + } +} + +} // namespace rpc_core_test diff --git a/3party/rpc_core/test/test_serialize.cpp b/3party/rpc_core/test/test_serialize.cpp new file mode 100644 index 0000000..4864dba --- /dev/null +++ b/3party/rpc_core/test/test_serialize.cpp @@ -0,0 +1,586 @@ +#include + +#include "assert_def.h" +#include "rpc_core.hpp" +#include "serialize/CustomType.h" + +namespace rpc_core_test { + +static size_t last_serialize_size = 0; + +template +void serialize_test(const T& a, R& b) { + std::string data = rpc_core::serialize(a); + last_serialize_size = data.size(); + RPC_CORE_LOGI(" size: %zu", last_serialize_size); + bool ret = rpc_core::deserialize(data, b); + ASSERT(ret); +} + +template +void raw_type_test() { + T a = 123; + T b; + serialize_test(a, b); + auto ok = (0 == memcmp(&a, &b, sizeof(T))); // NOLINT + ASSERT(ok); +} + +#define RAW_TYPE_TEST(t) \ + RPC_CORE_LOGI(" <" #t ">"); \ + raw_type_test(); + +#define ASSERT_SERIALIZE_SIZE(x) ASSERT(last_serialize_size == x) + +static bool is_little_endian() { + int x = 1; + return *(char*)&x != 0; +} + +static void test_auto_size() { + using namespace rpc_core::detail; + auto test_auto_size = [](size_t value, int except_size) { + RPC_CORE_LOGI("value: 0x%" PRIxMAX "(%" PRIiMAX ") except: %d", value, value, except_size); + auto_size a(value); + std::string payload = a.serialize(); + ASSERT(payload.size() == (size_t)except_size); + auto_size b; + int cost = b.deserialize(payload.data()); + ASSERT(cost = except_size); + ASSERT(value == b.value); + }; + test_auto_size(0x00, 1); + test_auto_size(0x01, 2); + test_auto_size(0xff, 2); + test_auto_size(0xfff, 3); + test_auto_size(0xffff, 3); + test_auto_size(0xfffff, 4); + test_auto_size(0xffffff, 4); + test_auto_size(0xfffffff, 5); + test_auto_size(0xffffffff, 5); + + auto test_auto_int = [](intmax_t value, int except_size) { + RPC_CORE_LOGI("value: 0x%" PRIxMAX "(%" PRIiMAX ") except: %d", value, value, except_size); + auto_intmax a(value); + std::string payload = a.serialize(); + ASSERT(payload.size() == (size_t)except_size); + auto_intmax b; + int cost = b.deserialize(payload.data()); + ASSERT(cost = except_size); + ASSERT(value == b.value); + }; + test_auto_int(0x00, 1); + test_auto_int(0xff, 2); + test_auto_int(-0xff, 2); + test_auto_int(0xffff, 3); + test_auto_int(-0xffff, 3); + test_auto_int(0xffffff, 4); + test_auto_int(-0xffffff, 4); + test_auto_int(intmax_t(0xffffffff), 5); + test_auto_int(-(intmax_t(0xffffffff)), 5); + + auto test_auto_uint = [](uintmax_t value, int except_size) { + RPC_CORE_LOGI("value: 0x%" PRIxMAX "(%" PRIiMAX ") except: %d", value, value, except_size); + auto_uintmax a(value); + std::string payload = a.serialize(); + ASSERT(payload.size() == (size_t)except_size); + auto_uintmax b; + int cost = b.deserialize(payload.data()); + ASSERT(cost = except_size); + ASSERT(value == b.value); + }; + test_auto_uint(0x00, 1); + test_auto_uint(0xff, 2); + test_auto_uint(0xffff, 3); + test_auto_uint(0xffffff, 4); + test_auto_uint(uintmax_t(0xffffffff), 5); +} + +void test_serialize() { + /// only support little endian + ASSERT(is_little_endian()); + + /// auto_size + test_auto_size(); + + /// raw type + { + int32_t a = -1; + int32_t b = 0; + + std::string data = rpc_core::serialize(a); + bool ret = rpc_core::deserialize(data, b); + ASSERT(ret); + + RPC_CORE_LOGI("raw type test..."); + RAW_TYPE_TEST(char); + ASSERT_SERIALIZE_SIZE(1); + RAW_TYPE_TEST(int8_t); + ASSERT_SERIALIZE_SIZE(1); + RAW_TYPE_TEST(uint8_t); + ASSERT_SERIALIZE_SIZE(1); + RAW_TYPE_TEST(int16_t); + ASSERT_SERIALIZE_SIZE(2); + RAW_TYPE_TEST(uint16_t); + ASSERT_SERIALIZE_SIZE(2); + RAW_TYPE_TEST(int32_t); + ASSERT_SERIALIZE_SIZE(2); + RAW_TYPE_TEST(uint32_t); + ASSERT_SERIALIZE_SIZE(2); + RAW_TYPE_TEST(int64_t); + ASSERT_SERIALIZE_SIZE(2); + RAW_TYPE_TEST(uint64_t); + ASSERT_SERIALIZE_SIZE(2); + RAW_TYPE_TEST(float); + ASSERT_SERIALIZE_SIZE(4); + RAW_TYPE_TEST(double); + ASSERT_SERIALIZE_SIZE(8); + RAW_TYPE_TEST(long double); + ASSERT_SERIALIZE_SIZE(16); + } + + /// enum + { + enum class Enum { + k_0, + k_1, + }; + RPC_CORE_LOGI("enum..."); + Enum a = Enum::k_1; + Enum b; + serialize_test(a, b); + ASSERT(a == b); + ASSERT_SERIALIZE_SIZE(2); + } + + /// std::array + { + RPC_CORE_LOGI("std::array..."); + std::array a{1, 2, 3}; + std::array b{}; + serialize_test(a, b); + ASSERT(a == b); + ASSERT_SERIALIZE_SIZE(2 /*size*/ + 2 * 3); + } + + /// std::string + { + RPC_CORE_LOGI("std::string..."); + std::string a = "test"; + std::string b; + serialize_test(a, b); + ASSERT(b == a); + ASSERT_SERIALIZE_SIZE(a.size()); + } + + /// std::wstring + { + RPC_CORE_LOGI("std::wstring..."); + std::wstring a = L"中文"; + std::wstring b; + serialize_test(a, b); + ASSERT(b == a); + ASSERT_SERIALIZE_SIZE(a.size() * sizeof(wchar_t)); + } + + /// std::tuple + { + RPC_CORE_LOGI("std::tuple..."); + bool msg1 = true; + uint32_t msg2 = 12; + std::string msg3 = "test"; + std::tuple a(msg1, msg2, msg3); + std::tuple b; + serialize_test(a, b); + ASSERT(std::get<0>(b) == msg1); + ASSERT(std::get<1>(b) == msg2); + ASSERT(std::get<2>(b) == msg3); + ASSERT(a == b); + ASSERT_SERIALIZE_SIZE((1) + (2) + (2 /*size*/ + msg3.size())); + } + + /// std::pair + { + RPC_CORE_LOGI("std::pair..."); + std::pair a{"k:1", "v:1"}; + std::pair b; + serialize_test(a, b); + ASSERT(b == a); + ASSERT_SERIALIZE_SIZE((2 /*size*/ + 3) * 2); + } + + /// list_like type + { + RPC_CORE_LOGI("std::vector..."); + std::vector a{1, 2, 3}; + std::vector b; + serialize_test(a, b); + ASSERT(a == b); + ASSERT_SERIALIZE_SIZE(2 /*size*/ + 2 * 3); + } + { + RPC_CORE_LOGI("std::list..."); + std::list a{1, 2, 3}; + std::list b; + serialize_test(a, b); + ASSERT(a == b); + ASSERT_SERIALIZE_SIZE(2 /*size*/ + 2 * 3); + } + { + RPC_CORE_LOGI("std::deque..."); + std::deque a{1, 2, 3}; + std::deque b; + serialize_test(a, b); + ASSERT(a == b); + ASSERT_SERIALIZE_SIZE(2 /*size*/ + 2 * 3); + } + + /// std container adaptors + { + RPC_CORE_LOGI("std::stack..."); + std::stack a; + a.push(1); + a.push(2); + a.push(3); + std::stack b; + serialize_test(a, b); + ASSERT(a == b); + ASSERT_SERIALIZE_SIZE(2 /*size*/ + 2 * 3); + } + { + RPC_CORE_LOGI("std::queue..."); + std::queue a; + a.push(1); + a.push(2); + a.push(3); + std::queue b; + serialize_test(a, b); + ASSERT(a == b); + ASSERT_SERIALIZE_SIZE(2 /*size*/ + 2 * 3); + } + { + RPC_CORE_LOGI("std::priority_queue..."); + std::priority_queue a; + a.push(1); + a.push(2); + a.push(3); + std::priority_queue b; + serialize_test(a, b); + for (uint32_t i = 0; i < a.size(); ++i) { + ASSERT(a.top() == b.top()); + a.pop(); + b.pop(); + } + ASSERT_SERIALIZE_SIZE(2 /*size*/ + 2 * 3); + } + + /// std::bitset + { + RPC_CORE_LOGI("std::bitset..."); + std::bitset<8> a; + a.set(); + std::bitset<8> b; + serialize_test(a, b); + ASSERT(a == b); + ASSERT_SERIALIZE_SIZE(8 /*11111111*/); + } + + /// std::forward_list + { + RPC_CORE_LOGI("std::forward_list..."); + std::forward_list a{1, 2, 3}; + std::forward_list b; + serialize_test(a, b); + ASSERT(a == b); + ASSERT_SERIALIZE_SIZE(2 /*size*/ + 2 * 3); + } + + /// std::set + { + RPC_CORE_LOGI("std::set..."); + std::set a{1, 2, 3}; + std::set b; + serialize_test(a, b); + ASSERT(a == b); + ASSERT_SERIALIZE_SIZE(2 /*size*/ + 2 * 3); + } + + /// std::multiset + { + RPC_CORE_LOGI("std::multiset..."); + std::multiset a{1, 2, 3}; + std::multiset b; + serialize_test(a, b); + ASSERT(a == b); + ASSERT_SERIALIZE_SIZE(2 /*size*/ + 2 * 3); + } + + /// std::unordered_multiset + { + RPC_CORE_LOGI("std::unordered_multiset..."); + std::unordered_multiset a{1, 2, 3}; + std::unordered_multiset b; + serialize_test(a, b); + ASSERT(a == b); + ASSERT_SERIALIZE_SIZE(2 /*size*/ + 2 * 3); + } + + /// std::map + { + RPC_CORE_LOGI("std::map..."); + std::map a{{"k:1", "v:1"}, {"k:2", "v:2"}, {"k:3", "v:3"}}; + std::map b; + serialize_test(a, b); + ASSERT(a == b); + ASSERT_SERIALIZE_SIZE(2 /*size*/ + (2 /*std::pair*/ + (2 + 3) * 2) * 3); + } + + /// std::unordered_map + { + RPC_CORE_LOGI("std::unordered_map..."); + std::unordered_map a{{"k:1", "v:1"}, {"k:2", "v:2"}, {"k:3", "v:3"}}; + std::unordered_map b; + serialize_test(a, b); + ASSERT(a == b); + ASSERT_SERIALIZE_SIZE(2 /*size*/ + (2 /*std::pair*/ + (2 + 3) * 2) * 3); + } + + /// std::multimap + { + RPC_CORE_LOGI("std::multimap..."); + std::multimap a{{"k:1", "v:1"}, {"k:2", "v:2"}, {"k:3", "v:3"}}; + std::multimap b; + serialize_test(a, b); + ASSERT(a == b); + ASSERT_SERIALIZE_SIZE(2 /*size*/ + (2 /*std::pair*/ + (2 + 3) * 2) * 3); + } + + /// std::unordered_multimap + { + RPC_CORE_LOGI("std::unordered_multimap..."); + std::unordered_multimap a{{"k:1", "v:1"}, {"k:2", "v:2"}, {"k:3", "v:3"}}; + std::unordered_multimap b; + serialize_test(a, b); + ASSERT(a == b); + ASSERT_SERIALIZE_SIZE(2 /*size*/ + (2 /*std::pair*/ + (2 + 3) * 2) * 3); + } + + /// ptr + { + RPC_CORE_LOGI("ptr..."); + int* a = (int*)123; + int* b = nullptr; + serialize_test(a, b); + ASSERT(a == b); + ASSERT_SERIALIZE_SIZE(2); // auto size + } + + /// binary_wrap + { + RPC_CORE_LOGI("binary_wrap..."); + { + uint8_t array[] = {1, 2, 3}; + size_t data_bytes = sizeof(array); + rpc_core::binary_wrap a(array, data_bytes); + rpc_core::binary_wrap b; + serialize_test(a, b); + ASSERT(b.size == data_bytes); + ASSERT(b.data != array); + ASSERT(0 == memcmp(array, b.data, data_bytes)); + ASSERT_SERIALIZE_SIZE(2 /*size*/ + data_bytes); + } + { + uint8_t array[] = {1, 2, 3}; + struct Test { + uint8_t* ptr = nullptr; + rpc_core::binary_wrap bin; + RPC_CORE_DEFINE_TYPE_INNER(ptr, bin); + }; + Test a; + a.ptr = array; + a.bin = {array, sizeof(array)}; + Test b; + serialize_test(a, b); + ASSERT(b.ptr == array); + ASSERT(b.bin.size == sizeof(array)); + ASSERT(b.bin.data != array); + ASSERT(0 == memcmp(array, b.bin.data, sizeof(array))); + } + } + + /// std::shared_ptr + { + RPC_CORE_LOGI("std::shared_ptr..."); + { + std::shared_ptr a = std::make_shared("test"); + std::shared_ptr b; + serialize_test(a, b); + ASSERT(*a == *b); + ASSERT_SERIALIZE_SIZE(1 /*flag*/ + a->size()); + } + { + std::shared_ptr a = nullptr; + std::shared_ptr b; + serialize_test(a, b); + ASSERT(a == b); + ASSERT_SERIALIZE_SIZE(1 /*flag*/); + } + } + + /// std::unique_ptr + { + RPC_CORE_LOGI("std::unique_ptr..."); + { + std::unique_ptr a = std::unique_ptr(new std::string("test")); + std::unique_ptr b; + serialize_test(a, b); + ASSERT(*a == *b); + ASSERT_SERIALIZE_SIZE(1 /*flag*/ + a->size()); + } + { + std::unique_ptr a = nullptr; + std::unique_ptr b; + serialize_test(a, b); + ASSERT(a == b); + ASSERT_SERIALIZE_SIZE(1 /*flag*/); + } + } + + /// std::complex + { + RPC_CORE_LOGI("std::complex..."); + { + std::complex a; + a.real(1.23f); + a.imag(3.21f); + std::complex b; + serialize_test(a, b); + ASSERT(a == b); + ASSERT_SERIALIZE_SIZE(4 /*float*/ * 2); + } + { + std::complex a; + { + CustomType t; + t.id = 1; + t.ids = {1, 2, 3}; + t.name = "test"; + a.real(t); + a.imag(t); + } + std::complex b; + serialize_test(a, b); + ASSERT(a == b); + ASSERT_SERIALIZE_SIZE(40); + } + } + + /// std::duration + { + RPC_CORE_LOGI("std::duration..."); + std::chrono::seconds a(123); + std::chrono::seconds b; + serialize_test(a, b); + ASSERT(a == b); + ASSERT_SERIALIZE_SIZE(2); // auto size + } + + /// std::time_point + { + RPC_CORE_LOGI("std::time_point..."); + std::chrono::time_point a = std::chrono::time_point::max(); + std::chrono::time_point b; + serialize_test(a, b); + ASSERT(a == b); + ASSERT_SERIALIZE_SIZE(9); + } + + /// custom class/struct + { + RPC_CORE_LOGI("custom type..."); + CustomType a; + a.id = 1; + a.ids = {1, 2, 3}; + a.name = "test"; + CustomType b; + serialize_test(a, b); + ASSERT(a == b); + ASSERT_SERIALIZE_SIZE((2) + (2 /*ids bytes*/ + 2 /*ids size*/ + 2 * 3) + (2 /*name bytes*/ + 4)); + } + + { + RPC_CORE_LOGI("custom ptr..."); + CustomTypePtr a; + a.int_n = nullptr; + a.int_v = (int32_t*)1; + a.unique_ptr_n = nullptr; + a.unique_ptr_v = std::unique_ptr(new int32_t(1)); + a.shared_ptr_n = nullptr; + a.shared_ptr_v = std::make_shared(1); + CustomTypePtr b; + serialize_test(a, b); + ASSERT(b.int_n == nullptr); + ASSERT(b.int_v == (int32_t*)1); + ASSERT(b.unique_ptr_n == nullptr); + ASSERT(*b.unique_ptr_v == 1); + ASSERT(b.shared_ptr_n == nullptr); + ASSERT(*b.shared_ptr_v == 1); + ASSERT_SERIALIZE_SIZE(23); + } + + { + RPC_CORE_LOGI("custom type(different alignas)..."); + CustomType2 a; + a.id1 = 1; + a.id2 = 2; + a.id3 = 3; + CustomType3 b; + serialize_test(a, b); + ASSERT(a.id1 == b.id1); + ASSERT(a.id2 == b.id2); + ASSERT(a.id3 == b.id3); + ASSERT_SERIALIZE_SIZE(4); + } + { + RPC_CORE_LOGI("custom type(nest define)..."); + test::CustomTypeNest a; + a.c2.id1 = 1; + a.c2.id2 = 2; + a.c2.id3 = 3; + test::CustomTypeNest b; + serialize_test(a, b); + ASSERT(a.c2.id1 == b.c2.id1); + ASSERT(a.c2.id2 == b.c2.id2); + ASSERT(a.c2.id3 == b.c2.id3); + ASSERT_SERIALIZE_SIZE(14); + } + { + RPC_CORE_LOGI("custom type(inner)..."); + test::CustomTypeNest2 a; + a.c2.id1 = 1; + a.c2.id2 = 2; + a.c2.id3 = 3; + test::CustomTypeNest2 b; + serialize_test(a, b); + ASSERT(a.c2.id1 == b.c2.id1); + ASSERT(a.c2.id2 == b.c2.id2); + ASSERT(a.c2.id3 == b.c2.id3); + ASSERT_SERIALIZE_SIZE(14); + } + + /// misc types + { + RPC_CORE_LOGI("misc types..."); + CustomType customType; + customType.id = 1; + customType.ids = {1, 2, 3}; + customType.name = "test"; + std::tuple>, std::string, CustomType> a{true, {{1}, {2}}, "test", customType}; + std::tuple>, std::string, CustomType> b; + serialize_test(a, b); + ASSERT(a == b); + ASSERT_SERIALIZE_SIZE(39); + } +} + +} // namespace rpc_core_test diff --git a/CMakeLists.txt b/CMakeLists.txt index 30b08be..c219b7a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -103,6 +103,7 @@ target_include_directories(${PROJECT_NAME} 3party/mongoose 3party/nlohmann 3party/nonstd + 3party/rpc_core/include 3party/rxcpp/Ix/CPP/src 3party/rxcpp/Rx/v2/src 3party/sigslot diff --git a/tests/3party/rpc_core/rpc_core_unittest.cpp b/tests/3party/rpc_core/rpc_core_unittest.cpp new file mode 100644 index 0000000..aeb84c9 --- /dev/null +++ b/tests/3party/rpc_core/rpc_core_unittest.cpp @@ -0,0 +1,40 @@ +#include "rpc_core/connection.hpp" +#include +#include +#include + +struct TestType { + int a; + std::string b; + bool c; + std::vector d; + std::map e; + std::vector> f; + RPC_CORE_DEFINE_TYPE_INNER(a, b, c, d, e, f); +}; + +TEST(rpc_core, base) +{ + TestType test_type; + auto loopback = std::make_shared(); + auto rpc_s = rpc_core::rpc::create(loopback); + rpc_s->set_timer([](uint32_t ms, const rpc_core::rpc::timeout_cb &cb) { + // RPC_CORE_UNUSED(ms); + // RPC_CORE_UNUSED(cb); + }); + rpc_s->set_ready(true); + + rpc_s->subscribe( + "test", [](const std::string &msg) -> std::string { return "ok"; }); + + auto rpc_c = rpc_core::rpc::create(loopback); + rpc_c->set_timer([](uint32_t ms, const rpc_core::rpc::timeout_cb &cb) { + RPC_CORE_UNUSED(ms); + RPC_CORE_UNUSED(cb); + }); + rpc_c->set_ready(true); + rpc_c->cmd("test") + ->msg(std::string("hello")) + ->rsp([](const std::string &rsp) { EXPECT_EQ(rsp, "ok"); }) + ->call(); +} diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index de1219e..7abde20 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -9,6 +9,7 @@ add_executable(ulib_test 3party/inja/inja_unittest.cpp 3party/nonstd/any_unittest.cpp 3party/nonstd/optional_unittest.cpp + 3party/rpc_core/rpc_core_unittest.cpp 3party/sqlpp11/sqlpp11_unittest.cpp ulib/base/types_unittest.cpp ulib/concorrency/countdown_latch_unittest.cpp