More unpacker work, reflection support
This commit is contained in:
parent
a65bff1697
commit
a2d480e723
36
MODULE.bazel.lock
generated
36
MODULE.bazel.lock
generated
@ -641,12 +641,13 @@
|
||||
"name": "apple_support~1.5.0~apple_cc_configure_extension~local_config_apple_cc_toolchains"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"recordedRepoMappingEntries": []
|
||||
}
|
||||
},
|
||||
"@@bazel_tools//tools/cpp:cc_configure.bzl%cc_configure_extension": {
|
||||
"general": {
|
||||
"bzlTransitiveDigest": "O9sf6ilKWU9Veed02jG9o2HM/xgV/UAyciuFBuxrFRY=",
|
||||
"bzlTransitiveDigest": "mcsWHq3xORJexV5/4eCvNOLxFOQKV6eli3fkr+tEaqE=",
|
||||
"accumulatedFileDigests": {},
|
||||
"envVariables": {},
|
||||
"generatedRepoSpecs": {
|
||||
@ -664,7 +665,14 @@
|
||||
"name": "bazel_tools~cc_configure_extension~local_config_cc_toolchains"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"recordedRepoMappingEntries": [
|
||||
[
|
||||
"bazel_tools",
|
||||
"bazel_tools",
|
||||
"bazel_tools"
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
"@@bazel_tools//tools/osx:xcode_configure.bzl%xcode_configure_extension": {
|
||||
@ -682,7 +690,8 @@
|
||||
"remote_xcode": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"recordedRepoMappingEntries": []
|
||||
}
|
||||
},
|
||||
"@@bazel_tools//tools/sh:sh_configure.bzl%sh_configure_extension": {
|
||||
@ -698,12 +707,13 @@
|
||||
"name": "bazel_tools~sh_configure_extension~local_config_sh"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"recordedRepoMappingEntries": []
|
||||
}
|
||||
},
|
||||
"@@rules_java~7.1.0//java:extensions.bzl%toolchains": {
|
||||
"general": {
|
||||
"bzlTransitiveDigest": "iUIRqCK7tkhvcDJCAfPPqSd06IHG0a8HQD0xeQyVAqw=",
|
||||
"bzlTransitiveDigest": "D02GmifxnV/IhYgspsJMDZ/aE8HxAjXgek5gi6FSto4=",
|
||||
"accumulatedFileDigests": {},
|
||||
"envVariables": {},
|
||||
"generatedRepoSpecs": {
|
||||
@ -1238,7 +1248,19 @@
|
||||
"build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_21\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"21\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk21_win//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk21_win//:jdk\",\n)\n"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"recordedRepoMappingEntries": [
|
||||
[
|
||||
"rules_java~7.1.0",
|
||||
"bazel_tools",
|
||||
"bazel_tools"
|
||||
],
|
||||
[
|
||||
"rules_java~7.1.0",
|
||||
"remote_java_tools",
|
||||
"rules_java~7.1.0~toolchains~remote_java_tools"
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,7 +3,7 @@ cc_library(
|
||||
name = "msgpack",
|
||||
hdrs = glob(["msgpack/**/*.h"]),
|
||||
includes = ["."],
|
||||
deps = ["@expected", "//include:path"],
|
||||
deps = ["@expected", "//include:path", "utility"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
@ -23,14 +23,6 @@ cc_library(
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "proto",
|
||||
hdrs = glob(["proto/**/*.h"]),
|
||||
includes = ["."],
|
||||
deps = ["@expected", "//include:path"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "utility",
|
||||
hdrs = glob(["utility/**/*.h"]),
|
||||
@ -39,6 +31,14 @@ cc_library(
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "proto",
|
||||
hdrs = glob(["proto/**/*.h"]),
|
||||
includes = ["."],
|
||||
deps = ["@expected", "//include:path", "utility"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
exports_files(
|
||||
["server.h"],
|
||||
visibility = ["//visibility:public"],
|
||||
|
||||
@ -62,6 +62,16 @@ struct format_arg<T> {
|
||||
type v;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct format_arg<std::string_view> {
|
||||
using type = std::string_view;
|
||||
|
||||
constexpr format_arg(std::string_view const& t) noexcept
|
||||
: v(t) {}
|
||||
|
||||
std::string_view v;
|
||||
};
|
||||
|
||||
template <detail::smart_pointer T>
|
||||
struct format_arg<T> {
|
||||
using type = void const*;
|
||||
|
||||
76
include/parselink/msgpack/core/detail/unpack_map.h
Normal file
76
include/parselink/msgpack/core/detail/unpack_map.h
Normal file
@ -0,0 +1,76 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// ___ __ _ _
|
||||
// / _ \__ _ _ __ ___ ___ / /(_)_ __ | | __
|
||||
// / /_)/ _` | '__/ __|/ _ \/ / | | '_ \| |/ /
|
||||
// / ___/ (_| | | \__ \ __/ /__| | | | | <
|
||||
// \/ \__,_|_| |___/\___\____/_|_| |_|_|\_\ .
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
// Author: Kurt Sassenrath
|
||||
// Module: msgpack
|
||||
//
|
||||
// Support for unpacking maps with known structure.
|
||||
//
|
||||
// Maps contain key, value pairs. These pairs may arrive in an
|
||||
// implementation-defined order; this code aims to provide the user of the
|
||||
// interface with a means to pass a set of handlers for each key.
|
||||
//
|
||||
// Copyright (c) 2023 Kurt Sassenrath.
|
||||
//
|
||||
// License TBD.
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifndef msgpack_core_detail_unpack_map_9f12af74a689aa51
|
||||
#define msgpack_core_detail_unpack_map_9f12af74a689aa51
|
||||
|
||||
#include "parselink/utility/ctstring.h"
|
||||
#include <algorithm>
|
||||
#include <tuple>
|
||||
|
||||
namespace msgpack {
|
||||
namespace map {
|
||||
|
||||
struct key_base {};
|
||||
|
||||
template <auto key_value, typename callable>
|
||||
struct key : key_base {
|
||||
static constexpr auto const& value = key_value;
|
||||
callable handler;
|
||||
|
||||
constexpr key(callable fn) noexcept
|
||||
: handler(std::move(fn)) {}
|
||||
};
|
||||
|
||||
template <auto key_value>
|
||||
constexpr auto on_key(auto callable) noexcept {
|
||||
return key<key_value, decltype(callable)>(std::move(callable));
|
||||
}
|
||||
|
||||
template <parselink::ct::string key_value>
|
||||
constexpr auto on_key(auto callable) noexcept {
|
||||
return key<key_value, decltype(callable)>(std::move(callable));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
concept is_key = std::is_base_of_v<key_base, T>;
|
||||
|
||||
consteval auto get_key(is_key auto const& key) {
|
||||
return std::decay_t<decltype(key)>::value;
|
||||
}
|
||||
|
||||
struct policy_type {};
|
||||
|
||||
struct required : policy_type {};
|
||||
|
||||
template <is_key... Keys>
|
||||
struct key_group {
|
||||
constexpr key_group(Keys&&... keys) noexcept
|
||||
: keys_(std::make_tuple(std::forward<Keys>(keys)...)){};
|
||||
|
||||
std::tuple<Keys...> keys_;
|
||||
constexpr static std::size_t size = sizeof...(Keys);
|
||||
}; // namespace map
|
||||
|
||||
} // namespace map
|
||||
} // namespace msgpack
|
||||
|
||||
#endif // msgpack_core_detail_unpack_map_9f12af74a689aa51
|
||||
@ -24,7 +24,6 @@
|
||||
#include <span>
|
||||
#include <string_view>
|
||||
|
||||
|
||||
namespace parselink {
|
||||
namespace proto {
|
||||
|
||||
@ -45,15 +44,17 @@ struct message : base_message {
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
concept message_type = std::is_base_of_v<base_message, T>;
|
||||
concept message_type = requires { T::message_name(); };
|
||||
|
||||
struct error_message {
|
||||
static constexpr auto message_name() noexcept { return "error"; }
|
||||
|
||||
struct error_message : message<"error"> {
|
||||
std::uint32_t code; // An error code
|
||||
std::string_view what; // A string
|
||||
};
|
||||
|
||||
// C->S: Request to (re)connect.
|
||||
struct connect_message : base_message {
|
||||
struct connect_message : message<"connect"> {
|
||||
std::uint32_t version; // The version of the client.
|
||||
std::string_view user_id; // The user id.
|
||||
std::span<std::byte> session_token; // An optional existing session token.
|
||||
|
||||
@ -21,10 +21,45 @@
|
||||
#ifndef parselink_proto_parser_ad351d41fe4c72dd
|
||||
#define parselink_proto_parser_ad351d41fe4c72dd
|
||||
|
||||
#include "parselink/logging.h"
|
||||
#include "parselink/proto/error.h"
|
||||
#include "parselink/proto/message.h"
|
||||
|
||||
#include "parselink/msgpack/core/unpacker.h"
|
||||
|
||||
#include <tl/expected.hpp>
|
||||
#include <boost/pfr.hpp>
|
||||
|
||||
namespace parselink {
|
||||
logging::logger& get_logger();
|
||||
}
|
||||
|
||||
namespace msgpack {
|
||||
|
||||
template <parselink::proto::message_type M>
|
||||
struct unpacker_adapter<M> {
|
||||
static constexpr auto unpack(auto& unpacker) noexcept
|
||||
-> tl::expected<M, error> {
|
||||
auto verify_name = unpacker.template unpack<std::string_view>();
|
||||
|
||||
if (!verify_name || verify_name != M::message_name()) {
|
||||
fmt::print("{} {}\n", verify_name, M::message_name());
|
||||
return tl::make_unexpected(error::wrong_type);
|
||||
}
|
||||
|
||||
auto mapsize = unpacker.template unpack<msgpack::map_desc>();
|
||||
|
||||
if (!mapsize) {
|
||||
return tl::make_unexpected(error::wrong_type);
|
||||
} else if (mapsize->count != boost::pfr::tuple_size_v<M>) {
|
||||
return tl::make_unexpected(error::wrong_type);
|
||||
}
|
||||
|
||||
return M{};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace msgpack
|
||||
|
||||
namespace parselink {
|
||||
namespace proto {
|
||||
|
||||
174
include/parselink/utility/ctreflect.h
Normal file
174
include/parselink/utility/ctreflect.h
Normal file
@ -0,0 +1,174 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// ___ __ _ _
|
||||
// / _ \__ _ _ __ ___ ___ / /(_)_ __ | | __
|
||||
// / /_)/ _` | '__/ __|/ _ \/ / | | '_ \| |/ /
|
||||
// / ___/ (_| | | \__ \ __/ /__| | | | | <
|
||||
// \/ \__,_|_| |___/\___\____/_|_| |_|_|\_\ .
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
// Author: Kurt Sassenrath
|
||||
// Module: Utility
|
||||
//
|
||||
// Compile-time reflection for structures.
|
||||
//
|
||||
// Copyright (c) 2023 Kurt Sassenrath.
|
||||
//
|
||||
// License TBD.
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifndef parselink_ct_reflect_080596cd36d52770
|
||||
#define parselink_ct_reflect_080596cd36d52770
|
||||
|
||||
#include <array>
|
||||
#include <source_location>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
|
||||
namespace parselink {
|
||||
namespace ct {
|
||||
|
||||
namespace detail {
|
||||
|
||||
// This allows us to reference a type instance without ever instantiating it.
|
||||
template <typename T>
|
||||
extern T const phantom;
|
||||
|
||||
// This type binds to anything, allowing us to sus out the number of data
|
||||
// members in an aggregate.
|
||||
struct any_type {
|
||||
template <typename T>
|
||||
constexpr operator T();
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
// This template takes a wrapped pointer to a data member of a theoretical
|
||||
// instance of that type, in order to retrieve the name at compile time.
|
||||
// Examples:
|
||||
// gcc:
|
||||
// constexpr auto parselink::ct::detail::src_string() [with auto Member = const_ptr<int>{(& phantom<structure>.structure::field)}]
|
||||
//
|
||||
// clang:
|
||||
// auto parselink::ct::detail::src_string() [Member = const_ptr<member_ptr>{&phantom.field}]
|
||||
// clang-format on
|
||||
template <auto Member>
|
||||
constexpr auto src_string() {
|
||||
return std::source_location::current().function_name();
|
||||
}
|
||||
|
||||
template <char StartDelim, char EndDelim>
|
||||
struct base_parse_traits {
|
||||
static constexpr char start_delim = StartDelim;
|
||||
static constexpr char end_delim = EndDelim;
|
||||
};
|
||||
|
||||
#ifdef __clang__
|
||||
struct parse : base_parse_traits<'.', '}'> {};
|
||||
#elif defined(__GNUC__)
|
||||
struct parse : base_parse_traits<':', ')'> {};
|
||||
#endif
|
||||
|
||||
static constexpr std::size_t max_members = 8;
|
||||
|
||||
// TODO: Logarithmic approach
|
||||
// This needs to be limited to max_members, otherwise clang will go off into
|
||||
// the weeds.
|
||||
template <typename T, typename... Members>
|
||||
requires(sizeof...(Members) <= max_members)
|
||||
consteval std::size_t count_members(Members&&... members) {
|
||||
if constexpr (requires { T{any_type{}, members...}; } == false) {
|
||||
return sizeof...(members);
|
||||
} else if constexpr (sizeof...(members) <= max_members) {
|
||||
return count_members<T>(members..., any_type{});
|
||||
} else {
|
||||
throw "Too many members / something went wrong!";
|
||||
}
|
||||
};
|
||||
|
||||
// This function takes an aggregate and attempts to bind it into a tuple.
|
||||
// Unfortunately, without variadic packs for structured bindings, this will
|
||||
// rely on some heavy boilerplate.
|
||||
template <typename T, std::size_t MemberCount = count_members<T>()>
|
||||
requires(MemberCount <= 8)
|
||||
consteval decltype(auto) as_tuple(T&& t) {
|
||||
if constexpr (MemberCount == 0) {
|
||||
return std::tuple{};
|
||||
} else if constexpr (MemberCount == 1) {
|
||||
auto&& [a0] = t;
|
||||
return std::tie(a0);
|
||||
} else if constexpr (MemberCount == 2) {
|
||||
auto&& [a0, a1] = t;
|
||||
return std::tie(a0, a1);
|
||||
} else if constexpr (MemberCount == 3) {
|
||||
auto&& [a0, a1, a2] = t;
|
||||
return std::tie(a0, a1, a2);
|
||||
} else if constexpr (MemberCount == 4) {
|
||||
auto&& [a0, a1, a2, a3] = t;
|
||||
return std::tie(a0, a1, a2, a3);
|
||||
} else if constexpr (MemberCount == 5) {
|
||||
auto&& [a0, a1, a2, a3, a4] = t;
|
||||
return std::tie(a0, a1, a2, a3, a4);
|
||||
} else if constexpr (MemberCount == 6) {
|
||||
auto&& [a0, a1, a2, a3, a4, a5] = t;
|
||||
return std::tie(a0, a1, a2, a3, a4, a5);
|
||||
} else if constexpr (MemberCount == 7) {
|
||||
auto&& [a0, a1, a2, a3, a4, a5, a6] = t;
|
||||
return std::tie(a0, a1, a2, a3, a4, a5, a6);
|
||||
} else if constexpr (MemberCount == 8) {
|
||||
auto&& [a0, a1, a2, a3, a4, a5, a6, a7] = t;
|
||||
return std::tie(a0, a1, a2, a3, a4, a5, a6, a7);
|
||||
} else {
|
||||
throw "Too many members!";
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
struct const_ptr {
|
||||
T const* ptr;
|
||||
};
|
||||
|
||||
template <std::size_t I, typename T>
|
||||
consteval decltype(auto) as_ptr(T&& t) noexcept {
|
||||
auto&& member = std::get<I>(as_tuple(t));
|
||||
using member_ptr = std::decay_t<decltype(member)>;
|
||||
return const_ptr<member_ptr>(&member);
|
||||
}
|
||||
|
||||
template <typename T, std::size_t I>
|
||||
consteval decltype(auto) raw_member_name() noexcept {
|
||||
return src_string<as_ptr<I>(phantom<T>)>();
|
||||
}
|
||||
|
||||
template <typename T, std::size_t I>
|
||||
consteval decltype(auto) get_member_name() noexcept {
|
||||
std::string_view raw = raw_member_name<T, I>();
|
||||
auto s = raw.rfind(parse::start_delim);
|
||||
auto e = raw.rfind(parse::end_delim);
|
||||
if (s == raw.npos || e == raw.npos) throw "name parsing is broken!";
|
||||
return raw.substr(s + 1, e - (s + 1));
|
||||
}
|
||||
|
||||
template <typename T, std::size_t... Is>
|
||||
consteval decltype(auto) get_member_names(std::index_sequence<Is...>) noexcept {
|
||||
return std::array{get_member_name<T, Is>()...};
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename T, std::size_t I>
|
||||
consteval decltype(auto) member_name() noexcept {
|
||||
std::string_view raw = detail::raw_member_name<T, I>();
|
||||
auto s = raw.rfind(detail::parse::start_delim);
|
||||
auto e = raw.rfind(detail::parse::end_delim);
|
||||
if (s == raw.npos || e == raw.npos) throw "name_of is broken!";
|
||||
return raw.substr(s + 1, e - (s + 1));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
consteval decltype(auto) member_names() noexcept {
|
||||
return detail::get_member_names<T>(
|
||||
std::make_index_sequence<detail::count_members<T>()>{});
|
||||
}
|
||||
|
||||
} // namespace ct
|
||||
} // namespace parselink
|
||||
|
||||
#endif // parselink_ct_reflect_080596cd36d52770
|
||||
@ -16,6 +16,10 @@
|
||||
//
|
||||
// License TBD.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef ct_string_4fab12ca46f0d931
|
||||
#define ct_string_4fab12ca46f0d931
|
||||
|
||||
#include <array>
|
||||
#include <string_view>
|
||||
|
||||
@ -116,3 +120,5 @@ static_assert(string("hello") + string(" world") == string("hello world"));
|
||||
|
||||
} // namespace ct
|
||||
} // namespace parselink
|
||||
|
||||
#endif // ct_string_4fab12ca46f0d931
|
||||
|
||||
@ -101,7 +101,8 @@ awaitable<void> simple_client::connect_to_server() noexcept {
|
||||
logger.debug("Connecting to {}", r.endpoint());
|
||||
std::array<std::byte, 4096> buff;
|
||||
msgpack::packer packer(buff);
|
||||
packer.pack("hello");
|
||||
packer.pack("error");
|
||||
packer.pack(msgpack::map_desc{2});
|
||||
auto span = packer.subspan();
|
||||
auto [ec, bw] = co_await socket.async_send_to(
|
||||
net::buffer(span.data(), span.size()), r.endpoint(),
|
||||
|
||||
@ -22,12 +22,15 @@
|
||||
#include "parselink/msgpack/core/unpacker.h"
|
||||
|
||||
namespace parselink {
|
||||
|
||||
namespace {
|
||||
logging::logger logger{"parser"};
|
||||
}
|
||||
|
||||
namespace proto {
|
||||
|
||||
namespace {
|
||||
|
||||
logging::logger logger{"parser"};
|
||||
|
||||
constexpr auto assign(auto& param, msgpack::unpacker& unpacker) noexcept
|
||||
-> tl::expected<void, error> {
|
||||
auto do_assign = [¶m](auto&& v) { param = v; };
|
||||
@ -46,7 +49,7 @@ tl::expected<connect_message, error> parse_connect_message(
|
||||
constexpr static tl::unexpected<error> bad_data(error::bad_data);
|
||||
|
||||
auto type = unpacker.unpack<std::string_view>();
|
||||
if (!type || type != "connect") return bad_data;
|
||||
if (!type || type != connect_message::name()) return bad_data;
|
||||
|
||||
auto entries = unpacker.unpack<msgpack::map_desc>();
|
||||
if (!entries) return bad_data;
|
||||
@ -68,3 +71,5 @@ tl::expected<connect_message, error> parse_connect_message(
|
||||
|
||||
} // namespace proto
|
||||
} // namespace parselink
|
||||
|
||||
parselink::logging::logger& parselink::get_logger() { return logger; }
|
||||
|
||||
@ -64,7 +64,14 @@ net::awaitable<void> udp_server::listen() noexcept {
|
||||
auto [ec, br] = co_await listener.async_receive_from(
|
||||
net::buffer(buff), remote, no_ex_coro);
|
||||
if (!ec) {
|
||||
auto sp = std::span(buff.begin(), br);
|
||||
logger.debug("From {}: {}", remote, std::span(buff.begin(), br));
|
||||
msgpack::unpacker unpacker(sp);
|
||||
unpacker.unpack<proto::error_message>()
|
||||
.map([](auto msg) { logger.debug("Got error message"); })
|
||||
.map_error([](auto err) {
|
||||
logger.error("Error getting msg: {}", err);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -5,5 +5,9 @@ cc_test(
|
||||
"*.cpp",
|
||||
"*.h",
|
||||
]),
|
||||
deps = ["//tests/msgpack:common", "@rapidcheck"],
|
||||
deps = [
|
||||
"//tests/msgpack:common",
|
||||
"@rapidcheck",
|
||||
"@boost//:pfr",
|
||||
],
|
||||
)
|
||||
|
||||
82
tests/msgpack/unpacker/maps.cpp
Normal file
82
tests/msgpack/unpacker/maps.cpp
Normal file
@ -0,0 +1,82 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// ___ __ _ _
|
||||
// / _ \__ _ _ __ ___ ___ / /(_)_ __ | | __
|
||||
// / /_)/ _` | '__/ __|/ _ \/ / | | '_ \| |/ /
|
||||
// / ___/ (_| | | \__ \ __/ /__| | | | | <
|
||||
// \/ \__,_|_| |___/\___\____/_|_| |_|_|\_\ .
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
// Author: Kurt Sassenrath
|
||||
// Module: msgpack
|
||||
//
|
||||
// Unpacker tests for maps.
|
||||
//
|
||||
// Copyright (c) 2023 Kurt Sassenrath.
|
||||
//
|
||||
// License TBD.
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "parselink/msgpack/core/detail/unpack_map.h"
|
||||
#include "parselink/utility/ctstring.h"
|
||||
#include "test_unpacker.h"
|
||||
|
||||
#include "parselink/utility/ctreflect.h"
|
||||
|
||||
#include <fmt/ranges.h>
|
||||
|
||||
using namespace boost::ut;
|
||||
|
||||
struct S {
|
||||
int abra;
|
||||
int bar;
|
||||
int cat;
|
||||
int dog;
|
||||
int lbue;
|
||||
int bue;
|
||||
int ue;
|
||||
};
|
||||
|
||||
suite test_on_key = [] {
|
||||
"on_key<int>"_test = [] {
|
||||
bool expected = false;
|
||||
auto key = msgpack::map::on_key<5>([&] { expected = true; });
|
||||
expect(!expected);
|
||||
key.handler();
|
||||
expect(expected);
|
||||
};
|
||||
"on_key<string>"_test = [] {
|
||||
bool expected = false;
|
||||
auto key = msgpack::map::on_key<"hello">([&] { expected = true; });
|
||||
expect(!expected);
|
||||
key.handler();
|
||||
expect(expected);
|
||||
};
|
||||
|
||||
"key_group<int>"_test = [] {
|
||||
auto keys = msgpack::map::key_group(
|
||||
msgpack::map::on_key<5>([] {}), msgpack::map::on_key<1>([] {}));
|
||||
constexpr auto size = decltype(keys)::size;
|
||||
constexpr auto first_key = get_key(std::get<0>(keys.keys_));
|
||||
constexpr auto second_key = get_key(std::get<1>(keys.keys_));
|
||||
static_assert(size == 2);
|
||||
expect(first_key == 5);
|
||||
expect(second_key == 1);
|
||||
};
|
||||
"key_group<string>"_test = [] {
|
||||
auto keys =
|
||||
msgpack::map::key_group(msgpack::map::on_key<"hello">([] {}),
|
||||
msgpack::map::on_key<"world">([] {}));
|
||||
constexpr auto size = decltype(keys)::size;
|
||||
constexpr auto first_key = get_key(std::get<0>(keys.keys_));
|
||||
constexpr auto second_key = get_key(std::get<1>(keys.keys_));
|
||||
static_assert(size == 2);
|
||||
expect(first_key == "hello");
|
||||
expect(second_key == "world");
|
||||
};
|
||||
"key_group_from_struct_names"_test = [] {
|
||||
constexpr auto namefn = parselink::ct::member_name<S, 1>();
|
||||
static_assert(parselink::ct::member_name<S, 1>() == "bar");
|
||||
fmt::print("{}\n", namefn);
|
||||
constexpr auto names = parselink::ct::member_names<S>();
|
||||
fmt::print("{}\n", names);
|
||||
};
|
||||
};
|
||||
@ -9,7 +9,7 @@
|
||||
// Author: Kurt Sassenrath
|
||||
// Module: msgpack
|
||||
//
|
||||
// Default packer tests.
|
||||
// Unpacker tests for unsigned integers.
|
||||
//
|
||||
// Copyright (c) 2023 Kurt Sassenrath.
|
||||
//
|
||||
|
||||
Loading…
Reference in New Issue
Block a user