feat add rpc_core
All checks were successful
rpcrypto-build / build (Debug, hisiv510.toolchain.cmake) (push) Successful in 1m6s
rpcrypto-build / build (Debug, himix200.toolchain.cmake) (push) Successful in 1m9s
rpcrypto-build / build (Release, himix200.toolchain.cmake) (push) Successful in 1m17s
rpcrypto-build / build (Release, hisiv510.toolchain.cmake) (push) Successful in 1m22s
linux-hisiv500-gcc / linux-gcc-hisiv500 (push) Successful in 1m39s
linux-mips64-gcc / linux-gcc-mips64el (push) Successful in 1m48s
linux-x64-gcc / linux-gcc (push) Successful in 2m3s

This commit is contained in:
tqcq 2024-01-21 16:05:01 +08:00
parent 6e1491fd41
commit c3b5a29da2
71 changed files with 4970 additions and 0 deletions

View File

@ -0,0 +1,5 @@
Language: Cpp
BasedOnStyle: Google
ColumnLimit: 150
AllowShortFunctionsOnASingleLine: Empty
AllowShortLambdasOnASingleLine: Empty

View File

@ -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

14
3party/rpc_core/.gitignore vendored Normal file
View File

@ -0,0 +1,14 @@
build/
# clion
.idea/
cmake-build-*/
# qt creator
CMakeLists.txt.user
# vscode
.vscode/
# thirdparty
/thirdparty/

View File

@ -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 ()

148
3party/rpc_core/README.md Normal file
View File

@ -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)

View File

@ -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"

View File

@ -0,0 +1,3 @@
#pragma once
#include "version.hpp"

View File

@ -0,0 +1,86 @@
#pragma once
#include <functional>
#include <string>
#include <utility>
// 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<void(std::string)> send_package_impl;
std::function<void(std::string)> 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<void(std::string)> send_bytes_impl;
std::function<void(const void *data, size_t size)> on_recv_bytes;
private:
detail::data_packer data_packer_;
};
} // namespace rpc_core

View File

@ -0,0 +1,58 @@
#pragma once
#include <cstddef>
#include <functional>
#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 <typename Callable>
struct callable_traits : functor_traits<Callable> {
typedef functor_tag callable_category;
};
// functions
template <typename Ret, typename... Args>
struct callable_traits<Ret(Args...)> : function_traits<Ret(Args...)> {
typedef function_tag callable_category;
};
// function pointers
template <typename Ret, typename... Args>
struct callable_traits<Ret (*)(Args...)> : function_traits<Ret(Args...)> {
typedef function_ptr_tag callable_category;
};
} // namespace detail
// Main template
/** Traits for a callable (function/functor/lambda/...) */
template <typename Callable>
struct callable_traits : detail::callable_traits<detail::remove_cvref_t<Callable>> {};
/** Convert a callable to a std::function<> */
template <typename Callable>
std::function<typename callable_traits<Callable>::function_type> to_stdfunction(Callable fun) {
std::function<typename callable_traits<Callable>::function_type> stdfun(std::forward<Callable>(fun));
return stdfun;
}
} // namespace rpc_core

View File

@ -0,0 +1,40 @@
#pragma once
#include <cstddef>
#include "helpers.hpp"
namespace rpc_core {
namespace detail {
namespace {
/** Define traits for a function type */
template <typename Fun>
struct function_traits;
template <typename Ret, typename... Args>
struct function_traits<Ret(Args...)> {
typedef Ret function_type(Args...);
typedef Ret return_type;
static constexpr std::size_t argc = types_count<Args...>::value;
template <std::size_t N>
using argument_type = typename types_n<N, Args...>::type;
};
template <typename Ret, typename... Args>
const std::size_t function_traits<Ret(Args...)>::argc;
} // namespace
} // namespace detail
template <typename Func>
struct function_traits : detail::function_traits<detail::remove_cvref_t<Func>> {};
template <typename Func>
struct function_traits<Func*> : detail::function_traits<detail::remove_cvref_t<Func>> {};
} // namespace rpc_core

View File

@ -0,0 +1,25 @@
#pragma once
#include "function.hpp"
#include "helpers.hpp"
#include "member_function.hpp"
namespace rpc_core {
namespace detail {
template <typename Class>
using call_operator_traits = member_function_traits<decltype(&Class::operator())>;
// classes with operator()
template <typename Class>
struct functor_traits : function_traits<typename call_operator_traits<Class>::function_type> {
typedef call_operator_traits<Class> call_operator;
};
} // namespace detail
template <typename Class>
struct functor_traits : detail::functor_traits<detail::remove_cvref_t<Class>> {};
} // namespace rpc_core

View File

@ -0,0 +1,58 @@
#pragma once
#include <cstddef>
namespace rpc_core {
namespace detail {
/** Remove reference and cv qualification */
template <typename T>
using remove_cvref_t = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
/** Count the number of types given to the template */
template <typename... Types>
struct types_count;
template <>
struct types_count<> {
static constexpr std::size_t value = 0;
};
template <typename Type, typename... Types>
struct types_count<Type, Types...> {
static constexpr std::size_t value = types_count<Types...>::value + 1;
};
/** Get the nth type given to the template */
template <std::size_t n, typename... Types>
struct types_n;
template <std::size_t N, typename Type, typename... Types>
struct types_n<N, Type, Types...> : types_n<N - 1, Types...> {};
template <typename Type, typename... Types>
struct types_n<0, Type, Types...> {
typedef Type type;
};
/** Test if a type is in a list given types */
template <typename Q, typename... Ts>
struct types_has;
template <typename Q>
struct types_has<Q> {
static constexpr bool value = false;
};
template <typename Q, typename... Ts>
struct types_has<Q, Q, Ts...> {
static constexpr bool value = true;
};
template <typename Q, typename T, typename... Ts>
struct types_has<Q, T, Ts...> : types_has<Q, Ts...> {};
} // namespace detail
} // namespace rpc_core

View File

