diff --git a/include/parselink/msgpack/core/detail/builtin_packable_types.h b/include/parselink/msgpack/core/detail/builtin_packable_types.h index 1dde8a1..dcc3777 100644 --- a/include/parselink/msgpack/core/detail/builtin_packable_types.h +++ b/include/parselink/msgpack/core/detail/builtin_packable_types.h @@ -194,7 +194,7 @@ struct builtin_packer : builtin_packer_base { static constexpr std::size_t len_size(std::string_view value) noexcept { auto const len = std::size(value); - if (len <= std::uint32_t(format::fixstr::mask)) return 0; + if (len <= static_cast(format::fixstr::mask)) return 0; return std::min(max_payload_length, std::bit_ceil(std::uint32_t((std::bit_width(len) + 7) >> 3))); } @@ -226,12 +226,66 @@ struct builtin_packer : builtin_packer_base { template T> struct builtin_packer : builtin_packer {}; -/* template <> */ -/* struct builtin_packer */ -/* : builtin_packer_base {}; */ +template <> +struct builtin_packer : builtin_packer_base { + static constexpr std::size_t rep_size(array_desc value) noexcept { + auto const len = value.count; + if (len <= static_cast(format::fixarray::mask)) { + return 0; + } + + if (len < 0x10000) return 2; + return 4; + } + + static constexpr auto marker(array_desc value) noexcept { + switch (rep_size(value)) { + case 0: + return format::fixarray::marker + | static_cast(value.count); + case 2: return format::array16::marker; + case 4: + default: return format::array32::marker; + } + } + + static constexpr auto pack(array_desc value, auto out) noexcept { + *out++ = marker(value); + return detail::pack_integral(value.count, out, rep_size(value)); + } +}; + +template <> +struct builtin_packer : builtin_packer_base { + static constexpr std::size_t rep_size(map_desc value) noexcept { + auto const len = value.count; + if (len <= static_cast(format::fixmap::mask)) { + return 0; + } + + if (len < 0x10000) return 2; + return 4; + } + + static constexpr auto marker(map_desc value) noexcept { + switch (rep_size(value)) { + case 0: + return format::fixmap::marker + | static_cast(value.count); + case 2: return format::map16::marker; + case 4: + default: return format::map32::marker; + } + } + + static constexpr auto pack(map_desc value, auto out) noexcept { + *out++ = marker(value); + return detail::pack_integral(value.count, out, rep_size(value)); + } +}; /* template <> */ -/* struct builtin_packer */ +/* struct builtin_packer */ /* : builtin_packer_base {}; */ // Requirements for builtin_packable types. diff --git a/tests/msgpack/test_packer.cpp b/tests/msgpack/test_packer.cpp index bbe2cf6..66a36f0 100644 --- a/tests/msgpack/test_packer.cpp +++ b/tests/msgpack/test_packer.cpp @@ -44,6 +44,24 @@ struct fmt::formatter : fmt::formatter { } }; +template <> +struct fmt::formatter : fmt::formatter { + template + auto format(msgpack::map_desc const& value, FormatContext& ctx) const { + return fmt::format_to( + ctx.out(), "{{msgpack::map_desc: {}}}", value.count); + } +}; + +template <> +struct fmt::formatter : fmt::formatter { + template + auto format(msgpack::array_desc const& value, FormatContext& ctx) const { + return fmt::format_to( + ctx.out(), "{{msgpack::array_desc: {}}}", value.count); + } +}; + namespace { template @@ -164,6 +182,42 @@ struct test_data { } }; +template <> +struct test_data { + static constexpr auto values = std::to_array({ + 1, // fixarray + 15, // fixarray + 16, // array16 + 65535, // array16 + 65536 // array32 + }); + + static constexpr auto payload = make_bytes(0x91, // fixarray + 0x9f, // fixarray + 0xdc, 0x00, 0x10, // array16 + 0xdc, 0xff, 0xff, // array16 + 0xdd, 0x00, 0x01, 0x00, 0x00 // array32 + ); +}; + +template <> +struct test_data { + static constexpr auto values = std::to_array({ + 1, // fixmap + 15, // fixmap + 16, // map16 + 65535, // map16 + 65536 // map32 + }); + + static constexpr auto payload = make_bytes(0x81, // fixmap + 0x8f, // fixmap + 0xde, 0x00, 0x10, // map16 + 0xde, 0xff, 0xff, // map16 + 0xdf, 0x00, 0x01, 0x00, 0x00 // map32 + ); +}; + template T> struct test_data { static constexpr auto values = std::to_array({ @@ -282,6 +336,9 @@ suite packer = [] { expect(test_deduced()); }; #endif + + // Byte ranges -> Binary + "packer::pack>"_test = [] { expect(test_deduced>()); }; @@ -319,4 +376,14 @@ suite packer = [] { expect(std::ranges::equal(payload, expected)); } }; + + // array_desc - Just the header of the array. + "packer::pack"_test = [] { + expect(test_deduced()); + }; + + // map_desc - Just the header of the map. + "packer::pack"_test = [] { + expect(test_deduced()); + }; };