From 5b84ab3b6852787f24f48534e7060603c051d5bf Mon Sep 17 00:00:00 2001 From: Ben Deane Date: Wed, 29 Oct 2025 09:33:02 -0600 Subject: [PATCH] :sparkles: Rename a field in a message Problem: - It is sometimes useful to rename a field in a message. Since fields are identified by name, this cannot be done with the existing `extend` mechanism. Solution: - Introduce `rename_field` for this purpose. --- include/msg/field.hpp | 5 ++++ include/msg/message.hpp | 34 ++++++++++++++++++++++++ test/msg/fail/CMakeLists.txt | 2 ++ test/msg/fail/rename_field_duplicate.cpp | 15 +++++++++++ test/msg/fail/rename_field_not_found.cpp | 13 +++++++++ test/msg/message.cpp | 9 +++++++ 6 files changed, 78 insertions(+) create mode 100644 test/msg/fail/rename_field_duplicate.cpp create mode 100644 test/msg/fail/rename_field_not_found.cpp diff --git a/include/msg/field.hpp b/include/msg/field.hpp index ecc59947..d8c7011d 100644 --- a/include/msg/field.hpp +++ b/include/msg/field.hpp @@ -535,6 +535,11 @@ class field_t : public field_spec_t>, using with_new_type = field_t, match::always_t, Ats...>; + // ====================================================================== + // rename field + template + using with_new_name = field_t; + // ====================================================================== // shift a field template diff --git a/include/msg/message.hpp b/include/msg/message.hpp index 0859b588..5e59b757 100644 --- a/include/msg/message.hpp +++ b/include/msg/message.hpp @@ -385,6 +385,7 @@ struct message { using num_fields_t = std::integral_constant; template using nth_field_t = stdx::nth_t; + using name_t = stdx::cts_t; using env_t = Env; using access_t = msg_access; using default_storage_t = typename access_t::default_storage_t; @@ -789,4 +790,37 @@ struct field_locator { template using relaxed_message = typename detail::field_locator::msg_type; + +namespace detail { +template struct replace_fields_q { + template + using fn = ::msg::message; +}; + +template +struct with_renamed_field { + using split_fields = boost::mp11::mp_partition_q>; + + using untouched_fs = boost::mp11::mp_second; + static_assert(boost::mp11::mp_count_if_q>::value == + 0, + "rename_field: New field name already exists in message"); + + using replaced_fs = boost::mp11::mp_first; + static_assert(not boost::mp11::mp_empty::value, + "rename_field: Old field name not found in message"); + + using new_f = typename boost::mp11::mp_first< + replaced_fs>::template with_new_name; + + using new_fields = boost::mp11::mp_push_back; + using msg = boost::mp11::mp_apply_q, new_fields>; +}; +} // namespace detail + +template +using rename_field = + typename detail::with_renamed_field::msg; } // namespace msg diff --git a/test/msg/fail/CMakeLists.txt b/test/msg/fail/CMakeLists.txt index 0af5cc91..9a1627dd 100644 --- a/test/msg/fail/CMakeLists.txt +++ b/test/msg/fail/CMakeLists.txt @@ -21,4 +21,6 @@ add_compile_fail_test(message_set_nonexistent_field.cpp LIBRARIES warnings cib_msg) add_compile_fail_test(message_uninitialized_field.cpp LIBRARIES warnings cib_msg) +add_compile_fail_test(rename_field_duplicate.cpp LIBRARIES warnings cib_msg) +add_compile_fail_test(rename_field_not_found.cpp LIBRARIES warnings cib_msg) add_compile_fail_test(view_upsize.cpp LIBRARIES warnings cib_msg) diff --git a/test/msg/fail/rename_field_duplicate.cpp b/test/msg/fail/rename_field_duplicate.cpp new file mode 100644 index 00000000..fe31c8a3 --- /dev/null +++ b/test/msg/fail/rename_field_duplicate.cpp @@ -0,0 +1,15 @@ +#include + +// EXPECT: New field name already exists in message +namespace { +using namespace msg; + +using test_field1 = + field<"f1", std::uint32_t>::located; +using test_field2 = + field<"f2", std::uint32_t>::located; + +using msg_defn = message<"test_msg", test_field1, test_field2>; +} // namespace + +auto main() -> int { using M = rename_field; } diff --git a/test/msg/fail/rename_field_not_found.cpp b/test/msg/fail/rename_field_not_found.cpp new file mode 100644 index 00000000..ed7b6d79 --- /dev/null +++ b/test/msg/fail/rename_field_not_found.cpp @@ -0,0 +1,13 @@ +#include + +// EXPECT: Old field name not found in message +namespace { +using namespace msg; + +using test_field1 = + field<"f1", std::uint32_t>::located; + +using msg_defn = message<"test_msg", test_field1>; +} // namespace + +auto main() -> int { using M = rename_field; } diff --git a/test/msg/message.cpp b/test/msg/message.cpp index 75a4a863..35c2192c 100644 --- a/test/msg/message.cpp +++ b/test/msg/message.cpp @@ -505,6 +505,15 @@ TEST_CASE("extend message with retyped field", "[message]") { STATIC_REQUIRE(std::is_same_v); } +TEST_CASE("rename field in message", "[message]") { + using base_defn = message<"msg_base", id_field, field1>; + using defn = rename_field; + using expected_f = + field<"f1_new", std::uint32_t>::located; + using expected_defn = message<"msg_base", id_field, expected_f>; + STATIC_REQUIRE(std::is_same_v); +} + TEST_CASE("message equivalence (owning)", "[message]") { test_msg m1{"f1"_field = 0xba11, "f2"_field = 0x42, "f3"_field = 0xd00d}; test_msg m2{"f1"_field = 0xba11, "f2"_field = 0x42, "f3"_field = 0xd00d};