@ -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 <typename Class, typename Func, typename... Qual>
struct member_function_traits_q : function_traits<Func> {
typedef Class class_type;
static constexpr bool is_const = types_has<const_tag, Qual...>::value;
static constexpr bool is_volatile = types_has<volatile_tag, Qual...>::value;
static constexpr bool is_lref = types_has<lref_tag, Qual...>::value;
static constexpr bool is_rref = types_has<rref_tag, Qual...>::value;
#if __cpp_noexcept_function_type
static constexpr bool is_noexcept = types_has<noexcept_tag, Qual...>::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 <typename Class, typename Func, typename... Qual>
const bool member_function_traits_q<Class, Func, Qual...>::is_const;
template <typename Class, typename Func, typename... Qual>
const bool member_function_traits_q<Class, Func, Qual...>::is_volatile;
template <typename Class, typename Func, typename... Qual>
const bool member_function_traits_q<Class, Func, Qual...>::is_lref;
template <typename Class, typename Func, typename... Qual>
const bool member_function_traits_q<Class, Func, Qual...>::is_rref;
#if __cpp_noexcept_function_type
template <typename Class, typename Func, typename... Qual>
const bool member_function_traits_q<Class, Func, Qual...>::is_noexcept;
#endif
} // namespace
template <typename MemFun>
struct member_function_traits;
template <typename Class, typename Ret, typename... Args>
struct member_function_traits<Ret (Class::*)(Args...)> : member_function_traits_q<Class, Ret(Args...)> {};
template <typename Class, typename Ret, typename... Args>
struct member_function_traits<Ret (Class::*)(Args...) const> : member_function_traits_q<Class, Ret(Args...), const_tag> {};
template <typename Class, typename Ret, typename... Args>
struct member_function_traits<Ret (Class::*)(Args...) volatile> : member_function_traits_q<Class, Ret(Args...), volatile_tag> {};
template <typename Class, typename Ret, typename... Args>
struct member_function_traits<Ret (Class::*)(Args...) const volatile> : member_function_traits_q<Class, Ret(Args...), const_tag, volatile_tag> {};
template <typename Class, typename Ret, typename... Args>
struct member_function_traits<Ret (Class::*)(Args...) &> : member_function_traits_q<Class, Ret(Args...), lref_tag> {};
template <typename Class, typename Ret, typename... Args>
struct member_function_traits<Ret (Class::*)(Args...) const &> : member_function_traits_q<Class, Ret(Args...), const_tag, lref_tag> {};
template <typename Class, typename Ret, typename... Args>
struct member_function_traits<Ret (Class::*)(Args...) volatile &> : member_function_traits_q<Class, Ret(Args...), volatile_tag, lref_tag> {};
template <typename Class, typename Ret, typename... Args>
struct member_function_traits<Ret (Class::*)(Args...) const volatile &>
: member_function_traits_q<Class, Ret(Args...), const_tag, volatile_tag, lref_tag> {};
template <typename Class, typename Ret, typename... Args>
struct member_function_traits<Ret (Class::*)(Args...) &&> : member_function_traits_q<Class, Ret(Args...), rref_tag> {};
template <typename Class, typename Ret, typename... Args>
struct member_function_traits<Ret (Class::*)(Args...) const &&> : member_function_traits_q<Class, Ret(Args...), const_tag, rref_tag> {};
template <typename Class, typename Ret, typename... Args>
struct member_function_traits<Ret (Class::*)(Args...) volatile &&> : member_function_traits_q<Class, Ret(Args...), volatile_tag, rref_tag> {};
template <typename Class, typename Ret, typename... Args>
struct member_function_traits<Ret (Class::*)(Args...) const volatile &&>
: member_function_traits_q<Class, Ret(Args...), const_tag, volatile_tag, rref_tag> {};
#if __cpp_noexcept_function_type
template <typename Class, typename Ret, typename... Args>
struct member_function_traits<Ret (Class::*)(Args...) noexcept> : member_function_traits_q<Class, Ret(Args...), noexcept_tag> {};
template <typename Class, typename Ret, typename... Args>
struct member_function_traits<Ret (Class::*)(Args...) const noexcept> : member_function_traits_q<Class, Ret(Args...), const_tag, noexcept_tag> {};
template <typename Class, typename Ret, typename... Args>
struct member_function_traits<Ret (Class::*)(Args...) volatile noexcept> : member_function_traits_q<Class, Ret(Args...), volatile_tag, noexcept_tag> {
};
template <typename Class, typename Ret, typename... Args>
struct member_function_traits<Ret (Class::*)(Args...) const volatile noexcept>
: member_function_traits_q<Class, Ret(Args...), const_tag, volatile_tag, noexcept_tag> {};
template <typename Class, typename Ret, typename... Args>
struct member_function_traits<Ret (Class::*)(Args...) & noexcept> : member_function_traits_q<Class, Ret(Args...), lref_tag, noexcept_tag> {};
template <typename Class, typename Ret, typename... Args>
struct member_function_traits<Ret (Class::*)(Args...) const & noexcept>
: member_function_traits_q<Class, Ret(Args...), const_tag, lref_tag, noexcept_tag> {};
template <typename Class, typename Ret, typename... Args>
struct member_function_traits<Ret (Class::*)(Args...) volatile & noexcept>
: member_function_traits_q<Class, Ret(Args...), volatile_tag, lref_tag, noexcept_tag> {};
template <typename Class, typename Ret, typename... Args>
struct member_function_traits<Ret (Class::*)(Args...) const volatile & noexcept>
: member_function_traits_q<Class, Ret(Args...), const_tag, volatile_tag, lref_tag, noexcept_tag> {};
template <typename Class, typename Ret, typename... Args>
struct member_function_traits<Ret (Class::*)(Args...) && noexcept> : member_function_traits_q<Class, Ret(Args...), rref_tag, noexcept_tag> {};
template <typename Class, typename Ret, typename... Args>
struct member_function_traits<Ret (Class::*)(Args...) const && noexcept>
: member_function_traits_q<Class, Ret(Args...), const_tag, rref_tag, noexcept_tag> {};
template <typename Class, typename Ret, typename... Args>
struct member_function_traits<Ret (Class::*)(Args...) volatile && noexcept>
: member_function_traits_q<Class, Ret(Args...), volatile_tag, rref_tag, noexcept_tag> {};
template <typename Class, typename Ret, typename... Args>
struct member_function_traits<Ret (Class::*)(Args...) const volatile && noexcept>
: member_function_traits_q<Class, Ret(Args...), const_tag, volatile_tag, rref_tag, noexcept_tag> {};
#endif // __cpp_noexcept_function_type
} // namespace detail
template <typename MemFunPtr>
struct member_function_traits : detail::member_function_traits<detail::remove_cvref_t<MemFunPtr>> {};
} // namespace rpc_core

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,120 @@
#pragma once
#include <cstdint>
#include <functional>
#include <string>
// #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<bool(const void *data, size_t size)> &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<void(std::string)> 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

View File

@ -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 <cstring>
#include <cstdlib>
#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 <string.h>
#include <stdlib.h>
#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 <android/log.h>
#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 <cstdio>
#else
#include <stdio.h>
#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 <mutex>
// 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<std::mutex> 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 <cstdint>
#ifdef L_O_G_GET_TID_CUSTOM
extern uint32_t L_O_G_GET_TID_CUSTOM();
#elif defined(_WIN32)
#include <processthreadsapi.h>
struct L_O_G_NS_GET_TID {
static inline uint32_t get_tid() {
return GetCurrentThreadId();
}
};
#elif defined(__linux__)
#include <sys/syscall.h>
#include <unistd.h>
struct L_O_G_NS_GET_TID {
static inline uint32_t get_tid() {
return syscall(SYS_gettid);
}
};
#else /* for mac, bsd.. */
#include <pthread.h>
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 <chrono>
#include <sstream>
#include <iomanip> // 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<std::chrono::milliseconds>(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

