├── .gitignore ├── .gitmodules ├── .vscode ├── launch.json └── settings.json ├── CMakeLists.txt ├── README.md ├── _external ├── CMakeLists.txt ├── asio │ └── CMakeLists.txt └── catch │ ├── CMakeLists.txt │ └── catch.hpp ├── msgpackpp ├── CMakeLists.txt └── include │ └── msgpackpp │ ├── msgpackpp.h │ ├── rpc.h │ └── windows_pipe_transport.h ├── samples_cpp17 ├── CMakeLists.txt ├── basic │ ├── CMakeLists.txt │ └── basic.cpp ├── cpp17_dispatcher │ ├── CMakeLists.txt │ └── main.cpp └── cpp17_nvim │ ├── CMakeLists.txt │ └── main.cpp ├── samples_cpp20 ├── CMakeLists.txt ├── cpp20_dispatch │ ├── CMakeLists.txt │ └── main.cpp └── cpp20_pingpong │ ├── CMakeLists.txt │ └── main.cpp └── test ├── CMakeLists.txt ├── call.cpp ├── client.cpp ├── dispatcher.cpp ├── error.cpp ├── fixture.h ├── main.cpp ├── msgpack.cpp ├── pipeline.cpp ├── request.cpp ├── rpc.cpp ├── serialize.cpp └── stream.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | Makefile* 2 | debug 3 | release 4 | obj 5 | *.sln 6 | *.suo 7 | *.sdf 8 | *.opensdf 9 | *.vcxproj* 10 | .deps 11 | ipch 12 | build 13 | .cache 14 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "asio"] 2 | path = _external/asio/asio 3 | url = https://github.com/chriskohlhoff/asio.git 4 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "basic", 9 | "type": "cppvsdbg", 10 | "request": "launch", 11 | "program": "${workspaceFolder}/build/samples_cpp17/basic/basic.exe", 12 | "args": [], 13 | "stopAtEntry": false, 14 | "cwd": "${workspaceFolder}", 15 | "environment": [], 16 | "console": "integratedTerminal" 17 | }, 18 | { 19 | "name": "cpp17_dispatcher", 20 | "type": "cppvsdbg", 21 | "request": "launch", 22 | "program": "${workspaceFolder}/build/samples_cpp17/cpp17_dispatcher/cpp17_dispatcher.exe", 23 | "args": [], 24 | "stopAtEntry": false, 25 | "cwd": "${workspaceFolder}", 26 | "environment": [], 27 | "console": "integratedTerminal" 28 | }, 29 | { 30 | "name": "cpp17_nvim", 31 | "type": "cppvsdbg", 32 | "request": "launch", 33 | "program": "${workspaceFolder}/build/samples_cpp17/cpp17_nvim/cpp17_nvim.exe", 34 | "args": [], 35 | "stopAtEntry": false, 36 | "cwd": "${workspaceFolder}", 37 | "environment": [], 38 | "console": "integratedTerminal" 39 | }, 40 | { 41 | "name": "cpp20_pingpong", 42 | "type": "cppvsdbg", 43 | "request": "launch", 44 | "program": "${workspaceFolder}/build/samples_cpp20/cpp20_pingpong/cpp20_pingpong.exe", 45 | "args": [], 46 | "stopAtEntry": false, 47 | "cwd": "${workspaceFolder}", 48 | "environment": [], 49 | "console": "integratedTerminal" 50 | }, 51 | { 52 | "name": "cpp20_dispatch", 53 | "type": "cppvsdbg", 54 | "request": "launch", 55 | "program": "${workspaceFolder}/build/samples_cpp20/cpp20_dispatch/cpp20_dispatch.exe", 56 | "args": [], 57 | "stopAtEntry": false, 58 | "cwd": "${workspaceFolder}", 59 | "environment": [], 60 | "console": "integratedTerminal" 61 | }, 62 | ] 63 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cmake.generator": "Ninja", 3 | "cmake.configureArgs": [ 4 | "-DCMAKE_EXPORT_COMPILE_COMMANDS=1", 5 | ], 6 | "cSpell.words": [ 7 | "Nvim", 8 | "msgpackpp" 9 | ], 10 | "files.associations": { 11 | "unordered_map": "cpp", 12 | "functional": "cpp", 13 | "future": "cpp", 14 | "*.ipp": "cpp", 15 | "memory": "cpp" 16 | }, 17 | } -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(msgpackpp) 2 | cmake_minimum_required(VERSION 3.14) 3 | 4 | if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") 5 | # using GCC 6 | add_compile_options(-Wall -Wno-unknown-pragmas -Wno-switch) 7 | elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") 8 | # using Visual Studio C++ 9 | add_compile_options(/source-charset:utf-8) 10 | endif() 11 | 12 | subdirs(_external msgpackpp samples_cpp17 samples_cpp20 test) 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # msgpackpp 2 | 3 | `c++17` header only [msgpack](https://github.com/msgpack/msgpack/blob/master/spec.md) implementation. 4 | 5 | `msgpack-rpc-asio` and `msgpackpp` is merged. 6 | 7 | backend. 8 | 9 | # header 10 | ## msgpackpp/msgpackpp.h 11 | 12 | * `c++17` header only msgpack implementation. 13 | * no dependency 14 | 15 | ## msgpackpp/rpc.h 16 | 17 | * `c++17` header only msgpack-rpc implementation. 18 | * depends on [asio header only](http://think-async.com/Asio/index.html) 19 | 20 | ## msgpackpp/windows_pipe_transport.h 21 | 22 | * Windows PIPE transport for `nvim --embed` 23 | * depends on Windows.h 24 | 25 | # ToDo 26 | 27 | ## Version 3 28 | * [x] merge `msgpackpp` submodule. rename `msgpack-rpc-asio` to `msgpackpp` 29 | * [ ] `c++20` co_await 30 | * [ ] error handling 31 | * [x] no throw API 32 | * [ ] use `std::span`. (using std::string_view) 33 | * [x] merge body_index & body_size 34 | 35 | ## Version 2 36 | 37 | * [x] `c++11` std::promise/future 38 | * [x] use https://github.com/ousttrue/msgpackpp backend 39 | * [x] fix unittest 40 | 41 | # unittest framework 42 | - https://github.com/philsquared/Catch 43 | 44 | # usage 45 | [samples/basic/basic.cpp](./samples/basic/basic.cpp) 46 | 47 | ```c++ 48 | #include 49 | #include 50 | 51 | int main(int argc, char **argv) 52 | { 53 | // pack 54 | //auto packer = msgpackpp::packer(); // delete copy constructor 55 | msgpackpp::packer packer; 56 | packer.pack_array(4); 57 | packer.pack_integer(0); 58 | packer.pack_integer(256); 59 | packer.pack_str("method"); 60 | packer.pack_map(3); 61 | packer.pack_str("x"); packer.pack_float(1.0f); 62 | packer.pack_str("y"); packer.pack_float(2.0f); 63 | packer.pack_str("z"); packer.pack_float(3.0f); 64 | 65 | // std::vector 66 | auto p = packer.get_payload(); 67 | 68 | // unpack 69 | auto u = msgpackpp::parser(p); 70 | std::cout << u.to_json() << std::endl; // json style for debug 71 | 72 | std::cout << u.is_array() << std::endl; 73 | std::cout << u[0].get_number() << std::endl; 74 | std::cout << u[1].get_number() << std::endl; 75 | std::cout << u[2].get_string() << std::endl; 76 | std::cout << u[3].is_map() << std::endl; 77 | std::cout << u[3]["x"].get_number() << std::endl; 78 | std::cout << u[3]["y"].get_number() << std::endl; 79 | std::cout << u[3]["z"].get_number() << std::endl; 80 | 81 | return 0; 82 | } 83 | ``` 84 | 85 | ``` 86 | [0,256,"method",{"x":1,"y":2,"z":3}] 87 | 1 88 | 0 89 | 256 90 | method 91 | 1 92 | 1 93 | 2 94 | 3 95 | ``` 96 | 97 | see [tests](tests/tests.cpp). 98 | 99 | # implemented types 100 | 101 | | c++ type | packer | parser | 102 | |-------------------------------|----------------------------|---------------------------------------------| 103 | | ``(void)`` | ``packer.pack_nil()`` | ``(parser.is_nil())`` | 104 | | ``bool`` | ``packer.pack_bool(b)`` | ``parser.get_bool()`` | 105 | | ``char`` | ``packer.pack_integer(n)`` | ``parser.get_number()`` | 106 | | ``short`` | ``packer.pack_integer(n)`` | ``parser.get_number()`` | 107 | | ``int`` | ``packer.pack_integer(n)`` | ``parser.get_number()`` | 108 | | ``long long`` | ``packer.pack_integer(n)`` | ``parser.get_number()`` | 109 | | ``unsigned char`` | ``packer.pack_integer(n)`` | ``parser.get_number()`` | 110 | | ``unsigned short`` | ``packer.pack_integer(n)`` | ``parser.get_number()`` | 111 | | ``unsigned int`` | ``packer.pack_integer(n)`` | ``parser.get_number()`` | 112 | | ``unsigned long long`` | ``packer.pack_integer(n)`` | ``parser.get_number()`` | 113 | | ``float`` | ``packer.pack_float(n)`` | ``parser.get_number()`` | 114 | | ``double`` | ``packer.pack_double(n)`` | ``parser.get_number()`` | 115 | | ``const char *`` | ``packer.pack_str(str)`` | | 116 | | ``std::string`` | ``packer.pack_str(str)`` | ``parser.get_str()`` | 117 | | ``std::vector`` | ``packer.pack_bin(bin)`` | ``parser.get_bin()`` | 118 | | ``std::tuple`` | ``packer << t`` | `` parser >> t`` | 119 | 120 | # usertype serializer & deserializer definition 121 | 122 | ## map type 123 | 124 | depends on element name. 125 | 126 | ```cpp 127 | struct Person 128 | { 129 | std::string name; 130 | int age; 131 | 132 | bool operator==(const Person &rhs)const 133 | { 134 | return name == rhs.name && age == rhs.age; 135 | } 136 | }; 137 | ``` 138 | 139 | json representation. 140 | 141 | ```json 142 | { 143 | "name": "hoge", 144 | "age": 100, 145 | } 146 | ``` 147 | 148 | ```cpp 149 | namespace msgpackpp 150 | { 151 | // Person p; 152 | // msgpackpp::packer packer; 153 | // packer << p; 154 | void serialize(packer &packer, const Person &p) 155 | { 156 | packer.pack_map(2) 157 | << "name" << p.name 158 | << "age" << p.age 159 | ; 160 | } 161 | 162 | // auto parser=msgpackpp::parser(msgpack_bytes); 163 | // Person p; 164 | // parser >> p; 165 | parser deserialize(const parser &u, Person &p) 166 | { 167 | auto uu = u[0]; 168 | auto count = u.count(); 169 | for (int i = 0; i> p.name; 176 | } 177 | else if (key == "age") { 178 | uu >> p.age; 179 | } 180 | else { 181 | // unknown key 182 | assert(false); 183 | } 184 | uu = uu.next(); 185 | } 186 | return uu; 187 | } 188 | } 189 | ``` 190 | 191 | use helper macro. 192 | 193 | ``` 194 | MPPP_MAP_SERIALIZER(Person, 2, name, age) 195 | ``` 196 | 197 | ## array type 198 | 199 | depends on element order. 200 | 201 | ```cpp 202 | struct Point 203 | { 204 | float x; 205 | float y; 206 | 207 | bool operator==(const Point &rhs)const 208 | { 209 | return x == rhs.x && y == rhs.y; 210 | } 211 | }; 212 | ``` 213 | 214 | json representation. 215 | 216 | ```json 217 | [1.0, 2.0] // [x, y] 218 | ``` 219 | 220 | ```cpp 221 | namespace msgpackpp 222 | { 223 | // Point p; 224 | // msgpackpp::packer packer; 225 | // packer << p; 226 | void serialize(packer &packer, const Point &p) 227 | { 228 | packer.pack_array(2) 229 | << p.x 230 | << p.y 231 | ; 232 | } 233 | 234 | // auto parser=msgpackpp::parser(msgpack_bytes); 235 | // Point p; 236 | // parser >> p; 237 | parser deserialize(const parser &u, Point &p) 238 | { 239 | assert(u.count() == 2); 240 | 241 | auto uu = u[0]; 242 | 243 | uu >> p.x; 244 | uu = uu.next(); 245 | 246 | uu >> p.y; 247 | uu = uu.next(); 248 | 249 | return uu; 250 | } 251 | } 252 | ``` 253 | 254 | use helper macro. 255 | ``` 256 | MPPP_ARRAY_SERIALIZER(Point, 2, x, y); 257 | ``` 258 | 259 | # procedure call 260 | 261 | for rpc implementation. 262 | 263 | ```cpp 264 | auto callback=[](int a, int b){ return a+b; } 265 | auto proc = msgpackpp::make_procedurecall(callback); 266 | msgpackpp::packer packer; 267 | packer << std::make_tuple(1, 2); 268 | auto result = proc(packer.get_payload()); 269 | 270 | R value; 271 | msgpackpp::parser(result) >> value; // value=3 272 | ``` 273 | 274 | - https://github.com/msgpack-rpc/msgpack-rpc/blob/master/spec.md 275 | 276 | ```cpp 277 | int id=1; 278 | auto p = msgpackpp::make_rpc_request(id, "method", 1, 2, 3); 279 | // [0, 1, "method", [1, 2, 3]] 280 | ``` 281 | -------------------------------------------------------------------------------- /_external/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | subdirs(asio catch) -------------------------------------------------------------------------------- /_external/asio/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(asio INTERFACE) 2 | target_include_directories(asio INTERFACE asio/asio/include) 3 | target_compile_definitions(asio INTERFACE _WIN32_WINNT=0x0601) 4 | -------------------------------------------------------------------------------- /_external/catch/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(catch INTERFACE) 2 | target_include_directories(catch INTERFACE ${CMAKE_CURRENT_LIST_DIR}) 3 | -------------------------------------------------------------------------------- /msgpackpp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(TARGET_NAME msgpackpp) 2 | add_library(${TARGET_NAME} INTERFACE) 3 | target_include_directories(${TARGET_NAME} 4 | INTERFACE ${CMAKE_CURRENT_LIST_DIR}/include) 5 | target_compile_options(${TARGET_NAME} INTERFACE /wd4267) 6 | -------------------------------------------------------------------------------- /msgpackpp/include/msgpackpp/msgpackpp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #pragma warning(push) 18 | #pragma warning(disable : 4244) 19 | #pragma warning(disable : 4996) 20 | #pragma warning(disable : 4018) 21 | 22 | #if _HAS_CXX17 23 | #include 24 | #else 25 | namespace std { 26 | class string_view { 27 | const char *m_p; 28 | size_t m_size; 29 | 30 | public: 31 | string_view() : m_p(0), m_size(0) {} 32 | 33 | string_view(const char *p, size_t size) : m_p(p), m_size(size) {} 34 | 35 | const char *begin() const { return m_p; } 36 | size_t size() const { return m_size; } 37 | const char *end() const { return m_p + m_size; } 38 | 39 | bool operator==(const string &rhs) const { 40 | return equal(begin(), end(), rhs.begin(), rhs.end()); 41 | } 42 | 43 | bool operator==(const string_view &rhs) const { 44 | return equal(begin(), end(), rhs.begin(), rhs.end()); 45 | } 46 | 47 | string str() const { return string(begin(), end()); } 48 | 49 | operator string() const { return str(); } 50 | }; 51 | 52 | inline ostream &operator<<(ostream &os, const string_view &view) { 53 | os << string(view.begin(), view.begin() + view.size()); 54 | return os; 55 | } 56 | 57 | inline bool operator==(const string &lhs, const string_view &rhs) { 58 | return equal(lhs.begin(), lhs.end(), begin(rhs), end(rhs)); 59 | } 60 | } // namespace std 61 | #endif 62 | 63 | namespace msgpackpp { 64 | 65 | struct pack_error : public std::runtime_error { 66 | pack_error(const char *msg) : runtime_error(msg) {} 67 | }; 68 | 69 | struct underflow_pack_error : public pack_error { 70 | underflow_pack_error() : pack_error("underflow") {} 71 | }; 72 | 73 | struct overflow_pack_error : public pack_error { 74 | overflow_pack_error() : pack_error("overflow") {} 75 | }; 76 | 77 | struct parse_error : public std::runtime_error { 78 | parse_error(const char *msg) : runtime_error(msg) {} 79 | }; 80 | 81 | struct empty_parse_error : public parse_error { 82 | empty_parse_error() : parse_error("empty") {} 83 | }; 84 | 85 | struct lack_parse_error : public parse_error { 86 | lack_parse_error() : parse_error("lack") {} 87 | }; 88 | 89 | struct invalid_parse_error : public parse_error { 90 | invalid_parse_error() : parse_error("invalid") {} 91 | }; 92 | 93 | struct not_implemented_parse_error : public parse_error { 94 | not_implemented_parse_error() : parse_error("not implemented") {} 95 | }; 96 | 97 | struct type_parse_error : public parse_error { 98 | type_parse_error() : parse_error("type") {} 99 | }; 100 | 101 | enum pack_type : std::uint8_t { 102 | #pragma region POSITIVE_FIXNUM 0x00 - 0x7F 103 | POSITIVE_FIXNUM = 0x00, 104 | POSITIVE_FIXNUM_0x01 = 0x01, 105 | POSITIVE_FIXNUM_0x02 = 0x02, 106 | POSITIVE_FIXNUM_0x03 = 0x03, 107 | POSITIVE_FIXNUM_0x04 = 0x04, 108 | POSITIVE_FIXNUM_0x05 = 0x05, 109 | POSITIVE_FIXNUM_0x06 = 0x06, 110 | POSITIVE_FIXNUM_0x07 = 0x07, 111 | POSITIVE_FIXNUM_0x08 = 0x08, 112 | POSITIVE_FIXNUM_0x09 = 0x09, 113 | POSITIVE_FIXNUM_0x0A = 0x0A, 114 | POSITIVE_FIXNUM_0x0B = 0x0B, 115 | POSITIVE_FIXNUM_0x0C = 0x0C, 116 | POSITIVE_FIXNUM_0x0D = 0x0D, 117 | POSITIVE_FIXNUM_0x0E = 0x0E, 118 | POSITIVE_FIXNUM_0x0F = 0x0F, 119 | 120 | POSITIVE_FIXNUM_0x10 = 0x10, 121 | POSITIVE_FIXNUM_0x11 = 0x11, 122 | POSITIVE_FIXNUM_0x12 = 0x12, 123 | POSITIVE_FIXNUM_0x13 = 0x13, 124 | POSITIVE_FIXNUM_0x14 = 0x14, 125 | POSITIVE_FIXNUM_0x15 = 0x15, 126 | POSITIVE_FIXNUM_0x16 = 0x16, 127 | POSITIVE_FIXNUM_0x17 = 0x17, 128 | POSITIVE_FIXNUM_0x18 = 0x18, 129 | POSITIVE_FIXNUM_0x19 = 0x19, 130 | POSITIVE_FIXNUM_0x1A = 0x1A, 131 | POSITIVE_FIXNUM_0x1B = 0x1B, 132 | POSITIVE_FIXNUM_0x1C = 0x1C, 133 | POSITIVE_FIXNUM_0x1D = 0x1D, 134 | POSITIVE_FIXNUM_0x1E = 0x1E, 135 | POSITIVE_FIXNUM_0x1F = 0x1F, 136 | 137 | POSITIVE_FIXNUM_0x20 = 0x20, 138 | POSITIVE_FIXNUM_0x21 = 0x21, 139 | POSITIVE_FIXNUM_0x22 = 0x22, 140 | POSITIVE_FIXNUM_0x23 = 0x23, 141 | POSITIVE_FIXNUM_0x24 = 0x24, 142 | POSITIVE_FIXNUM_0x25 = 0x25, 143 | POSITIVE_FIXNUM_0x26 = 0x26, 144 | POSITIVE_FIXNUM_0x27 = 0x27, 145 | POSITIVE_FIXNUM_0x28 = 0x28, 146 | POSITIVE_FIXNUM_0x29 = 0x29, 147 | POSITIVE_FIXNUM_0x2A = 0x2A, 148 | POSITIVE_FIXNUM_0x2B = 0x2B, 149 | POSITIVE_FIXNUM_0x2C = 0x2C, 150 | POSITIVE_FIXNUM_0x2D = 0x2D, 151 | POSITIVE_FIXNUM_0x2E = 0x2E, 152 | POSITIVE_FIXNUM_0x2F = 0x2F, 153 | 154 | POSITIVE_FIXNUM_0x30 = 0x30, 155 | POSITIVE_FIXNUM_0x31 = 0x31, 156 | POSITIVE_FIXNUM_0x32 = 0x32, 157 | POSITIVE_FIXNUM_0x33 = 0x33, 158 | POSITIVE_FIXNUM_0x34 = 0x34, 159 | POSITIVE_FIXNUM_0x35 = 0x35, 160 | POSITIVE_FIXNUM_0x36 = 0x36, 161 | POSITIVE_FIXNUM_0x37 = 0x37, 162 | POSITIVE_FIXNUM_0x38 = 0x38, 163 | POSITIVE_FIXNUM_0x39 = 0x39, 164 | POSITIVE_FIXNUM_0x3A = 0x3A, 165 | POSITIVE_FIXNUM_0x3B = 0x3B, 166 | POSITIVE_FIXNUM_0x3C = 0x3C, 167 | POSITIVE_FIXNUM_0x3D = 0x3D, 168 | POSITIVE_FIXNUM_0x3E = 0x3E, 169 | POSITIVE_FIXNUM_0x3F = 0x3F, 170 | 171 | POSITIVE_FIXNUM_0x40 = 0x40, 172 | POSITIVE_FIXNUM_0x41 = 0x41, 173 | POSITIVE_FIXNUM_0x42 = 0x42, 174 | POSITIVE_FIXNUM_0x43 = 0x43, 175 | POSITIVE_FIXNUM_0x44 = 0x44, 176 | POSITIVE_FIXNUM_0x45 = 0x45, 177 | POSITIVE_FIXNUM_0x46 = 0x46, 178 | POSITIVE_FIXNUM_0x47 = 0x47, 179 | POSITIVE_FIXNUM_0x48 = 0x48, 180 | POSITIVE_FIXNUM_0x49 = 0x49, 181 | POSITIVE_FIXNUM_0x4A = 0x4A, 182 | POSITIVE_FIXNUM_0x4B = 0x4B, 183 | POSITIVE_FIXNUM_0x4C = 0x4C, 184 | POSITIVE_FIXNUM_0x4D = 0x4D, 185 | POSITIVE_FIXNUM_0x4E = 0x4E, 186 | POSITIVE_FIXNUM_0x4F = 0x4F, 187 | 188 | POSITIVE_FIXNUM_0x50 = 0x50, 189 | POSITIVE_FIXNUM_0x51 = 0x51, 190 | POSITIVE_FIXNUM_0x52 = 0x52, 191 | POSITIVE_FIXNUM_0x53 = 0x53, 192 | POSITIVE_FIXNUM_0x54 = 0x54, 193 | POSITIVE_FIXNUM_0x55 = 0x55, 194 | POSITIVE_FIXNUM_0x56 = 0x56, 195 | POSITIVE_FIXNUM_0x57 = 0x57, 196 | POSITIVE_FIXNUM_0x58 = 0x58, 197 | POSITIVE_FIXNUM_0x59 = 0x59, 198 | POSITIVE_FIXNUM_0x5A = 0x5A, 199 | POSITIVE_FIXNUM_0x5B = 0x5B, 200 | POSITIVE_FIXNUM_0x5C = 0x5C, 201 | POSITIVE_FIXNUM_0x5D = 0x5D, 202 | POSITIVE_FIXNUM_0x5E = 0x5E, 203 | POSITIVE_FIXNUM_0x5F = 0x5F, 204 | 205 | POSITIVE_FIXNUM_0x60 = 0x60, 206 | POSITIVE_FIXNUM_0x61 = 0x61, 207 | POSITIVE_FIXNUM_0x62 = 0x62, 208 | POSITIVE_FIXNUM_0x63 = 0x63, 209 | POSITIVE_FIXNUM_0x64 = 0x64, 210 | POSITIVE_FIXNUM_0x65 = 0x65, 211 | POSITIVE_FIXNUM_0x66 = 0x66, 212 | POSITIVE_FIXNUM_0x67 = 0x67, 213 | POSITIVE_FIXNUM_0x68 = 0x68, 214 | POSITIVE_FIXNUM_0x69 = 0x69, 215 | POSITIVE_FIXNUM_0x6A = 0x6A, 216 | POSITIVE_FIXNUM_0x6B = 0x6B, 217 | POSITIVE_FIXNUM_0x6C = 0x6C, 218 | POSITIVE_FIXNUM_0x6D = 0x6D, 219 | POSITIVE_FIXNUM_0x6E = 0x6E, 220 | POSITIVE_FIXNUM_0x6F = 0x6F, 221 | 222 | POSITIVE_FIXNUM_0x70 = 0x70, 223 | POSITIVE_FIXNUM_0x71 = 0x71, 224 | POSITIVE_FIXNUM_0x72 = 0x72, 225 | POSITIVE_FIXNUM_0x73 = 0x73, 226 | POSITIVE_FIXNUM_0x74 = 0x74, 227 | POSITIVE_FIXNUM_0x75 = 0x75, 228 | POSITIVE_FIXNUM_0x76 = 0x76, 229 | POSITIVE_FIXNUM_0x77 = 0x77, 230 | POSITIVE_FIXNUM_0x78 = 0x78, 231 | POSITIVE_FIXNUM_0x79 = 0x79, 232 | POSITIVE_FIXNUM_0x7A = 0x7A, 233 | POSITIVE_FIXNUM_0x7B = 0x7B, 234 | POSITIVE_FIXNUM_0x7C = 0x7C, 235 | POSITIVE_FIXNUM_0x7D = 0x7D, 236 | POSITIVE_FIXNUM_0x7E = 0x7E, 237 | POSITIVE_FIXNUM_0x7F = 0x7F, 238 | #pragma endregion 239 | 240 | #pragma region FIX_MAP 0x80 - 0x8F 241 | FIX_MAP = 0x80, 242 | FIX_MAP_0x1 = 0x81, 243 | FIX_MAP_0x2 = 0x82, 244 | FIX_MAP_0x3 = 0x83, 245 | FIX_MAP_0x4 = 0x84, 246 | FIX_MAP_0x5 = 0x85, 247 | FIX_MAP_0x6 = 0x86, 248 | FIX_MAP_0x7 = 0x87, 249 | FIX_MAP_0x8 = 0x88, 250 | FIX_MAP_0x9 = 0x89, 251 | FIX_MAP_0xA = 0x8A, 252 | FIX_MAP_0xB = 0x8B, 253 | FIX_MAP_0xC = 0x8C, 254 | FIX_MAP_0xD = 0x8D, 255 | FIX_MAP_0xE = 0x8E, 256 | FIX_MAP_0xF = 0x8F, 257 | #pragma endregion 258 | 259 | #pragma region FIX_ARRAY 0x90 - 0x9F 260 | FIX_ARRAY = 0x90, 261 | FIX_ARRAY_0x1 = 0x91, 262 | FIX_ARRAY_0x2 = 0x92, 263 | FIX_ARRAY_0x3 = 0x93, 264 | FIX_ARRAY_0x4 = 0x94, 265 | FIX_ARRAY_0x5 = 0x95, 266 | FIX_ARRAY_0x6 = 0x96, 267 | FIX_ARRAY_0x7 = 0x97, 268 | FIX_ARRAY_0x8 = 0x98, 269 | FIX_ARRAY_0x9 = 0x99, 270 | FIX_ARRAY_0xA = 0x9A, 271 | FIX_ARRAY_0xB = 0x9B, 272 | FIX_ARRAY_0xC = 0x9C, 273 | FIX_ARRAY_0xD = 0x9D, 274 | FIX_ARRAY_0xE = 0x9E, 275 | FIX_ARRAY_0xF = 0x9F, 276 | #pragma endregion 277 | 278 | #pragma region FIX_STR 0xA0 - 0xBF 279 | FIX_STR = 0xA0, 280 | FIX_STR_0x01 = 0xA1, 281 | FIX_STR_0x02 = 0xA2, 282 | FIX_STR_0x03 = 0xA3, 283 | FIX_STR_0x04 = 0xA4, 284 | FIX_STR_0x05 = 0xA5, 285 | FIX_STR_0x06 = 0xA6, 286 | FIX_STR_0x07 = 0xA7, 287 | FIX_STR_0x08 = 0xA8, 288 | FIX_STR_0x09 = 0xA9, 289 | FIX_STR_0x0A = 0xAA, 290 | FIX_STR_0x0B = 0xAB, 291 | FIX_STR_0x0C = 0xAC, 292 | FIX_STR_0x0D = 0xAD, 293 | FIX_STR_0x0E = 0xAE, 294 | FIX_STR_0x0F = 0xAF, 295 | FIX_STR_0x10 = 0xB0, 296 | FIX_STR_0x11 = 0xB1, 297 | FIX_STR_0x12 = 0xB2, 298 | FIX_STR_0x13 = 0xB3, 299 | FIX_STR_0x14 = 0xB4, 300 | FIX_STR_0x15 = 0xB5, 301 | FIX_STR_0x16 = 0xB6, 302 | FIX_STR_0x17 = 0xB7, 303 | FIX_STR_0x18 = 0xB8, 304 | FIX_STR_0x19 = 0xB9, 305 | FIX_STR_0x1A = 0xBA, 306 | FIX_STR_0x1B = 0xBB, 307 | FIX_STR_0x1C = 0xBC, 308 | FIX_STR_0x1D = 0xBD, 309 | FIX_STR_0x1E = 0xBE, 310 | FIX_STR_0x1F = 0xBF, 311 | #pragma endregion 312 | 313 | NIL = 0xC0, 314 | NEVER_USED = 0xC1, 315 | False = 0xC2, // avoid match windows False 316 | True = 0xC3, // avoid match windows True 317 | 318 | BIN8 = 0xC4, 319 | BIN16 = 0xC5, 320 | BIN32 = 0xC6, 321 | 322 | EXT8 = 0xC7, 323 | EXT16 = 0xC8, 324 | EXT32 = 0xC9, 325 | 326 | FLOAT = 0xCA, 327 | DOUBLE = 0xCB, 328 | UINT8 = 0xCC, 329 | UINT16 = 0xCD, 330 | UINT32 = 0xCE, 331 | UINT64 = 0xCF, 332 | INT8 = 0xD0, 333 | INT16 = 0xD1, 334 | INT32 = 0xD2, 335 | INT64 = 0xD3, 336 | 337 | FIX_EXT_1 = 0xD4, 338 | FIX_EXT_2 = 0xD5, 339 | FIX_EXT_4 = 0xD6, 340 | FIX_EXT_8 = 0xD7, 341 | FIX_EXT_16 = 0xD8, 342 | 343 | STR8 = 0xD9, 344 | STR16 = 0xDA, 345 | STR32 = 0xDB, 346 | 347 | ARRAY16 = 0xDC, 348 | ARRAY32 = 0xDD, 349 | MAP16 = 0xDE, 350 | MAP32 = 0xDF, 351 | 352 | #pragma region NEGATIVE_FIXNUM 0xE0 - 0xFF 353 | NEGATIVE_FIXNUM = 0xE0, // 1110 0000 = -32 354 | NEGATIVE_FIXNUM_0x1F = 0xE1, // -31 355 | NEGATIVE_FIXNUM_0x1E = 0xE2, 356 | NEGATIVE_FIXNUM_0x1D = 0xE3, 357 | NEGATIVE_FIXNUM_0x1C = 0xE4, 358 | NEGATIVE_FIXNUM_0x1B = 0xE5, 359 | NEGATIVE_FIXNUM_0x1A = 0xE6, 360 | NEGATIVE_FIXNUM_0x19 = 0xE7, 361 | NEGATIVE_FIXNUM_0x18 = 0xE8, 362 | NEGATIVE_FIXNUM_0x17 = 0xE9, 363 | NEGATIVE_FIXNUM_0x16 = 0xEA, 364 | NEGATIVE_FIXNUM_0x15 = 0xEB, 365 | NEGATIVE_FIXNUM_0x14 = 0xEC, 366 | NEGATIVE_FIXNUM_0x13 = 0xED, 367 | NEGATIVE_FIXNUM_0x12 = 0xEE, 368 | NEGATIVE_FIXNUM_0x11 = 0xEF, 369 | NEGATIVE_FIXNUM_0x10 = 0xF0, 370 | NEGATIVE_FIXNUM_0x0F = 0xF1, 371 | NEGATIVE_FIXNUM_0x0E = 0xF2, 372 | NEGATIVE_FIXNUM_0x0D = 0xF3, 373 | NEGATIVE_FIXNUM_0x0C = 0xF4, 374 | NEGATIVE_FIXNUM_0x0B = 0xF5, 375 | NEGATIVE_FIXNUM_0x0A = 0xF6, 376 | NEGATIVE_FIXNUM_0x09 = 0xF7, 377 | NEGATIVE_FIXNUM_0x08 = 0xF8, 378 | NEGATIVE_FIXNUM_0x07 = 0xF9, 379 | NEGATIVE_FIXNUM_0x06 = 0xFA, 380 | NEGATIVE_FIXNUM_0x05 = 0xFB, 381 | NEGATIVE_FIXNUM_0x04 = 0xFC, 382 | NEGATIVE_FIXNUM_0x03 = 0xFD, 383 | NEGATIVE_FIXNUM_0x02 = 0xFE, 384 | NEGATIVE_FIXNUM_0x01 = 0xFF, // -1 385 | #pragma endregion 386 | }; 387 | 388 | enum class parse_status { 389 | ok, 390 | empty, 391 | lack, 392 | invalid, 393 | type, 394 | }; 395 | 396 | template struct status_scope { 397 | template struct result { 398 | Status status; 399 | T value; 400 | operator T() const { return value; } 401 | bool is_ok() const { return status == OK_VALUE; } 402 | template result cast() const { 403 | return {status, static_cast(value)}; 404 | } 405 | }; 406 | 407 | template static result OK(const T &value) { 408 | return {OK_VALUE, value}; 409 | } 410 | }; 411 | using parse_scope = status_scope; 412 | template using parse_result = parse_scope::result; 413 | 414 | template parse_result OK(const T &value) { 415 | return parse_scope::OK(value); 416 | } 417 | 418 | inline parse_result no_size_parse_error(const uint8_t *, int) { 419 | return {parse_status::invalid}; 420 | } 421 | 422 | template 423 | inline parse_result return_n(const uint8_t *, int) { 424 | return OK(n); 425 | } 426 | 427 | template 428 | parse_result body_number(const uint8_t *m_p, int m_size) { 429 | switch (sizeof(T)) { 430 | case 1: 431 | if (m_size < 1 + sizeof(T)) { 432 | return {parse_status::lack}; 433 | } 434 | return OK(static_cast(m_p[1])); 435 | case 2: 436 | if (m_size < 1 + sizeof(T)) { 437 | return {parse_status::lack}; 438 | } 439 | return OK(static_cast((m_p[1] << 8) | m_p[2])); 440 | case 4: { 441 | if (m_size < 1 + sizeof(T)) { 442 | return {parse_status::lack}; 443 | } 444 | std::uint8_t buf[] = {m_p[4], m_p[3], m_p[2], m_p[1]}; 445 | return OK(*reinterpret_cast(buf)); 446 | } 447 | case 8: { 448 | if (m_size < 1 + sizeof(T)) { 449 | return {parse_status::lack}; 450 | } 451 | std::uint8_t buf[] = {m_p[8], m_p[7], m_p[6], m_p[5], 452 | m_p[4], m_p[3], m_p[2], m_p[1]}; 453 | return OK(*reinterpret_cast(buf)); 454 | } 455 | } 456 | 457 | return {parse_status::invalid}; 458 | } 459 | 460 | struct body_index_and_size { 461 | int index; 462 | 463 | parse_result (*size)(const uint8_t *p, int size); 464 | 465 | static constexpr parse_result from_type(pack_type t) { 466 | switch (t) { 467 | #pragma region POSITIVE_FIXNUM 0x00 - 0x7F 468 | case POSITIVE_FIXNUM: 469 | case POSITIVE_FIXNUM_0x01: 470 | case POSITIVE_FIXNUM_0x02: 471 | case POSITIVE_FIXNUM_0x03: 472 | case POSITIVE_FIXNUM_0x04: 473 | case POSITIVE_FIXNUM_0x05: 474 | case POSITIVE_FIXNUM_0x06: 475 | case POSITIVE_FIXNUM_0x07: 476 | case POSITIVE_FIXNUM_0x08: 477 | case POSITIVE_FIXNUM_0x09: 478 | case POSITIVE_FIXNUM_0x0A: 479 | case POSITIVE_FIXNUM_0x0B: 480 | case POSITIVE_FIXNUM_0x0C: 481 | case POSITIVE_FIXNUM_0x0D: 482 | case POSITIVE_FIXNUM_0x0E: 483 | case POSITIVE_FIXNUM_0x0F: 484 | 485 | case POSITIVE_FIXNUM_0x10: 486 | case POSITIVE_FIXNUM_0x11: 487 | case POSITIVE_FIXNUM_0x12: 488 | case POSITIVE_FIXNUM_0x13: 489 | case POSITIVE_FIXNUM_0x14: 490 | case POSITIVE_FIXNUM_0x15: 491 | case POSITIVE_FIXNUM_0x16: 492 | case POSITIVE_FIXNUM_0x17: 493 | case POSITIVE_FIXNUM_0x18: 494 | case POSITIVE_FIXNUM_0x19: 495 | case POSITIVE_FIXNUM_0x1A: 496 | case POSITIVE_FIXNUM_0x1B: 497 | case POSITIVE_FIXNUM_0x1C: 498 | case POSITIVE_FIXNUM_0x1D: 499 | case POSITIVE_FIXNUM_0x1E: 500 | case POSITIVE_FIXNUM_0x1F: 501 | 502 | case POSITIVE_FIXNUM_0x20: 503 | case POSITIVE_FIXNUM_0x21: 504 | case POSITIVE_FIXNUM_0x22: 505 | case POSITIVE_FIXNUM_0x23: 506 | case POSITIVE_FIXNUM_0x24: 507 | case POSITIVE_FIXNUM_0x25: 508 | case POSITIVE_FIXNUM_0x26: 509 | case POSITIVE_FIXNUM_0x27: 510 | case POSITIVE_FIXNUM_0x28: 511 | case POSITIVE_FIXNUM_0x29: 512 | case POSITIVE_FIXNUM_0x2A: 513 | case POSITIVE_FIXNUM_0x2B: 514 | case POSITIVE_FIXNUM_0x2C: 515 | case POSITIVE_FIXNUM_0x2D: 516 | case POSITIVE_FIXNUM_0x2E: 517 | case POSITIVE_FIXNUM_0x2F: 518 | 519 | case POSITIVE_FIXNUM_0x30: 520 | case POSITIVE_FIXNUM_0x31: 521 | case POSITIVE_FIXNUM_0x32: 522 | case POSITIVE_FIXNUM_0x33: 523 | case POSITIVE_FIXNUM_0x34: 524 | case POSITIVE_FIXNUM_0x35: 525 | case POSITIVE_FIXNUM_0x36: 526 | case POSITIVE_FIXNUM_0x37: 527 | case POSITIVE_FIXNUM_0x38: 528 | case POSITIVE_FIXNUM_0x39: 529 | case POSITIVE_FIXNUM_0x3A: 530 | case POSITIVE_FIXNUM_0x3B: 531 | case POSITIVE_FIXNUM_0x3C: 532 | case POSITIVE_FIXNUM_0x3D: 533 | case POSITIVE_FIXNUM_0x3E: 534 | case POSITIVE_FIXNUM_0x3F: 535 | 536 | case POSITIVE_FIXNUM_0x40: 537 | case POSITIVE_FIXNUM_0x41: 538 | case POSITIVE_FIXNUM_0x42: 539 | case POSITIVE_FIXNUM_0x43: 540 | case POSITIVE_FIXNUM_0x44: 541 | case POSITIVE_FIXNUM_0x45: 542 | case POSITIVE_FIXNUM_0x46: 543 | case POSITIVE_FIXNUM_0x47: 544 | case POSITIVE_FIXNUM_0x48: 545 | case POSITIVE_FIXNUM_0x49: 546 | case POSITIVE_FIXNUM_0x4A: 547 | case POSITIVE_FIXNUM_0x4B: 548 | case POSITIVE_FIXNUM_0x4C: 549 | case POSITIVE_FIXNUM_0x4D: 550 | case POSITIVE_FIXNUM_0x4E: 551 | case POSITIVE_FIXNUM_0x4F: 552 | 553 | case POSITIVE_FIXNUM_0x50: 554 | case POSITIVE_FIXNUM_0x51: 555 | case POSITIVE_FIXNUM_0x52: 556 | case POSITIVE_FIXNUM_0x53: 557 | case POSITIVE_FIXNUM_0x54: 558 | case POSITIVE_FIXNUM_0x55: 559 | case POSITIVE_FIXNUM_0x56: 560 | case POSITIVE_FIXNUM_0x57: 561 | case POSITIVE_FIXNUM_0x58: 562 | case POSITIVE_FIXNUM_0x59: 563 | case POSITIVE_FIXNUM_0x5A: 564 | case POSITIVE_FIXNUM_0x5B: 565 | case POSITIVE_FIXNUM_0x5C: 566 | case POSITIVE_FIXNUM_0x5D: 567 | case POSITIVE_FIXNUM_0x5E: 568 | case POSITIVE_FIXNUM_0x5F: 569 | 570 | case POSITIVE_FIXNUM_0x60: 571 | case POSITIVE_FIXNUM_0x61: 572 | case POSITIVE_FIXNUM_0x62: 573 | case POSITIVE_FIXNUM_0x63: 574 | case POSITIVE_FIXNUM_0x64: 575 | case POSITIVE_FIXNUM_0x65: 576 | case POSITIVE_FIXNUM_0x66: 577 | case POSITIVE_FIXNUM_0x67: 578 | case POSITIVE_FIXNUM_0x68: 579 | case POSITIVE_FIXNUM_0x69: 580 | case POSITIVE_FIXNUM_0x6A: 581 | case POSITIVE_FIXNUM_0x6B: 582 | case POSITIVE_FIXNUM_0x6C: 583 | case POSITIVE_FIXNUM_0x6D: 584 | case POSITIVE_FIXNUM_0x6E: 585 | case POSITIVE_FIXNUM_0x6F: 586 | 587 | case POSITIVE_FIXNUM_0x70: 588 | case POSITIVE_FIXNUM_0x71: 589 | case POSITIVE_FIXNUM_0x72: 590 | case POSITIVE_FIXNUM_0x73: 591 | case POSITIVE_FIXNUM_0x74: 592 | case POSITIVE_FIXNUM_0x75: 593 | case POSITIVE_FIXNUM_0x76: 594 | case POSITIVE_FIXNUM_0x77: 595 | case POSITIVE_FIXNUM_0x78: 596 | case POSITIVE_FIXNUM_0x79: 597 | case POSITIVE_FIXNUM_0x7A: 598 | case POSITIVE_FIXNUM_0x7B: 599 | case POSITIVE_FIXNUM_0x7C: 600 | case POSITIVE_FIXNUM_0x7D: 601 | case POSITIVE_FIXNUM_0x7E: 602 | case POSITIVE_FIXNUM_0x7F: 603 | return OK(body_index_and_size{1, return_n<0>}); 604 | #pragma endregion 605 | 606 | #pragma region FIX_MAP 0x80 - 0x8F 607 | case FIX_MAP: 608 | case FIX_MAP_0x1: 609 | case FIX_MAP_0x2: 610 | case FIX_MAP_0x3: 611 | case FIX_MAP_0x4: 612 | case FIX_MAP_0x5: 613 | case FIX_MAP_0x6: 614 | case FIX_MAP_0x7: 615 | case FIX_MAP_0x8: 616 | case FIX_MAP_0x9: 617 | case FIX_MAP_0xA: 618 | case FIX_MAP_0xB: 619 | case FIX_MAP_0xC: 620 | case FIX_MAP_0xD: 621 | case FIX_MAP_0xE: 622 | case FIX_MAP_0xF: 623 | return OK(body_index_and_size{1, no_size_parse_error}); 624 | #pragma endregion 625 | 626 | #pragma region FIX_ARRAY 0x90 - 0x9F 627 | case FIX_ARRAY: 628 | case FIX_ARRAY_0x1: 629 | case FIX_ARRAY_0x2: 630 | case FIX_ARRAY_0x3: 631 | case FIX_ARRAY_0x4: 632 | case FIX_ARRAY_0x5: 633 | case FIX_ARRAY_0x6: 634 | case FIX_ARRAY_0x7: 635 | case FIX_ARRAY_0x8: 636 | case FIX_ARRAY_0x9: 637 | case FIX_ARRAY_0xA: 638 | case FIX_ARRAY_0xB: 639 | case FIX_ARRAY_0xC: 640 | case FIX_ARRAY_0xD: 641 | case FIX_ARRAY_0xE: 642 | case FIX_ARRAY_0xF: 643 | return OK(body_index_and_size{1, no_size_parse_error}); 644 | #pragma endregion 645 | 646 | #pragma region FIX_STR 0xA0 - 0xBF 647 | case FIX_STR: 648 | return OK(body_index_and_size{1, return_n<0>}); 649 | case FIX_STR_0x01: 650 | return OK(body_index_and_size{1, return_n<1>}); 651 | case FIX_STR_0x02: 652 | return OK(body_index_and_size{1, return_n<2>}); 653 | case FIX_STR_0x03: 654 | return OK(body_index_and_size{1, return_n<3>}); 655 | case FIX_STR_0x04: 656 | return OK(body_index_and_size{1, return_n<4>}); 657 | case FIX_STR_0x05: 658 | return OK(body_index_and_size{1, return_n<5>}); 659 | case FIX_STR_0x06: 660 | return OK(body_index_and_size{1, return_n<6>}); 661 | case FIX_STR_0x07: 662 | return OK(body_index_and_size{1, return_n<7>}); 663 | case FIX_STR_0x08: 664 | return OK(body_index_and_size{1, return_n<8>}); 665 | case FIX_STR_0x09: 666 | return OK(body_index_and_size{1, return_n<9>}); 667 | case FIX_STR_0x0A: 668 | return OK(body_index_and_size{1, return_n<10>}); 669 | case FIX_STR_0x0B: 670 | return OK(body_index_and_size{1, return_n<11>}); 671 | case FIX_STR_0x0C: 672 | return OK(body_index_and_size{1, return_n<12>}); 673 | case FIX_STR_0x0D: 674 | return OK(body_index_and_size{1, return_n<13>}); 675 | case FIX_STR_0x0E: 676 | return OK(body_index_and_size{1, return_n<14>}); 677 | case FIX_STR_0x0F: 678 | return OK(body_index_and_size{1, return_n<15>}); 679 | case FIX_STR_0x10: 680 | return OK(body_index_and_size{1, return_n<16>}); 681 | case FIX_STR_0x11: 682 | return OK(body_index_and_size{1, return_n<17>}); 683 | case FIX_STR_0x12: 684 | return OK(body_index_and_size{1, return_n<18>}); 685 | case FIX_STR_0x13: 686 | return OK(body_index_and_size{1, return_n<19>}); 687 | case FIX_STR_0x14: 688 | return OK(body_index_and_size{1, return_n<20>}); 689 | case FIX_STR_0x15: 690 | return OK(body_index_and_size{1, return_n<21>}); 691 | case FIX_STR_0x16: 692 | return OK(body_index_and_size{1, return_n<22>}); 693 | case FIX_STR_0x17: 694 | return OK(body_index_and_size{1, return_n<23>}); 695 | case FIX_STR_0x18: 696 | return OK(body_index_and_size{1, return_n<24>}); 697 | case FIX_STR_0x19: 698 | return OK(body_index_and_size{1, return_n<25>}); 699 | case FIX_STR_0x1A: 700 | return OK(body_index_and_size{1, return_n<26>}); 701 | case FIX_STR_0x1B: 702 | return OK(body_index_and_size{1, return_n<27>}); 703 | case FIX_STR_0x1C: 704 | return OK(body_index_and_size{1, return_n<28>}); 705 | case FIX_STR_0x1D: 706 | return OK(body_index_and_size{1, return_n<29>}); 707 | case FIX_STR_0x1E: 708 | return OK(body_index_and_size{1, return_n<30>}); 709 | case FIX_STR_0x1F: 710 | return OK(body_index_and_size{1, return_n<31>}); 711 | #pragma endregion 712 | 713 | case NIL: 714 | return OK(body_index_and_size{1, return_n<0>}); 715 | case NEVER_USED: 716 | return {parse_status::invalid}; 717 | case False: 718 | return OK(body_index_and_size{1, return_n<0>}); 719 | case True: 720 | return OK(body_index_and_size{1, return_n<0>}); 721 | 722 | case BIN8: 723 | return OK(body_index_and_size{ 724 | 1 + 1, [](auto p, int size) { 725 | return body_number(p, size).cast(); 726 | }}); 727 | case BIN16: 728 | return OK(body_index_and_size{ 729 | 1 + 2, [](auto p, int size) { 730 | return body_number(p, size).cast(); 731 | }}); 732 | case BIN32: 733 | return OK(body_index_and_size{1 + 4, [](auto p, int size) { 734 | return body_number(p, size); 735 | }}); 736 | 737 | case EXT8: 738 | return OK(body_index_and_size{ 739 | 1 + 1 + 1, [](auto p, int size) { 740 | return body_number(p, size).cast(); 741 | }}); 742 | case EXT16: 743 | return OK(body_index_and_size{ 744 | 1 + 2 + 1, [](auto p, int size) { 745 | return body_number(p, size).cast(); 746 | }}); 747 | case EXT32: 748 | return OK(body_index_and_size{1 + 4 + 1, [](auto p, int size) { 749 | return body_number(p, size); 750 | }}); 751 | 752 | case FLOAT: 753 | return OK(body_index_and_size{1, return_n<4>}); 754 | case DOUBLE: 755 | return OK(body_index_and_size{1, return_n<8>}); 756 | case UINT8: 757 | return OK(body_index_and_size{1, return_n<1>}); 758 | case UINT16: 759 | return OK(body_index_and_size{1, return_n<2>}); 760 | case UINT32: 761 | return OK(body_index_and_size{1, return_n<4>}); 762 | case UINT64: 763 | return OK(body_index_and_size{1, return_n<8>}); 764 | case INT8: 765 | return OK(body_index_and_size{1, return_n<1>}); 766 | case INT16: 767 | return OK(body_index_and_size{1, return_n<2>}); 768 | case INT32: 769 | return OK(body_index_and_size{1, return_n<4>}); 770 | case INT64: 771 | return OK(body_index_and_size{1, return_n<8>}); 772 | 773 | case FIX_EXT_1: 774 | return OK(body_index_and_size{1 + 1, return_n<1>}); 775 | case FIX_EXT_2: 776 | return OK(body_index_and_size{1 + 1, return_n<2>}); 777 | case FIX_EXT_4: 778 | return OK(body_index_and_size{1 + 1, return_n<4>}); 779 | case FIX_EXT_8: 780 | return OK(body_index_and_size{1 + 1, return_n<8>}); 781 | case FIX_EXT_16: 782 | return OK(body_index_and_size{1 + 1, return_n<16>}); 783 | 784 | case STR8: 785 | return OK(body_index_and_size{ 786 | 1 + 1, [](auto p, int size) { 787 | return body_number(p, size).cast(); 788 | }}); 789 | case STR16: 790 | return OK(body_index_and_size{ 791 | 1 + 2, [](auto p, int size) { 792 | return body_number(p, size).cast(); 793 | }}); 794 | case STR32: 795 | return OK(body_index_and_size{1 + 4, [](auto p, int size) { 796 | return body_number(p, size); 797 | }}); 798 | 799 | case ARRAY16: 800 | return OK(body_index_and_size{1 + 2, no_size_parse_error}); 801 | case ARRAY32: 802 | return OK(body_index_and_size{1 + 4, no_size_parse_error}); 803 | case MAP16: 804 | return OK(body_index_and_size{1 + 2, no_size_parse_error}); 805 | case MAP32: 806 | return OK(body_index_and_size{1 + 4, no_size_parse_error}); 807 | 808 | #pragma region NEGATIVE_FIXNUM 0xE0 - 0xFF 809 | case NEGATIVE_FIXNUM: 810 | case NEGATIVE_FIXNUM_0x1F: 811 | case NEGATIVE_FIXNUM_0x1E: 812 | case NEGATIVE_FIXNUM_0x1D: 813 | case NEGATIVE_FIXNUM_0x1C: 814 | case NEGATIVE_FIXNUM_0x1B: 815 | case NEGATIVE_FIXNUM_0x1A: 816 | case NEGATIVE_FIXNUM_0x19: 817 | case NEGATIVE_FIXNUM_0x18: 818 | case NEGATIVE_FIXNUM_0x17: 819 | case NEGATIVE_FIXNUM_0x16: 820 | case NEGATIVE_FIXNUM_0x15: 821 | case NEGATIVE_FIXNUM_0x14: 822 | case NEGATIVE_FIXNUM_0x13: 823 | case NEGATIVE_FIXNUM_0x12: 824 | case NEGATIVE_FIXNUM_0x11: 825 | case NEGATIVE_FIXNUM_0x10: 826 | case NEGATIVE_FIXNUM_0x0F: 827 | case NEGATIVE_FIXNUM_0x0E: 828 | case NEGATIVE_FIXNUM_0x0D: 829 | case NEGATIVE_FIXNUM_0x0C: 830 | case NEGATIVE_FIXNUM_0x0B: 831 | case NEGATIVE_FIXNUM_0x0A: 832 | case NEGATIVE_FIXNUM_0x09: 833 | case NEGATIVE_FIXNUM_0x08: 834 | case NEGATIVE_FIXNUM_0x07: 835 | case NEGATIVE_FIXNUM_0x06: 836 | case NEGATIVE_FIXNUM_0x05: 837 | case NEGATIVE_FIXNUM_0x04: 838 | case NEGATIVE_FIXNUM_0x03: 839 | case NEGATIVE_FIXNUM_0x02: 840 | case NEGATIVE_FIXNUM_0x01: 841 | return OK(body_index_and_size{1, return_n<0>}); 842 | #pragma endregion 843 | 844 | default: 845 | return {parse_status::invalid}; 846 | } 847 | } 848 | }; 849 | 850 | class packer { 851 | typedef std::vector buffer; 852 | std::shared_ptr m_buffer; 853 | 854 | private: 855 | template void push_number_reverse(T n) { 856 | auto size = sizeof(T); 857 | auto _p = reinterpret_cast(&n) + (size - 1); 858 | for (size_t i = 0; i < size; ++i, --_p) { 859 | m_buffer->push_back(*_p); 860 | } 861 | } 862 | 863 | public: 864 | packer() : m_buffer(new buffer) {} 865 | 866 | packer(const std::shared_ptr &buffer) : m_buffer(buffer) {} 867 | 868 | packer(const packer &) = delete; 869 | packer &operator=(const packer &) = delete; 870 | 871 | template void push(const Range &r) { 872 | m_buffer->insert(m_buffer->end(), std::begin(r), std::end(r)); 873 | } 874 | 875 | packer &pack_nil() { 876 | m_buffer->push_back(pack_type::NIL); 877 | return *this; 878 | } 879 | 880 | template packer &pack_integer(T n) { 881 | if (n < 0) { 882 | if (n >= -32) { 883 | m_buffer->push_back(pack_type::NEGATIVE_FIXNUM | 884 | static_cast((n + 32))); 885 | } else if (n >= std::numeric_limits::min()) { 886 | m_buffer->push_back(pack_type::INT8); 887 | m_buffer->push_back(n); 888 | } else if (n >= std::numeric_limits::min()) { 889 | m_buffer->push_back(pack_type::INT16); 890 | // network byteorder 891 | push_number_reverse(static_cast(n)); 892 | } else if (n >= std::numeric_limits::min()) { 893 | m_buffer->push_back(pack_type::INT32); 894 | // network byteorder 895 | push_number_reverse(static_cast(n)); 896 | } else if (n >= std::numeric_limits::min()) { 897 | m_buffer->push_back(pack_type::INT64); 898 | // network byteorder 899 | push_number_reverse(static_cast(n)); 900 | } else { 901 | throw underflow_pack_error(); 902 | } 903 | } else { 904 | if (n <= 0x7F) { 905 | m_buffer->push_back(static_cast(n)); 906 | } else if (n <= std::numeric_limits::max()) { 907 | m_buffer->push_back(pack_type::UINT8); 908 | m_buffer->push_back(static_cast(n)); 909 | } else if (n <= std::numeric_limits::max()) { 910 | m_buffer->push_back(pack_type::UINT16); 911 | // network byteorder 912 | push_number_reverse(static_cast(n)); 913 | } else if (n <= std::numeric_limits::max()) { 914 | m_buffer->push_back(pack_type::UINT32); 915 | // network byteorder 916 | push_number_reverse(static_cast(n)); 917 | } else if (n <= std::numeric_limits::max()) { 918 | m_buffer->push_back(pack_type::UINT64); 919 | // network byteorder 920 | push_number_reverse(static_cast(n)); 921 | } else { 922 | throw overflow_pack_error(); 923 | } 924 | } 925 | return *this; 926 | } 927 | 928 | packer &pack_float(float n) { 929 | m_buffer->push_back(pack_type::FLOAT); 930 | push_number_reverse(n); 931 | return *this; 932 | } 933 | 934 | packer &pack_double(double n) { 935 | m_buffer->push_back(pack_type::DOUBLE); 936 | push_number_reverse(n); 937 | return *this; 938 | } 939 | 940 | packer &pack_bool(bool isTrue) { 941 | if (isTrue) { 942 | m_buffer->push_back(pack_type::True); 943 | } else { 944 | m_buffer->push_back(pack_type::False); 945 | } 946 | return *this; 947 | } 948 | 949 | packer &pack_str(const char *str) { return pack_str(std::string(str)); } 950 | 951 | template packer &pack_str(const Range &r) { 952 | auto size = static_cast(std::distance(std::begin(r), std::end(r))); 953 | if (size < 32) { 954 | m_buffer->push_back(pack_type::FIX_STR | static_cast(size)); 955 | push(r); 956 | } else if (size <= std::numeric_limits::max()) { 957 | m_buffer->push_back(pack_type::STR8); 958 | m_buffer->push_back(static_cast(size)); 959 | push(r); 960 | } else if (size <= std::numeric_limits::max()) { 961 | m_buffer->push_back(pack_type::STR16); 962 | push_number_reverse(static_cast(size)); 963 | push(r); 964 | } else if (size <= std::numeric_limits::max()) { 965 | m_buffer->push_back(pack_type::STR32); 966 | push_number_reverse(static_cast(size)); 967 | push(r); 968 | } else { 969 | throw overflow_pack_error(); 970 | } 971 | return *this; 972 | } 973 | 974 | template packer &pack_bin(const Range &r) { 975 | auto size = static_cast(std::distance(std::begin(r), std::end(r))); 976 | if (size <= std::numeric_limits::max()) { 977 | m_buffer->push_back(pack_type::BIN8); 978 | m_buffer->push_back(static_cast(size)); 979 | push(r); 980 | } else if (size <= std::numeric_limits::max()) { 981 | m_buffer->push_back(pack_type::BIN16); 982 | push_number_reverse(static_cast(size)); 983 | push(r); 984 | } else if (size <= std::numeric_limits::max()) { 985 | m_buffer->push_back(pack_type::BIN32); 986 | push_number_reverse(static_cast(size)); 987 | push(r); 988 | } else { 989 | throw overflow_pack_error(); 990 | } 991 | return *this; 992 | } 993 | 994 | packer &pack_array(size_t n) { 995 | if (n <= 15) { 996 | m_buffer->push_back(pack_type::FIX_ARRAY | static_cast(n)); 997 | } else if (n <= std::numeric_limits::max()) { 998 | m_buffer->push_back(pack_type::ARRAY16); 999 | push_number_reverse(static_cast(n)); 1000 | } else if (n <= std::numeric_limits::max()) { 1001 | m_buffer->push_back(pack_type::ARRAY32); 1002 | push_number_reverse(static_cast(n)); 1003 | } else { 1004 | throw overflow_pack_error(); 1005 | } 1006 | return *this; 1007 | } 1008 | 1009 | packer &pack_map(size_t n) { 1010 | if (n <= 15) { 1011 | m_buffer->push_back(pack_type::FIX_MAP | static_cast(n)); 1012 | } else if (n <= std::numeric_limits::max()) { 1013 | m_buffer->push_back(pack_type::MAP16); 1014 | push_number_reverse(static_cast(n)); 1015 | } else if (n <= std::numeric_limits::max()) { 1016 | m_buffer->push_back(pack_type::MAP32); 1017 | push_number_reverse(static_cast(n)); 1018 | } else { 1019 | throw overflow_pack_error(); 1020 | } 1021 | return *this; 1022 | } 1023 | 1024 | template packer &pack_ext(char type, const Range &r) { 1025 | auto size = static_cast(std::distance(std::begin(r), std::end(r))); 1026 | 1027 | // FIXEXT 1028 | switch (size) { 1029 | case 1: 1030 | m_buffer->push_back(pack_type::FIX_EXT_1); 1031 | m_buffer->push_back(type); 1032 | push(r); 1033 | break; 1034 | 1035 | case 2: 1036 | m_buffer->push_back(pack_type::FIX_EXT_2); 1037 | m_buffer->push_back(type); 1038 | push(r); 1039 | break; 1040 | 1041 | case 4: 1042 | m_buffer->push_back(pack_type::FIX_EXT_4); 1043 | m_buffer->push_back(type); 1044 | push(r); 1045 | break; 1046 | 1047 | case 8: 1048 | m_buffer->push_back(pack_type::FIX_EXT_8); 1049 | m_buffer->push_back(type); 1050 | push(r); 1051 | break; 1052 | 1053 | case 16: 1054 | m_buffer->push_back(pack_type::FIX_EXT_16); 1055 | m_buffer->push_back(type); 1056 | push(r); 1057 | break; 1058 | 1059 | default: 1060 | // EXT 1061 | if (size <= std::numeric_limits::max()) { 1062 | m_buffer->push_back(pack_type::EXT8); 1063 | m_buffer->push_back(static_cast(size)); 1064 | m_buffer->push_back(type); 1065 | push(r); 1066 | } else if (size <= std::numeric_limits::max()) { 1067 | m_buffer->push_back(pack_type::EXT16); 1068 | push_number_reverse(static_cast(size)); 1069 | m_buffer->push_back(type); 1070 | push(r); 1071 | } else if (size <= std::numeric_limits::max()) { 1072 | m_buffer->push_back(pack_type::EXT32); 1073 | push_number_reverse(static_cast(size)); 1074 | m_buffer->push_back(type); 1075 | push(r); 1076 | } else { 1077 | throw overflow_pack_error(); 1078 | } 1079 | } 1080 | 1081 | return *this; 1082 | } 1083 | 1084 | const buffer &get_payload() const { return *m_buffer; } 1085 | }; 1086 | 1087 | class parser { 1088 | const std::uint8_t *m_p = nullptr; 1089 | inline parse_result header() const { 1090 | if (m_size < 1) { 1091 | return {parse_status::empty}; 1092 | } 1093 | return OK(static_cast(m_p[0])); 1094 | } 1095 | int m_size = -1; 1096 | 1097 | public: 1098 | parser() {} 1099 | 1100 | parser(const std::vector &v) 1101 | : m_p(v.data()), m_size(static_cast(v.size())) {} 1102 | 1103 | parser(const std::uint8_t *p, int size) : m_p(p), m_size(size) { 1104 | if (m_size < 0) { 1105 | throw lack_parse_error(); 1106 | } 1107 | } 1108 | 1109 | bool is_emtpy() const { return m_size == 0; } 1110 | 1111 | const uint8_t *data() const noexcept { return m_p; } 1112 | 1113 | int consumed_size() const { 1114 | auto n = next().value; 1115 | return n.m_p - m_p; 1116 | } 1117 | 1118 | std::vector copy_bytes() const { 1119 | auto p = data(); 1120 | return std::vector(p, p + consumed_size()); 1121 | } 1122 | 1123 | std::string to_json() const { 1124 | std::stringstream ss; 1125 | to_json(ss); 1126 | return ss.str(); 1127 | } 1128 | 1129 | void to_json(std::ostream &os) const noexcept(false) { 1130 | if (is_array()) { 1131 | 1132 | os << '['; 1133 | 1134 | auto item_count = count(); 1135 | auto type = header(); 1136 | auto offset = body_index_and_size::from_type(type).value.index; 1137 | auto current = parser(m_p + offset, m_size - offset); 1138 | for (uint8_t i = 0; i < item_count; ++i) { 1139 | if (i > 0) { 1140 | os << ','; 1141 | } 1142 | 1143 | current.to_json(os); 1144 | 1145 | current = current.next(); 1146 | } 1147 | 1148 | os << ']'; 1149 | 1150 | } else if (is_map()) { 1151 | 1152 | os << '{'; 1153 | 1154 | auto item_count = count(); 1155 | auto type = header(); 1156 | auto offset = body_index_and_size::from_type(type).value.index; 1157 | auto current = parser(m_p + offset, m_size - offset); 1158 | for (uint8_t i = 0; i < item_count; ++i) { 1159 | if (i > 0) { 1160 | os << ','; 1161 | } 1162 | 1163 | // key 1164 | current.to_json(os); 1165 | current = current.next(); 1166 | 1167 | os << ':'; 1168 | 1169 | // value 1170 | current.to_json(os); 1171 | current = current.next(); 1172 | } 1173 | 1174 | os << '}'; 1175 | 1176 | } else { 1177 | 1178 | if (is_nil()) { 1179 | 1180 | os << "null"; 1181 | 1182 | } else if (is_bool()) { 1183 | if (get_bool()) { 1184 | os << "true"; 1185 | } else { 1186 | os << "false"; 1187 | } 1188 | } else if (is_number()) { 1189 | os << get_number(); 1190 | } else if (is_string()) { 1191 | os << '"' << get_string() << '"'; 1192 | } else if (is_binary()) { 1193 | auto type = header(); 1194 | auto body = body_index_and_size::from_type(type).value; 1195 | os << "[bin:" << body.size(m_p, m_size).value << "bytes]"; 1196 | } else if (is_ext()) { 1197 | auto type = header(); 1198 | auto body = body_index_and_size::from_type(type).value; 1199 | os << "[ext:" << body.size(m_p, m_size).value << "bytes]"; 1200 | } else { 1201 | auto type = header(); 1202 | throw invalid_parse_error(); 1203 | } 1204 | } 1205 | } 1206 | 1207 | parse_result advance(size_t n) const noexcept { 1208 | if (n > m_size) { 1209 | return {parse_status::lack}; 1210 | } 1211 | return OK(parser(m_p + n, static_cast(m_size - n))); 1212 | } 1213 | 1214 | #pragma region leaf 1215 | parse_result advance_bool(bool &value) const noexcept { 1216 | auto type = header(); 1217 | if (!type.is_ok()) { 1218 | return {type.status}; 1219 | } 1220 | if (type == pack_type::True) 1221 | value = true; 1222 | else if (type == pack_type::False) 1223 | value = false; 1224 | else 1225 | return {parse_status::type}; 1226 | return advance(1); 1227 | } 1228 | 1229 | bool get_bool() const { 1230 | bool value; 1231 | advance_bool(value); 1232 | return value; 1233 | } 1234 | 1235 | private: 1236 | parse_result advance_string(std::string_view &value, size_t offset, 1237 | size_t size) const noexcept { 1238 | auto head = m_p + offset; 1239 | value = std::string_view((char *)head, size); 1240 | return advance(offset + size); 1241 | } 1242 | 1243 | public: 1244 | parse_result advance_string(std::string_view &value) const noexcept { 1245 | auto type = header(); 1246 | if (!type.is_ok()) { 1247 | return {type.status}; 1248 | } 1249 | switch (type) { 1250 | case pack_type::STR32: 1251 | return advance_string(value, 1 + 4, 1252 | body_number(m_p, m_size)); 1253 | case pack_type::STR16: 1254 | return advance_string(value, 1 + 2, 1255 | body_number(m_p, m_size)); 1256 | case pack_type::STR8: 1257 | return advance_string(value, 1 + 1, 1258 | body_number(m_p, m_size)); 1259 | case pack_type::FIX_STR: 1260 | return advance_string(value, 1, 0); 1261 | case pack_type::FIX_STR_0x01: 1262 | return advance_string(value, 1, 1); 1263 | case pack_type::FIX_STR_0x02: 1264 | return advance_string(value, 1, 2); 1265 | case pack_type::FIX_STR_0x03: 1266 | return advance_string(value, 1, 3); 1267 | case pack_type::FIX_STR_0x04: 1268 | return advance_string(value, 1, 4); 1269 | case pack_type::FIX_STR_0x05: 1270 | return advance_string(value, 1, 5); 1271 | case pack_type::FIX_STR_0x06: 1272 | return advance_string(value, 1, 6); 1273 | case pack_type::FIX_STR_0x07: 1274 | return advance_string(value, 1, 7); 1275 | case pack_type::FIX_STR_0x08: 1276 | return advance_string(value, 1, 8); 1277 | case pack_type::FIX_STR_0x09: 1278 | return advance_string(value, 1, 9); 1279 | case pack_type::FIX_STR_0x0A: 1280 | return advance_string(value, 1, 10); 1281 | case pack_type::FIX_STR_0x0B: 1282 | return advance_string(value, 1, 11); 1283 | case pack_type::FIX_STR_0x0C: 1284 | return advance_string(value, 1, 12); 1285 | case pack_type::FIX_STR_0x0D: 1286 | return advance_string(value, 1, 13); 1287 | case pack_type::FIX_STR_0x0E: 1288 | return advance_string(value, 1, 14); 1289 | case pack_type::FIX_STR_0x0F: 1290 | return advance_string(value, 1, 15); 1291 | case pack_type::FIX_STR_0x10: 1292 | return advance_string(value, 1, 16); 1293 | case pack_type::FIX_STR_0x11: 1294 | return advance_string(value, 1, 17); 1295 | case pack_type::FIX_STR_0x12: 1296 | return advance_string(value, 1, 18); 1297 | case pack_type::FIX_STR_0x13: 1298 | return advance_string(value, 1, 19); 1299 | case pack_type::FIX_STR_0x14: 1300 | return advance_string(value, 1, 20); 1301 | case pack_type::FIX_STR_0x15: 1302 | return advance_string(value, 1, 21); 1303 | case pack_type::FIX_STR_0x16: 1304 | return advance_string(value, 1, 22); 1305 | case pack_type::FIX_STR_0x17: 1306 | return advance_string(value, 1, 23); 1307 | case pack_type::FIX_STR_0x18: 1308 | return advance_string(value, 1, 24); 1309 | case pack_type::FIX_STR_0x19: 1310 | return advance_string(value, 1, 25); 1311 | case pack_type::FIX_STR_0x1A: 1312 | return advance_string(value, 1, 26); 1313 | case pack_type::FIX_STR_0x1B: 1314 | return advance_string(value, 1, 27); 1315 | case pack_type::FIX_STR_0x1C: 1316 | return advance_string(value, 1, 28); 1317 | case pack_type::FIX_STR_0x1D: 1318 | return advance_string(value, 1, 29); 1319 | case pack_type::FIX_STR_0x1E: 1320 | return advance_string(value, 1, 30); 1321 | case pack_type::FIX_STR_0x1F: 1322 | return advance_string(value, 1, 31); 1323 | default: 1324 | return {parse_status::type}; 1325 | } 1326 | } 1327 | 1328 | std::string_view get_string() const { 1329 | std::string_view value; 1330 | advance_string(value); 1331 | return value; 1332 | } 1333 | 1334 | parse_result 1335 | advance_binary_view(std::string_view &value) const noexcept { 1336 | auto type = header(); 1337 | if (!type.is_ok()) { 1338 | return {type.status}; 1339 | } 1340 | switch (type) { 1341 | case pack_type::BIN32: { 1342 | auto begin = m_p + 1 + 4; 1343 | auto n = body_number(m_p, m_size); 1344 | if (!n.is_ok()) { 1345 | return {n.status}; 1346 | } 1347 | value = std::string_view((char *)begin, n); 1348 | return advance(1 + 4 + n); 1349 | } 1350 | 1351 | case pack_type::BIN16: { 1352 | auto begin = m_p + 1 + 2; 1353 | auto n = body_number(m_p, m_size); 1354 | if (!n.is_ok()) { 1355 | return {n.status}; 1356 | } 1357 | value = std::string_view((char *)begin, n); 1358 | return advance(1 + 2 + n); 1359 | } 1360 | case pack_type::BIN8: { 1361 | auto begin = m_p + 1 + 1; 1362 | auto n = body_number(m_p, m_size); 1363 | if (!n.is_ok()) { 1364 | return {n.status}; 1365 | } 1366 | value = std::string_view((char *)begin, n); 1367 | return advance(1 + 1 + n); 1368 | } 1369 | 1370 | case pack_type::EXT32: { 1371 | auto begin = m_p + 2 + 4; 1372 | auto n = body_number(m_p, m_size); 1373 | if (!n.is_ok()) { 1374 | return {n.status}; 1375 | } 1376 | value = std::string_view((char *)begin, n); 1377 | return advance(2 + 4 + n); 1378 | } 1379 | 1380 | case pack_type::EXT16: { 1381 | auto begin = m_p + 2 + 2; 1382 | auto n = body_number(m_p, m_size); 1383 | if (!n.is_ok()) { 1384 | return {n.status}; 1385 | } 1386 | value = std::string_view((char *)begin, n); 1387 | return advance(2 + 2 + n); 1388 | } 1389 | case pack_type::EXT8: { 1390 | auto begin = m_p + 2 + 1; 1391 | auto n = body_number(m_p, m_size); 1392 | if (!n.is_ok()) { 1393 | return {n.status}; 1394 | } 1395 | value = std::string_view((char *)begin, n); 1396 | return advance(2 + 1 + n); 1397 | } 1398 | 1399 | case pack_type::FIX_EXT_1: { 1400 | auto begin = m_p + 1 + 1; 1401 | auto n = 1; 1402 | value = std::string_view((char *)begin, n); 1403 | return advance(1 + 1 + n); 1404 | } 1405 | 1406 | case pack_type::FIX_EXT_2: { 1407 | auto begin = m_p + 1 + 1; 1408 | auto n = 2; 1409 | value = std::string_view((char *)begin, n); 1410 | return advance(1 + 1 + n); 1411 | } 1412 | 1413 | case pack_type::FIX_EXT_4: { 1414 | auto begin = m_p + 1 + 1; 1415 | auto n = 4; 1416 | value = std::string_view((char *)begin, n); 1417 | return advance(1 + 1 + n); 1418 | } 1419 | 1420 | case pack_type::FIX_EXT_8: { 1421 | auto begin = m_p + 1 + 1; 1422 | auto n = 8; 1423 | value = std::string_view((char *)begin, n); 1424 | return advance(1 + 1 + n); 1425 | } 1426 | 1427 | case pack_type::FIX_EXT_16: { 1428 | auto begin = m_p + 1 + 1; 1429 | auto n = 16; 1430 | value = std::string_view((char *)begin, n); 1431 | return advance(1 + 1 + n); 1432 | } 1433 | 1434 | default: 1435 | return {parse_status::type}; 1436 | } 1437 | } 1438 | 1439 | std::string_view get_binary_view() const { 1440 | std::string_view bytes; 1441 | advance_binary_view(bytes); 1442 | return bytes; 1443 | } 1444 | 1445 | parse_result 1446 | advance_binary(std::vector &value) const noexcept { 1447 | std::string_view view; 1448 | auto parser = advance_binary_view(view); 1449 | if (!parser.is_ok()) { 1450 | return {parser.status}; 1451 | } 1452 | value = std::vector(view.begin(), view.end()); 1453 | return parser; 1454 | } 1455 | 1456 | std::vector get_binary() const { 1457 | auto view = get_binary_view(); 1458 | std::vector bytes(view.begin(), view.end()); 1459 | return bytes; 1460 | } 1461 | 1462 | parse_result 1463 | advance_ext(std::tuple &value) const noexcept { 1464 | char type; 1465 | auto _header = header(); 1466 | if (!_header.is_ok()) { 1467 | return {_header.status}; 1468 | } 1469 | switch (_header) { 1470 | case FIX_EXT_1: 1471 | case FIX_EXT_2: 1472 | case FIX_EXT_4: 1473 | case FIX_EXT_8: 1474 | case FIX_EXT_16: 1475 | type = m_p[1]; 1476 | break; 1477 | case EXT8: 1478 | type = m_p[1 + 1]; 1479 | break; 1480 | case EXT16: 1481 | type = m_p[1 + 2]; 1482 | break; 1483 | case EXT32: 1484 | type = m_p[1 + 4]; 1485 | break; 1486 | 1487 | default: 1488 | return {parse_status::type}; 1489 | } 1490 | 1491 | std::string_view bytes; 1492 | auto result = advance_binary_view(bytes); 1493 | if (!result.is_ok()) { 1494 | return {result.status}; 1495 | } 1496 | value = std::make_tuple(type, bytes); 1497 | return result; 1498 | } 1499 | 1500 | std::tuple get_ext() const { 1501 | std::tuple value; 1502 | advance_ext(value); 1503 | return value; 1504 | } 1505 | 1506 | template 1507 | parse_result advance_number(T &value) const noexcept { 1508 | auto type = header(); 1509 | if (!type.is_ok()) { 1510 | return {type.status}; 1511 | } 1512 | 1513 | if (type <= 0x7f) { 1514 | // small int(0 - 127) 1515 | value = type; 1516 | return advance(1); 1517 | } 1518 | 1519 | switch (type) { 1520 | case pack_type::UINT8: 1521 | value = m_p[1]; 1522 | return advance(1 + 1); 1523 | case pack_type::UINT16: 1524 | value = body_number(m_p, m_size); 1525 | return advance(1 + 2); 1526 | case pack_type::UINT32: 1527 | value = body_number(m_p, m_size); 1528 | return advance(1 + 4); 1529 | case pack_type::UINT64: 1530 | value = body_number(m_p, m_size); 1531 | return advance(1 + 8); 1532 | case pack_type::INT8: 1533 | value = m_p[1]; 1534 | return advance(1 + 1); 1535 | case pack_type::INT16: 1536 | value = body_number(m_p, m_size); 1537 | return advance(1 + 2); 1538 | case pack_type::INT32: 1539 | value = body_number(m_p, m_size); 1540 | return advance(1 + 4); 1541 | case pack_type::INT64: 1542 | value = body_number(m_p, m_size); 1543 | return advance(1 + 8); 1544 | case pack_type::FLOAT: 1545 | value = body_number(m_p, m_size); 1546 | return advance(1 + 4); 1547 | case pack_type::DOUBLE: 1548 | value = body_number(m_p, m_size); 1549 | return advance(1 + 8); 1550 | case pack_type::NEGATIVE_FIXNUM: 1551 | value = -32; 1552 | return advance(1); 1553 | case pack_type::NEGATIVE_FIXNUM_0x1F: 1554 | value = -31; 1555 | return advance(1); 1556 | case pack_type::NEGATIVE_FIXNUM_0x1E: 1557 | value = -30; 1558 | return advance(1); 1559 | case pack_type::NEGATIVE_FIXNUM_0x1D: 1560 | value = -29; 1561 | return advance(1); 1562 | case pack_type::NEGATIVE_FIXNUM_0x1C: 1563 | value = -28; 1564 | return advance(1); 1565 | case pack_type::NEGATIVE_FIXNUM_0x1B: 1566 | value = -27; 1567 | return advance(1); 1568 | case pack_type::NEGATIVE_FIXNUM_0x1A: 1569 | value = -26; 1570 | return advance(1); 1571 | case pack_type::NEGATIVE_FIXNUM_0x19: 1572 | value = -25; 1573 | return advance(1); 1574 | case pack_type::NEGATIVE_FIXNUM_0x18: 1575 | value = -24; 1576 | return advance(1); 1577 | case pack_type::NEGATIVE_FIXNUM_0x17: 1578 | value = -23; 1579 | return advance(1); 1580 | case pack_type::NEGATIVE_FIXNUM_0x16: 1581 | value = -22; 1582 | return advance(1); 1583 | case pack_type::NEGATIVE_FIXNUM_0x15: 1584 | value = -21; 1585 | return advance(1); 1586 | case pack_type::NEGATIVE_FIXNUM_0x14: 1587 | value = -20; 1588 | return advance(1); 1589 | case pack_type::NEGATIVE_FIXNUM_0x13: 1590 | value = -19; 1591 | return advance(1); 1592 | case pack_type::NEGATIVE_FIXNUM_0x12: 1593 | value = -18; 1594 | return advance(1); 1595 | case pack_type::NEGATIVE_FIXNUM_0x11: 1596 | value = -17; 1597 | return advance(1); 1598 | case pack_type::NEGATIVE_FIXNUM_0x10: 1599 | value = -16; 1600 | return advance(1); 1601 | case pack_type::NEGATIVE_FIXNUM_0x0F: 1602 | value = -15; 1603 | return advance(1); 1604 | case pack_type::NEGATIVE_FIXNUM_0x0E: 1605 | value = -14; 1606 | return advance(1); 1607 | case pack_type::NEGATIVE_FIXNUM_0x0D: 1608 | value = -13; 1609 | return advance(1); 1610 | case pack_type::NEGATIVE_FIXNUM_0x0C: 1611 | value = -12; 1612 | return advance(1); 1613 | case pack_type::NEGATIVE_FIXNUM_0x0B: 1614 | value = -11; 1615 | return advance(1); 1616 | case pack_type::NEGATIVE_FIXNUM_0x0A: 1617 | value = -10; 1618 | return advance(1); 1619 | case pack_type::NEGATIVE_FIXNUM_0x09: 1620 | value = -9; 1621 | return advance(1); 1622 | case pack_type::NEGATIVE_FIXNUM_0x08: 1623 | value = -8; 1624 | return advance(1); 1625 | case pack_type::NEGATIVE_FIXNUM_0x07: 1626 | value = -7; 1627 | return advance(1); 1628 | case pack_type::NEGATIVE_FIXNUM_0x06: 1629 | value = -6; 1630 | return advance(1); 1631 | case pack_type::NEGATIVE_FIXNUM_0x05: 1632 | value = -5; 1633 | return advance(1); 1634 | case pack_type::NEGATIVE_FIXNUM_0x04: 1635 | value = -4; 1636 | return advance(1); 1637 | case pack_type::NEGATIVE_FIXNUM_0x03: 1638 | value = -3; 1639 | return advance(1); 1640 | case pack_type::NEGATIVE_FIXNUM_0x02: 1641 | value = -2; 1642 | return advance(1); 1643 | case pack_type::NEGATIVE_FIXNUM_0x01: 1644 | value = -1; 1645 | return advance(1); 1646 | default: 1647 | return {parse_status::type}; 1648 | } 1649 | } 1650 | 1651 | template T get_number() const { 1652 | T value; 1653 | advance_number(value); 1654 | return value; 1655 | } 1656 | 1657 | bool is_nil() const noexcept { 1658 | auto type = header(); 1659 | if (!type.is_ok()) { 1660 | return false; 1661 | } 1662 | return type == pack_type::NIL; 1663 | } 1664 | 1665 | bool is_bool() const noexcept { 1666 | auto type = header(); 1667 | if (!type.is_ok()) { 1668 | return false; 1669 | } 1670 | return type == pack_type::True || type == pack_type::False; 1671 | } 1672 | 1673 | bool is_number() const noexcept { 1674 | auto type = header(); 1675 | if (!type.is_ok()) { 1676 | return false; 1677 | } 1678 | switch (type) { 1679 | #pragma region POSITIVE_FIXNUM 0x00 - 0x7F 1680 | case POSITIVE_FIXNUM: 1681 | case POSITIVE_FIXNUM_0x01: 1682 | case POSITIVE_FIXNUM_0x02: 1683 | case POSITIVE_FIXNUM_0x03: 1684 | case POSITIVE_FIXNUM_0x04: 1685 | case POSITIVE_FIXNUM_0x05: 1686 | case POSITIVE_FIXNUM_0x06: 1687 | case POSITIVE_FIXNUM_0x07: 1688 | case POSITIVE_FIXNUM_0x08: 1689 | case POSITIVE_FIXNUM_0x09: 1690 | case POSITIVE_FIXNUM_0x0A: 1691 | case POSITIVE_FIXNUM_0x0B: 1692 | case POSITIVE_FIXNUM_0x0C: 1693 | case POSITIVE_FIXNUM_0x0D: 1694 | case POSITIVE_FIXNUM_0x0E: 1695 | case POSITIVE_FIXNUM_0x0F: 1696 | 1697 | case POSITIVE_FIXNUM_0x10: 1698 | case POSITIVE_FIXNUM_0x11: 1699 | case POSITIVE_FIXNUM_0x12: 1700 | case POSITIVE_FIXNUM_0x13: 1701 | case POSITIVE_FIXNUM_0x14: 1702 | case POSITIVE_FIXNUM_0x15: 1703 | case POSITIVE_FIXNUM_0x16: 1704 | case POSITIVE_FIXNUM_0x17: 1705 | case POSITIVE_FIXNUM_0x18: 1706 | case POSITIVE_FIXNUM_0x19: 1707 | case POSITIVE_FIXNUM_0x1A: 1708 | case POSITIVE_FIXNUM_0x1B: 1709 | case POSITIVE_FIXNUM_0x1C: 1710 | case POSITIVE_FIXNUM_0x1D: 1711 | case POSITIVE_FIXNUM_0x1E: 1712 | case POSITIVE_FIXNUM_0x1F: 1713 | 1714 | case POSITIVE_FIXNUM_0x20: 1715 | case POSITIVE_FIXNUM_0x21: 1716 | case POSITIVE_FIXNUM_0x22: 1717 | case POSITIVE_FIXNUM_0x23: 1718 | case POSITIVE_FIXNUM_0x24: 1719 | case POSITIVE_FIXNUM_0x25: 1720 | case POSITIVE_FIXNUM_0x26: 1721 | case POSITIVE_FIXNUM_0x27: 1722 | case POSITIVE_FIXNUM_0x28: 1723 | case POSITIVE_FIXNUM_0x29: 1724 | case POSITIVE_FIXNUM_0x2A: 1725 | case POSITIVE_FIXNUM_0x2B: 1726 | case POSITIVE_FIXNUM_0x2C: 1727 | case POSITIVE_FIXNUM_0x2D: 1728 | case POSITIVE_FIXNUM_0x2E: 1729 | case POSITIVE_FIXNUM_0x2F: 1730 | 1731 | case POSITIVE_FIXNUM_0x30: 1732 | case POSITIVE_FIXNUM_0x31: 1733 | case POSITIVE_FIXNUM_0x32: 1734 | case POSITIVE_FIXNUM_0x33: 1735 | case POSITIVE_FIXNUM_0x34: 1736 | case POSITIVE_FIXNUM_0x35: 1737 | case POSITIVE_FIXNUM_0x36: 1738 | case POSITIVE_FIXNUM_0x37: 1739 | case POSITIVE_FIXNUM_0x38: 1740 | case POSITIVE_FIXNUM_0x39: 1741 | case POSITIVE_FIXNUM_0x3A: 1742 | case POSITIVE_FIXNUM_0x3B: 1743 | case POSITIVE_FIXNUM_0x3C: 1744 | case POSITIVE_FIXNUM_0x3D: 1745 | case POSITIVE_FIXNUM_0x3E: 1746 | case POSITIVE_FIXNUM_0x3F: 1747 | 1748 | case POSITIVE_FIXNUM_0x40: 1749 | case POSITIVE_FIXNUM_0x41: 1750 | case POSITIVE_FIXNUM_0x42: 1751 | case POSITIVE_FIXNUM_0x43: 1752 | case POSITIVE_FIXNUM_0x44: 1753 | case POSITIVE_FIXNUM_0x45: 1754 | case POSITIVE_FIXNUM_0x46: 1755 | case POSITIVE_FIXNUM_0x47: 1756 | case POSITIVE_FIXNUM_0x48: 1757 | case POSITIVE_FIXNUM_0x49: 1758 | case POSITIVE_FIXNUM_0x4A: 1759 | case POSITIVE_FIXNUM_0x4B: 1760 | case POSITIVE_FIXNUM_0x4C: 1761 | case POSITIVE_FIXNUM_0x4D: 1762 | case POSITIVE_FIXNUM_0x4E: 1763 | case POSITIVE_FIXNUM_0x4F: 1764 | 1765 | case POSITIVE_FIXNUM_0x50: 1766 | case POSITIVE_FIXNUM_0x51: 1767 | case POSITIVE_FIXNUM_0x52: 1768 | case POSITIVE_FIXNUM_0x53: 1769 | case POSITIVE_FIXNUM_0x54: 1770 | case POSITIVE_FIXNUM_0x55: 1771 | case POSITIVE_FIXNUM_0x56: 1772 | case POSITIVE_FIXNUM_0x57: 1773 | case POSITIVE_FIXNUM_0x58: 1774 | case POSITIVE_FIXNUM_0x59: 1775 | case POSITIVE_FIXNUM_0x5A: 1776 | case POSITIVE_FIXNUM_0x5B: 1777 | case POSITIVE_FIXNUM_0x5C: 1778 | case POSITIVE_FIXNUM_0x5D: 1779 | case POSITIVE_FIXNUM_0x5E: 1780 | case POSITIVE_FIXNUM_0x5F: 1781 | 1782 | case POSITIVE_FIXNUM_0x60: 1783 | case POSITIVE_FIXNUM_0x61: 1784 | case POSITIVE_FIXNUM_0x62: 1785 | case POSITIVE_FIXNUM_0x63: 1786 | case POSITIVE_FIXNUM_0x64: 1787 | case POSITIVE_FIXNUM_0x65: 1788 | case POSITIVE_FIXNUM_0x66: 1789 | case POSITIVE_FIXNUM_0x67: 1790 | case POSITIVE_FIXNUM_0x68: 1791 | case POSITIVE_FIXNUM_0x69: 1792 | case POSITIVE_FIXNUM_0x6A: 1793 | case POSITIVE_FIXNUM_0x6B: 1794 | case POSITIVE_FIXNUM_0x6C: 1795 | case POSITIVE_FIXNUM_0x6D: 1796 | case POSITIVE_FIXNUM_0x6E: 1797 | case POSITIVE_FIXNUM_0x6F: 1798 | 1799 | case POSITIVE_FIXNUM_0x70: 1800 | case POSITIVE_FIXNUM_0x71: 1801 | case POSITIVE_FIXNUM_0x72: 1802 | case POSITIVE_FIXNUM_0x73: 1803 | case POSITIVE_FIXNUM_0x74: 1804 | case POSITIVE_FIXNUM_0x75: 1805 | case POSITIVE_FIXNUM_0x76: 1806 | case POSITIVE_FIXNUM_0x77: 1807 | case POSITIVE_FIXNUM_0x78: 1808 | case POSITIVE_FIXNUM_0x79: 1809 | case POSITIVE_FIXNUM_0x7A: 1810 | case POSITIVE_FIXNUM_0x7B: 1811 | case POSITIVE_FIXNUM_0x7C: 1812 | case POSITIVE_FIXNUM_0x7D: 1813 | case POSITIVE_FIXNUM_0x7E: 1814 | case POSITIVE_FIXNUM_0x7F: 1815 | #pragma endregion 1816 | 1817 | case FLOAT: 1818 | case DOUBLE: 1819 | case UINT8: 1820 | case UINT16: 1821 | case UINT32: 1822 | case UINT64: 1823 | case INT8: 1824 | case INT16: 1825 | case INT32: 1826 | case INT64: 1827 | 1828 | #pragma region NEGATIVE_FIXNUM 0xE0 - 0xFF 1829 | case NEGATIVE_FIXNUM: 1830 | case NEGATIVE_FIXNUM_0x1F: 1831 | case NEGATIVE_FIXNUM_0x1E: 1832 | case NEGATIVE_FIXNUM_0x1D: 1833 | case NEGATIVE_FIXNUM_0x1C: 1834 | case NEGATIVE_FIXNUM_0x1B: 1835 | case NEGATIVE_FIXNUM_0x1A: 1836 | case NEGATIVE_FIXNUM_0x19: 1837 | case NEGATIVE_FIXNUM_0x18: 1838 | case NEGATIVE_FIXNUM_0x17: 1839 | case NEGATIVE_FIXNUM_0x16: 1840 | case NEGATIVE_FIXNUM_0x15: 1841 | case NEGATIVE_FIXNUM_0x14: 1842 | case NEGATIVE_FIXNUM_0x13: 1843 | case NEGATIVE_FIXNUM_0x12: 1844 | case NEGATIVE_FIXNUM_0x11: 1845 | case NEGATIVE_FIXNUM_0x10: 1846 | case NEGATIVE_FIXNUM_0x0F: 1847 | case NEGATIVE_FIXNUM_0x0E: 1848 | case NEGATIVE_FIXNUM_0x0D: 1849 | case NEGATIVE_FIXNUM_0x0C: 1850 | case NEGATIVE_FIXNUM_0x0B: 1851 | case NEGATIVE_FIXNUM_0x0A: 1852 | case NEGATIVE_FIXNUM_0x09: 1853 | case NEGATIVE_FIXNUM_0x08: 1854 | case NEGATIVE_FIXNUM_0x07: 1855 | case NEGATIVE_FIXNUM_0x06: 1856 | case NEGATIVE_FIXNUM_0x05: 1857 | case NEGATIVE_FIXNUM_0x04: 1858 | case NEGATIVE_FIXNUM_0x03: 1859 | case NEGATIVE_FIXNUM_0x02: 1860 | case NEGATIVE_FIXNUM_0x01: 1861 | #pragma endregion 1862 | return true; 1863 | } 1864 | 1865 | return false; 1866 | } 1867 | 1868 | bool is_binary() const noexcept { 1869 | auto type = header(); 1870 | if (!type.is_ok()) { 1871 | return false; 1872 | } 1873 | switch (type) { 1874 | case pack_type::BIN8: 1875 | case pack_type::BIN16: 1876 | case pack_type::BIN32: 1877 | return true; 1878 | } 1879 | 1880 | return false; 1881 | } 1882 | 1883 | bool is_ext() const noexcept { 1884 | auto type = header(); 1885 | if (!type.is_ok()) { 1886 | return false; 1887 | } 1888 | switch (type) { 1889 | case pack_type::FIX_EXT_1: 1890 | case pack_type::FIX_EXT_2: 1891 | case pack_type::FIX_EXT_4: 1892 | case pack_type::FIX_EXT_8: 1893 | case pack_type::FIX_EXT_16: 1894 | case pack_type::EXT8: 1895 | case pack_type::EXT16: 1896 | case pack_type::EXT32: 1897 | return true; 1898 | } 1899 | 1900 | return false; 1901 | } 1902 | 1903 | bool is_string() const noexcept { 1904 | auto type = header(); 1905 | if (!type.is_ok()) { 1906 | return false; 1907 | } 1908 | switch (type) { 1909 | case pack_type::STR32: 1910 | case pack_type::STR16: 1911 | case pack_type::STR8: 1912 | case pack_type::FIX_STR: 1913 | case pack_type::FIX_STR_0x01: 1914 | case pack_type::FIX_STR_0x02: 1915 | case pack_type::FIX_STR_0x03: 1916 | case pack_type::FIX_STR_0x04: 1917 | case pack_type::FIX_STR_0x05: 1918 | case pack_type::FIX_STR_0x06: 1919 | case pack_type::FIX_STR_0x07: 1920 | case pack_type::FIX_STR_0x08: 1921 | case pack_type::FIX_STR_0x09: 1922 | case pack_type::FIX_STR_0x0A: 1923 | case pack_type::FIX_STR_0x0B: 1924 | case pack_type::FIX_STR_0x0C: 1925 | case pack_type::FIX_STR_0x0D: 1926 | case pack_type::FIX_STR_0x0E: 1927 | case pack_type::FIX_STR_0x0F: 1928 | case pack_type::FIX_STR_0x10: 1929 | case pack_type::FIX_STR_0x11: 1930 | case pack_type::FIX_STR_0x12: 1931 | case pack_type::FIX_STR_0x13: 1932 | case pack_type::FIX_STR_0x14: 1933 | case pack_type::FIX_STR_0x15: 1934 | case pack_type::FIX_STR_0x16: 1935 | case pack_type::FIX_STR_0x17: 1936 | case pack_type::FIX_STR_0x18: 1937 | case pack_type::FIX_STR_0x19: 1938 | case pack_type::FIX_STR_0x1A: 1939 | case pack_type::FIX_STR_0x1B: 1940 | case pack_type::FIX_STR_0x1C: 1941 | case pack_type::FIX_STR_0x1D: 1942 | case pack_type::FIX_STR_0x1E: 1943 | case pack_type::FIX_STR_0x1F: 1944 | return true; 1945 | } 1946 | 1947 | return false; 1948 | } 1949 | #pragma endregion 1950 | 1951 | #pragma region array or map 1952 | bool is_array() const noexcept { 1953 | auto type = header(); 1954 | if (!type.is_ok()) { 1955 | return false; 1956 | } 1957 | switch (type) { 1958 | case pack_type::FIX_ARRAY: 1959 | case pack_type::FIX_ARRAY_0x1: 1960 | case pack_type::FIX_ARRAY_0x2: 1961 | case pack_type::FIX_ARRAY_0x3: 1962 | case pack_type::FIX_ARRAY_0x4: 1963 | case pack_type::FIX_ARRAY_0x5: 1964 | case pack_type::FIX_ARRAY_0x6: 1965 | case pack_type::FIX_ARRAY_0x7: 1966 | case pack_type::FIX_ARRAY_0x8: 1967 | case pack_type::FIX_ARRAY_0x9: 1968 | case pack_type::FIX_ARRAY_0xA: 1969 | case pack_type::FIX_ARRAY_0xB: 1970 | case pack_type::FIX_ARRAY_0xC: 1971 | case pack_type::FIX_ARRAY_0xD: 1972 | case pack_type::FIX_ARRAY_0xE: 1973 | case pack_type::FIX_ARRAY_0xF: 1974 | case pack_type::ARRAY16: 1975 | case pack_type::ARRAY32: 1976 | return true; 1977 | } 1978 | 1979 | return false; 1980 | } 1981 | 1982 | bool is_map() const noexcept { 1983 | auto type = header(); 1984 | if (!type.is_ok()) { 1985 | return false; 1986 | } 1987 | switch (type) { 1988 | case pack_type::FIX_MAP: 1989 | case pack_type::FIX_MAP_0x1: 1990 | case pack_type::FIX_MAP_0x2: 1991 | case pack_type::FIX_MAP_0x3: 1992 | case pack_type::FIX_MAP_0x4: 1993 | case pack_type::FIX_MAP_0x5: 1994 | case pack_type::FIX_MAP_0x6: 1995 | case pack_type::FIX_MAP_0x7: 1996 | case pack_type::FIX_MAP_0x8: 1997 | case pack_type::FIX_MAP_0x9: 1998 | case pack_type::FIX_MAP_0xA: 1999 | case pack_type::FIX_MAP_0xB: 2000 | case pack_type::FIX_MAP_0xC: 2001 | case pack_type::FIX_MAP_0xD: 2002 | case pack_type::FIX_MAP_0xE: 2003 | case pack_type::FIX_MAP_0xF: 2004 | case pack_type::MAP16: 2005 | case pack_type::MAP32: 2006 | return true; 2007 | } 2008 | 2009 | return false; 2010 | } 2011 | 2012 | parse_result count() const { 2013 | auto _header = header(); 2014 | if (!_header.is_ok()) { 2015 | return {_header.status}; 2016 | } 2017 | auto type = _header; 2018 | switch (type) { 2019 | case pack_type::FIX_ARRAY: 2020 | return OK(static_cast(0)); 2021 | case pack_type::FIX_ARRAY_0x1: 2022 | return OK(static_cast(1)); 2023 | case pack_type::FIX_ARRAY_0x2: 2024 | return OK(static_cast(2)); 2025 | case pack_type::FIX_ARRAY_0x3: 2026 | return OK(static_cast(3)); 2027 | case pack_type::FIX_ARRAY_0x4: 2028 | return OK(static_cast(4)); 2029 | case pack_type::FIX_ARRAY_0x5: 2030 | return OK(static_cast(5)); 2031 | case pack_type::FIX_ARRAY_0x6: 2032 | return OK(static_cast(6)); 2033 | case pack_type::FIX_ARRAY_0x7: 2034 | return OK(static_cast(7)); 2035 | case pack_type::FIX_ARRAY_0x8: 2036 | return OK(static_cast(8)); 2037 | case pack_type::FIX_ARRAY_0x9: 2038 | return OK(static_cast(9)); 2039 | case pack_type::FIX_ARRAY_0xA: 2040 | return OK(static_cast(10)); 2041 | case pack_type::FIX_ARRAY_0xB: 2042 | return OK(static_cast(11)); 2043 | case pack_type::FIX_ARRAY_0xC: 2044 | return OK(static_cast(12)); 2045 | case pack_type::FIX_ARRAY_0xD: 2046 | return OK(static_cast(13)); 2047 | case pack_type::FIX_ARRAY_0xE: 2048 | return OK(static_cast(14)); 2049 | case pack_type::FIX_ARRAY_0xF: 2050 | return OK(static_cast(15)); 2051 | case pack_type::ARRAY16: 2052 | return body_number(m_p, m_size).cast(); 2053 | case pack_type::ARRAY32: 2054 | return body_number(m_p, m_size); 2055 | case pack_type::FIX_MAP: 2056 | return OK(static_cast(0)); 2057 | case pack_type::FIX_MAP_0x1: 2058 | return OK(static_cast(1)); 2059 | case pack_type::FIX_MAP_0x2: 2060 | return OK(static_cast(2)); 2061 | case pack_type::FIX_MAP_0x3: 2062 | return OK(static_cast(3)); 2063 | case pack_type::FIX_MAP_0x4: 2064 | return OK(static_cast(4)); 2065 | case pack_type::FIX_MAP_0x5: 2066 | return OK(static_cast(5)); 2067 | case pack_type::FIX_MAP_0x6: 2068 | return OK(static_cast(6)); 2069 | case pack_type::FIX_MAP_0x7: 2070 | return OK(static_cast(7)); 2071 | case pack_type::FIX_MAP_0x8: 2072 | return OK(static_cast(8)); 2073 | case pack_type::FIX_MAP_0x9: 2074 | return OK(static_cast(9)); 2075 | case pack_type::FIX_MAP_0xA: 2076 | return OK(static_cast(10)); 2077 | case pack_type::FIX_MAP_0xB: 2078 | return OK(static_cast(11)); 2079 | case pack_type::FIX_MAP_0xC: 2080 | return OK(static_cast(12)); 2081 | case pack_type::FIX_MAP_0xD: 2082 | return OK(static_cast(13)); 2083 | case pack_type::FIX_MAP_0xE: 2084 | return OK(static_cast(14)); 2085 | case pack_type::FIX_MAP_0xF: 2086 | return OK(static_cast(15)); 2087 | case pack_type::MAP16: 2088 | return body_number(m_p, m_size).cast(); 2089 | case pack_type::MAP32: 2090 | return body_number(m_p, m_size); 2091 | } 2092 | 2093 | return {parse_status::invalid}; 2094 | } 2095 | 2096 | parse_result first_array_item() const noexcept { 2097 | auto type = header(); 2098 | if (!type.is_ok()) { 2099 | return {type.status}; 2100 | } 2101 | if (!is_array() && !is_map()) { 2102 | return {parse_status::type}; 2103 | } 2104 | if (count() == 0) { 2105 | return {parse_status::invalid}; 2106 | } 2107 | auto body = body_index_and_size::from_type(type); 2108 | if (!body.is_ok()) { 2109 | return {body.status}; 2110 | } 2111 | auto offset = body.value.index; 2112 | if (offset > m_size) { 2113 | return {parse_status::lack}; 2114 | } 2115 | return OK(parser(m_p + offset, m_size - offset)); 2116 | } 2117 | 2118 | parser operator[](int index) const { 2119 | auto current = first_array_item().value; 2120 | for (int i = 0; i < index; ++i) { 2121 | current = current.next(); 2122 | } 2123 | return current; 2124 | } 2125 | 2126 | // string key accessor for map 2127 | parser operator[](const std::string &key) const { 2128 | auto type = header(); 2129 | auto offset = body_index_and_size::from_type(type).value.index; 2130 | auto current = parser(m_p + offset, m_size - offset); 2131 | auto item_count = count(); 2132 | for (uint8_t i = 0; i < item_count; ++i) { 2133 | // key 2134 | if (current.is_string()) { 2135 | if (current.get_string() == key) { 2136 | return current.next(); 2137 | } 2138 | } 2139 | 2140 | current = current.next(); 2141 | current = current.next(); 2142 | } 2143 | 2144 | // not found 2145 | return {}; 2146 | } 2147 | 2148 | parse_result next() const noexcept { 2149 | if (m_size < 1) { 2150 | return {parse_status::empty}; 2151 | } 2152 | auto type = static_cast(m_p[0]); 2153 | auto _body = body_index_and_size::from_type(type); 2154 | if (!_body.is_ok()) { 2155 | return {_body.status}; 2156 | } 2157 | auto body = _body.value; 2158 | 2159 | if (is_array()) { 2160 | auto offset = body.index; 2161 | if (offset > m_size) { 2162 | return {parse_status::lack}; 2163 | } 2164 | auto current = parser(m_p + offset, m_size - offset); 2165 | auto item_count = count(); 2166 | if (!item_count.is_ok()) { 2167 | return {item_count.status}; 2168 | } 2169 | for (uint8_t i = 0; i < item_count; ++i) { 2170 | auto _current = current.next(); 2171 | if (!_current.is_ok()) { 2172 | return {_current.status}; 2173 | } 2174 | current = _current.value; 2175 | } 2176 | return OK(current); 2177 | } else if (is_map()) { 2178 | auto offset = body.index; 2179 | if (offset > m_size) { 2180 | return {parse_status::lack}; 2181 | } 2182 | auto current = parser(m_p + offset, m_size - offset); 2183 | auto item_count = count(); 2184 | if (!item_count.is_ok()) { 2185 | return {item_count.status}; 2186 | } 2187 | for (uint8_t i = 0; i < item_count; ++i) { 2188 | // k 2189 | auto _key = current.next(); 2190 | if (!_key.is_ok()) { 2191 | return {_key.status}; 2192 | } 2193 | current = _key.value; 2194 | // v 2195 | auto _value = current.next(); 2196 | if (!_value.is_ok()) { 2197 | return {_value.status}; 2198 | } 2199 | current = _value.value; 2200 | } 2201 | return OK(current); 2202 | } else { 2203 | auto size = body.size(m_p, m_size); 2204 | if (!size.is_ok()) { 2205 | return {size.status}; 2206 | } 2207 | auto offset = body.index + size; 2208 | if (offset > m_size) { 2209 | return {parse_status::lack}; 2210 | } 2211 | auto current = parser(m_p + offset, m_size - offset); 2212 | return OK(current); 2213 | } 2214 | } 2215 | #pragma endregion 2216 | }; 2217 | 2218 | #pragma region tuple helper 2219 | template 2220 | std::tuple cons(const T &car, const std::tuple &cdr) { 2221 | return std::tuple_cat(std::make_tuple(car), cdr); 2222 | } 2223 | 2224 | // 2225 | template struct tuple_cdr_impl; 2226 | 2227 | template 2228 | struct tuple_cdr_impl> { 2229 | using type = std::tuple::type...>; 2230 | }; 2231 | 2232 | template 2233 | struct tuple_cdr 2234 | : tuple_cdr_impl::value>> {}; 2235 | 2236 | template 2237 | typename tuple_cdr::type>::type 2238 | cdr_impl(T &&t, std::index_sequence) { 2239 | return std::make_tuple(std::get(t)...); 2240 | } 2241 | 2242 | template 2243 | typename tuple_cdr::type>::type cdr(T &&t) { 2244 | return cdr_impl( 2245 | std::forward(t), 2246 | std::make_index_sequence< 2247 | std::tuple_size::type>::value>{}); 2248 | } 2249 | #pragma endregion 2250 | 2251 | #pragma region serializer 2252 | template inline packer &operator<<(packer &p, const T &t) { 2253 | serialize(p, t); 2254 | return p; 2255 | } 2256 | 2257 | struct nil_t {}; 2258 | constexpr nil_t nil = nil_t{}; 2259 | inline void serialize(packer &p, const nil_t) { p.pack_nil(); } 2260 | inline void serialize(packer &p, const char *t) { p.pack_str(t); } 2261 | inline void serialize(packer &p, std::string_view t) { p.pack_str(t); } 2262 | inline void serialize(packer &p, bool t) { p.pack_bool(t); } 2263 | 2264 | inline void serialize(packer &p, signed char t) { p.pack_integer(t); } 2265 | inline void serialize(packer &p, signed short t) { p.pack_integer(t); } 2266 | inline void serialize(packer &p, signed int t) { p.pack_integer(t); } 2267 | inline void serialize(packer &p, signed long long t) { p.pack_integer(t); } 2268 | inline void serialize(packer &p, unsigned char t) { p.pack_integer(t); } 2269 | inline void serialize(packer &p, unsigned short t) { p.pack_integer(t); } 2270 | inline void serialize(packer &p, unsigned int t) { p.pack_integer(t); } 2271 | inline void serialize(packer &p, unsigned long long t) { p.pack_integer(t); } 2272 | 2273 | inline void serialize(packer &p, float t) { p.pack_float(t); } 2274 | inline void serialize(packer &p, double t) { p.pack_double(t); } 2275 | 2276 | #pragma region serialize tuple 2277 | inline void _serialize(const std::tuple<> &t, packer &p) {} 2278 | 2279 | template 2280 | inline void _serialize(const std::tuple &t, packer &p) { 2281 | serialize(p, std::get<0>(t)); 2282 | } 2283 | 2284 | template 2285 | inline void _serialize(const std::tuple &t, packer &p) { 2286 | serialize(p, std::get<0>(t)); 2287 | _serialize(cdr(t), p); 2288 | } 2289 | 2290 | template 2291 | inline void serialize(packer &p, const std::tuple &t) { 2292 | auto size = 2293 | std::tuple_size::type>::value; 2294 | p.pack_array(size); 2295 | _serialize(t, p); 2296 | } 2297 | #pragma endregion 2298 | #pragma endregion 2299 | 2300 | #pragma region deserializer 2301 | template inline parser operator>>(const parser &u, T &t) { 2302 | return deserialize(u, t); 2303 | } 2304 | 2305 | inline parser deserialize(const parser &u, bool &value) { 2306 | return u.advance_bool(value); 2307 | } 2308 | 2309 | inline parser deserialize(const parser &u, signed char &value) { 2310 | return u.advance_number(value); 2311 | } 2312 | inline parser deserialize(const parser &u, signed short &value) { 2313 | return u.advance_number(value); 2314 | } 2315 | inline parser deserialize(const parser &u, signed int &value) { 2316 | return u.advance_number(value); 2317 | } 2318 | inline parser deserialize(const parser &u, signed long long &value) { 2319 | return u.advance_number(value); 2320 | } 2321 | inline parser deserialize(const parser &u, unsigned char &value) { 2322 | return u.advance_number(value); 2323 | } 2324 | inline parser deserialize(const parser &u, unsigned short &value) { 2325 | return u.advance_number(value); 2326 | } 2327 | inline parser deserialize(const parser &u, unsigned int &value) { 2328 | return u.advance_number(value); 2329 | } 2330 | inline parser deserialize(const parser &u, unsigned long long &value) { 2331 | return u.advance_number(value); 2332 | } 2333 | inline parser deserialize(const parser &u, float &value) { 2334 | return u.advance_number(value); 2335 | } 2336 | inline parser deserialize(const parser &u, double &value) { 2337 | return u.advance_number(value); 2338 | } 2339 | 2340 | inline parser deserialize(const parser &u, parser &x) { 2341 | x = u[0]; 2342 | return u[0].next(); 2343 | } 2344 | 2345 | #pragma region deserialize tuple 2346 | inline parser _deserialize(std::tuple<> &value, const parser &u) { return u; } 2347 | 2348 | template 2349 | inline parser _deserialize(std::tuple &value, const parser &u) { 2350 | // unpack 2351 | T t; 2352 | auto uu = deserialize(u, t); 2353 | 2354 | value = std::make_tuple(t); 2355 | 2356 | return uu; 2357 | } 2358 | 2359 | template 2360 | inline parser _deserialize(std::tuple &value, const parser &u) { 2361 | // unpack 2362 | T t; 2363 | auto uu = deserialize(u, t); 2364 | 2365 | decltype(cdr(value)) remain; 2366 | auto uuu = _deserialize(remain, uu); 2367 | 2368 | value = std::tuple_cat(std::make_tuple(t), remain); 2369 | 2370 | return uuu; 2371 | } 2372 | 2373 | template 2374 | inline parser deserialize(const parser &u, std::tuple &value) { 2375 | assert(u.is_array()); 2376 | auto count = u.count(); 2377 | if (count != 2378 | std::tuple_size< 2379 | typename std::remove_reference::type>::value) { 2380 | std::stringstream ss; 2381 | ss << "invalid arguments count: " << count << ", but expected: " 2382 | << std::tuple_size< 2383 | typename std::remove_reference::type>::value; 2384 | throw std::runtime_error(ss.str()); 2385 | } 2386 | return _deserialize(value, u[0]); 2387 | } 2388 | #pragma endregion 2389 | #pragma endregion 2390 | 2391 | #pragma region Range serialization 2392 | template inline void serialize(packer &p, const Range &value) { 2393 | auto b = std::begin(value); 2394 | auto e = std::end(value); 2395 | p.pack_array(std::distance(b, e)); 2396 | for (auto it = b; it != e; ++it) { 2397 | p << *it; 2398 | } 2399 | } 2400 | template 2401 | inline parser deserialize(const parser &u, Range &value) { 2402 | auto count = u.count(); 2403 | value.resize(count); 2404 | auto uu = u[0]; 2405 | for (auto &v : value) 2406 | // for (int i = 0; i < count; ++i) 2407 | { 2408 | uu >> v; 2409 | uu = uu.next(); 2410 | } 2411 | return uu; 2412 | } 2413 | 2414 | template <> 2415 | inline void 2416 | serialize>(packer &p, 2417 | const std::vector &t) { 2418 | p.pack_bin(t); 2419 | } 2420 | template <> 2421 | inline parser 2422 | deserialize>(const parser &u, 2423 | std::vector &value) { 2424 | return u.advance_binary(value); 2425 | } 2426 | 2427 | template <> 2428 | inline parser deserialize(const parser &u, std::string &value) { 2429 | std::string_view view; 2430 | auto uu = u.advance_string(view); 2431 | value.assign(view.begin(), view.end()); 2432 | return uu; 2433 | } 2434 | 2435 | template <> 2436 | inline parser deserialize(const parser &u, 2437 | std::string_view &value) { 2438 | auto uu = u.advance_string(value); 2439 | return uu; 2440 | } 2441 | 2442 | template inline T deserialize(const std::vector &b) { 2443 | T value; 2444 | parser(b) >> value; 2445 | return value; 2446 | } 2447 | 2448 | template <> 2449 | inline void serialize(packer &p, const std::string &t) { 2450 | p.pack_str(t); 2451 | } 2452 | 2453 | #pragma region 2454 | 2455 | #pragma region stream out 2456 | // json like 2457 | inline std::ostream &operator<<(std::ostream &os, const parser &p) { 2458 | p.to_json(os); 2459 | return os; 2460 | } 2461 | #pragma endregion 2462 | 2463 | #pragma region procedure call 2464 | using bytes = std::vector; 2465 | using procedurecall = std::function; 2466 | 2467 | #pragma region void 2468 | template 2469 | procedurecall _make_procedurecall(const F &f, void (C::*)(AS...) const, 2470 | std::index_sequence) { 2471 | return [f](const parser &parser) -> bytes { 2472 | // unpack args 2473 | std::tuple args; 2474 | parser >> args; 2475 | 2476 | // call 2477 | f(std::move(std::get(args))...); 2478 | 2479 | // pack result 2480 | msgpackpp::packer packer; 2481 | packer.pack_nil(); 2482 | return packer.get_payload(); 2483 | }; 2484 | } 2485 | 2486 | template 2487 | procedurecall _make_procedurecall(F f, void (C::*)(AS...) const) { 2488 | return _make_procedurecall(f, &decltype(f)::operator(), 2489 | std::index_sequence_for{}); 2490 | } 2491 | 2492 | template 2493 | procedurecall _make_procedurecall(void (*f)(AS...), 2494 | std::index_sequence) { 2495 | return [f](const parser &parser) -> bytes { 2496 | // unpack args 2497 | std::tuple args; 2498 | parser >> args; 2499 | 2500 | // call 2501 | f(std::move(std::get(args))...); 2502 | 2503 | // pack result 2504 | msgpackpp::packer packer; 2505 | packer.pack_nil(); 2506 | return packer.get_payload(); 2507 | }; 2508 | } 2509 | 2510 | #pragma endregion 2511 | 2512 | #pragma region result 2513 | template 2514 | procedurecall _make_procedurecall(const F &f, R (C::*)(AS...) const, 2515 | std::index_sequence) { 2516 | return [f](const parser &parser) -> bytes { 2517 | // unpack args 2518 | std::tuple args; 2519 | parser >> args; 2520 | 2521 | // call 2522 | auto r = f(std::move(std::get(args))...); 2523 | 2524 | // pack result 2525 | msgpackpp::packer packer; 2526 | packer << r; 2527 | return packer.get_payload(); 2528 | }; 2529 | } 2530 | 2531 | template 2532 | procedurecall _make_procedurecall(F f, R (C::*)(AS...) const) { 2533 | return _make_procedurecall(f, &decltype(f)::operator(), 2534 | std::index_sequence_for{}); 2535 | } 2536 | 2537 | template 2538 | procedurecall _make_procedurecall(R (*f)(AS...), std::index_sequence) { 2539 | return [f](const parser &parser) -> bytes { 2540 | // unpack args 2541 | std::tuple args; 2542 | parser >> args; 2543 | 2544 | // call 2545 | auto r = f(std::move(std::get(args))...); 2546 | 2547 | // pack result 2548 | msgpackpp::packer packer; 2549 | packer << r; 2550 | return packer.get_payload(); 2551 | }; 2552 | } 2553 | #pragma endregion 2554 | 2555 | template procedurecall make_procedurecall(F f) { 2556 | return _make_procedurecall(f, &decltype(f)::operator()); 2557 | } 2558 | 2559 | template 2560 | procedurecall make_procedurecall(R (*f)(AS...)) { 2561 | return _make_procedurecall(f, std::index_sequence_for{}); 2562 | } 2563 | 2564 | template 2565 | procedurecall make_methodcall(C *c, R (C::*f)(AS...)) { 2566 | return make_procedurecall([c, f](AS... args) { (*c.*f)(args...); }); 2567 | } 2568 | 2569 | #pragma region call 2570 | template 2571 | decltype(auto) _procedure_call(F f, R (C::*)(AS...) const, AS... args) { 2572 | auto proc = make_procedurecall(f); 2573 | packer packer; 2574 | packer << std::make_tuple(args...); 2575 | auto result = proc(packer.get_payload()); 2576 | 2577 | R value; 2578 | parser(result) >> value; 2579 | return value; 2580 | } 2581 | 2582 | template 2583 | decltype(auto) procedure_call(F f, AS... args) { 2584 | return _procedure_call(f, &decltype(f)::operator(), args...); 2585 | } 2586 | #pragma endregion 2587 | 2588 | #pragma endregion 2589 | } // namespace msgpackpp 2590 | 2591 | /// https://stackoverflow.com/questions/36925989/how-to-define-recursive-variadic-macros 2592 | #define MPPP_EXPAND(x) x 2593 | #define MPPP_CAT_I(x, y) x##y 2594 | #define MPPP_CAT(x, y) MPPP_CAT_I(x, y) 2595 | 2596 | #pragma region PACK_MAP 2597 | #define MPPP_PACK_KV(v, k) << #k << (v).k 2598 | #define MPPP_PACK_KV_1(v, k0) MPPP_PACK_KV(v, k0) 2599 | #define MPPP_PACK_KV_2(v, k0, k1) MPPP_PACK_KV_1(v, k0) MPPP_PACK_KV(v, k1) 2600 | #define MPPP_PACK_KV_3(v, k0, k1, k2) \ 2601 | MPPP_PACK_KV_2(v, k0, k1) MPPP_PACK_KV(v, k2) 2602 | #define MPPP_PACK_KV_4(v, k0, k1, k2, k3) \ 2603 | MPPP_PACK_KV_3(v, k0, k1, k2) MPPP_PACK_KV(v, k3) 2604 | #define MPPP_PACK_KV_5(v, k0, k1, k2, k3, k4) \ 2605 | MPPP_PACK_KV_4(v, k0, k1, k2, k3) MPPP_PACK_KV(v, k4) 2606 | #define MPPP_PACK_KV_N(n, v, ...) \ 2607 | p.pack_map(n); \ 2608 | p MPPP_CAT(MPPP_PACK_KV_, n) MPPP_EXPAND((v, __VA_ARGS__)) 2609 | #define MPPP_PACK_KV_TYPE(TYPE, n, ...) \ 2610 | inline void serialize(packer &p, const TYPE &value) { \ 2611 | MPPP_PACK_KV_N MPPP_EXPAND((n, value, __VA_ARGS__)); \ 2612 | } 2613 | #define MPPP_PACK_KV_SHARED(TYPE, n, ...) \ 2614 | inline void serialize(packer &p, const std::shared_ptr &value) { \ 2615 | MPPP_PACK_KV_N MPPP_EXPAND((n, *value, __VA_ARGS__)); \ 2616 | } 2617 | #pragma endregion 2618 | 2619 | #pragma region UNPACK_MAP 2620 | #define MPPP_UNPACK_KV(v, k) else if (key == #k) uu >> (v).k; 2621 | #define MPPP_UNPACK_KV_1(v, k0) MPPP_UNPACK_KV(v, k0) 2622 | #define MPPP_UNPACK_KV_2(v, k0, k1) \ 2623 | MPPP_UNPACK_KV_1(v, k0) MPPP_UNPACK_KV(v, k1) 2624 | #define MPPP_UNPACK_KV_3(v, k0, k1, k2) \ 2625 | MPPP_UNPACK_KV_2(v, k0, k1) MPPP_UNPACK_KV(v, k2) 2626 | #define MPPP_UNPACK_KV_4(v, k0, k1, k2, k3) \ 2627 | MPPP_UNPACK_KV_3(v, k0, k1, k2) MPPP_UNPACK_KV(v, k3) 2628 | #define MPPP_UNPACK_KV_5(v, k0, k1, k2, k3, k4) \ 2629 | MPPP_UNPACK_KV_4(v, k0, k1, k2, k3) MPPP_UNPACK_KV(v, k4) 2630 | #define MPPP_UNPACK_KV_N(n, v, ...) \ 2631 | MPPP_UNPACK_KV_BEGIN() \ 2632 | MPPP_CAT(MPPP_UNPACK_KV_, n) \ 2633 | MPPP_EXPAND((v, __VA_ARGS__)) MPPP_UNPACK_KV_END() 2634 | #define MPPP_UNPACK_KV_TYPE(TYPE, n, ...) \ 2635 | inline parser deserialize(const parser &u, TYPE &value) { \ 2636 | MPPP_UNPACK_KV_N MPPP_EXPAND((n, value, __VA_ARGS__)); \ 2637 | } 2638 | #define MPPP_UNPACK_KV_SHARED(TYPE, n, ...) \ 2639 | inline parser deserialize(const parser &u, std::shared_ptr &value) { \ 2640 | if (!value) { \ 2641 | value = std::make_shared(); \ 2642 | } \ 2643 | MPPP_UNPACK_KV_N MPPP_EXPAND((n, *value, __VA_ARGS__)); \ 2644 | } 2645 | 2646 | #define MPPP_UNPACK_KV_BEGIN() \ 2647 | auto count = u.count(); \ 2648 | auto uu = u[0]; \ 2649 | for (uint8_t i = 0; i < count; ++i) { \ 2650 | std::string key; \ 2651 | uu >> key; \ 2652 | uu = uu.next(); \ 2653 | \ 2654 | if (false) { \ 2655 | } 2656 | 2657 | #define MPPP_UNPACK_KV_END() \ 2658 | else { \ 2659 | } \ 2660 | uu = uu.next(); \ 2661 | } \ 2662 | return uu; 2663 | 2664 | #pragma endregion 2665 | 2666 | #define MPPP_MAP_SERIALIZER(TYPE, n, ...) \ 2667 | namespace msgpackpp { \ 2668 | MPPP_PACK_KV_TYPE MPPP_EXPAND((TYPE, n, __VA_ARGS__)) MPPP_UNPACK_KV_TYPE \ 2669 | MPPP_EXPAND((TYPE, n, __VA_ARGS__)) \ 2670 | } 2671 | #define MPPP_MAP_SERIALIZER_SHAREDP(TYPE, n, ...) \ 2672 | namespace msgpackpp { \ 2673 | MPPP_PACK_KV_SHARED MPPP_EXPAND((TYPE, n, \ 2674 | __VA_ARGS__)) MPPP_UNPACK_KV_SHARED \ 2675 | MPPP_EXPAND((TYPE, n, __VA_ARGS__)) \ 2676 | } 2677 | 2678 | #pragma region PACK_ARRAY 2679 | #define MPPP_PACK_ARRAY(v, k) << (v).k 2680 | #define MPPP_PACK_ARRAY_1(v, k0) MPPP_PACK_ARRAY(v, k0) 2681 | #define MPPP_PACK_ARRAY_2(v, k0, k1) \ 2682 | MPPP_PACK_ARRAY_1(v, k0) MPPP_PACK_ARRAY(v, k1) 2683 | #define MPPP_PACK_ARRAY_3(v, k0, k1, k2) \ 2684 | MPPP_PACK_ARRAY_2(v, k0, k1) MPPP_PACK_ARRAY(v, k2) 2685 | #define MPPP_PACK_ARRAY_4(v, k0, k1, k2, k3) \ 2686 | MPPP_PACK_ARRAY_3(v, k0, k1, k2) MPPP_PACK_ARRAY(v, k3) 2687 | #define MPPP_PACK_ARRAY_5(v, k0, k1, k2, k3, k4) \ 2688 | MPPP_PACK_ARRAY_4(v, k0, k1, k2, k3) MPPP_PACK_ARRAY(v, k4) 2689 | #define MPPP_PACK_ARRAY_N(n, v, ...) \ 2690 | p.pack_array(n); \ 2691 | p MPPP_CAT(MPPP_PACK_ARRAY_, n) MPPP_EXPAND((v, __VA_ARGS__)) 2692 | #define MPPP_PACK_ARRAY_TYPE(TYPE, n, ...) \ 2693 | inline void serialize(packer &p, const TYPE &value) { \ 2694 | MPPP_PACK_ARRAY_N MPPP_EXPAND((n, value, __VA_ARGS__)); \ 2695 | } 2696 | #define MPPP_PACK_ARRAY_SHARED(TYPE, n, ...) \ 2697 | inline void serialize(packer &p, const std::shared_ptr &value) { \ 2698 | MPPP_PACK_ARRAY_N MPPP_EXPAND((n, *value, __VA_ARGS__)); \ 2699 | } 2700 | #pragma endregion 2701 | 2702 | #pragma region UNPACK_ARRAY 2703 | #define MPPP_UNPACK_ARRAY(v, k) \ 2704 | uu >> (v).k; \ 2705 | uu = uu.next(); 2706 | #define MPPP_UNPACK_ARRAY_1(v, k0) MPPP_UNPACK_ARRAY(v, k0) 2707 | #define MPPP_UNPACK_ARRAY_2(v, k0, k1) \ 2708 | MPPP_UNPACK_ARRAY_1(v, k0) MPPP_UNPACK_ARRAY(v, k1) 2709 | #define MPPP_UNPACK_ARRAY_3(v, k0, k1, k2) \ 2710 | MPPP_UNPACK_ARRAY_2(v, k0, k1) MPPP_UNPACK_ARRAY(v, k2) 2711 | #define MPPP_UNPACK_ARRAY_4(v, k0, k1, k2, k3) \ 2712 | MPPP_UNPACK_ARRAY_3(v, k0, k1, k2) MPPP_UNPACK_ARRAY(v, k3) 2713 | #define MPPP_UNPACK_ARRAY_5(v, k0, k1, k2, k3, k4) \ 2714 | MPPP_UNPACK_ARRAY_4(v, k0, k1, k2, k3) MPPP_UNPACK_ARRAY(v, k4) 2715 | #define MPPP_UNPACK_ARRAY_N(n, v, ...) \ 2716 | auto uu = u[0]; \ 2717 | MPPP_CAT(MPPP_UNPACK_ARRAY_, n) MPPP_EXPAND((v, __VA_ARGS__)) return uu; 2718 | #define MPPP_UNPACK_ARRAY_TYPE(TYPE, n, ...) \ 2719 | inline parser deserialize(const parser &u, TYPE &value) { \ 2720 | MPPP_UNPACK_ARRAY_N MPPP_EXPAND((n, value, __VA_ARGS__)); \ 2721 | } 2722 | #define MPPP_UNPACK_ARRAY_SHARED(TYPE, n, ...) \ 2723 | inline parser deserialize(const parser &u, std::shared_ptr &value) { \ 2724 | if (!value) { \ 2725 | value = std::make_shared(); \ 2726 | } \ 2727 | MPPP_UNPACK_ARRAY_N MPPP_EXPAND((n, *value, __VA_ARGS__)); \ 2728 | } 2729 | 2730 | #pragma endregion 2731 | 2732 | #define MPPP_ARRAY_SERIALIZER(TYPE, n, ...) \ 2733 | namespace msgpackpp { \ 2734 | MPPP_PACK_ARRAY_TYPE MPPP_EXPAND((TYPE, n, \ 2735 | __VA_ARGS__)) MPPP_UNPACK_ARRAY_TYPE \ 2736 | MPPP_EXPAND((TYPE, n, __VA_ARGS__)) \ 2737 | } 2738 | 2739 | // RPC request 2740 | namespace msgpackpp { 2741 | template 2742 | std::vector make_rpc_request(int id, const std::string &method, 2743 | AS... args) { 2744 | packer packer; 2745 | packer.pack_array(4); 2746 | packer << 0; // request type 2747 | packer << id; 2748 | packer << method; 2749 | packer << std::make_tuple(args...); 2750 | return packer.get_payload(); 2751 | } 2752 | 2753 | template 2754 | std::vector make_rpc_response(int id, const std::string &error, 2755 | A result) { 2756 | packer packer; 2757 | packer.pack_array(4); 2758 | packer << 1; // response type 2759 | packer << id; 2760 | packer << error; 2761 | packer << result; 2762 | return packer.get_payload(); 2763 | } 2764 | 2765 | inline std::vector 2766 | make_rpc_response_packed(int id, const std::string &error, 2767 | const bytes &packed) { 2768 | packer packer; 2769 | packer.pack_array(4); 2770 | packer << 1; // response type 2771 | packer << id; 2772 | packer << error; 2773 | packer.push(packed); 2774 | return packer.get_payload(); 2775 | } 2776 | 2777 | template 2778 | std::vector make_rpc_notify(const std::string &method, 2779 | AS... args) { 2780 | packer packer; 2781 | packer.pack_array(3); 2782 | packer << 2; // notify type 2783 | packer << method; 2784 | packer << std::make_tuple(args...); 2785 | return packer.get_payload(); 2786 | } 2787 | 2788 | inline std::vector 2789 | make_rpc_notify_packed(const std::string &method, const bytes &packed) { 2790 | packer packer; 2791 | packer.pack_array(3); 2792 | packer << 2; // notify type 2793 | packer << method; 2794 | packer.push(packed); 2795 | return packer.get_payload(); 2796 | } 2797 | 2798 | } // namespace msgpackpp 2799 | 2800 | #pragma warning(pop) 2801 | -------------------------------------------------------------------------------- /msgpackpp/include/msgpackpp/rpc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "msgpackpp.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace msgpackpp { 12 | 13 | using on_read_t = std::function; 14 | 15 | inline std::future connect_async(asio::ip::tcp::socket &socket, 16 | const asio::ip::tcp::endpoint &ep) { 17 | std::promise p1; 18 | auto f1 = p1.get_future(); 19 | // asio::ip::tcp::socket socket(context); 20 | socket.async_connect(ep, [p1 = std::move(p1)](asio::error_code ec) mutable { 21 | p1.set_value(); 22 | }); 23 | return f1; 24 | } 25 | 26 | class server { 27 | ::asio::io_service &m_io_service; 28 | ::asio::ip::tcp::acceptor m_acceptor; 29 | 30 | using on_accepted_t = std::function; 31 | on_accepted_t m_on_accepted; 32 | 33 | public: 34 | server(::asio::io_service &io_service) 35 | : m_io_service(io_service), m_acceptor(io_service) {} 36 | 37 | server(::asio::io_service &io_service, on_accepted_t on_accepted) 38 | : m_io_service(io_service), m_acceptor(io_service), 39 | m_on_accepted(on_accepted) {} 40 | 41 | ~server() {} 42 | 43 | void set_on_accepted(on_accepted_t on_accepted) { 44 | m_on_accepted = on_accepted; 45 | } 46 | 47 | void listen(::asio::ip::tcp::endpoint endpoint) { 48 | m_acceptor.open(endpoint.protocol()); 49 | m_acceptor.bind(endpoint); 50 | m_acceptor.listen(); 51 | start_accept(); 52 | } 53 | 54 | void stop() { m_acceptor.close(); } 55 | 56 | private: 57 | void start_accept() { 58 | auto on_accept = [self = this](const ::asio::error_code &error, 59 | asio::ip::tcp::socket socket) { 60 | if (error) { 61 | throw error; 62 | } else { 63 | if (!self->m_on_accepted) { 64 | throw std::runtime_error("m_on_accepted"); 65 | } 66 | self->m_on_accepted(std::move(socket)); 67 | } 68 | // next 69 | self->start_accept(); 70 | }; 71 | m_acceptor.async_accept(on_accept); 72 | } 73 | }; 74 | 75 | class SocketTransport { 76 | asio::ip::tcp::socket m_socket; 77 | std::vector m_buf; 78 | 79 | public: 80 | SocketTransport(asio::ip::tcp::socket socket) 81 | : m_socket(std::move(socket)), m_buf(1024) {} 82 | 83 | void start_read(const on_read_t &callback) { 84 | auto on_read = [self = this, callback](const uint8_t *p, 85 | size_t bytes_transferred) { 86 | if (!p) { 87 | return; 88 | } else { 89 | assert(bytes_transferred); 90 | callback(p, bytes_transferred); 91 | // read loop 92 | self->start_read(callback); 93 | } 94 | }; 95 | read_async(on_read); 96 | } 97 | 98 | private: 99 | void read_async( 100 | const std::function &callback) { 101 | asio::async_read(m_socket, asio::buffer(m_buf), asio::transfer_at_least(1), 102 | [self = this, callback](asio::error_code ec, size_t size) { 103 | if (ec) { 104 | callback(nullptr, 0); 105 | } else { 106 | callback(self->m_buf.data(), size); 107 | } 108 | }); 109 | } 110 | 111 | public: 112 | void write_async(const std::vector &bytes) { 113 | auto p = std::make_shared>(); 114 | *p = bytes; 115 | 116 | asio::async_write(m_socket, asio::buffer(*p), 117 | [p /*keep*/](asio::error_code ec, size_t size) { 118 | // 119 | }); 120 | } 121 | }; 122 | 123 | template 124 | class session : public std::enable_shared_from_this> { 125 | Transport m_transport; 126 | 127 | // force shard_ptr 128 | session(Transport transport) : m_transport(std::move(transport)) {} 129 | 130 | public: 131 | ~session() {} 132 | 133 | template 134 | static std::shared_ptr> create(T t, on_read_t func = on_read_t()) { 135 | auto s = std::shared_ptr>(new session(std::move(t))); 136 | s->m_transport.start_read(func); 137 | return s; 138 | } 139 | 140 | Transport &transport() { return m_transport; } 141 | 142 | public: 143 | void write_async(const std::vector &buffer) { 144 | m_transport.write_async(buffer); 145 | } 146 | }; 147 | 148 | class func_call_error : public std::runtime_error { 149 | public: 150 | func_call_error(const std::string &msg) : std::runtime_error(msg) {} 151 | }; 152 | 153 | class func_call { 154 | public: 155 | enum STATUS_TYPE { 156 | STATUS_WAIT, 157 | STATUS_RECEIVED, 158 | STATUS_ERROR, 159 | }; 160 | 161 | private: 162 | STATUS_TYPE m_status; 163 | msgpackpp::bytes m_error; 164 | msgpackpp::bytes m_result; 165 | std::string m_request; 166 | std::mutex m_mutex; 167 | std::condition_variable_any m_cond; 168 | 169 | using on_result_func = std::function; 170 | on_result_func m_callback; 171 | 172 | public: 173 | func_call(const std::string &s, const on_result_func &callback) 174 | : m_status(STATUS_WAIT), m_request(s), m_callback(callback) {} 175 | 176 | void set_result(const msgpackpp::parser &result) { 177 | if (m_status != STATUS_WAIT) { 178 | throw func_call_error("already finishded"); 179 | } 180 | std::lock_guard lock(m_mutex); 181 | m_status = STATUS_RECEIVED; 182 | m_result = result.copy_bytes(); 183 | notify(); 184 | } 185 | 186 | void set_error(const msgpackpp::parser &error) { 187 | if (m_status != STATUS_WAIT) { 188 | throw func_call_error("already finishded"); 189 | } 190 | std::lock_guard lock(m_mutex); 191 | m_status = STATUS_ERROR; 192 | m_error = error.copy_bytes(); 193 | notify(); 194 | } 195 | 196 | bool is_error() const { return m_status == STATUS_ERROR; } 197 | 198 | // blocking 199 | func_call &sync() { 200 | std::lock_guard lock(m_mutex); 201 | if (m_status == STATUS_WAIT) { 202 | m_cond.wait(m_mutex); 203 | } 204 | return *this; 205 | } 206 | 207 | const msgpackpp::bytes &get_result() const { 208 | if (m_status == STATUS_RECEIVED) { 209 | return m_result; 210 | } else { 211 | throw func_call_error("not ready"); 212 | } 213 | } 214 | 215 | std::string string() const { 216 | std::stringstream ss; 217 | ss << m_request << " = "; 218 | switch (m_status) { 219 | case func_call::STATUS_WAIT: 220 | ss << "?"; 221 | break; 222 | case func_call::STATUS_RECEIVED: 223 | ss << msgpackpp::parser(m_result); 224 | break; 225 | case func_call::STATUS_ERROR: 226 | ss << "!"; 227 | break; 228 | default: 229 | ss << "!?"; 230 | break; 231 | } 232 | 233 | return ss.str(); 234 | } 235 | 236 | private: 237 | void notify() { 238 | if (m_callback) { 239 | m_callback(this); 240 | } 241 | m_cond.notify_all(); 242 | } 243 | }; 244 | 245 | inline std::ostream &operator<<(std::ostream &os, const func_call &request) { 246 | os << request.string(); 247 | return os; 248 | } 249 | 250 | enum class rpc_errors { 251 | success, 252 | stream_error, 253 | error_dispatcher_no_handler, 254 | error_params_not_array, 255 | error_params_too_many, 256 | error_params_not_enough, 257 | error_params_convert, 258 | error_not_implemented, 259 | error_self_pointer_is_null, 260 | no_request_for_response, 261 | invalid_format, 262 | }; 263 | 264 | using rpc_scope = status_scope; 265 | template using rpc_result = rpc_scope::result; 266 | 267 | template class rpc_base { 268 | std::shared_ptr> m_session; 269 | 270 | // request 271 | std::unordered_map m_handlerMap; 272 | int m_next_msg_id = 1; 273 | 274 | // response 275 | std::vector m_read_buffer; 276 | std::unordered_map> m_request_map; 277 | 278 | // using on_error_t = std::function; 279 | // on_error_t m_on_error = [](error_code) {}; 280 | 281 | using on_send_t = std::function &data)>; 282 | on_send_t m_on_send = [](const std::vector &data) {}; 283 | 284 | using on_msg_t = std::function; 285 | on_msg_t m_on_msg = [](const msgpackpp::parser &msg) {}; 286 | 287 | using on_rpc_error_t = 288 | std::function; 289 | on_rpc_error_t m_on_rpc_error = [](auto, auto) {}; 290 | 291 | public: 292 | // void set_on_error(const on_error_t &on_error) { m_on_error = on_error; } 293 | void set_on_rpc_error(const on_rpc_error_t &callback) { 294 | m_on_rpc_error = callback; 295 | } 296 | 297 | void set_on_send(const on_send_t &on_send) { m_on_send = on_send; } 298 | 299 | void set_on_msg(const on_msg_t &on_msg) { m_on_msg = on_msg; } 300 | 301 | void attach(Transport t) { 302 | // start socket read 303 | m_session = msgpackpp::session::create( 304 | std::move(t), [self = this](const uint8_t *data, size_t size) mutable { 305 | self->on_receive(data, size); 306 | }); 307 | } 308 | 309 | std::shared_ptr> session() const { return m_session; } 310 | 311 | public: 312 | void add_proc(const std::string &method, 313 | const msgpackpp::procedurecall &proc) { 314 | m_handlerMap.insert(std::make_pair(method, proc)); 315 | } 316 | 317 | template 318 | void add_handler(const std::string &method, const F &f) { 319 | auto proc = msgpackpp::make_procedurecall(f); 320 | m_handlerMap.insert(std::make_pair(method, proc)); 321 | } 322 | 323 | template 324 | void add_bind(const std::string &method, C *c, R (C::*f)(AS...)) { 325 | auto proc = msgpackpp::make_methodcall(c, f); 326 | m_handlerMap.insert(std::make_pair(method, proc)); 327 | } 328 | 329 | void on_receive(const uint8_t *data, size_t size) noexcept { 330 | std::copy(data, data + size, std::back_inserter(m_read_buffer)); 331 | 332 | auto msg = 333 | msgpackpp::parser(m_read_buffer.data(), (int)m_read_buffer.size()); 334 | while (true) { 335 | auto current = msg; 336 | auto _msg = msg.next(); 337 | if (_msg.is_ok()) { 338 | msg = _msg; 339 | auto result = on_message(current); 340 | if (!result.is_ok()) { 341 | m_on_rpc_error(result.status, msg); 342 | } 343 | } else { 344 | if (_msg.status == parse_status::empty || 345 | _msg.status == parse_status::lack) { 346 | // next 347 | break; 348 | } else { 349 | m_on_rpc_error(rpc_errors::stream_error, {}); 350 | } 351 | } 352 | } 353 | auto d = msg.data() - m_read_buffer.data(); 354 | if (d) { 355 | m_read_buffer.erase(m_read_buffer.begin(), m_read_buffer.begin() + d); 356 | } 357 | } 358 | 359 | private: 360 | rpc_result on_message(const msgpackpp::parser &msg) noexcept { 361 | // logger 362 | m_on_msg(msg); 363 | 364 | if (!msg.is_array()) { 365 | return {rpc_errors::invalid_format}; 366 | } 367 | if (!msg[0].is_number()) { 368 | return {rpc_errors::invalid_format}; 369 | } 370 | auto type = msg[0].get_number(); 371 | switch (type) { 372 | case 0: { 373 | // request [0, id, method, args] 374 | if (msg.count() != 4) { 375 | return {rpc_errors::invalid_format}; 376 | } 377 | auto id = msg[1].get_number(); 378 | auto method = msg[2].get_string(); 379 | // execute callback 380 | auto result = dispatch(std::string(method.begin(), method.end()), msg[3]); 381 | if (result.is_ok()) { 382 | auto response = msgpackpp::make_rpc_response_packed(id, "", result); 383 | write_async(response); 384 | } else { 385 | m_on_rpc_error(result.status, msg); 386 | } 387 | return rpc_scope::OK(true); 388 | } 389 | 390 | case 2: { 391 | // response [2, method, args] 392 | if (msg.count() != 3) { 393 | return {rpc_errors::invalid_format}; 394 | } 395 | 396 | auto method = msg[1].get_string(); 397 | // execute callback. no return value 398 | auto result = dispatch(std::string(method.begin(), method.end()), msg[2]); 399 | if (!result.is_ok()) { 400 | m_on_rpc_error(result.status, msg); 401 | } 402 | return rpc_scope::OK(true); 403 | } 404 | 405 | case 1: { 406 | // response [1, id, error, result] 407 | if (msg.count() != 4) { 408 | return {rpc_errors::invalid_format}; 409 | } 410 | auto id = msg[1].get_number(); 411 | if (id == 0) { 412 | // error message 413 | m_on_rpc_error(rpc_errors::invalid_format, msg); 414 | } else { 415 | auto found = m_request_map.find(id); 416 | if (found != m_request_map.end()) { 417 | if (msg[2].is_nil() || 418 | msg[2].is_string() && msg[2].get_string() == "") { 419 | found->second->set_result(msg[3]); 420 | } else { 421 | found->second->set_error(msg[2]); 422 | } 423 | } else { 424 | m_on_rpc_error(rpc_errors::no_request_for_response, msg); 425 | } 426 | } 427 | return rpc_scope::OK(true); 428 | } 429 | 430 | default: { 431 | return {rpc_errors::invalid_format}; 432 | } 433 | } 434 | } 435 | 436 | public: 437 | rpc_result dispatch(const std::string &method_name, 438 | const msgpackpp::parser ¶ms) { 439 | auto found = m_handlerMap.find(method_name); 440 | if (found == m_handlerMap.end()) { 441 | return {rpc_errors::error_dispatcher_no_handler}; 442 | } 443 | 444 | auto func = found->second; 445 | return rpc_scope::OK(func(params)); 446 | } 447 | 448 | public: 449 | template 450 | std::future> request_async(const std::string &method, 451 | ARGS... args) { 452 | auto p = std::make_shared>>(); 453 | auto f = p->get_future(); 454 | 455 | auto message = 456 | msgpackpp::make_rpc_request(m_next_msg_id++, method, args...); 457 | send_request_async(message, p); 458 | 459 | return f; 460 | } 461 | 462 | template 463 | void notify(const std::string &method, ARGS... args) { 464 | auto message = msgpackpp::make_rpc_notify(method, args...); 465 | write_async(message); 466 | } 467 | 468 | void notify_raw(const std::string &method, const msgpackpp::bytes &raw) { 469 | auto message = msgpackpp::make_rpc_notify_packed(method, raw); 470 | write_async(message); 471 | } 472 | 473 | void write_async(const std::vector &data) { 474 | m_on_send(data); 475 | m_session->write_async(data); 476 | } 477 | 478 | private: 479 | void 480 | send_request_async(const msgpackpp::bytes &mesage, 481 | std::shared_ptr>> p) { 482 | auto parsed = msgpackpp::parser(mesage); 483 | auto req = std::make_shared( 484 | parsed.to_json(), [p](func_call *f) mutable { 485 | if (f->is_error()) { 486 | std::exception_ptr ep = std::current_exception(); 487 | p->set_exception(ep); 488 | } else { 489 | p->set_value(f->get_result()); 490 | } 491 | }); 492 | m_request_map.insert(std::make_pair(parsed[1].get_number(), req)); 493 | write_async(mesage); 494 | } 495 | }; 496 | using rpc = rpc_base; 497 | 498 | } // namespace msgpackpp 499 | -------------------------------------------------------------------------------- /msgpackpp/include/msgpackpp/windows_pipe_transport.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace msgpackpp { 5 | 6 | class WindowsPipeTransport { 7 | asio::io_context &m_context; 8 | HANDLE m_reader; 9 | HANDLE m_writer; 10 | std::thread m_thread; 11 | 12 | public: 13 | WindowsPipeTransport(WindowsPipeTransport &&rhs) : m_context(rhs.m_context) { 14 | m_reader = rhs.m_reader; 15 | rhs.m_reader = nullptr; 16 | m_writer = rhs.m_writer; 17 | rhs.m_writer = nullptr; 18 | m_thread = std::move(rhs.m_thread); 19 | rhs.m_thread = {}; 20 | } 21 | WindowsPipeTransport(asio::io_context &context, HANDLE reader, HANDLE writer) 22 | : m_context(context), m_reader(reader), m_writer(writer) {} 23 | 24 | ~WindowsPipeTransport() { 25 | if (m_thread.joinable()) { 26 | CancelSynchronousIo(m_thread.native_handle()); 27 | m_thread.join(); 28 | } 29 | } 30 | 31 | void start_read( 32 | const std::function &callback) { 33 | 34 | assert(!m_thread.joinable()); 35 | 36 | m_thread = std::thread([self = this, callback]() { 37 | char buf[1024]; 38 | while (true) { 39 | DWORD bytes_read; 40 | BOOL success = 41 | ReadFile(self->m_reader, buf, static_cast(sizeof(buf)), 42 | &bytes_read, nullptr); 43 | if (success && bytes_read) { 44 | // execute on asio_context 45 | auto copy = std::vector(buf, buf + bytes_read); 46 | self->m_context.post( 47 | [callback, copy]() { callback(copy.data(), copy.size()); }); 48 | } else { 49 | // execute on asio_context 50 | self->m_context.post([callback]() { callback(nullptr, 0); }); 51 | break; 52 | } 53 | } 54 | }); 55 | } 56 | 57 | void write_async(const std::vector &bytes) { 58 | DWORD bytes_write; 59 | BOOL success = 60 | WriteFile(m_writer, bytes.data(), static_cast(bytes.size()), 61 | &bytes_write, nullptr); 62 | if (!success) { 63 | auto error = GetLastError(); 64 | } 65 | } 66 | }; 67 | 68 | } // namespace msgpackpp -------------------------------------------------------------------------------- /samples_cpp17/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | subdirs(basic cpp17_dispatcher cpp17_nvim) 2 | -------------------------------------------------------------------------------- /samples_cpp17/basic/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(basic basic.cpp) 2 | target_link_libraries(basic PRIVATE msgpackpp) 3 | -------------------------------------------------------------------------------- /samples_cpp17/basic/basic.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(int argc, char **argv) { 5 | // pack 6 | msgpackpp::packer packer; 7 | packer.pack_array(4); 8 | packer.pack_integer(0); 9 | packer.pack_integer(256); 10 | packer.pack_str("method"); 11 | packer.pack_map(3); 12 | packer.pack_str("x"); 13 | packer.pack_float(1.0f); 14 | packer.pack_str("y"); 15 | packer.pack_float(2.0f); 16 | packer.pack_str("z"); 17 | packer.pack_float(3.0f); 18 | 19 | // std::vector 20 | auto p = packer.get_payload(); 21 | 22 | // parse 23 | auto u = msgpackpp::parser(p); 24 | std::cout << u << std::endl; // json style for debug 25 | 26 | std::cout << u.is_array() << std::endl; 27 | std::cout << u[0].get_number() << std::endl; 28 | std::cout << u[1].get_number() << std::endl; 29 | std::cout << u[2].get_string() << std::endl; 30 | std::cout << u[3].is_map() << std::endl; 31 | std::cout << u[3]["x"].get_number() << std::endl; 32 | std::cout << u[3]["y"].get_number() << std::endl; 33 | std::cout << u[3]["z"].get_number() << std::endl; 34 | 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /samples_cpp17/cpp17_dispatcher/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(TARGET_NAME cpp17_dispatcher) 2 | add_executable(${TARGET_NAME} main.cpp) 3 | set_property(TARGET ${TARGET_NAME} PROPERTY CXX_STANDARD 17) 4 | target_link_libraries(${TARGET_NAME} PRIVATE asio msgpackpp) 5 | -------------------------------------------------------------------------------- /samples_cpp17/cpp17_dispatcher/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | const auto PORT = 8070; 5 | 6 | int client(asio::io_context &context, asio::ip::tcp::endpoint ep) { 7 | asio::io_context::work work(context); 8 | std::thread client_thread([&context]() { 9 | context.run(); 10 | std::cout << "[client]exit" << std::endl; 11 | }); 12 | 13 | // connect 14 | asio::ip::tcp::socket socket(context); 15 | msgpackpp::connect_async(socket, ep).get(); 16 | std::cout << "[client]connected" << std::endl; 17 | 18 | // client 19 | msgpackpp::rpc client; 20 | client.attach(std::move(socket)); 21 | auto result = client.request_async("add", 1, 2).get(); 22 | 23 | // stop 24 | context.stop(); 25 | client_thread.join(); 26 | 27 | // deserialize 28 | int value; 29 | msgpackpp::parser(result) >> value; 30 | 31 | return value; 32 | } 33 | 34 | int main(int argc, char **argv) { 35 | 36 | auto ep = asio::ip::tcp::endpoint(asio::ip::address::from_string("127.0.0.1"), 37 | PORT); 38 | 39 | // server rpc 40 | msgpackpp::rpc dispatcher; 41 | dispatcher.add_handler("add", [](int a, int b) { return a + b; }); 42 | 43 | // server 44 | asio::io_context server_context; 45 | msgpackpp::server server( 46 | server_context, [&dispatcher](asio::ip::tcp::socket socket) mutable { 47 | dispatcher.attach(std::move(socket)); 48 | }); 49 | server.listen(ep); 50 | std::thread server_thread([&server_context]() { server_context.run(); }); 51 | 52 | // client 53 | asio::io_context client_context; 54 | auto result = client(client_context, ep); 55 | std::cout << "result = " << result << std::endl; 56 | 57 | // stop asio 58 | server_context.stop(); 59 | server_thread.join(); 60 | std::cout << "[server]join" << std::endl; 61 | 62 | return 0; 63 | } 64 | -------------------------------------------------------------------------------- /samples_cpp17/cpp17_nvim/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(TARGET_NAME cpp17_nvim) 2 | add_executable(${TARGET_NAME} main.cpp) 3 | set_property(TARGET ${TARGET_NAME} PROPERTY CXX_STANDARD 17) 4 | target_link_libraries(${TARGET_NAME} msgpackpp asio) 5 | -------------------------------------------------------------------------------- /samples_cpp17/cpp17_nvim/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | class Nvim { 6 | HANDLE _stdin_read = nullptr; 7 | HANDLE _stdin_write = nullptr; 8 | HANDLE _stdout_read = nullptr; 9 | HANDLE _stdout_write = nullptr; 10 | PROCESS_INFORMATION _process_info = {0}; 11 | 12 | std::wstring m_command; 13 | 14 | Nvim(const wchar_t *command) : m_command(command) { 15 | SECURITY_ATTRIBUTES sec_attribs = {0}; 16 | sec_attribs.nLength = sizeof(SECURITY_ATTRIBUTES); 17 | sec_attribs.bInheritHandle = true; 18 | CreatePipe(&this->_stdin_read, &this->_stdin_write, &sec_attribs, 0); 19 | CreatePipe(&this->_stdout_read, &this->_stdout_write, &sec_attribs, 0); 20 | } 21 | 22 | public: 23 | ~Nvim() { 24 | 25 | DWORD exit_code; 26 | GetExitCodeProcess(_process_info.hProcess, &exit_code); 27 | if (exit_code == STILL_ACTIVE) { 28 | CloseHandle(ReadHandle()); 29 | CloseHandle(WriteHandle()); 30 | TerminateProcess(this->_process_info.hProcess, 0); 31 | CloseHandle(this->_process_info.hProcess); 32 | } 33 | } 34 | 35 | wchar_t *Command() { return m_command.data(); } 36 | HANDLE ReadHandle() const { return _stdout_read; } 37 | HANDLE WriteHandle() const { return _stdin_write; } 38 | 39 | static std::shared_ptr Launch(const wchar_t *command) { 40 | 41 | auto nvim = std::shared_ptr(new Nvim(command)); 42 | if (nvim->_stdin_write == INVALID_HANDLE_VALUE) { 43 | return nullptr; 44 | } 45 | 46 | STARTUPINFOW startup_info = {0}; 47 | startup_info.cb = sizeof(STARTUPINFO); 48 | startup_info.dwFlags = STARTF_USESTDHANDLES; 49 | startup_info.hStdInput = nvim->_stdin_read; 50 | startup_info.hStdOutput = nvim->_stdout_write; 51 | startup_info.hStdError = nvim->_stdout_write; 52 | 53 | if (!CreateProcessW(nullptr, nvim->Command(), nullptr, nullptr, true, 54 | CREATE_NO_WINDOW, nullptr, nullptr, &startup_info, 55 | &nvim->_process_info)) { 56 | return nullptr; 57 | } 58 | 59 | HANDLE job_object = CreateJobObjectW(nullptr, nullptr); 60 | JOBOBJECT_EXTENDED_LIMIT_INFORMATION job_info = {0}; 61 | job_info.BasicLimitInformation.LimitFlags = 62 | JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; 63 | SetInformationJobObject(job_object, JobObjectExtendedLimitInformation, 64 | &job_info, sizeof(job_info)); 65 | AssignProcessToJobObject(job_object, nvim->_process_info.hProcess); 66 | 67 | return nvim; 68 | } 69 | }; 70 | 71 | int main(int argc, char **argv) { 72 | 73 | auto nvim = Nvim::Launch(L"nvim --embed"); 74 | if (!nvim) { 75 | return 1; 76 | } 77 | 78 | asio::io_context context; 79 | asio::io_context::work work(context); 80 | std::thread context_thead([&context]() { context.run(); }); 81 | 82 | msgpackpp::rpc_base rpc; 83 | 84 | rpc.set_on_msg([](auto p) { 85 | // 86 | std::cout << p << std::endl; 87 | }); 88 | rpc.set_on_send([](const std::vector &p) { 89 | std::cout << msgpackpp::parser(p) << std::endl; 90 | }); 91 | 92 | rpc.attach(msgpackpp::WindowsPipeTransport(context, nvim->ReadHandle(), 93 | nvim->WriteHandle())); 94 | 95 | { 96 | auto result = rpc.request_async("nvim_get_api_info").get(); 97 | std::cout << msgpackpp::parser(result) << std::endl; 98 | } 99 | 100 | { rpc.notify("nvim_set_var", "nvy", 1); } 101 | 102 | { 103 | auto result = rpc.request_async("nvim_eval", "stdpath('config')").get(); 104 | std::cout << msgpackpp::parser(result) << std::endl; 105 | } 106 | 107 | { 108 | msgpackpp::packer args; 109 | args.pack_array(3); 110 | args << 190; 111 | args << 45; 112 | args.pack_map(1); 113 | args << "ext_linegrid" << true; 114 | rpc.notify_raw("nvim_ui_attach", args.get_payload()); 115 | } 116 | 117 | context.stop(); 118 | context_thead.join(); 119 | 120 | return 0; 121 | } 122 | -------------------------------------------------------------------------------- /samples_cpp20/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | subdirs(cpp20_pingpong cpp20_dispatch) 2 | -------------------------------------------------------------------------------- /samples_cpp20/cpp20_dispatch/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(TARGET_NAME cpp20_dispatch) 2 | add_executable(${TARGET_NAME} main.cpp) 3 | set_property(TARGET ${TARGET_NAME} PROPERTY CXX_STANDARD 20) 4 | target_compile_options(${TARGET_NAME} PUBLIC $<$:/await>) 5 | target_compile_definitions(${TARGET_NAME} PRIVATE ASIO_DISABLE_STD_COROUTINE) 6 | target_link_libraries(${TARGET_NAME} PRIVATE asio msgpackpp) 7 | -------------------------------------------------------------------------------- /samples_cpp20/cpp20_dispatch/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | const auto PORT = 8070; 8 | 9 | asio::awaitable client(asio::io_context &context, 10 | asio::ip::tcp::endpoint ep) { 11 | 12 | // auto client = co_await msgpackpp::client::connect_awaitable(context, ep); 13 | 14 | // // client 15 | // asio::io_context client_io; 16 | // msgpackpp::client client(client_io); 17 | // // asio::io_context::work work(client_io); 18 | // std::thread client_thread([&client_io]() { 19 | // client_io.run(); 20 | // std::cout << "[client]exit" << std::endl; 21 | // }); 22 | 23 | // std::cout << "[client]connect: " << ep << "..." << std::endl; 24 | // client 25 | // .connect_async(asio::ip::tcp::endpoint( 26 | // asio::ip::address::from_string("127.0.0.1"), PORT)) 27 | // .get(); 28 | // std::cout << "[client]connected" << std::endl; 29 | 30 | // auto result = client.call("add", 1, 2).get(); 31 | 32 | // client_io.stop(); 33 | // client_thread.join(); 34 | 35 | // co_return result; 36 | 37 | co_return 1; 38 | } 39 | 40 | int main(int argc, char **argv) { 41 | 42 | auto ep = asio::ip::tcp::endpoint(asio::ip::address::from_string("127.0.0.1"), 43 | PORT); 44 | 45 | // server rpc 46 | msgpackpp::rpc dispatcher; 47 | dispatcher.add_handler("add", [](int a, int b) { return a + b; }); 48 | 49 | // server 50 | asio::io_context server_context; 51 | msgpackpp::server server(server_context, 52 | [&dispatcher](asio::ip::tcp::socket socket) { 53 | dispatcher.attach(std::move(socket)); 54 | }); 55 | server.listen(ep); 56 | std::thread server_thread([&server_context]() { server_context.run(); }); 57 | 58 | // client 59 | asio::io_context client_context; 60 | auto result = asio::co_spawn(client_context.get_executor(), 61 | client(client_context, ep), asio::use_future); 62 | std::cout << "result = " << result.get() << std::endl; 63 | 64 | // stop asio 65 | server_context.stop(); 66 | server_thread.join(); 67 | std::cout << "[server]join" << std::endl; 68 | 69 | return 0; 70 | } 71 | -------------------------------------------------------------------------------- /samples_cpp20/cpp20_pingpong/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(TARGET_NAME cpp20_pingpong) 2 | add_executable(${TARGET_NAME} main.cpp) 3 | set_property(TARGET ${TARGET_NAME} PROPERTY CXX_STANDARD 20) 4 | target_compile_options(${TARGET_NAME} PUBLIC $<$:/await>) 5 | target_compile_definitions(${TARGET_NAME} PRIVATE ASIO_DISABLE_STD_COROUTINE) 6 | target_link_libraries(${TARGET_NAME} PRIVATE asio) 7 | -------------------------------------------------------------------------------- /samples_cpp20/cpp20_pingpong/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | const auto PORT = 8070; 20 | 21 | constexpr auto use_nothrow_awaitable = 22 | asio::experimental::as_tuple(asio::use_awaitable); 23 | 24 | static std::string to_string(const asio::streambuf &buf) { 25 | auto p = asio::buffer_cast(buf.data()); 26 | return std::string(p, p + buf.size()); 27 | } 28 | 29 | class server { 30 | asio::io_context &_context; 31 | asio::ip::tcp::acceptor _acceptor; 32 | 33 | public: 34 | server(asio::io_context &context) : _context(context), _acceptor(context) {} 35 | ~server() {} 36 | 37 | void listen(const asio::ip::tcp::endpoint &ep) { 38 | std::cout << "[server]listen: " << ep << "..." << std::endl; 39 | _acceptor.open(ep.protocol()); 40 | _acceptor.bind(ep); 41 | _acceptor.listen(); 42 | 43 | auto ex = _context.get_executor(); 44 | asio::co_spawn(ex, accept_loop(), asio::detached); 45 | } 46 | 47 | asio::awaitable accept_loop() { 48 | 49 | while (true) { 50 | 51 | auto [e, socket] = co_await _acceptor.async_accept(use_nothrow_awaitable); 52 | if (e) { 53 | std::cout << "[server]accept error: " << e << std::endl; 54 | break; 55 | } 56 | std::cout << "[server]accepted" << std::endl; 57 | 58 | auto ex = _context.get_executor(); 59 | asio::co_spawn(ex, session(std::move(socket)), asio::detached); 60 | } 61 | } 62 | 63 | asio::awaitable session(asio::ip::tcp::socket socket) { 64 | 65 | asio::streambuf buf; 66 | auto [e1, read_size] = co_await asio::async_read( 67 | socket, buf, asio::transfer_at_least(1), use_nothrow_awaitable); 68 | 69 | auto pong = to_string(buf); 70 | std::cout << "[server]ping: " << pong << std::endl; 71 | pong += "pong"; 72 | auto [e2, write_size] = co_await asio::async_write( 73 | socket, asio::buffer(pong), use_nothrow_awaitable); 74 | std::cout << "[server]pong: " << write_size << std::endl; 75 | } 76 | }; 77 | 78 | asio::awaitable client(asio::io_context &context, 79 | asio::ip::tcp::endpoint ep) { 80 | using namespace std::literals::chrono_literals; 81 | 82 | std::cout << "[client]wait 1000ms..." << std::endl; 83 | asio::system_timer timer(context); 84 | timer.expires_from_now(1000ms); 85 | co_await timer.async_wait(asio::use_awaitable); 86 | 87 | std::cout << "[client]connect: " << ep << "..." << std::endl; 88 | asio::ip::tcp::socket socket(context); 89 | co_await socket.async_connect(ep, asio::use_awaitable); 90 | std::cout << "[client]connected" << std::endl; 91 | 92 | std::cout << "[client]ping..." << std::endl; 93 | std::string ping("ping"); 94 | auto write_size = co_await asio::async_write(socket, asio::buffer(ping), 95 | asio::use_awaitable); 96 | assert(write_size == 4); 97 | 98 | std::cout << "[client]read..." << std::endl; 99 | asio::streambuf buf; 100 | auto read_size = co_await asio::async_read( 101 | socket, buf, asio::transfer_at_least(1), asio::use_awaitable); 102 | co_return to_string(buf); 103 | } 104 | 105 | int main(int argc, char **argv) { 106 | 107 | auto ep = asio::ip::tcp::endpoint(asio::ip::address::from_string("127.0.0.1"), 108 | PORT); 109 | 110 | // server 111 | asio::io_context server_context; 112 | server server(server_context); 113 | server.listen(ep); 114 | std::thread server_thread([&server_context]() { server_context.run(); }); 115 | 116 | // client 117 | asio::io_context client_context; 118 | auto co = std::bind(&client, std::ref(client_context), ep); 119 | auto result = 120 | asio::co_spawn(client_context.get_executor(), co, asio::use_future); 121 | client_context.run(); 122 | auto pong = result.get(); 123 | std::cout << "pong: " << pong << std::endl; 124 | 125 | // stop asio 126 | server_context.stop(); 127 | server_thread.join(); 128 | std::cout << "[server]join" << std::endl; 129 | 130 | return 0; 131 | } 132 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(TARGET_NAME test) 2 | add_executable( 3 | ${TARGET_NAME} 4 | main.cpp 5 | # msgpack 6 | msgpack.cpp 7 | serialize.cpp 8 | rpc.cpp 9 | stream.cpp 10 | request.cpp 11 | # rpc 12 | call.cpp 13 | client.cpp 14 | dispatcher.cpp 15 | error.cpp 16 | pipeline.cpp) 17 | set_property(TARGET ${TARGET_NAME} PROPERTY CXX_STANDARD 17) 18 | 19 | target_link_libraries(${TARGET_NAME} PRIVATE catch msgpackpp asio) 20 | -------------------------------------------------------------------------------- /test/call.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "fixture.h" 4 | #include 5 | 6 | TEST_CASE("func0") { 7 | const static int PORT = 8070; 8 | 9 | Fixture f(PORT); 10 | 11 | // client 12 | asio::io_service client_io; 13 | asio::io_context::work work(client_io); 14 | asio::ip::tcp::socket socket(client_io); 15 | std::thread client_thread([&client_io]() { client_io.run(); }); 16 | msgpackpp::connect_async( 17 | socket, asio::ip::tcp::endpoint( 18 | ::asio::ip::address::from_string("127.0.0.1"), PORT)) 19 | .get(); 20 | 21 | // request 22 | msgpackpp::rpc client; 23 | client.attach(std::move(socket)); 24 | REQUIRE(msgpackpp::deserialize(client.request_async("zero").get()) == 0); 25 | 26 | client_io.stop(); 27 | client_thread.join(); 28 | } 29 | 30 | TEST_CASE("func1") { 31 | const static int PORT = 8070; 32 | 33 | Fixture f(PORT); 34 | 35 | // client 36 | asio::io_service client_io; 37 | asio::io_context::work work(client_io); 38 | asio::ip::tcp::socket socket(client_io); 39 | std::thread client_thread([&client_io]() { client_io.run(); }); 40 | msgpackpp::connect_async( 41 | socket, asio::ip::tcp::endpoint( 42 | ::asio::ip::address::from_string("127.0.0.1"), PORT)) 43 | .get(); 44 | 45 | // request 46 | msgpackpp::rpc client; 47 | client.attach(std::move(socket)); 48 | auto req = client.request_async("acc", 1); 49 | req.wait(); 50 | int result = msgpackpp::deserialize(req.get()); 51 | REQUIRE(result == 1); 52 | 53 | client_io.stop(); 54 | client_thread.join(); 55 | } 56 | 57 | TEST_CASE("func2") { 58 | const static int PORT = 8070; 59 | 60 | Fixture f(PORT); 61 | 62 | // client 63 | asio::io_service client_io; 64 | asio::io_context::work work(client_io); 65 | asio::ip::tcp::socket socket(client_io); 66 | std::thread client_thread([&client_io]() { client_io.run(); }); 67 | msgpackpp::connect_async( 68 | socket, asio::ip::tcp::endpoint( 69 | ::asio::ip::address::from_string("127.0.0.1"), PORT)) 70 | .get(); 71 | 72 | // request 73 | msgpackpp::rpc client; 74 | client.attach(std::move(socket)); 75 | REQUIRE(msgpackpp::deserialize(client.request_async("add", 3, 4).get()) == 7); 76 | 77 | client_io.stop(); 78 | client_thread.join(); 79 | } 80 | 81 | TEST_CASE("func3") { 82 | const static int PORT = 8070; 83 | 84 | Fixture f(PORT); 85 | 86 | // client 87 | asio::io_service client_io; 88 | asio::io_context::work work(client_io); 89 | asio::ip::tcp::socket socket(client_io); 90 | std::thread client_thread([&client_io]() { client_io.run(); }); 91 | msgpackpp::connect_async( 92 | socket, asio::ip::tcp::endpoint( 93 | ::asio::ip::address::from_string("127.0.0.1"), PORT)) 94 | .get(); 95 | 96 | // request 97 | msgpackpp::rpc client; 98 | client.attach(std::move(socket)); 99 | REQUIRE(msgpackpp::deserialize(client.request_async("add3", 3, 4, 5).get()) == 100 | 12); 101 | 102 | client_io.stop(); 103 | client_thread.join(); 104 | } 105 | 106 | TEST_CASE("func4") { 107 | const static int PORT = 8070; 108 | 109 | Fixture f(PORT); 110 | 111 | // client 112 | asio::io_service client_io; 113 | asio::io_context::work work(client_io); 114 | asio::ip::tcp::socket socket(client_io); 115 | std::thread client_thread([&client_io]() { client_io.run(); }); 116 | msgpackpp::connect_async( 117 | socket, asio::ip::tcp::endpoint( 118 | ::asio::ip::address::from_string("127.0.0.1"), PORT)) 119 | .get(); 120 | 121 | // request 122 | msgpackpp::rpc client; 123 | client.attach(std::move(socket)); 124 | REQUIRE(msgpackpp::deserialize(client.request_async("add4", 3, 4, 5, 6).get()) == 125 | 18); 126 | 127 | client_io.stop(); 128 | client_thread.join(); 129 | } 130 | -------------------------------------------------------------------------------- /test/client.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | #include "fixture.h" 7 | 8 | TEST_CASE("client") { 9 | const static int PORT = 8070; 10 | 11 | Fixture fixture(PORT); 12 | 13 | // client 14 | asio::io_service client_io; 15 | asio::io_context::work work(client_io); 16 | asio::ip::tcp::socket socket(client_io); 17 | std::thread client_thread([&client_io]() { client_io.run(); }); 18 | msgpackpp::connect_async( 19 | socket, asio::ip::tcp::endpoint( 20 | ::asio::ip::address::from_string("127.0.0.1"), PORT)) 21 | .get(); 22 | 23 | // request 24 | msgpackpp::rpc client; 25 | client.attach(std::move(socket)); 26 | REQUIRE(msgpackpp::deserialize(client.request_async("add", 1, 2).get()) == 3); 27 | 28 | auto request2 = client.request_async("add", 3, 4); 29 | request2.wait(); 30 | int result2 = msgpackpp::deserialize(request2.get()); 31 | REQUIRE(result2 == 7); 32 | 33 | auto request3 = client.request_async("add", 5, 6); 34 | request3.wait(); 35 | int result3 = msgpackpp::deserialize(request3.get()); 36 | REQUIRE(result3 == 11); 37 | 38 | // close 39 | client_io.stop(); 40 | client_thread.join(); 41 | } 42 | -------------------------------------------------------------------------------- /test/dispatcher.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | class Dummy { 7 | public: 8 | bool unary(int a) { return true; } 9 | int binary(int a, int b) { return a + b; } 10 | int func3(int a, int b, int c) { return a + b + c; } 11 | int func4(int a, int b, int c, int d) { return a + b + c + d; } 12 | }; 13 | 14 | // 0 15 | static float zero() { return 0; } 16 | 17 | TEST_CASE("dispatcher0") { 18 | ::asio::io_service io_service; 19 | msgpackpp::rpc dispatcher; 20 | 21 | // function pointer 22 | dispatcher.add_handler("fp", &zero); 23 | 24 | // lambda 25 | dispatcher.add_handler("lambda", []() { return 0; }); 26 | 27 | // std::function 28 | dispatcher.add_handler("std::function", std::function(zero)); 29 | } 30 | 31 | // 1 32 | static bool unary(double n) { return false; } 33 | 34 | TEST_CASE("dispatcher1") { 35 | ::asio::io_service io_service; 36 | msgpackpp::rpc dispatcher; 37 | 38 | // function pointer 39 | dispatcher.add_handler("fp", &unary); 40 | 41 | // lambda 42 | dispatcher.add_handler("lambda", [](int a) { return a; }); 43 | 44 | // std::function 45 | dispatcher.add_handler("std::function", std::function(unary)); 46 | 47 | // std::bind 48 | Dummy d; 49 | dispatcher.add_bind("std::bind", &d, &Dummy::unary); 50 | } 51 | 52 | // 2 53 | static int binary(int a, int b) { return a + b; } 54 | 55 | TEST_CASE("dispatcher2") { 56 | ::asio::io_service io_service; 57 | msgpackpp::rpc dispatcher; 58 | 59 | // function pointer 60 | dispatcher.add_handler("fp", &binary); 61 | 62 | // lambda 63 | dispatcher.add_handler("lambda", [](int a, int b) { return a + b; }); 64 | 65 | // std::function 66 | dispatcher.add_handler("std::function", std::function(binary)); 67 | 68 | // std::bind 69 | Dummy d; 70 | dispatcher.add_bind("std::bind", &d, &Dummy::binary); 71 | } 72 | 73 | // 3 74 | static int func3(int a, int b, int c) { return a + b + c; } 75 | 76 | TEST_CASE("dispatcher3") { 77 | ::asio::io_service io_service; 78 | msgpackpp::rpc dispatcher; 79 | 80 | // function pointer 81 | dispatcher.add_handler("fp", &func3); 82 | 83 | // lambda 84 | dispatcher.add_handler("lambda", 85 | [](int a, int b, int c) { return a + b + c; }); 86 | 87 | // std::function 88 | dispatcher.add_handler("std::function", 89 | std::function(func3)); 90 | 91 | // std::bind 92 | Dummy d; 93 | dispatcher.add_bind("std::bind", &d, &Dummy::func3); 94 | } 95 | 96 | // 4 97 | static int func4(int a, int b, int c, int d) { return a + b + c + d; } 98 | 99 | TEST_CASE("dispatcher4") { 100 | ::asio::io_service io_service; 101 | msgpackpp::rpc dispatcher; 102 | 103 | // function pointer 104 | dispatcher.add_handler("fp", &func4); 105 | 106 | // lambda 107 | dispatcher.add_handler( 108 | "lambda", [](int a, int b, int c, int d) { return a + b + c + d; }); 109 | 110 | // std::function 111 | dispatcher.add_handler("std::function", 112 | std::function(func4)); 113 | 114 | // std::bind 115 | Dummy d; 116 | dispatcher.add_bind("std::bind", &d, &Dummy::func4); 117 | } 118 | -------------------------------------------------------------------------------- /test/error.cpp: -------------------------------------------------------------------------------- 1 | // ToDo 2 | 3 | // request 4 | // long request 5 | 6 | // server 7 | // BindError 8 | 9 | // execution 10 | // exception throw 11 | 12 | // result 13 | // type error 14 | // not ready error 15 | 16 | #include 17 | 18 | #include "fixture.h" 19 | #include 20 | 21 | TEST_CASE("error_handling") { 22 | const static int PORT = 8070; 23 | 24 | Fixture f(PORT); 25 | 26 | // client 27 | asio::io_service client_io; 28 | asio::io_context::work work(client_io); 29 | asio::ip::tcp::socket socket(client_io); 30 | std::thread client_thread([&client_io]() { client_io.run(); }); 31 | msgpackpp::connect_async( 32 | socket, asio::ip::tcp::endpoint( 33 | ::asio::ip::address::from_string("127.0.0.1"), PORT)) 34 | .get(); 35 | 36 | // request 37 | msgpackpp::rpc client; 38 | client.attach(std::move(socket)); 39 | 40 | // no method 41 | { 42 | auto request = client.request_async("no_such_method"); 43 | request.wait(); 44 | // REQUIRE(request->is_error()); 45 | // REQUIRE(request->get_error_code()== 46 | // msgpackpp::error_dispatcher_no_handler); 47 | } 48 | // too many arguments 49 | { 50 | auto request = client.request_async("acc", 1, 2); 51 | request.wait(); 52 | // REQUIRE(request->is_error()); 53 | // REQUIRE(request->get_error_code()== msgpackpp::error_params_too_many); 54 | } 55 | // not enough arguments 56 | { 57 | auto request = client.request_async("add", 1); 58 | request.wait(); 59 | // REQUIRE(request->is_error()); 60 | // REQUIRE(request->get_error_code()== 61 | // msgpackpp::error_params_not_enough); 62 | } 63 | // invalid argument type 64 | { 65 | auto request = client.request_async("add", "a", "b"); 66 | request.wait(); 67 | // REQUIRE(request->is_error()); 68 | // REQUIRE(request->get_error_code()== msgpackpp::error_params_convert); 69 | } 70 | 71 | client_io.stop(); 72 | client_thread.join(); 73 | } 74 | -------------------------------------------------------------------------------- /test/fixture.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | struct Fixture { 6 | msgpackpp::rpc dispatcher; 7 | 8 | asio::io_service server_io; 9 | msgpackpp::server server; 10 | std::shared_ptr server_thread; 11 | std::mutex m_mutex; 12 | 13 | Fixture(int port) : server(server_io) { 14 | dispatcher.add_handler("zero", &Fixture::zero); 15 | dispatcher.add_handler("acc", &Fixture::unary); 16 | dispatcher.add_handler("add", &Fixture::binary); 17 | dispatcher.add_handler("add3", 18 | [](int a, int b, int c) { return a + b + c; }); 19 | dispatcher.add_handler( 20 | "add4", [](int a, int b, int c, int d) { return a + b + c + d; }); 21 | 22 | server.set_on_accepted( 23 | [pDispatcher = &dispatcher](asio::ip::tcp::socket socket) { 24 | pDispatcher->attach(std::move(socket)); 25 | }); 26 | 27 | auto &mutex = m_mutex; 28 | // auto error_handler = [&mutex](asio::error_code error) { 29 | // if (error == asio::error::connection_reset) { 30 | // // closed 31 | // return; 32 | // } 33 | // std::lock_guard lock(mutex); 34 | // auto msg = error.message(); 35 | // std::cerr << msg << std::endl; 36 | // }; 37 | // server.set_error_handler(error_handler); 38 | 39 | server.listen(asio::ip::tcp::endpoint(asio::ip::tcp::v4(), port)); 40 | server_thread = std::make_shared([&] { server_io.run(); }); 41 | } 42 | ~Fixture() { 43 | server_io.stop(); 44 | server_thread->join(); 45 | } 46 | 47 | std::mutex &mutex() { return m_mutex; } 48 | 49 | static int zero() { return 0; } 50 | static int unary(int a) { 51 | static int acc = 0; 52 | acc += a; 53 | return acc; 54 | } 55 | static int binary(int a, int b) { return a + b; } 56 | }; 57 | -------------------------------------------------------------------------------- /test/main.cpp: -------------------------------------------------------------------------------- 1 | #define CATCH_CONFIG_MAIN 2 | #include 3 | -------------------------------------------------------------------------------- /test/msgpack.cpp: -------------------------------------------------------------------------------- 1 | /// 2 | /// https://github.com/msgpack/msgpack/blob/master/spec.md 3 | /// 4 | #include 5 | #include 6 | #include 7 | 8 | /// nil: 9 | /// +--------+ 10 | /// | 0xc0 | 11 | /// +--------+ 12 | TEST_CASE("nil") { 13 | // packing 14 | auto p = msgpackpp::packer().pack_nil().get_payload(); 15 | 16 | // check 17 | REQUIRE(1 == p.size()); 18 | REQUIRE(0xc0 == p[0]); 19 | } 20 | 21 | /// false: 22 | /// +--------+ 23 | /// | 0xc2 | 24 | /// +--------+ 25 | TEST_CASE("false") { 26 | // packing 27 | auto p = msgpackpp::packer().pack_bool(false).get_payload(); 28 | 29 | // check 30 | REQUIRE(1 == p.size()); 31 | REQUIRE(0xc2 == p[0]); 32 | } 33 | 34 | /// true: 35 | /// +--------+ 36 | /// | 0xc3 | 37 | /// +--------+ 38 | TEST_CASE("true") { 39 | // packing 40 | auto p = msgpackpp::packer().pack_bool(true).get_payload(); 41 | 42 | // check 43 | REQUIRE(1 == p.size()); 44 | REQUIRE(0xc3 == p[0]); 45 | } 46 | 47 | /// positive fixnum stores 7-bit positive integer 48 | /// +--------+ 49 | /// |0XXXXXXX| 50 | /// +--------+ 51 | TEST_CASE("small_int") { 52 | // packing 53 | auto p = msgpackpp::packer().pack_integer(1).get_payload(); 54 | 55 | // check 56 | REQUIRE(1 == p.size()); 57 | REQUIRE(0x01 == p[0]); 58 | 59 | // unpack 60 | auto parsed = msgpackpp::parser(p.data(), p.size()); 61 | REQUIRE(1 == parsed.get_number()); 62 | } 63 | 64 | /// negative fixnum stores 5-bit negative integer(-1 to -32) 65 | /// +--------+ 66 | /// |111YYYYY| 67 | /// +--------+ 68 | TEST_CASE("small_negative_int") { 69 | // packing 70 | auto p = msgpackpp::packer().pack_integer(-1).get_payload(); 71 | 72 | // check 73 | REQUIRE(1 == p.size()); 74 | REQUIRE(msgpackpp::pack_type::NEGATIVE_FIXNUM_0x01 == p[0]); 75 | 76 | // unpack 77 | auto parsed = msgpackpp::parser(p.data(), p.size()); 78 | REQUIRE(-1 == parsed.get_number()); 79 | } 80 | 81 | /// uint 8 stores a 8-bit unsigned integer 82 | /// +--------+--------+ 83 | /// | 0xcc |ZZZZZZZZ| 84 | /// +--------+--------+ 85 | TEST_CASE("uint8") { 86 | // packing 87 | auto p = msgpackpp::packer().pack_integer(128).get_payload(); 88 | 89 | // check 90 | REQUIRE(2 == p.size()); 91 | REQUIRE(0xcc == p[0]); 92 | 93 | // unpack 94 | auto parsed = msgpackpp::parser(p.data(), p.size()); 95 | REQUIRE(128 == parsed.get_number()); 96 | } 97 | 98 | /// uint 16 stores a 16-bit big-endian unsigned integer 99 | /// +--------+--------+--------+ 100 | /// | 0xcd |ZZZZZZZZ|ZZZZZZZZ| 101 | /// +--------+--------+--------+ 102 | TEST_CASE("uint16") { 103 | // packing 104 | auto p = msgpackpp::packer().pack_integer(256).get_payload(); 105 | 106 | // check 107 | REQUIRE(3 == p.size()); 108 | REQUIRE(0xcd == p[0]); 109 | REQUIRE(0x01 == p[1]); 110 | REQUIRE(0x00 == p[2]); 111 | 112 | // unpack 113 | auto parsed = msgpackpp::parser(p.data(), p.size()); 114 | REQUIRE(256 == parsed.get_number()); 115 | } 116 | 117 | /// uint 32 stores a 32-bit big-endian unsigned integer 118 | /// +--------+--------+--------+--------+--------+ 119 | /// | 0xce |ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ 120 | /// +--------+--------+--------+--------+--------+ 121 | TEST_CASE("uint32") { 122 | { 123 | int value = 65536; 124 | 125 | // packing 126 | auto p = msgpackpp::packer().pack_integer(value).get_payload(); 127 | 128 | // check 129 | REQUIRE(5 == p.size()); 130 | REQUIRE(0xce == p[0]); 131 | REQUIRE(0x00 == p[1]); 132 | REQUIRE(0x01 == p[2]); 133 | REQUIRE(0x00 == p[3]); 134 | REQUIRE(0x00 == p[4]); 135 | 136 | // unpack 137 | auto parsed = msgpackpp::parser(p.data(), p.size()); 138 | REQUIRE(value == parsed.get_number()); 139 | } 140 | 141 | { 142 | unsigned int value = 4294967295; 143 | 144 | // packing 145 | auto p = msgpackpp::packer().pack_integer(value).get_payload(); 146 | 147 | // check 148 | REQUIRE(5 == p.size()); 149 | REQUIRE(0xce == p[0]); 150 | 151 | // unpack 152 | auto parsed = msgpackpp::parser(p.data(), p.size()); 153 | REQUIRE(value == parsed.get_number()); 154 | } 155 | } 156 | 157 | /// uint 64 stores a 64-bit big-endian unsigned integer 158 | /// +--------+--------+--------+--------+--------+--------+--------+--------+--------+ 159 | /// | 0xcf 160 | /// |ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ| 161 | /// +--------+--------+--------+--------+--------+--------+--------+--------+--------+ 162 | TEST_CASE("uint64") { 163 | unsigned long long value = 4294967296; 164 | 165 | // packing 166 | auto p = msgpackpp::packer().pack_integer(value).get_payload(); 167 | 168 | // check 169 | REQUIRE(9 == p.size()); 170 | REQUIRE(0xcf == p[0]); 171 | REQUIRE(0x00 == p[1]); 172 | REQUIRE(0x00 == p[2]); 173 | REQUIRE(0x00 == p[3]); 174 | REQUIRE(0x01 == p[4]); 175 | REQUIRE(0x00 == p[5]); 176 | REQUIRE(0x00 == p[6]); 177 | REQUIRE(0x00 == p[7]); 178 | REQUIRE(0x00 == p[8]); 179 | 180 | // unpack 181 | auto parsed = msgpackpp::parser(p.data(), p.size()); 182 | REQUIRE(value == parsed.get_number()); 183 | } 184 | 185 | /// int 8 stores a 8-bit signed integer 186 | /// +--------+--------+ 187 | /// | 0xd0 |ZZZZZZZZ| 188 | /// +--------+--------+ 189 | TEST_CASE("int8") { 190 | char value = -33; 191 | 192 | // packing 193 | auto p = msgpackpp::packer().pack_integer(value).get_payload(); 194 | 195 | // check 196 | REQUIRE(2 == p.size()); 197 | REQUIRE(0xd0 == p[0]); 198 | REQUIRE(0xdf == p[1]); 199 | 200 | // unpack 201 | auto parsed = msgpackpp::parser(p.data(), p.size()); 202 | REQUIRE(value == parsed.get_number()); 203 | } 204 | 205 | /// int 16 stores a 16-bit big-endian signed integer 206 | /// +--------+--------+--------+ 207 | /// | 0xd1 |ZZZZZZZZ|ZZZZZZZZ| 208 | /// +--------+--------+--------+ 209 | TEST_CASE("int16") { 210 | int value = -256; 211 | 212 | // packing 213 | auto p = msgpackpp::packer().pack_integer(value).get_payload(); 214 | 215 | // check 216 | REQUIRE(3 == p.size()); 217 | REQUIRE(0xd1 == p[0]); 218 | 219 | // unpack 220 | auto parsed = msgpackpp::parser(p.data(), p.size()); 221 | REQUIRE(value == parsed.get_number()); 222 | } 223 | 224 | /// int 32 stores a 32-bit big-endian signed integer 225 | /// +--------+--------+--------+--------+--------+ 226 | /// | 0xd2 |ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ| 227 | /// +--------+--------+--------+--------+--------+ 228 | TEST_CASE("int32") { 229 | int value = -65535; 230 | 231 | // packing 232 | auto p = msgpackpp::packer().pack_integer(value).get_payload(); 233 | 234 | // check 235 | REQUIRE(5 == p.size()); 236 | REQUIRE(0xd2 == p[0]); 237 | 238 | // unpack 239 | auto parsed = msgpackpp::parser(p.data(), p.size()); 240 | REQUIRE(value == parsed.get_number()); 241 | } 242 | 243 | /// int 64 stores a 64-bit big-endian signed integer 244 | /// +--------+--------+--------+--------+--------+--------+--------+--------+--------+ 245 | /// | 0xd3 246 | /// |ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ| 247 | /// +--------+--------+--------+--------+--------+--------+--------+--------+--------+ 248 | TEST_CASE("int64") { 249 | long long value = -4294967296; 250 | 251 | // packing 252 | auto p = msgpackpp::packer().pack_integer(value).get_payload(); 253 | 254 | // check 255 | REQUIRE(9 == p.size()); 256 | REQUIRE(0xd3 == p[0]); 257 | 258 | // unpack 259 | auto parsed = msgpackpp::parser(p.data(), p.size()); 260 | REQUIRE(value == parsed.get_number()); 261 | } 262 | 263 | /// float 32 stores a floating point number in IEEE 754 single precision 264 | /// floating point number format: 265 | /// +--------+--------+--------+--------+--------+ 266 | /// | 0xca |XXXXXXXX|XXXXXXXX|XXXXXXXX|XXXXXXXX 267 | /// +--------+--------+--------+--------+--------+ 268 | TEST_CASE("float32") { 269 | float value = 1.5f; 270 | 271 | // packing 272 | auto p = msgpackpp::packer().pack_float(value).get_payload(); 273 | 274 | // check 275 | REQUIRE(5 == p.size()); 276 | REQUIRE(0xca == p[0]); 277 | 278 | // unpack 279 | auto parsed = msgpackpp::parser(p.data(), p.size()); 280 | REQUIRE(value == parsed.get_number()); 281 | } 282 | 283 | /// float 64 stores a floating point number in IEEE 754 double precision 284 | /// floating point number format: 285 | /// +--------+--------+--------+--------+--------+--------+--------+--------+--------+ 286 | /// | 0xcb 287 | /// |YYYYYYYY|YYYYYYYY|YYYYYYYY|YYYYYYYY|YYYYYYYY|YYYYYYYY|YYYYYYYY|YYYYYYYY| 288 | /// +--------+--------+--------+--------+--------+--------+--------+--------+--------+ 289 | TEST_CASE("float64") { 290 | double value = 1.111111111111111111111111111111111111111111111111; 291 | 292 | // packing 293 | auto p = msgpackpp::packer().pack_double(value).get_payload(); 294 | 295 | // check 296 | REQUIRE(9 == p.size()); 297 | REQUIRE(0xcb == p[0]); 298 | 299 | // unpack 300 | auto parsed = msgpackpp::parser(p.data(), p.size()); 301 | REQUIRE(value == parsed.get_number()); 302 | } 303 | 304 | /// fixstr stores a byte array whose length is upto 31 bytes: 305 | /// +--------+========+ 306 | /// |101XXXXX| data | 307 | /// +--------+========+ 308 | TEST_CASE("fixstr") { 309 | auto str = "abc"; 310 | 311 | // packing 312 | auto p = msgpackpp::packer().pack_str(str).get_payload(); 313 | 314 | // check 315 | REQUIRE((1 + 3) == p.size()); 316 | 317 | // unpack 318 | auto parsed = msgpackpp::parser(p.data(), p.size()); 319 | REQUIRE(parsed.get_string() == str); 320 | } 321 | 322 | /// str 8 stores a byte array whose length is upto (2^8)-1 bytes: 323 | /// +--------+--------+========+ 324 | /// | 0xd9 |YYYYYYYY| data | 325 | /// +--------+--------+========+ 326 | TEST_CASE("str8") { 327 | auto str = "0123456789" 328 | "0123456789" 329 | "0123456789" 330 | "01"; 331 | 332 | // packing 333 | auto p = msgpackpp::packer().pack_str(str).get_payload(); 334 | 335 | // check 336 | REQUIRE((2 + 32) == p.size()); 337 | REQUIRE(0xd9 == p[0]); 338 | 339 | // unpack 340 | auto parsed = msgpackpp::parser(p.data(), p.size()); 341 | auto parsed_str = parsed.get_string(); 342 | REQUIRE(parsed_str == str); 343 | } 344 | 345 | /// str 16 stores a byte array whose length is upto (2^16)-1 bytes: 346 | /// +--------+--------+--------+========+ 347 | /// | 0xda |ZZZZZZZZ|ZZZZZZZZ| data | 348 | /// +--------+--------+--------+========+ 349 | TEST_CASE("str16") { 350 | auto str = "0123456789" 351 | "0123456789" 352 | "0123456789" 353 | "0123456789" 354 | "0123456789" 355 | "0123456789" 356 | "0123456789" 357 | "0123456789" 358 | "0123456789" 359 | "0123456789" 360 | "0123456789" 361 | "0123456789" 362 | "0123456789" 363 | "0123456789" 364 | "0123456789" 365 | "0123456789" 366 | "0123456789" 367 | "0123456789" 368 | "0123456789" 369 | "0123456789" 370 | "0123456789" 371 | "0123456789" 372 | "0123456789" 373 | "0123456789" 374 | "0123456789" 375 | "0123456"; 376 | 377 | // packing 378 | auto p = msgpackpp::packer().pack_str(str).get_payload(); 379 | 380 | // check 381 | REQUIRE((3 + 257) == p.size()); 382 | REQUIRE(0xda == p[0]); 383 | 384 | // unpack 385 | auto parsed = msgpackpp::parser(p.data(), p.size()); 386 | REQUIRE(parsed.get_string() == str); 387 | } 388 | 389 | /// str 32 stores a byte array whose length is upto (2^32)-1 bytes: 390 | /// +--------+--------+--------+--------+--------+========+ 391 | /// | 0xdb |AAAAAAAA|AAAAAAAA|AAAAAAAA|AAAAAAAA| data | 392 | /// +--------+--------+--------+--------+--------+========+ 393 | TEST_CASE("str32") { 394 | auto len = (0xFFFF + 2); 395 | char buf[0xFFFF + 2] = {}; 396 | for (int i = 0; i < len; ++i) { 397 | buf[i] = ('0' + (i % 10)); 398 | } 399 | 400 | // packing 401 | auto p = 402 | msgpackpp::packer().pack_str(std::string(buf, buf + len)).get_payload(); 403 | 404 | // check 405 | REQUIRE(0xdb == p[0]); 406 | REQUIRE((5 + len) == p.size()); 407 | 408 | // unpack 409 | auto parsed = msgpackpp::parser(p.data(), p.size()); 410 | REQUIRE(parsed.get_string() == std::string(buf, buf + len)); 411 | } 412 | 413 | /// bin 8 stores a byte array whose length is upto (2^8)-1 bytes: 414 | /// +--------+--------+========+ 415 | /// | 0xc4 |XXXXXXXX| data | 416 | /// +--------+--------+========+ 417 | TEST_CASE("bin8") { 418 | std::vector buf; 419 | buf.push_back(0); 420 | 421 | // packing 422 | auto p = msgpackpp::packer().pack_bin(buf).get_payload(); 423 | 424 | // check 425 | REQUIRE(2 + 1 == p.size()); 426 | REQUIRE(0xc4 == p[0]); 427 | 428 | // unpack 429 | auto parsed = msgpackpp::parser(p.data(), p.size()); 430 | REQUIRE(buf == parsed.get_binary()); 431 | } 432 | 433 | /// bin 16 stores a byte array whose length is upto (2^16)-1 bytes: 434 | /// +--------+--------+--------+========+ 435 | /// | 0xc5 |YYYYYYYY|YYYYYYYY| data | 436 | /// +--------+--------+--------+========+ 437 | TEST_CASE("bin16") { 438 | std::vector buf; 439 | for (int i = 0; i < 0xFF + 1; ++i) { 440 | buf.push_back(i % 0xFF); 441 | } 442 | 443 | // packing 444 | auto p = msgpackpp::packer().pack_bin(buf).get_payload(); 445 | 446 | // check 447 | REQUIRE(3 + 0xFF + 1 == p.size()); 448 | REQUIRE(0xc5 == p[0]); 449 | 450 | // unpack 451 | auto parsed = msgpackpp::parser(p.data(), p.size()); 452 | REQUIRE(buf == parsed.get_binary()); 453 | } 454 | 455 | /// bin 32 stores a byte array whose length is upto (2^32)-1 bytes: 456 | /// +--------+--------+--------+--------+--------+========+ 457 | /// | 0xc6 |ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ| data | 458 | /// +--------+--------+--------+--------+--------+========+ 459 | TEST_CASE("bin32") { 460 | std::vector buf; 461 | for (int i = 0; i < 0xFFFF + 1; ++i) { 462 | buf.push_back(i % 0xFF); 463 | } 464 | 465 | // packing 466 | auto p = msgpackpp::packer().pack_bin(buf).get_payload(); 467 | 468 | // check 469 | REQUIRE(5 + 0xFFFF + 1 == p.size()); 470 | REQUIRE(0xc6 == p[0]); 471 | 472 | // unpack 473 | auto parsed = msgpackpp::parser(p.data(), p.size()); 474 | REQUIRE(buf == parsed.get_binary()); 475 | } 476 | 477 | /// fixarray stores an array whose length is upto 15 elements: 478 | /// +--------+~~~~~~~~~~~~~~~~~+ 479 | /// |1001XXXX| N objects | 480 | /// +--------+~~~~~~~~~~~~~~~~~+ 481 | TEST_CASE("fixarray") { 482 | // packing 483 | msgpackpp::packer packer; 484 | packer.pack_array(3) << 1 << "str" << true; 485 | auto p = packer.get_payload(); 486 | 487 | // check 488 | REQUIRE(msgpackpp::pack_type::FIX_ARRAY_0x3 == p[0]); 489 | 490 | // unpack 491 | auto parsed = msgpackpp::parser(p.data(), p.size()); 492 | REQUIRE(parsed.is_array()); 493 | 494 | REQUIRE(3 == parsed.count()); 495 | REQUIRE(1 == parsed[0].get_number()); 496 | REQUIRE(std::string("str") == parsed[1].get_string()); 497 | REQUIRE(true == parsed[2].get_bool()); 498 | } 499 | 500 | /// array 16 stores an array whose length is upto (2^16)-1 elements: 501 | /// +--------+--------+--------+~~~~~~~~~~~~~~~~~+ 502 | /// | 0xdc |YYYYYYYY|YYYYYYYY| N objects | 503 | /// +--------+--------+--------+~~~~~~~~~~~~~~~~~+ 504 | TEST_CASE("array16") { 505 | // packing 506 | msgpackpp::packer packer; 507 | packer.pack_array(16) << 1 << "str1" << true << 1.5f << 2 << "str2" << false 508 | << 1.6f << 3 << "str3" << true << 1.7 << 4 << "str4" 509 | << false << 1.8; 510 | auto p = packer.get_payload(); 511 | 512 | // check 513 | REQUIRE(0xdc == p[0]); 514 | 515 | // unpack 516 | auto parsed = msgpackpp::parser(p.data(), p.size()); 517 | REQUIRE(parsed.is_array()); 518 | 519 | // array 520 | REQUIRE(16 == parsed.count()); 521 | REQUIRE(1 == parsed[0].get_number()); 522 | REQUIRE("str1" == parsed[1].get_string()); 523 | REQUIRE(true == parsed[2].get_bool()); 524 | REQUIRE(1.5f == parsed[3].get_number()); 525 | } 526 | 527 | /// array 32 stores an array whose length is upto (2^32)-1 elements: 528 | /// +--------+--------+--------+--------+--------+~~~~~~~~~~~~~~~~~+ 529 | /// | 0xdd |ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ| N objects | 530 | /// +--------+--------+--------+--------+--------+~~~~~~~~~~~~~~~~~+ 531 | TEST_CASE("array32") { 532 | // packing 533 | auto count = static_cast(0xFFFF + 1); 534 | auto payload = std::make_shared>(count); 535 | payload->clear(); 536 | 537 | msgpackpp::packer packer(payload); 538 | 539 | packer.pack_array(count); 540 | for (unsigned int i = 0; i < count; ++i) { 541 | packer << i; 542 | } 543 | auto p = packer.get_payload(); 544 | 545 | // check 546 | REQUIRE(0xdd == p[0]); 547 | 548 | // unpack 549 | auto parsed = msgpackpp::parser(p.data(), p.size()); 550 | REQUIRE(parsed.is_array()); 551 | 552 | // array 553 | REQUIRE(count == parsed.count()); 554 | 555 | for (unsigned int i = 0; i < count; i += 1000) { 556 | REQUIRE(i == parsed[i].get_number()); 557 | } 558 | 559 | REQUIRE(count - 1 == parsed[count - 1].get_number()); 560 | } 561 | 562 | /// fixmap stores a map whose length is upto 15 elements 563 | /// +--------+~~~~~~~~~~~~~~~~~+ 564 | /// |1000XXXX| N*2 objects | 565 | /// +--------+~~~~~~~~~~~~~~~~~+ 566 | TEST_CASE("fixmap") { 567 | // packing 568 | msgpackpp::packer packer; 569 | packer.pack_map(3) << "key1" << 0 << "key2" << 1 << "key3" << 2; 570 | auto p = packer.get_payload(); 571 | 572 | // check 573 | REQUIRE(msgpackpp::FIX_MAP_0x3 == p[0]); 574 | 575 | // unpack 576 | auto parsed = msgpackpp::parser(p.data(), p.size()); 577 | REQUIRE(parsed.is_map()); 578 | 579 | REQUIRE(3 == parsed.count()); 580 | 581 | auto count = parsed.count(); 582 | for (size_t i = 0; i < count; ++i) { 583 | std::stringstream ss; 584 | ss << "key" << (i + 1); 585 | REQUIRE(ss.str() == parsed[i * 2].get_string()); 586 | REQUIRE(i == parsed[i * 2 + 1].get_number()); 587 | } 588 | 589 | REQUIRE(0 == parsed["key1"].get_number()); 590 | REQUIRE(1 == parsed["key2"].get_number()); 591 | REQUIRE(2 == parsed["key3"].get_number()); 592 | } 593 | 594 | /// map 16 stores a map whose length is upto (2^16)-1 elements 595 | /// +--------+--------+--------+~~~~~~~~~~~~~~~~~+ 596 | /// | 0xde |YYYYYYYY|YYYYYYYY| N*2 objects | 597 | /// +--------+--------+--------+~~~~~~~~~~~~~~~~~+ 598 | TEST_CASE("map16") { 599 | // packing 600 | msgpackpp::packer packer; 601 | packer.pack_map(17) << "key1" << 0 << "key2" << 1 << "key3" << 2 << "key4" 602 | << 3 << "key5" << 4 << "key6" << 5 << "key7" << 6 603 | << "key8" << 7 << "key9" << 8 << "key10" << 9 << "key11" 604 | << 10 << "key12" << 11 << "key13" << 12 << "key14" << 13 605 | << "key15" << 14 << "key16" << 15 << "key17" << 16; 606 | auto p = packer.get_payload(); 607 | 608 | // check 609 | REQUIRE(0xde == p[0]); 610 | 611 | // unpack 612 | auto parsed = msgpackpp::parser(p.data(), p.size()); 613 | REQUIRE(parsed.is_map()); 614 | 615 | // map 616 | REQUIRE(17 == parsed.count()); 617 | 618 | for (auto i = 0; i < 17; ++i) { 619 | std::stringstream ss; 620 | ss << "key" << (i + 1); 621 | REQUIRE(ss.str() == parsed[i * 2].get_string()); 622 | REQUIRE(i == parsed[i * 2 + 1].get_number()); 623 | } 624 | } 625 | 626 | /// map 32 stores a map whose length is upto (2^32)-1 elements 627 | /// +--------+--------+--------+--------+--------+~~~~~~~~~~~~~~~~~+ 628 | /// | 0xdf |ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ| N*2 objects | 629 | /// +--------+--------+--------+--------+--------+~~~~~~~~~~~~~~~~~+ 630 | TEST_CASE("map32") { 631 | // packing 632 | msgpackpp::packer packer; 633 | packer.pack_map(0xFFFF + 1); 634 | for (int i = 0; i < 0xFFFF + 1; ++i) { 635 | std::stringstream ss; 636 | ss << "key" << (i + 1); 637 | packer << ss.str() << i; 638 | } 639 | auto p = packer.get_payload(); 640 | 641 | // check 642 | REQUIRE(0xdf == p[0]); 643 | 644 | // unpack 645 | auto parsed = msgpackpp::parser(p.data(), p.size()); 646 | REQUIRE(parsed.is_map()); 647 | 648 | // map 649 | REQUIRE(0xFFFF + 1 == parsed.count()); 650 | 651 | REQUIRE(0 == parsed["key1"].get_number()); 652 | REQUIRE(10000 == parsed["key10001"].get_number()); 653 | REQUIRE(20000 == parsed["key20001"].get_number()); 654 | REQUIRE(40000 == parsed["key40001"].get_number()); 655 | REQUIRE(0xFFFF == parsed["key65536"].get_number()); 656 | } 657 | 658 | /// fixext 1 stores an integer and a byte array whose length is 1 byte 659 | /// +--------+--------+--------+ 660 | /// | 0xd4 | type | data | 661 | /// +--------+--------+--------+ 662 | TEST_CASE("fixext1") { 663 | // packing 664 | std::array value = {0x23}; 665 | auto p = msgpackpp::packer().pack_ext(0x12, value).get_payload(); 666 | 667 | // check 668 | REQUIRE(3 == p.size()); 669 | REQUIRE(0xd4 == p[0]); 670 | 671 | // unpack 672 | auto parsed = msgpackpp::parser(p.data(), p.size()); 673 | 674 | auto [type, view] = parsed.get_ext(); 675 | REQUIRE(type == 0x12); 676 | REQUIRE(view[0] == 0x23); 677 | } 678 | 679 | /// fixext 2 stores an integer and a byte array whose length is 2 bytes 680 | /// +--------+--------+--------+--------+ 681 | /// | 0xd5 | type | data | 682 | /// +--------+--------+--------+--------+ 683 | TEST_CASE("fixext2") { 684 | // packing 685 | auto value = {(char)0x23, (char)0x34}; 686 | auto p = msgpackpp::packer().pack_ext(0x12, value).get_payload(); 687 | 688 | // check 689 | REQUIRE(4 == p.size()); 690 | REQUIRE(0xd5 == p[0]); 691 | 692 | // unpack 693 | auto parsed = msgpackpp::parser(p.data(), p.size()); 694 | 695 | auto [type, view] = parsed.get_ext(); 696 | REQUIRE(type == 0x12); 697 | REQUIRE(view[0] == 0x23); 698 | REQUIRE(view[1] == 0x34); 699 | } 700 | 701 | /// fixext 4 stores an integer and a byte array whose length is 4 bytes 702 | /// +--------+--------+--------+--------+--------+--------+ 703 | /// | 0xd6 | type | data | 704 | /// +--------+--------+--------+--------+--------+--------+ 705 | TEST_CASE("fixext4") { 706 | // packing 707 | char value[] = {0x23, 0x34, 0x56, 0x78}; 708 | auto p = msgpackpp::packer().pack_ext(0x12, value).get_payload(); 709 | 710 | // check 711 | REQUIRE(6 == p.size()); 712 | REQUIRE(0xd6 == p[0]); 713 | 714 | // unpack 715 | auto parsed = msgpackpp::parser(p.data(), p.size()); 716 | 717 | auto [type, view] = parsed.get_ext(); 718 | REQUIRE(type == 0x12); 719 | REQUIRE(view[0] == 0x23); 720 | REQUIRE(view[1] == 0x34); 721 | REQUIRE(view[2] == 0x56); 722 | REQUIRE(view[3] == 0x78); 723 | } 724 | 725 | /// fixext 8 stores an integer and a byte array whose length is 8 bytes 726 | /// +--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+ 727 | /// | 0xd7 | type | data | 728 | /// +--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+ 729 | TEST_CASE("fixext8") { 730 | // packing 731 | char value[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; 732 | auto p = msgpackpp::packer().pack_ext(0x12, value).get_payload(); 733 | 734 | // check 735 | REQUIRE(10 == p.size()); 736 | REQUIRE(0xd7 == p[0]); 737 | 738 | // unpack 739 | auto parsed = msgpackpp::parser(p.data(), p.size()); 740 | 741 | auto [type, view] = parsed.get_ext(); 742 | REQUIRE(type == 0x12); 743 | REQUIRE(view[0] == 0x01); 744 | REQUIRE(view[1] == 0x02); 745 | REQUIRE(view[2] == 0x03); 746 | REQUIRE(view[3] == 0x04); 747 | REQUIRE(view[4] == 0x05); 748 | REQUIRE(view[5] == 0x06); 749 | REQUIRE(view[6] == 0x07); 750 | REQUIRE(view[7] == 0x08); 751 | } 752 | 753 | /// fixext 16 stores an integer and a byte array whose length is 16 bytes 754 | /// +--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+ 755 | /// | 0xd8 | type | data 756 | /// +--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+ 757 | /// +--------+--------+--------+--------+--------+--------+--------+--------+ 758 | /// data (cont.) | 759 | /// +--------+--------+--------+--------+--------+--------+--------+--------+ 760 | TEST_CASE("fixext16") { 761 | // packing 762 | char value[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 763 | 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10}; 764 | auto p = msgpackpp::packer().pack_ext(0x12, value).get_payload(); 765 | 766 | // check 767 | REQUIRE(18 == p.size()); 768 | REQUIRE(0xd8 == p[0]); 769 | 770 | // unpack 771 | auto parsed = msgpackpp::parser(p.data(), p.size()); 772 | 773 | auto [type, view] = parsed.get_ext(); 774 | REQUIRE(type == 0x12); 775 | REQUIRE(view[0] == 0x01); 776 | REQUIRE(view[1] == 0x02); 777 | REQUIRE(view[2] == 0x03); 778 | REQUIRE(view[3] == 0x04); 779 | REQUIRE(view[4] == 0x05); 780 | REQUIRE(view[5] == 0x06); 781 | REQUIRE(view[6] == 0x07); 782 | REQUIRE(view[7] == 0x08); 783 | REQUIRE(view[8] == 0x09); 784 | REQUIRE(view[9] == 0x0a); 785 | REQUIRE(view[10] == 0x0b); 786 | REQUIRE(view[11] == 0x0c); 787 | REQUIRE(view[12] == 0x0d); 788 | REQUIRE(view[13] == 0x0e); 789 | REQUIRE(view[14] == 0x0f); 790 | REQUIRE(view[15] == 0x10); 791 | } 792 | 793 | /// ext 8 stores an integer and a byte array whose length is upto (2^8)-1 bytes: 794 | /// +--------+--------+--------+========+ 795 | /// | 0xc7 |XXXXXXXX| type | data | 796 | /// +--------+--------+--------+========+ 797 | TEST_CASE("ext8") { 798 | std::vector buf; 799 | for (int i = 0; i < 20; ++i) { 800 | buf.push_back(i); 801 | } 802 | 803 | // packing 804 | auto p = msgpackpp::packer().pack_ext(0x12, buf).get_payload(); 805 | 806 | // check 807 | REQUIRE(1 + 1 + 1 + buf.size() == p.size()); 808 | REQUIRE(0xc7 == p[0]); 809 | 810 | // unpack 811 | auto parsed = msgpackpp::parser(p.data(), p.size()); 812 | 813 | auto [type, view] = parsed.get_ext(); 814 | REQUIRE(type == 0x12); 815 | 816 | for (int i = 0; i < buf.size(); ++i) { 817 | REQUIRE(i == view[i]); 818 | } 819 | } 820 | 821 | /// ext 16 stores an integer and a byte array whose length is upto (2^16)-1 822 | /// bytes: 823 | /// +--------+--------+--------+--------+========+ 824 | /// | 0xc8 |YYYYYYYY|YYYYYYYY| type | data | 825 | /// +--------+--------+--------+--------+========+ 826 | TEST_CASE("ext16") { 827 | std::vector buf; 828 | for (int i = 0; i < 300; ++i) { 829 | buf.push_back(i % 128); 830 | } 831 | 832 | // packing 833 | auto p = msgpackpp::packer().pack_ext(0x12, buf).get_payload(); 834 | 835 | // check 836 | REQUIRE(1 + 2 + 1 + buf.size() == p.size()); 837 | REQUIRE(0xc8 == p[0]); 838 | 839 | // unpack 840 | auto parsed = msgpackpp::parser(p.data(), p.size()); 841 | 842 | auto [type, view] = parsed.get_ext(); 843 | REQUIRE(type == 0x12); 844 | 845 | for (int i = 0; i < buf.size(); ++i) { 846 | REQUIRE(i % 128 == view[i]); 847 | } 848 | } 849 | 850 | /// ext 32 stores an integer and a byte array whose length is upto (2^32)-1 851 | /// bytes: 852 | /// +--------+--------+--------+--------+--------+--------+========+ 853 | /// | 0xc9 |ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ| type | data | 854 | /// +--------+--------+--------+--------+--------+--------+========+ 855 | TEST_CASE("ext32") { 856 | std::vector buf; 857 | for (int i = 0; i < 0xFFFF + 5; ++i) { 858 | buf.push_back(i % 128); 859 | } 860 | 861 | // packing 862 | auto p = msgpackpp::packer().pack_ext(0x12, buf).get_payload(); 863 | 864 | // check 865 | REQUIRE(1 + 4 + 1 + buf.size() == p.size()); 866 | REQUIRE(0xc9 == p[0]); 867 | 868 | // unpack 869 | auto parsed = msgpackpp::parser(p.data(), p.size()); 870 | 871 | auto [type, view] = parsed.get_ext(); 872 | REQUIRE(type == 0x12); 873 | 874 | for (int i = 0; i < buf.size(); ++i) { 875 | REQUIRE(i % 128 == view[i]); 876 | } 877 | } 878 | -------------------------------------------------------------------------------- /test/pipeline.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "fixture.h" 6 | 7 | TEST_CASE("pipeline") { 8 | const static int PORT = 8070; 9 | 10 | Fixture fixture(PORT); 11 | 12 | // client 13 | asio::io_service client_io; 14 | asio::io_context::work work(client_io); 15 | asio::ip::tcp::socket socket(client_io); 16 | std::thread client_thread([&client_io]() { client_io.run(); }); 17 | msgpackpp::connect_async( 18 | socket, asio::ip::tcp::endpoint( 19 | ::asio::ip::address::from_string("127.0.0.1"), PORT)) 20 | .get(); 21 | 22 | // request 23 | msgpackpp::rpc client; 24 | client.attach(std::move(socket)); 25 | REQUIRE(msgpackpp::deserialize(client.request_async("add", 1, 2).get()) == 3); 26 | 27 | auto request2 = client.request_async("add", 3, 4); 28 | request2.wait(); 29 | int result2 = msgpackpp::deserialize(request2.get()); 30 | REQUIRE(result2 == 7); 31 | 32 | client_io.stop(); 33 | client_thread.join(); 34 | } 35 | -------------------------------------------------------------------------------- /test/request.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | TEST_CASE("request0") { 5 | { 6 | auto request = msgpackpp::make_rpc_request(1, "count"); 7 | msgpackpp::parser parsed(request); 8 | REQUIRE(parsed.is_array()); 9 | REQUIRE(parsed.count() == 4); 10 | auto data = parsed.copy_bytes(); 11 | REQUIRE(parsed[1].get_number() == 1); 12 | REQUIRE(parsed[2].get_string() == "count"); 13 | } 14 | } 15 | 16 | TEST_CASE("request1") { 17 | { 18 | auto request = msgpackpp::make_rpc_request(1, "sin", 3.14); 19 | msgpackpp::parser parsed(request); 20 | REQUIRE(parsed[1].get_number() == 1); 21 | REQUIRE(parsed[2].get_string() == "sin"); 22 | REQUIRE(parsed[3][0].get_number() == 3.14); 23 | } 24 | } 25 | 26 | TEST_CASE("request2") { 27 | { 28 | auto request = msgpackpp::make_rpc_request(1, "add", 1, 2); 29 | msgpackpp::parser parsed(request); 30 | REQUIRE(parsed[1].get_number() == 1); 31 | REQUIRE(parsed[2].get_string() == "add"); 32 | REQUIRE(parsed[3][0].get_number() == 1); 33 | REQUIRE(parsed[3][1].get_number() == 2); 34 | } 35 | { 36 | auto request = msgpackpp::make_rpc_request(2, "mul", 1.0f, 0.5f); 37 | msgpackpp::parser parsed(request); 38 | REQUIRE(parsed[1].get_number() == 2); 39 | REQUIRE(parsed[2].get_string() == "mul"); 40 | REQUIRE(parsed[3][0].get_number() == 1.0f); 41 | REQUIRE(parsed[3][1].get_number() == 0.5f); 42 | } 43 | } 44 | 45 | TEST_CASE("request3") { 46 | { 47 | auto request = msgpackpp::make_rpc_request(1, "add", 1, 2, 3); 48 | msgpackpp::parser parsed(request); 49 | REQUIRE(parsed[1].get_number() == 1); 50 | REQUIRE(parsed[2].get_string() == "add"); 51 | REQUIRE(parsed[3][0].get_number() == 1); 52 | REQUIRE(parsed[3][1].get_number() == 2); 53 | REQUIRE(parsed[3][2].get_number() == 3); 54 | } 55 | } 56 | 57 | TEST_CASE("request4") { 58 | { 59 | auto request = msgpackpp::make_rpc_request(1, "add", 1, 2, 3, 4); 60 | msgpackpp::parser parsed(request); 61 | REQUIRE(parsed[1].get_number() == 1); 62 | REQUIRE(parsed[2].get_string() == "add"); 63 | REQUIRE(parsed[3][0].get_number() == 1); 64 | REQUIRE(parsed[3][1].get_number() == 2); 65 | REQUIRE(parsed[3][2].get_number() == 3); 66 | REQUIRE(parsed[3][3].get_number() == 4); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /test/rpc.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | static void v() {} 6 | static void v1(int a) {} 7 | static float f() {} 8 | static float f1(int a) {} 9 | 10 | template void a(const F &f) { std::cout << "a" << std::endl; } 11 | template void a(R (*f)(AS...)) { 12 | std::cout << "b" << std::endl; 13 | } 14 | 15 | struct Some { 16 | void Go() { ; } 17 | int To() { return 0; } 18 | static void St() {} 19 | }; 20 | 21 | auto l = []() {}; 22 | 23 | TEST_CASE("make_procedure") { 24 | msgpackpp::make_procedurecall(l); 25 | msgpackpp::make_procedurecall(v); 26 | // msgpackpp::make_procedurecall(b); 27 | Some s; 28 | msgpackpp::make_methodcall(&s, &Some::Go); 29 | msgpackpp::make_methodcall(&s, &Some::To); 30 | msgpackpp::make_procedurecall(&Some::St); 31 | } 32 | 33 | TEST_CASE("procedure_call") { 34 | // 0 args 35 | REQUIRE(1 == msgpackpp::procedure_call([] { return 1; })); 36 | 37 | // 2 args 38 | REQUIRE(3 == 39 | msgpackpp::procedure_call([](int a, int b) { return a + b; }, 1, 2)); 40 | 41 | REQUIRE(-1 == 42 | msgpackpp::procedure_call([](int a, int b) { return a - b; }, 1, 2)); 43 | 44 | // string 45 | REQUIRE("a" == msgpackpp::procedure_call([]() { return std::string("a"); })); 46 | 47 | REQUIRE("b" == msgpackpp::procedure_call([](std::string src) { return src; }, 48 | std::string("b"))); 49 | } 50 | -------------------------------------------------------------------------------- /test/serialize.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | template void Test(T src) { 5 | // serialize 6 | msgpackpp::packer packer; 7 | packer << src; 8 | auto p = packer.get_payload(); 9 | 10 | // deserialize 11 | auto parsed = msgpackpp::parser(p.data(), p.size()); 12 | T value; 13 | parsed >> value; 14 | 15 | REQUIRE(src == value); 16 | } 17 | 18 | struct Person { 19 | std::string name; 20 | int age; 21 | 22 | bool operator==(const Person &rhs) const { 23 | return name == rhs.name && age == rhs.age; 24 | } 25 | }; 26 | MPPP_MAP_SERIALIZER(Person, 2, name, age) 27 | 28 | struct Point { 29 | float x; 30 | float y; 31 | 32 | bool operator==(const Point &rhs) const { return x == rhs.x && y == rhs.y; } 33 | }; 34 | MPPP_ARRAY_SERIALIZER(Point, 2, x, y); 35 | 36 | TEST_CASE("serialize") { 37 | Test(true); 38 | Test(false); 39 | Test(0); 40 | Test(1); 41 | Test(std::numeric_limits::max()); 42 | Test(std::numeric_limits::max() + 1); 43 | Test(std::numeric_limits::max() + 1); 44 | Test(std::numeric_limits::max() + 1); 45 | Test(-32); 46 | Test(std::numeric_limits::min()); 47 | Test(std::numeric_limits::min() - 1); 48 | Test(std::numeric_limits::min() - 1); 49 | Test(std::numeric_limits::min() - 1); 50 | Test(1.1f); 51 | Test(1.1); 52 | Test(std::vector{1, 2, 3}); 53 | Test(std::vector{"a", "ab", "hoge"}); 54 | 55 | Test(std::vector{1, 2, 3}); 56 | 57 | Test(std::string(u8"日本語")); 58 | 59 | Test(std::make_tuple(true, 0, 1.5, std::string(u8"ABC"))); 60 | 61 | // user type 62 | Test(Person{"hoge", 100}); 63 | Test(Point{1.5f, 2.5f}); 64 | } 65 | -------------------------------------------------------------------------------- /test/stream.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | TEST_CASE("stream") { 6 | // packing 7 | auto p = msgpackpp::packer().pack_nil().pack_nil().pack_nil().get_payload(); 8 | 9 | // push incomplete message 10 | p.push_back(msgpackpp::EXT32); 11 | 12 | // unpacking 13 | auto parsed = msgpackpp::parser(p); 14 | for (int i = 0; i < 3; ++i) { 15 | REQUIRE(parsed.is_nil()); 16 | parsed = parsed.next(); 17 | } 18 | 19 | try { 20 | auto last = parsed.next(); 21 | } catch (const std::runtime_error &) { 22 | // throw if incomplete message 23 | auto a = 0; 24 | } 25 | } 26 | --------------------------------------------------------------------------------