Skip to content

Commit 5b84ab3

Browse files
committed
✨ 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<Msg, OldName, NewName>` for this purpose.
1 parent 2add973 commit 5b84ab3

File tree

6 files changed

+78
-0
lines changed

6 files changed

+78
-0
lines changed

include/msg/field.hpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,11 @@ class field_t : public field_spec_t<Name, T, detail::field_size<Ats...>>,
535535
using with_new_type =
536536
field_t<Name, U, detail::with_default<U>, match::always_t, Ats...>;
537537

538+
// ======================================================================
539+
// rename field
540+
template <stdx::ct_string NewName>
541+
using with_new_name = field_t<NewName, T, Default, M, Ats...>;
542+
538543
// ======================================================================
539544
// shift a field
540545
template <auto N, typename Unit = bit_unit>

include/msg/message.hpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,7 @@ struct message {
385385
using num_fields_t = std::integral_constant<std::size_t, sizeof...(Fields)>;
386386
template <std::size_t I> using nth_field_t = stdx::nth_t<I, Fields...>;
387387

388+
using name_t = stdx::cts_t<Name>;
388389
using env_t = Env;
389390
using access_t = msg_access<Name, Fields...>;
390391
using default_storage_t = typename access_t::default_storage_t;
@@ -789,4 +790,37 @@ struct field_locator<Name, Env, Fields...> {
789790

790791
template <stdx::ct_string Name, typename... Ts>
791792
using relaxed_message = typename detail::field_locator<Name, Ts...>::msg_type;
793+
794+
namespace detail {
795+
template <typename Msg> struct replace_fields_q {
796+
template <typename... Fs>
797+
using fn = ::msg::message<Msg::name_t::value, typename Msg::env_t, Fs...>;
798+
};
799+
800+
template <typename Msg, stdx::ct_string OldName, stdx::ct_string NewName>
801+
struct with_renamed_field {
802+
using split_fields = boost::mp11::mp_partition_q<typename Msg::fields_t,
803+
matching_name<OldName>>;
804+
805+
using untouched_fs = boost::mp11::mp_second<split_fields>;
806+
static_assert(boost::mp11::mp_count_if_q<untouched_fs,
807+
matching_name<NewName>>::value ==
808+
0,
809+
"rename_field: New field name already exists in message");
810+
811+
using replaced_fs = boost::mp11::mp_first<split_fields>;
812+
static_assert(not boost::mp11::mp_empty<replaced_fs>::value,
813+
"rename_field: Old field name not found in message");
814+
815+
using new_f = typename boost::mp11::mp_first<
816+
replaced_fs>::template with_new_name<NewName>;
817+
818+
using new_fields = boost::mp11::mp_push_back<untouched_fs, new_f>;
819+
using msg = boost::mp11::mp_apply_q<replace_fields_q<Msg>, new_fields>;
820+
};
821+
} // namespace detail
822+
823+
template <typename Msg, stdx::ct_string OldName, stdx::ct_string NewName>
824+
using rename_field =
825+
typename detail::with_renamed_field<Msg, OldName, NewName>::msg;
792826
} // namespace msg

test/msg/fail/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,6 @@ add_compile_fail_test(message_set_nonexistent_field.cpp LIBRARIES warnings
2121
cib_msg)
2222
add_compile_fail_test(message_uninitialized_field.cpp LIBRARIES warnings
2323
cib_msg)
24+
add_compile_fail_test(rename_field_duplicate.cpp LIBRARIES warnings cib_msg)
25+
add_compile_fail_test(rename_field_not_found.cpp LIBRARIES warnings cib_msg)
2426
add_compile_fail_test(view_upsize.cpp LIBRARIES warnings cib_msg)
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#include <msg/message.hpp>
2+
3+
// EXPECT: New field name already exists in message
4+
namespace {
5+
using namespace msg;
6+
7+
using test_field1 =
8+
field<"f1", std::uint32_t>::located<at{0_dw, 31_msb, 24_lsb}>;
9+
using test_field2 =
10+
field<"f2", std::uint32_t>::located<at{0_dw, 23_msb, 16_lsb}>;
11+
12+
using msg_defn = message<"test_msg", test_field1, test_field2>;
13+
} // namespace
14+
15+
auto main() -> int { using M = rename_field<msg_defn, "f1", "f2">; }
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#include <msg/message.hpp>
2+
3+
// EXPECT: Old field name not found in message
4+
namespace {
5+
using namespace msg;
6+
7+
using test_field1 =
8+
field<"f1", std::uint32_t>::located<at{0_dw, 31_msb, 24_lsb}>;
9+
10+
using msg_defn = message<"test_msg", test_field1>;
11+
} // namespace
12+
13+
auto main() -> int { using M = rename_field<msg_defn, "f", "F">; }

test/msg/message.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -505,6 +505,15 @@ TEST_CASE("extend message with retyped field", "[message]") {
505505
STATIC_REQUIRE(std::is_same_v<defn, expected_defn>);
506506
}
507507

508+
TEST_CASE("rename field in message", "[message]") {
509+
using base_defn = message<"msg_base", id_field, field1>;
510+
using defn = rename_field<base_defn, "f1", "f1_new">;
511+
using expected_f =
512+
field<"f1_new", std::uint32_t>::located<at{0_dw, 15_msb, 0_lsb}>;
513+
using expected_defn = message<"msg_base", id_field, expected_f>;
514+
STATIC_REQUIRE(std::is_same_v<defn, expected_defn>);
515+
}
516+
508517
TEST_CASE("message equivalence (owning)", "[message]") {
509518
test_msg m1{"f1"_field = 0xba11, "f2"_field = 0x42, "f3"_field = 0xd00d};
510519
test_msg m2{"f1"_field = 0xba11, "f2"_field = 0x42, "f3"_field = 0xd00d};

0 commit comments

Comments
 (0)