View File

@ -0,0 +1,168 @@
#pragma once
#include <map>
#include <memory>
#include <utility>
#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<std::pair<bool, msg_wrapper>(msg_wrapper)>;
using rsp_handle = std::function<bool(msg_wrapper)>;
using timeout_cb = std::function<void()>;
using timer_impl = std::function<void(uint32_t ms, timeout_cb)>;
public:
explicit msg_dispatcher(std::shared_ptr<connection> conn) : conn_(std::move(conn)) {
auto alive = std::weak_ptr<void>(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::msg_type>(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>(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<void>(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<connection> conn_;
std::map<cmd_type, cmd_handle> cmd_handle_map_;
std::map<seq_type, rsp_handle> rsp_handle_map_;
std::map<seq_type, rsp_handle> pong_handle_map_;
timer_impl timer_impl_;
std::shared_ptr<void> is_alive_ = std::make_shared<uint8_t>();
};
} // namespace detail
} // namespace rpc_core

View File

@ -0,0 +1,59 @@
#pragma once
#include <string>
#include <utility>
#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 <typename T>
std::pair<bool, T> 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 <typename T>
static std::pair<bool, msg_wrapper> 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

View File

@ -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

View File

@ -0,0 +1,26 @@
#pragma once
#include <cstddef>
#include <string>
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

View File

@ -0,0 +1,24 @@
#pragma once
#include <type_traits>
namespace rpc_core {
namespace detail {
template <typename Base, typename T, typename... Args>
struct all_base_of {
static constexpr bool value = std::is_base_of<Base, T>::value && all_base_of<Base, Args...>::value;
};
template <typename Base, typename T>
struct all_base_of<Base, T> {
static constexpr bool value = std::is_base_of<Base, T>::value;
};
template <typename T>
constexpr const T& min(const T& a, const T& b) {
return a < b ? a : b;
}
} // namespace detail
} // namespace rpc_core

View File

@ -0,0 +1,61 @@
#pragma once
#include <algorithm>
#include <memory>
#include <vector>
// #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<dispose> create() {
return std::make_shared<dispose>();
}
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<request_w> requests_;
};
using dispose_s = std::shared_ptr<dispose>;
} // namespace rpc_core

View File

@ -0,0 +1,35 @@
#pragma once
#include "flatbuffers/flatbuffers.h"
#include "rpc_core/serialize.hpp"
namespace rpc_core {
template <typename T, typename std::enable_if<std::is_base_of<::flatbuffers::NativeTable, T>::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 <typename T, typename std::enable_if<std::is_base_of<::flatbuffers::NativeTable, T>::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<TableType>();
if (!ok) {
ia.error = true;
return ia;
}
flatbuffers::GetRoot<TableType>(ia.data)->UnPackTo(&t);
return ia;
}
} // namespace rpc_core

View File

@ -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 <typename T, typename std::enable_if<std::is_same<nlohmann::json, T>::value, int>::type = 0>
serialize_oarchive& operator>>(const T& t, serialize_oarchive& oa) {
t.dump() >> oa;
return oa;
}
template <typename T, typename std::enable_if<std::is_same<nlohmann::json, T>::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

View File

@ -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 <typename T, typename std::enable_if<std::is_same<CLASS, T>::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 <typename T, typename std::enable_if<std::is_same<CLASS, T>::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<T>(); \
} 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);

View File

@ -0,0 +1,384 @@
#pragma once
#include <cassert>
#include <memory>
#include <utility>
#ifndef RPC_CORE_FEATURE_DISABLE_FUTURE
#include <future>
#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<request> {
friend class rpc;
public:
using request_s = std::shared_ptr<request>;
using request_w = std::weak_ptr<request>;
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<rpc_proto>;
using send_proto_w = std::weak_ptr<rpc_proto>;
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 <typename... Args>
static request_s create(Args&&... args) {
auto r = std::shared_ptr<request>(new request(std::forward<Args>(args)...), [](request* p) {
delete p;
});
r->init();
return r;
}
public:
std::shared_ptr<request> cmd(cmd_type cmd) {
cmd_ = std::move(cmd);
return shared_from_this();
}
template <typename T>
request_s msg(T&& message) {
this->payload_ = serialize(std::forward<T>(message));
return shared_from_this();
}
template <typename F, typename std::enable_if<callable_traits<F>::argc, int>::type = 0>
request_s rsp(RPC_CORE_MOVE_PARAM(F) cb) {
using T = detail::remove_cvref_t<typename callable_traits<F>::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<T>();
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 <typename F, typename std::enable_if<!callable_traits<F>::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<request> finally(std::function<void(finally_t)> finally) {
finally_ = std::move(finally);
return shared_from_this();
}
std::shared_ptr<request> finally(RPC_CORE_MOVE_PARAM(std::function<void()>) 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<request> timeout_ms(uint32_t timeout_ms) {
timeout_ms_ = timeout_ms;
return shared_from_this();
}
/**
* timeout callback for wait `rsp`
*/
std::shared_ptr<request> timeout(RPC_CORE_MOVE_PARAM(std::function<void()>) 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<request> 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<request> 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 <typename T>
struct future_ret;
template <typename R, typename std::enable_if<!std::is_same<R, void>::value, int>::type = 0>
std::future<future_ret<R>> future(const send_proto_s& rpc = nullptr);
template <typename R, typename std::enable_if<std::is_same<R, void>::value, int>::type = 0>
std::future<future_ret<void>> 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<bool(detail::msg_wrapper)> rsp_handle_;
uint32_t timeout_ms_ = 3000;
std::function<void()> timeout_cb_;
finally_t finally_type_ = finally_t::no_need_rsp;
std::function<void(finally_t)> finally_;
int retry_count_ = 0;
bool waiting_rsp_ = false;
bool is_ping_ = false;
};
#ifndef RPC_CORE_FEATURE_DISABLE_FUTURE
template <typename T>
struct request::future_ret {
finally_t type;
T data;
};
template <>
struct request::future_ret<void> {
finally_t type;
};
template <typename R, typename std::enable_if<!std::is_same<R, void>::value, int>::type>
std::future<request::future_ret<R>> request::future(const request::send_proto_s& rpc) {
auto promise = std::make_shared<std::promise<future_ret<R>>>();
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 <typename R, typename std::enable_if<std::is_same<R, void>::value, int>::type>
std::future<request::future_ret<void>> request::future(const request::send_proto_s& rpc) {
auto promise = std::make_shared<std::promise<request::future_ret<void>>>();
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

View File

@ -0,0 +1,165 @@
#pragma once
#include <memory>
#include <utility>
// 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<rpc>, public request::rpc_proto {
public:
using timeout_cb = detail::msg_dispatcher::timeout_cb;
public:
template <typename... Args>
static std::shared_ptr<rpc> create(Args&&... args) {
return std::shared_ptr<rpc>(new rpc(std::forward<Args>(args)...), [](rpc* p) {
delete p;
});
}
private:
explicit rpc(std::shared_ptr<connection> conn = std::make_shared<default_connection>()) : 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<connection> 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 <typename F>
void subscribe(const cmd_type& cmd, RPC_CORE_MOVE_PARAM(F) handle) {
constexpr bool F_ReturnIsEmpty = std::is_void<typename detail::callable_traits<F>::return_type>::value;
constexpr bool F_ParamIsEmpty = detail::callable_traits<F>::argc == 0;
subscribe_helper<F, F_ReturnIsEmpty, F_ParamIsEmpty>()(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::msg_type>(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 <typename F, bool F_ReturnIsEmpty, bool F_ParamIsEmpty>
struct subscribe_helper;
template <typename F>
struct subscribe_helper<F, false, false> {
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<typename detail::callable_traits<F>::template argument_type<0>>;
using F_Return = detail::remove_cvref_t<typename detail::callable_traits<F>::return_type>;
auto r = msg.unpack_as<F_Param>();
F_Return ret;
if (r.first) {
ret = handle(std::move(r.second));
}
return detail::msg_wrapper::make_rsp(msg.seq, &ret, r.first);
});
}
};
template <typename F>
struct subscribe_helper<F, true, false> {
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<typename detail::callable_traits<F>::template argument_type<0>>;
auto r = msg.unpack_as<F_Param>();
if (r.first) {
handle(std::move(r.second));
}
return detail::msg_wrapper::make_rsp<uint8_t>(msg.seq, nullptr, r.first);
});
}
};
template <typename F>
struct subscribe_helper<F, false, true> {
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<F>::return_type;
F_Return ret = handle();
return detail::msg_wrapper::make_rsp(msg.seq, &ret, true);
});
}
};
template <typename F>
struct subscribe_helper<F, true, true> {
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<uint8_t>(msg.seq, nullptr, true);
});
}
};
private:
std::shared_ptr<connection> conn_;
detail::msg_dispatcher dispatcher_;
seq_type seq_{0};
bool is_ready_ = false;
};
} // namespace rpc_core

