#include #include #include #include #include using namespace boost::ut; namespace { template constexpr bool operator==(std::span a, std::span b) noexcept { return std::equal(a.begin(), a.end(), b.begin(), b.end()); } template constexpr std::array as_bytes(T&& t) { return std::bit_cast>(std::forward(t)); } template constexpr std::array make_bytes(Bytes&&... bytes) { return {std::byte(std::forward(bytes))...}; } template struct oversized_array { std::array data; std::size_t size; }; constexpr auto to_bytes_array_oversized(auto const& container) { using value_type = std::decay_t; oversized_array arr; std::copy(std::begin(container), std::end(container), std::begin(arr.data)); arr.size = std::distance(std::begin(container), std::end(container)); return arr; } consteval auto generate_bytes(auto callable) { constexpr auto oversized = to_bytes_array_oversized(callable()); using value_type = std::decay_t; std::array out; std::copy(std::begin(oversized.data), std::next(std::begin(oversized.data), oversized.size), std::begin(out)); return out; } consteval auto build_string(auto callable) { constexpr auto string_array = generate_bytes(callable); return string_array; } template constexpr auto cat(std::array const&... a) noexcept { std::array out; std::size_t index{}; ((std::copy_n(a.begin(), Sizes, out.begin() + index), index += Sizes), ...); return out; } constexpr auto repeat(std::span sv, std::size_t count) { std::vector range; range.reserve(sv.size() * count); for (decltype(count) i = 0; i < count; ++i) { std::copy_n(sv.begin(), sv.size(), std::back_inserter(range)); } return range; } constexpr auto repeat(std::string_view sv, std::size_t count) { std::vector range; range.reserve(sv.size() * count); for (decltype(count) i = 0; i < count; ++i) { std::copy_n(sv.begin(), sv.size(), std::back_inserter(range)); } return range; } constexpr auto from_string_view(std::string_view sv) { std::vector range; range.resize(sv.size()); auto itr = range.begin(); for (auto c : sv) { *itr = std::byte(c); ++itr; } return range; } template std::ostream& operator<<(std::ostream& os, tl::expected const& exp) { if (exp.has_value()) { os << "Value: '" << *exp << "'"; } else { os << "Error"; } return os; } bool test_incomplete_message(auto const& payload) { // Test incomplete message. for (decltype(payload.size()) i = 1; i < payload.size() - 1; ++i) { // Test incomplete message. msgpack::token_reader reader(std::span(payload.data(), i)); auto token = reader.read_one(); if (token != tl::make_unexpected(msgpack::error::incomplete_message)) { fmt::print("Got the wrong response reading subview[0,{}] of " "payload: {}\n", i, token->get().value()); return false; } } return true; } bool test_end_of_message(auto& reader) { return reader.read_one() == tl::make_unexpected(msgpack::error::end_of_message); } } // namespace template <> struct fmt::formatter { template constexpr auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { return ctx.begin(); } template auto format(msgpack::token const& v, FormatContext& ctx) const { auto out = fmt::format_to( ctx.out(), "()))); break; case msgpack::format::type::signed_int: out = fmt::format_to(out, "{}", (*(v.get()))); break; case msgpack::format::type::boolean: out = fmt::format_to(out, "{}", (*(v.get()))); break; case msgpack::format::type::string: out = fmt::format_to(out, "{}", (*(v.get()))); break; case msgpack::format::type::binary: out = fmt::format_to( out, "{}", (*(v.get>()))); break; case msgpack::format::type::map: out = fmt::format_to(out, "(arity: {})", (v.get()->count)); break; case msgpack::format::type::array: out = fmt::format_to(out, "(arity: {})", (v.get()->count)); break; case msgpack::format::type::nil: out = fmt::format_to(out, "(nil)"); break; case msgpack::format::type::invalid: out = fmt::format_to(out, "(invalid)"); break; default: break; } return fmt::format_to(out, ">"); } }; suite views_tests = [] { "read format::fixmap"_test = [] { // A MessagePack map of 3 strings to 8-bit unsigned integers. static constexpr auto strings = std::to_array({ "one", "two", "three", "array", "four", "map", "five", }); constexpr auto payload = cat(make_bytes(0x87, 0xa3), generate_bytes([] { return from_string_view(strings[0]); }), make_bytes(0x01, 0xa3), generate_bytes([] { return from_string_view(strings[1]); }), make_bytes(0x02, 0xa5), generate_bytes([] { return from_string_view(strings[2]); }), make_bytes(0x03, 0xa5), generate_bytes([] { return from_string_view(strings[3]); }), // Array of size 2, two fixints: make_bytes(0x92, 0x32, 0x33), make_bytes(0xa4), generate_bytes([] { return from_string_view(strings[4]); }), make_bytes(0x04, 0xa3), generate_bytes([] { return from_string_view(strings[5]); }), // Map of size 3, 6 total fixints. make_bytes(0x83, 0x01, 0x02, 0x03, 0x04, 0x33, 0x11), make_bytes(0xa4), generate_bytes([] { return from_string_view(strings[6]); }) // make_bytes(0x05) ); std::array tokens; msgpack::token_reader reader(payload); auto result = reader.read_some(tokens).map([](auto read_tokens) { for (auto const& [k, v] : msgpack::map_view(read_tokens)) { fmt::print("map[{}] = {}\n", k, v); } }); expect(result.has_value()); }; };