41#include <boost/json.hpp>
47 class boost_json_adapter;
52 using serial_t = boost::json::object;
53 using bytes_t = std::string;
59 [[nodiscard]]
static std::string to_bytes(boost::json::value&& serial_obj)
61 return boost::json::serialize(serial_obj);
64 [[nodiscard]]
static std::optional<boost::json::object> from_bytes(std::string&& bytes)
66 boost::system::error_code ec;
67 boost::json::value val = boost::json::parse(bytes, ec);
79 const auto& obj = val.get_object();
81 if (
const auto ex_it = obj.find(
"except_type"); ex_it != obj.end())
83 if (
const auto& ex_val = ex_it->value();
84 !ex_val.is_int64() || (ex_val.get_int64() != 0 && !obj.contains(
"err_mesg")))
90 return std::make_optional(std::move(obj));
93 if (
const auto fname_it = obj.find(
"func_name"); fname_it == obj.end()
94 || !fname_it->value().is_string() || fname_it->value().get_string().empty())
99 if (
const auto args_it = obj.find(
"args");
100 args_it == obj.end() || !args_it->value().is_array())
105 return std::make_optional(std::move(obj));
108 static boost::json::object empty_object() {
return boost::json::object{}; }
110 template<
typename R,
typename... Args>
111 [[nodiscard]]
static boost::json::object serialize_pack(
112 const detail::packed_func<R, Args...>& pack)
114 boost::json::object obj{};
115 obj[
"func_name"] = pack.get_func_name();
116 auto& args = obj[
"args"].emplace_array();
117 args.reserve(
sizeof...(Args));
118 detail::for_each_tuple(pack.get_args(),
119 [&args](
auto&& elem) { push_args(std::forward<decltype(elem)>(elem), args); });
123 obj[
"except_type"] =
static_cast<int>(pack.get_except_type());
124 obj[
"err_mesg"] = pack.get_err_mesg();
128 if constexpr (!std::is_void_v<R>)
131 push_arg(pack.get_result(), obj[
"result"]);
137 template<
typename R,
typename... Args>
138 [[nodiscard]]
static detail::packed_func<R, Args...> deserialize_pack(
139 const boost::json::object& serial_obj)
141 const auto& args_val = serial_obj.at(
"args");
142 [[maybe_unused]]
unsigned arg_counter = 0;
143 typename detail::packed_func<R, Args...>::args_t args{ parse_args<Args>(
144 args_val, arg_counter)... };
146 if constexpr (std::is_void_v<R>)
148 detail::packed_func<void, Args...> pack(
149 serial_obj.at(
"func_name").get_string().c_str(), std::move(args));
151 if (serial_obj.contains(
"except_type"))
153 pack.set_exception(serial_obj.at(
"err_mesg").get_string().c_str(),
154 static_cast<exception_type
>(serial_obj.at(
"except_type").get_int64()));
161 if (serial_obj.contains(
"result") && !serial_obj.at(
"result").is_null())
163 return detail::packed_func<R, Args...>(
164 serial_obj.at(
"func_name").get_string().c_str(),
165 parse_arg<R>(serial_obj.at(
"result")), std::move(args));
168 detail::packed_func<R, Args...> pack(
169 serial_obj.at(
"func_name").get_string().c_str(), std::nullopt, std::move(args));
171 if (serial_obj.contains(
"except_type"))
173 pack.set_exception(serial_obj.at(
"err_mesg").get_string().c_str(),
174 static_cast<exception_type
>(serial_obj.at(
"except_type").get_int64()));
181 [[nodiscard]]
static std::string get_func_name(
const boost::json::object& serial_obj)
183 return serial_obj.at(
"func_name").get_string().c_str();
186 [[nodiscard]]
static rpc_exception extract_exception(
const boost::json::object& serial_obj)
188 return rpc_exception{ serial_obj.at(
"err_mesg").as_string().c_str(),
189 static_cast<exception_type
>(serial_obj.at(
"except_type").as_int64()) };
192 static void set_exception(boost::json::object& serial_obj,
const rpc_exception& ex)
194 serial_obj[
"except_type"] =
static_cast<int>(ex.get_type());
195 serial_obj[
"err_mesg"] = boost::json::string{ ex.what() };
199 static boost::json::object serialize(
const T& val) =
delete;
202 static T deserialize(
const boost::json::object& serial_obj) =
delete;
206 [[nodiscard]]
static constexpr bool validate_arg(
const boost::json::value& arg)
noexcept
208 if constexpr (std::is_same_v<T, bool>)
210 return arg.is_bool();
212 else if constexpr (std::is_integral_v<T>)
214 return arg.is_int64() || arg.is_uint64();
216 else if constexpr (std::is_floating_point_v<T>)
218 return arg.is_double();
220 else if constexpr (std::is_same_v<T, std::string>)
222 return arg.is_string();
224 else if constexpr (rpc_hpp::detail::is_container_v<T>)
226 return arg.is_array();
230 return arg.is_object();
234 [[nodiscard]]
static std::string mismatch_string(
235 std::string&& expect_type,
const boost::json::value& obj)
237 const auto get_type_str = [&obj]()
noexcept
241 case boost::json::kind::bool_:
244 case boost::json::kind::int64:
247 case boost::json::kind::uint64:
250 case boost::json::kind::double_:
253 case boost::json::kind::string:
256 case boost::json::kind::array:
259 case boost::json::kind::object:
263 case boost::json::kind::null:
268 return {
"Boost.JSON expected type: " + std::move(expect_type)
269 +
", got type: " + get_type_str() };
273 static void push_arg(T&& arg, boost::json::value& obj)
275 using no_ref_t = std::remove_cv_t<std::remove_reference_t<T>>;
277 if constexpr (std::is_arithmetic_v<no_ref_t>)
281 else if constexpr (std::is_same_v<no_ref_t, std::string>)
283 obj = boost::json::string{ arg.c_str() };
285 else if constexpr (rpc_hpp::detail::is_container_v<no_ref_t>)
287 obj = boost::json::array{};
288 auto& arr = obj.get_array();
289 arr.reserve(arg.size());
291 for (
auto&& val : arg)
293 push_args(std::forward<
decltype(val)>(val), arr);
296 else if constexpr (rpc_hpp::detail::is_serializable_v<boost_json_adapter, no_ref_t>)
298 obj = no_ref_t::template serialize<boost_json_adapter>(std::forward<T>(arg));
302 obj = serialize<no_ref_t>(std::forward<T>(arg));
307 static void push_args(T&& arg, boost::json::array& obj_arr)
309 boost::json::value tmp{};
310 push_arg(std::forward<T>(arg), tmp);
311 obj_arr.push_back(std::move(tmp));
315 [[nodiscard]]
static std::remove_cv_t<std::remove_reference_t<T>> parse_arg(
316 const boost::json::value& arg)
318 using no_ref_t = std::remove_cv_t<std::remove_reference_t<T>>;
320 if (!validate_arg<no_ref_t>(arg))
325 if constexpr (std::is_arithmetic_v<no_ref_t> || std::is_same_v<no_ref_t, std::string>)
327 return boost::json::value_to<no_ref_t>(arg);
329 else if constexpr (rpc_hpp::detail::is_container_v<no_ref_t>)
331 using subvalue_t =
typename no_ref_t::value_type;
333 auto& arr = arg.get_array();
334 no_ref_t container{};
335 container.reserve(arr.size());
336 unsigned arg_counter = 0;
338 for (
const auto& val : arr)
340 container.push_back(parse_args<subvalue_t>(val, arg_counter));
345 else if constexpr (rpc_hpp::detail::is_serializable_v<boost_json_adapter, no_ref_t>)
347 return no_ref_t::template deserialize<boost_json_adapter>(arg.get_object());
351 return deserialize<no_ref_t>(arg.get_object());
356 [[nodiscard]]
static std::remove_cv_t<std::remove_reference_t<T>> parse_args(
357 const boost::json::value& arg_arr,
unsigned& index)
359 if (!arg_arr.is_array())
361 return parse_arg<T>(arg_arr);
364 const auto& arr = arg_arr.get_array();
366 if (index >= arr.size())
371 return parse_arg<T>(arr[index++]);
Definition: rpc_boost_json.hpp:57
Top-level namespace for rpc.hpp classes and functions.
Definition: rpc.hpp:88