View File

@ -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"

View File

@ -0,0 +1,38 @@
#pragma once
#include <cstdint>
#include <memory>
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<uint8_t> _data_;
};
template <typename T, typename std::enable_if<std::is_same<T, binary_wrap>::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 <typename T, typename std::enable_if<std::is_same<T, binary_wrap>::value, int>::type = 0>
inline serialize_iarchive& operator<<(T& t, serialize_iarchive& ia) {
t.size << ia;
t._data_ = std::shared_ptr<uint8_t>(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

View File

@ -0,0 +1,73 @@
#pragma once
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <string>
namespace rpc_core {
namespace detail {
template <typename int_impl_t>
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<size_t>;
using auto_intmax = auto_size_type<intmax_t>;
using auto_uintmax = auto_size_type<uintmax_t>;
template <typename T>
struct is_auto_size_type : std::false_type {};
template <typename T>
struct is_auto_size_type<auto_size_type<T>> : std::true_type {};
} // namespace detail
} // namespace rpc_core

View File

@ -0,0 +1,57 @@
#pragma once
#include <array>
#include "../detail/callable/helpers.hpp"
namespace rpc_core {
namespace detail {
template <typename T>
struct is_std_array : std::false_type {};
template <typename T, size_t Size>
struct is_std_array<std::array<T, Size>> : std::true_type {};
} // namespace detail
template <typename T, typename std::enable_if<detail::is_std_array<T>::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<detail::remove_cvref_t<decltype(item)>>::value) {
item >> oa;
} else {
serialize_oarchive tmp;
item >> tmp;
tmp >> oa;
}
}
return oa;
}
template <typename T, typename std::enable_if<detail::is_std_array<T>::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<detail::remove_cvref_t<decltype(item)>>::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

View File

@ -0,0 +1,42 @@
#pragma once
#include <string>
namespace rpc_core {
namespace detail {
template <typename T>
struct is_std_basic_string : std::false_type {};
template <typename... Args>
struct is_std_basic_string<std::basic_string<Args...>> : std::true_type {};
} // namespace detail
template <typename T, typename std::enable_if<detail::is_std_basic_string<T>::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 <typename T, typename std::enable_if<detail::is_std_basic_string<T>::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>(t);
} else {
oa.data.append((char*)t.data(), t.size() * sizeof(VT));
}
return oa;
}
template <typename T, typename std::enable_if<detail::is_std_basic_string<T>::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

View File

