diff --git a/docs/message.adoc b/docs/message.adoc index 5c3df952..4cd32162 100644 --- a/docs/message.adoc +++ b/docs/message.adoc @@ -210,6 +210,34 @@ The second parameter to `pack` (`std::uint8_t` in the example above) defines how the messages are packed together - in this case, each subsequent message is byte-aligned. +CAUTION: After combining or packing messages, the fields inside them may have +moved! + +Any matchers defined on the original fields may cause problems when matching +against raw data, because they will be looking in the wrong place. (Matching +when the message type is known is OK, because the field is resolved by its +name.) + +To avoid matcher problems, define matchers after combining or packing messages. +To help with this, use the `field_t` alias on the message definition if needed. + +[source,cpp] +---- +using type_f = field<"type", std::uint32_t>::located; +using header_defn = message<"header", type_f>; + +using data_f = field<"data">, std::uint32_t>::located; +using payload_defn = message<"payload", data_f>; + +using msg_defn = extend< + pack<"msg", std::uint8_t, header_defn, payload_defn>, + type_f::with_required<1>>; + +// msg_defn does not contain data_f because packing moved it +// but we can get the actual data field by name, if we need it +using new_data_f = msg_defn::field_t<"data">; +---- + ==== Owning vs view types An owning message uses underlying storage: by default, this is a `std::array` of diff --git a/include/msg/field_matchers.hpp b/include/msg/field_matchers.hpp index a4d10f26..53b2d424 100644 --- a/include/msg/field_matchers.hpp +++ b/include/msg/field_matchers.hpp @@ -186,7 +186,7 @@ struct rel_matcher_t { if constexpr (stdx::range) { return Field::extract(msg); } else { - return Field::extract(std::data(msg)); + return msg.get(Field{}); } } }; diff --git a/include/msg/message.hpp b/include/msg/message.hpp index b7f4ff6e..d887371f 100644 --- a/include/msg/message.hpp +++ b/include/msg/message.hpp @@ -209,8 +209,7 @@ template class msg_access { template constexpr static auto set1(R &&r, V v) -> void { - using Field = std::remove_cvref_t>( - FieldsTuple{}))>; + using Field = field_t>; check>(); Field::insert(std::forward(r), static_cast(v.value)); @@ -218,20 +217,19 @@ template class msg_access { template constexpr static auto set_default(R &&r) -> void { - using Field = - std::remove_cvref_t(FieldsTuple{}))>; - check>(); - Field::insert_default(std::forward(r)); + check, std::remove_cvref_t>(); + field_t::insert_default(std::forward(r)); } template constexpr static auto get(R &&r) { - using Field = - std::remove_cvref_t(FieldsTuple{}))>; - check>(); - return Field::extract(std::forward(r)); + check, std::remove_cvref_t>(); + return field_t::extract(std::forward(r)); } public: + template + using field_t = std::remove_cvref_t(FieldsTuple{}))>; + template constexpr static auto set(R &&r, field_name...) -> void { (set_default(r), ...); @@ -369,6 +367,9 @@ struct message { std::integral_constant::template in>; + template + using field_t = typename access_t::template field_t>; + template