diff --git a/include/msg/message.hpp b/include/msg/message.hpp index 8986c2e7..b7f4ff6e 100644 --- a/include/msg/message.hpp +++ b/include/msg/message.hpp @@ -356,6 +356,9 @@ template struct msg_base { template struct message { using fields_t = stdx::type_list; + using num_fields_t = std::integral_constant; + template using nth_field_t = stdx::nth_t; + using env_t = Env; using access_t = msg_access; using default_storage_t = typename access_t::default_storage_t; diff --git a/include/msg/message_destructure.hpp b/include/msg/message_destructure.hpp new file mode 100644 index 00000000..b0fa7e9f --- /dev/null +++ b/include/msg/message_destructure.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include + +#include + +#include +#include +#include +#include + +template +struct std::tuple_size : M::definition_t::num_fields_t {}; + +template +struct std::tuple_element + : std::type_identity< + typename M::definition_t::template nth_field_t::value_type> {}; + +namespace msg::detail { +template +constexpr auto get(M &&m) -> decltype(auto) { + return std::forward(m).get(typename std::remove_cvref_t< + M>::definition_t::template nth_field_t{}); +} +} // namespace msg::detail diff --git a/test/msg/message.cpp b/test/msg/message.cpp index dc54b687..dcef4669 100644 --- a/test/msg/message.cpp +++ b/test/msg/message.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -73,6 +74,24 @@ TEST_CASE("construct with field values", "[message]") { CHECK(0x0042'd00d == data[1]); } +TEST_CASE("message supports tuple protocol", "[message]") { + [[maybe_unused]] test_msg msg{"f1"_field = 0xba11, "f2"_field = 0x42, + "f3"_field = 0xd00d}; + STATIC_REQUIRE(std::tuple_size_v == 4); + STATIC_REQUIRE( + std::is_same_v, std::uint32_t>); +} + +TEST_CASE("destructure owning message", "[message]") { + test_msg msg{"f1"_field = 0xba11, "f2"_field = 0x42, "f3"_field = 0xd00d}; + STATIC_REQUIRE(std::tuple_size_v == 4); + auto const [f1, id, f3, f2] = msg; + CHECK(0x80 == id); + CHECK(0xba11 == f1); + CHECK(0x42 == f2); + CHECK(0xd00d == f3); +} + TEST_CASE("use field names as template args", "[message]") { auto msg = []() { return test_msg{F = 0xba11}; @@ -123,6 +142,18 @@ TEST_CASE("view with read-only external storage", "[message]") { CHECK(0xd00d == msg.get("f3"_field)); } +TEST_CASE("destructure message view", "[message]") { + auto const arr = + typename msg_defn::default_storage_t{0x8000'ba11, 0x0042'd00d}; + const_view msg{arr}; + + auto const [f1, id, f3, f2] = msg; + CHECK(0x80 == id); + CHECK(0xba11 == f1); + CHECK(0x42 == f2); + CHECK(0xd00d == f3); +} + TEST_CASE("view with external storage (oversized)", "[message]") { auto const arr = std::array{0x8000'ba11, 0x0042'd00d}; msg_defn::view_t msg{arr};