@ -0,0 +1,33 @@
#pragma once
#include <bitset>
#include <string>
#include <type_traits>
namespace rpc_core {
namespace detail {
template <typename T>
struct is_std_bitset : std::false_type {};
template <std::size_t N>
struct is_std_bitset<std::bitset<N>> : std::true_type {};
} // namespace detail
template <typename T, typename std::enable_if<detail::is_std_bitset<T>::value, int>::type = 0>
serialize_oarchive& operator>>(const T& t, serialize_oarchive& oa) {
oa.data.append(t.to_string());
return oa;
}
template <typename T, typename std::enable_if<detail::is_std_bitset<T>::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

View File

@ -0,0 +1,53 @@
#pragma once
#include <chrono>
#include <type_traits>
namespace rpc_core {
namespace detail {
template <typename T>
struct is_std_chrono_duration : std::false_type {};
template <typename... Args>
struct is_std_chrono_duration<std::chrono::duration<Args...>> : std::true_type {};
template <typename T>
struct is_std_chrono_time_point : std::false_type {};
template <typename... Args>
struct is_std_chrono_time_point<std::chrono::time_point<Args...>> : std::true_type {};
} // namespace detail
template <typename T, typename std::enable_if<detail::is_std_chrono_duration<T>::value, int>::type = 0>
serialize_oarchive& operator>>(const T& t, serialize_oarchive& oa) {
detail::auto_intmax count(t.count());
count >> oa;
return oa;
}
template <typename T, typename std::enable_if<detail::is_std_chrono_duration<T>::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 <typename T, typename std::enable_if<detail::is_std_chrono_time_point<T>::value, int>::type = 0>
serialize_oarchive& operator>>(const T& t, serialize_oarchive& oa) {
t.time_since_epoch() >> oa;
return oa;
}
template <typename T, typename std::enable_if<detail::is_std_chrono_time_point<T>::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

View File

@ -0,0 +1,52 @@
#pragma once
#include <complex>
#include <type_traits>
namespace rpc_core {
namespace detail {
template <typename T>
struct is_std_complex : std::false_type {};
template <typename T>
struct is_std_complex<std::complex<T>> : std::true_type {};
} // namespace detail
template <typename T, typename std::enable_if<detail::is_std_complex<T>::value, int>::type = 0>
serialize_oarchive& operator>>(const T& t, serialize_oarchive& oa) {
using VT = typename T::value_type;
if (std::is_fundamental<VT>::value) {
t.real() >> oa;
t.imag() >> oa;
} else {
oa & t.real();
oa & t.imag();
}
return oa;
}
template <typename T, typename std::enable_if<detail::is_std_complex<T>::value, int>::type = 0>
serialize_iarchive& operator<<(T& t, serialize_iarchive& ia) {
using VT = typename T::value_type;
if (std::is_fundamental<VT>::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

View File

@ -0,0 +1,36 @@
#pragma once
#include <queue>
#include <stack>
namespace rpc_core {
namespace detail {
template <typename T>
struct is_std_stack : std::false_type {};
template <typename... Args>
struct is_std_stack<std::stack<Args...>> : std::true_type {};
template <typename... Args>
struct is_std_stack<std::queue<Args...>> : std::true_type {};
template <typename... Args>
struct is_std_stack<std::priority_queue<Args...>> : std::true_type {};
} // namespace detail
template <typename T, typename std::enable_if<detail::is_std_stack<T>::value, int>::type = 0>
serialize_oarchive& operator>>(const T& t, serialize_oarchive& oa) {
(typename T::container_type&)t >> oa;
return oa;
}
template <typename T, typename std::enable_if<detail::is_std_stack<T>::value, int>::type = 0>
serialize_iarchive& operator<<(T& t, serialize_iarchive& ia) {
(typename T::container_type&)t << ia;
return ia;
}
} // namespace rpc_core

View File

@ -0,0 +1,58 @@
#pragma once
#include <forward_list>
#include "../detail/callable/helpers.hpp"
namespace rpc_core {
namespace detail {
template <typename T>
struct is_std_forward_list : std::false_type {};
template <typename... Args>
struct is_std_forward_list<std::forward_list<Args...>> : std::true_type {};
} // namespace detail
template <typename T, typename std::enable_if<detail::is_std_forward_list<T>::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<detail::remove_cvref_t<decltype(item)>>::value) {
item >> oa;
} else {
serialize_oarchive tmp;
item >> tmp;
tmp >> oa;
}
}
return oa;
}
template <typename T, typename std::enable_if<detail::is_std_forward_list<T>::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<detail::remove_cvref_t<decltype(item)>>::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

View File

@ -0,0 +1,63 @@
#pragma once
#include <deque>
#include <list>
#include <vector>
namespace rpc_core {
namespace detail {
template <typename T>
struct is_std_list_like : std::false_type {};
template <typename... Args>
struct is_std_list_like<std::vector<Args...>> : std::true_type {};
template <typename... Args>
struct is_std_list_like<std::list<Args...>> : std::true_type {};
template <typename... Args>
struct is_std_list_like<std::deque<Args...>> : std::true_type {};
} // namespace detail
template <typename T, typename std::enable_if<detail::is_std_list_like<T>::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<detail::remove_cvref_t<decltype(item)>>::value) {
item >> oa;
} else {
serialize_oarchive tmp;
item >> tmp;
tmp >> oa;
}
}
return oa;
}
template <typename T, typename std::enable_if<detail::is_std_list_like<T>::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<detail::remove_cvref_t<decltype(item)>>::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

View File

@ -0,0 +1,57 @@
#pragma once
#include <map>
#include <unordered_map>
namespace rpc_core {
namespace detail {
template <typename T>
struct is_std_map_like : std::false_type {};
template <typename... Args>
struct is_std_map_like<std::map<Args...>> : std::true_type {};
template <typename... Args>
struct is_std_map_like<std::unordered_map<Args...>> : std::true_type {};
template <typename... Args>
struct is_std_map_like<std::multimap<Args...>> : std::true_type {};
template <typename... Args>
struct is_std_map_like<std::unordered_multimap<Args...>> : std::true_type {};
} // namespace detail
template <typename T, typename std::enable_if<detail::is_std_map_like<T>::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 <typename T, typename std::enable_if<detail::is_std_map_like<T>::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

View File

@ -0,0 +1,34 @@
#pragma once
#include <tuple>
namespace rpc_core {
namespace detail {
template <typename T>
struct is_std_pair : std::false_type {};
template <typename... Args>
struct is_std_pair<std::pair<Args...>> : std::true_type {};
} // namespace detail
template <typename T, typename std::enable_if<detail::is_std_pair<T>::value, int>::type = 0>
inline serialize_oarchive& operator>>(const T& t, serialize_oarchive& oa) {
std::tie(t.first, t.second) >> oa;
return oa;
}
template <typename T, typename std::enable_if<detail::is_std_pair<T>::value, int>::type = 0>
serialize_iarchive& operator<<(T& t, serialize_iarchive& ia) {
using first_type = detail::remove_cvref_t<decltype(t.first)>;
using second_type = detail::remove_cvref_t<decltype(t.second)>;
auto& tt = (std::pair<first_type, second_type>&)t;
std::tuple<first_type, second_type> tup;
tup << ia;
std::tie(tt.first, tt.second) = std::move(tup);
return ia;
}
} // namespace rpc_core

View File

@ -0,0 +1,65 @@
#pragma once
#include <set>
#include <unordered_set>
namespace rpc_core {
namespace detail {
template <typename T>
struct is_std_set_like : std::false_type {};
template <typename... Args>
struct is_std_set_like<std::set<Args...>> : std::true_type {};
template <typename... Args>
struct is_std_set_like<std::unordered_set<Args...>> : std::true_type {};
template <typename... Args>
struct is_std_set_like<std::multiset<Args...>> : std::true_type {};
template <typename... Args>
struct is_std_set_like<std::unordered_multiset<Args...>> : std::true_type {};
} // namespace detail
template <typename T, typename std::enable_if<detail::is_std_set_like<T>::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<detail::remove_cvref_t<decltype(item)>>::value) {
item >> oa;
} else {
serialize_oarchive tmp;
item >> tmp;
tmp >> oa;
}
}
return oa;
}
template <typename T, typename std::enable_if<detail::is_std_set_like<T>::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<detail::remove_cvref_t<decltype(item)>>::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

View File

@ -0,0 +1,40 @@
#pragma once
#include <memory>
namespace rpc_core {
namespace detail {
template <typename T>
struct is_std_shared_ptr : std::false_type {};
template <typename... Args>
struct is_std_shared_ptr<std::shared_ptr<Args...>> : std::true_type {};
} // namespace detail
template <typename T, typename std::enable_if<detail::is_std_shared_ptr<T>::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 <typename T, typename std::enable_if<detail::is_std_shared_ptr<T>::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<Type>();
*t << ia;
}
return ia;
}
} // namespace rpc_core

View File

@ -0,0 +1,147 @@
#pragma once
#include <tuple>
#include "../detail/callable/helpers.hpp"
namespace rpc_core {
namespace detail {
template <std::size_t I, typename T>
using tuple_element_t = detail::remove_cvref_t<typename std::tuple_element<I, detail::remove_cvref_t<T>>::type>;
template <typename T>
struct is_tuple : std::false_type {};
template <typename... Args>
struct is_tuple<std::tuple<Args...>> : std::true_type {};
template <typename T>
struct is_std_ignore {
static const bool value = std::is_same<detail::remove_cvref_t<decltype(std::ignore)>, T>::value;
};
enum class tuple_serialize_type {
Ignore,
RawType,
Normal,
};
template <typename T>
struct tuple_serialize_type_check {
static constexpr tuple_serialize_type value = std::is_fundamental<T>::value ? tuple_serialize_type::RawType
: is_std_ignore<T>::value ? tuple_serialize_type::Ignore
: tuple_serialize_type::Normal;
};
template <typename Tuple, std::size_t I, tuple_serialize_type type>
struct tuple_serialize_helper_impl;
template <typename Tuple, std::size_t I>
struct tuple_serialize_helper_impl<Tuple, I, tuple_serialize_type::Normal> {
static void serialize(const Tuple& t, serialize_oarchive& oa) {
serialize_oarchive tmp;
std::get<I>(t) >> tmp;
tmp >> oa;
}
};
template <typename Tuple, std::size_t I>
struct tuple_serialize_helper_impl<Tuple, I, tuple_serialize_type::RawType> {
static void serialize(const Tuple& t, serialize_oarchive& oa) {
std::get<I>(t) >> oa;
}
};
template <typename Tuple, std::size_t I>
struct tuple_serialize_helper_impl<Tuple, I, tuple_serialize_type::Ignore> {
static void serialize(const Tuple& t, serialize_oarchive& oa) {
RPC_CORE_UNUSED(t);
RPC_CORE_UNUSED(oa);
}
};
template <typename Tuple, std::size_t N>
struct tuple_serialize_helper {
static void serialize(const Tuple& t, serialize_oarchive& oa) {
tuple_serialize_helper<Tuple, N - 1>::serialize(t, oa);
tuple_serialize_helper_impl<Tuple, N - 1, tuple_serialize_type_check<tuple_element_t<N - 1, Tuple>>::value>::serialize(t, oa);
}
};
template <typename Tuple>
struct tuple_serialize_helper<Tuple, 1> {
static void serialize(const Tuple& t, serialize_oarchive& oa) {
tuple_serialize_helper_impl<Tuple, 0, tuple_serialize_type_check<tuple_element_t<0, Tuple>>::value>::serialize(t, oa);
}
};
template <typename... Args>
void tuple_serialize(const std::tuple<Args...>& t, serialize_oarchive& oa) {
tuple_serialize_helper<decltype(t), sizeof...(Args)>::serialize(t, oa);
}
template <typename Tuple, std::size_t I, tuple_serialize_type type>
struct tuple_de_serialize_helper_impl;
template <typename Tuple, std::size_t I>
struct tuple_de_serialize_helper_impl<Tuple, I, tuple_serialize_type::Normal> {
static void de_serialize(Tuple& t, serialize_iarchive& ia) {
serialize_iarchive tmp;
tmp << ia;
std::get<I>(t) << tmp;
}
};
template <typename Tuple, std::size_t I>
struct tuple_de_serialize_helper_impl<Tuple, I, tuple_serialize_type::RawType> {
static void de_serialize(Tuple& t, serialize_iarchive& ia) {
std::get<I>(t) << ia;
}
};
template <typename Tuple, std::size_t I>
struct tuple_de_serialize_helper_impl<Tuple, I, tuple_serialize_type::Ignore> {
static void de_serialize(Tuple& t, serialize_iarchive& ia) {
RPC_CORE_UNUSED(t);
RPC_CORE_UNUSED(ia);
}
};
template <typename Tuple, std::size_t N>
struct tuple_de_serialize_helper {
static void de_serialize(Tuple& t, serialize_iarchive& ia) {
tuple_de_serialize_helper<Tuple, N - 1>::de_serialize(t, ia);
if (ia.error) return;
tuple_de_serialize_helper_impl<Tuple, N - 1, tuple_serialize_type_check<tuple_element_t<N - 1, Tuple>>::value>::de_serialize(t, ia);
}
};
template <typename Tuple>
struct tuple_de_serialize_helper<Tuple, 1> {
static void de_serialize(Tuple& t, serialize_iarchive& ia) {
tuple_de_serialize_helper_impl<Tuple, 0, tuple_serialize_type_check<tuple_element_t<0, Tuple>>::value>::de_serialize(t, ia);
}
};
template <typename... Args>
void tuple_de_serialize(std::tuple<Args...>& t, serialize_iarchive& ia) {
tuple_de_serialize_helper<decltype(t), sizeof...(Args)>::de_serialize(t, ia);
}
} // namespace detail
template <typename T, typename std::enable_if<detail::is_tuple<T>::value, int>::type = 0>
serialize_oarchive& operator>>(const T& t, serialize_oarchive& oa) {
detail::tuple_serialize(t, oa);
return oa;
}
template <typename T, typename std::enable_if<detail::is_tuple<T>::value, int>::type = 0>
serialize_iarchive& operator<<(T& t, serialize_iarchive& ia) {
detail::tuple_de_serialize(t, ia);
return ia;
}
} // namespace rpc_core

View File

@ -0,0 +1,40 @@
#pragma once
#include <memory>
namespace rpc_core {
namespace detail {
template <typename T>
struct is_std_unique_ptr : std::false_type {};
template <typename... Args>
struct is_std_unique_ptr<std::unique_ptr<Args...>> : std::true_type {};
} // namespace detail
template <typename T, typename std::enable_if<detail::is_std_unique_ptr<T>::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 <typename T, typename std::enable_if<detail::is_std_unique_ptr<T>::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<Type>(new Type);
*t << ia;
}
return ia;
}
} // namespace rpc_core

View File

@ -0,0 +1,20 @@
#pragma once
namespace rpc_core {
template <typename T, typename std::enable_if<std::is_enum<T>::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 <typename T, typename std::enable_if<std::is_enum<T>::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

View File

@ -0,0 +1,22 @@
#pragma once
#include <cstdint>
namespace rpc_core {
template <typename T, typename std::enable_if<std::is_pointer<T>::value, int>::type = 0>
inline serialize_oarchive& operator>>(const T& t, serialize_oarchive& oa) {
auto ptr = (intptr_t)t;
ptr >> oa;
return oa;
}
template <typename T, typename std::enable_if<std::is_pointer<T>::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

View File

@ -0,0 +1,54 @@
#pragma once
#include <cstring>
#include <type_traits>
#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<size_t>(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

View File

@ -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 <string>
#include <type_traits>
#include "../detail/noncopyable.hpp"
#include "../detail/string_view.hpp"
namespace rpc_core {
template <typename T, typename std::enable_if<std::is_fundamental<T>::value, int>::type = 0>
inline serialize_oarchive& operator&(serialize_oarchive& oa, const T& t) {
t >> oa;
return oa;
}
template <typename T, typename std::enable_if<!std::is_fundamental<T>::value, int>::type = 0>
inline serialize_oarchive& operator&(serialize_oarchive& oa, const T& t) {
serialize_oarchive tmp;
t >> tmp;
tmp >> oa;
return oa;
}
template <typename T, typename std::enable_if<std::is_fundamental<T>::value, int>::type = 0>
inline serialize_iarchive& operator&(serialize_iarchive& ia, T& t) {
if (ia.error) return ia;
t << ia;
return ia;
}
template <typename T, typename std::enable_if<!std::is_fundamental<T>::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__) \
}

View File

@ -0,0 +1,17 @@
#pragma once
namespace rpc_core {
template <typename T, typename std::enable_if<std::is_same<T, void>::value, int>::type = 0>
inline serialize_oarchive& operator>>(const T& t, serialize_oarchive& oa) {
RPC_CORE_UNUSED(t);
return oa;
}
template <typename T, typename std::enable_if<std::is_same<T, void>::value, int>::type = 0>
inline serialize_iarchive& operator<<(T& t, serialize_iarchive& ia) {
RPC_CORE_UNUSED(t);
return ia;
}
} // namespace rpc_core

View File

@ -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 <typename T>
inline std::string serialize(T&& t) {
serialize_oarchive ar;
std::forward<T>(t) >> ar;
return std::move(ar.data);
}
template <typename T>
inline bool deserialize(const detail::string_view& data, T& t) {
serialize_iarchive ar(data);
t << ar;
return !ar.error;
}
template <typename T, typename std::enable_if<detail::is_auto_size_type<T>::value, int>::type = 0>
inline serialize_oarchive& operator>>(const T& t, serialize_oarchive& oa) {
oa.data.append(t.serialize());
return oa;
}
template <typename T, typename std::enable_if<detail::is_auto_size_type<T>::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

View File

@ -0,0 +1,25 @@
#pragma once
#include <cstdint>
#include <string>
// 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

View File

@ -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)

View File

@ -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"
]
}
}

View File

@ -0,0 +1,12 @@
#pragma once
#include <cstdio>
#include <cstdlib>
// 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__)))

View File

@ -0,0 +1,31 @@
#include <cstdio>
#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;
}

View File

@ -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);

View File

@ -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);

View File

@ -0,0 +1 @@
DisableFormat: true

View File

@ -0,0 +1,9 @@
namespace msg;
table FbMsg {
id: int;
age: uint8;
name: string;
}
root_type FbMsg;

View File

@ -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<int32_t>(VT_ID, 0);
}
uint8_t age() const {
return GetField<uint8_t>(VT_AGE, 0);
}
const ::flatbuffers::String *name() const {
return GetPointer<const ::flatbuffers::String *>(VT_NAME);
}
bool Verify(::flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) &&
VerifyField<int32_t>(verifier, VT_ID, 4) &&
VerifyField<uint8_t>(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<FbMsg> 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<int32_t>(FbMsg::VT_ID, id, 0);
}
void add_age(uint8_t age) {
fbb_.AddElement<uint8_t>(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<FbMsg> Finish() {
const auto end = fbb_.EndTable(start_);
auto o = ::flatbuffers::Offset<FbMsg>(end);
return o;
}
};
inline ::flatbuffers::Offset<FbMsg> 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<FbMsg> 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<FbMsg> 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<FbMsgT>(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> FbMsg::Pack(::flatbuffers::FlatBufferBuilder &_fbb, const FbMsgT* _o, const ::flatbuffers::rehasher_function_t *_rehasher) {
return CreateFbMsg(_fbb, _o, _rehasher);
}
inline ::flatbuffers::Offset<FbMsg> 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<msg::FbMsg>(buf);
}
inline const msg::FbMsg *GetSizePrefixedFbMsg(const void *buf) {
return ::flatbuffers::GetSizePrefixedRoot<msg::FbMsg>(buf);
}
inline bool VerifyFbMsgBuffer(
::flatbuffers::Verifier &verifier) {
return verifier.VerifyBuffer<msg::FbMsg>(nullptr);
}
inline bool VerifySizePrefixedFbMsgBuffer(
::flatbuffers::Verifier &verifier) {
return verifier.VerifySizePrefixedBuffer<msg::FbMsg>(nullptr);
}
inline void FinishFbMsgBuffer(
::flatbuffers::FlatBufferBuilder &fbb,
::flatbuffers::Offset<msg::FbMsg> root) {
fbb.Finish(root);
}
inline void FinishSizePrefixedFbMsgBuffer(
::flatbuffers::FlatBufferBuilder &fbb,
::flatbuffers::Offset<msg::FbMsg> root) {
fbb.FinishSizePrefixed(root);
}
inline std::unique_ptr<msg::FbMsgT> UnPackFbMsg(
const void *buf,
const ::flatbuffers::resolver_function_t *res = nullptr) {
return std::unique_ptr<msg::FbMsgT>(GetFbMsg(buf)->UnPack(res));
}
inline std::unique_ptr<msg::FbMsgT> UnPackSizePrefixedFbMsg(
const void *buf,
const ::flatbuffers::resolver_function_t *res = nullptr) {
return std::unique_ptr<msg::FbMsgT>(GetSizePrefixedFbMsg(buf)->UnPack(res));
}
} // namespace msg
#endif // FLATBUFFERS_GENERATED_FBMSG_MSG_H_

View File

@ -0,0 +1,65 @@
#pragma once
#include "rpc_core/serialize.hpp"
struct CustomType {
uint32_t id = 0;
std::vector<uint32_t> 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<int32_t> unique_ptr_n;
std::unique_ptr<int32_t> unique_ptr_v;
std::shared_ptr<int32_t> shared_ptr_n;
std::shared_ptr<int32_t> 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

View File

@ -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);

View File

@ -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

View File

@ -0,0 +1,95 @@
#include <ctime>
#include <random>
#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<int> 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

View File

@ -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

View File

@ -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<loopback_connection>();
// 创建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<std::string>().get();
ASSERT(result.type == finally_t::normal);
ASSERT(result.data == "test");
}
{
auto result = rpc->ping()->future<void>().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

View File

@ -0,0 +1,586 @@
#include <cinttypes>
#include "assert_def.h"
#include "rpc_core.hpp"
#include "serialize/CustomType.h"
namespace rpc_core_test {
static size_t last_serialize_size = 0;
template <typename T, typename R>
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 <typename T>
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<t>();
#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<uint32_t, 3> a{1, 2, 3};
std::array<uint32_t, 3> 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<bool, uint32_t, std::string> a(msg1, msg2, msg3);
std::tuple<bool, uint32_t, std::string> 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<std::string, std::string> a{"k:1", "v:1"};
std::pair<std::string, std::string> 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<uint32_t> a{1, 2, 3};
std::vector<uint32_t> b;
serialize_test(a, b);
ASSERT(a == b);
ASSERT_SERIALIZE_SIZE(2 /*size*/ + 2 * 3);
}
{
RPC_CORE_LOGI("std::list...");
std::list<uint32_t> a{1, 2, 3};
std::list<uint32_t> b;
serialize_test(a, b);
ASSERT(a == b);
ASSERT_SERIALIZE_SIZE(2 /*size*/ + 2 * 3);
}
{
RPC_CORE_LOGI("std::deque...");
std::deque<uint32_t> a{1, 2, 3};
std::deque<uint32_t> 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<uint32_t> a;
a.push(1);
a.push(2);
a.push(3);
std::stack<uint32_t> b;
serialize_test(a, b);
ASSERT(a == b);
ASSERT_SERIALIZE_SIZE(2 /*size*/ + 2 * 3);
}
{
RPC_CORE_LOGI("std::queue...");
std::queue<uint32_t> a;
a.push(1);
a.push(2);
a.push(3);
std::queue<uint32_t> b;
serialize_test(a, b);
ASSERT(a == b);
ASSERT_SERIALIZE_SIZE(2 /*size*/ + 2 * 3);
}
{
RPC_CORE_LOGI("std::priority_queue...");
std::priority_queue<uint32_t> a;
a.push(1);
a.push(2);
a.push(3);
std::priority_queue<uint32_t> 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<uint32_t> a{1, 2, 3};
std::forward_list<uint32_t> b;
serialize_test(a, b);
ASSERT(a == b);
ASSERT_SERIALIZE_SIZE(2 /*size*/ + 2 * 3);
}
/// std::set
{
RPC_CORE_LOGI("std::set...");
std::set<uint32_t> a{1, 2, 3};
std::set<uint32_t> b;
serialize_test(a, b);
ASSERT(a == b);
ASSERT_SERIALIZE_SIZE(2 /*size*/ + 2 * 3);
}
/// std::multiset
{
RPC_CORE_LOGI("std::multiset...");
std::multiset<uint32_t> a{1, 2, 3};
std::multiset<uint32_t> 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<uint32_t> a{1, 2, 3};
std::unordered_multiset<uint32_t> b;
serialize_test(a, b);
ASSERT(a == b);
ASSERT_SERIALIZE_SIZE(2 /*size*/ + 2 * 3);
}
/// std::map
{
RPC_CORE_LOGI("std::map...");
std::map<std::string, std::string> a{{"k:1", "v:1"}, {"k:2", "v:2"}, {"k:3", "v:3"}};
std::map<std::string, std::string> 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<std::string, std::string> a{{"k:1", "v:1"}, {"k:2", "v:2"}, {"k:3", "v:3"}};
std::unordered_map<std::string, std::string> 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<std::string, std::string> a{{"k:1", "v:1"}, {"k:2", "v:2"}, {"k:3", "v:3"}};
std::multimap<std::string, std::string> 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<std::string, std::string> a{{"k:1", "v:1"}, {"k:2", "v:2"}, {"k:3", "v:3"}};
std::unordered_multimap<std::string, std::string> 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<std::string> a = std::make_shared<std::string>("test");
std::shared_ptr<std::string> b;
serialize_test(a, b);
ASSERT(*a == *b);
ASSERT_SERIALIZE_SIZE(1 /*flag*/ + a->size());
}
{
std::shared_ptr<std::string> a = nullptr;
std::shared_ptr<std::string> 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<std::string> a = std::unique_ptr<std::string>(new std::string("test"));
std::unique_ptr<std::string> b;
serialize_test(a, b);
ASSERT(*a == *b);
ASSERT_SERIALIZE_SIZE(1 /*flag*/ + a->size());
}
{
std::unique_ptr<std::string> a = nullptr;
std::unique_ptr<std::string> b;
serialize_test(a, b);
ASSERT(a == b);
ASSERT_SERIALIZE_SIZE(1 /*flag*/);
}
}
/// std::complex
{
RPC_CORE_LOGI("std::complex...");
{
std::complex<float> a;
a.real(1.23f);
a.imag(3.21f);
std::complex<float> b;
serialize_test(a, b);
ASSERT(a == b);
ASSERT_SERIALIZE_SIZE(4 /*float*/ * 2);
}
{
std::complex<CustomType> a;
{
CustomType t;
t.id = 1;
t.ids = {1, 2, 3};
t.name = "test";
a.real(t);
a.imag(t);
}
std::complex<CustomType> 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<std::chrono::steady_clock> a = std::chrono::time_point<std::chrono::steady_clock>::max();
std::chrono::time_point<std::chrono::steady_clock> 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<int32_t>(new int32_t(1));
a.shared_ptr_n = nullptr;
a.shared_ptr_v = std::make_shared<int32_t>(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<bool, std::vector<std::tuple<uint32_t>>, std::string, CustomType> a{true, {{1}, {2}}, "test", customType};
std::tuple<bool, std::vector<std::tuple<uint32_t>>, std::string, CustomType> b;
serialize_test(a, b);
ASSERT(a == b);
ASSERT_SERIALIZE_SIZE(39);
}
}
} // namespace rpc_core_test

View File

@ -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

View File

@ -0,0 +1,40 @@
#include "rpc_core/connection.hpp"
#include <gtest/gtest.h>
#include <rpc_core.hpp>
#include <ulib/base/types.h>
struct TestType {
int a;
std::string b;
bool c;
std::vector<int> d;
std::map<std::string, int> e;
std::vector<std::map<std::string, int>> f;
RPC_CORE_DEFINE_TYPE_INNER(a, b, c, d, e, f);
};
TEST(rpc_core, base)
{
TestType test_type;
auto loopback = std::make_shared<rpc_core::loopback_connection>();
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();
}

View File

@ -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