3#include "../messages.hpp"
13template<
typename UserRegistry,
typename OutputSpec_,
typename InputSpec_,
typename... CommandTypes>
25template<
typename... MessageDefs>
34template<
typename ProcessedTuple,
typename... Remaining>
38template<
typename... ProcessedDefs>
44template<
typename... ProcessedDefs,
typename First,
typename... Rest>
48 template<
typename MessageDef>
50 static constexpr uint16_t value = []()
constexpr {
51 if constexpr (
sizeof...(ProcessedDefs) == 0) {
55 ((max_id = (ProcessedDefs::prefix == MessageDef::prefix &&
56 ProcessedDefs::subprefix == MessageDef::subprefix &&
57 ProcessedDefs::local_id > max_id) ?
58 ProcessedDefs::local_id : max_id), ...);
65 using CurrentProcessed = std::conditional_t<
68 typename First::Payload,
71 HighestID<First>::value + 1
76 using RestResult =
typename AutoAssignIDsProcess<std::tuple<ProcessedDefs..., CurrentProcessed>, Rest...>::Result;
79 using Result =
decltype(std::tuple_cat(
80 std::declval<std::tuple<CurrentProcessed>>(),
81 std::declval<RestResult>()
85template<
typename... MessageDefs>
94template<
typename... MessageDefs>
97 if constexpr (
sizeof...(MessageDefs) <= 1) {
100 return check_all_pairs<MessageDefs...>();
105 template<
typename First,
typename Second,
typename... Rest>
106 static constexpr bool check_all_pairs() {
108 static_cast<uint8_t
>(First::prefix),
113 static_cast<uint8_t
>(Second::prefix),
118 static_assert(id1 != id2,
"Message ID collision detected!");
120 if constexpr (
sizeof...(Rest) > 0) {
121 return check_all_pairs<First, Rest...>() && check_all_pairs<Second, Rest...>();
147template<
typename... MessageDefs>
151 using ProcessedDefs =
typename AutoAssignIDs<MessageDefs...>::Result;
154 template<
typename Tuple>
155 struct ExtractPayloads;
157 template<
typename... Defs>
158 struct ExtractPayloads<std::tuple<Defs...>> {
159 using PayloadTypes = std::tuple<
typename Defs::Payload...>;
167 using PayloadTypes =
typename ExtractPayloads<ProcessedDefs>::PayloadTypes;
170 template<
typename T,
typename Tuple>
173 template<
typename T,
typename... Types>
175 static constexpr bool value = (std::is_same_v<T, Types> || ...);
182 static constexpr size_t num_types =
sizeof...(MessageDefs);
186 template<
typename... Payloads>
209 template<
typename... SpecificTypes>
211 static_assert(
sizeof...(SpecificTypes) > 0,
212 "max_size_for_types requires at least one type");
215 static_assert((is_registered_v<SpecificTypes> && ...),
216 "All types must be registered in the message registry");
219 return std::max({sertial::Message<TimsMessage<SpecificTypes>>
::max_buffer_size...});
224 template<
typename PayloadT,
typename Tuple>
225 struct FindMessageDef;
227 template<
typename PayloadT,
typename... Defs>
228 struct FindMessageDef<PayloadT, std::tuple<Defs...>> {
230 template<
typename Def>
231 static constexpr bool matches = std::is_same_v<typename Def::Payload, PayloadT>;
233 template<
typename First,
typename... Rest>
234 static constexpr auto find_impl() {
235 if constexpr (matches<First>) {
237 }
else if constexpr (
sizeof...(Rest) > 0) {
238 return find_impl<Rest...>();
245 using type =
decltype(find_impl<Defs...>());
249 template<
typename PayloadT>
250 static constexpr uint32_t get_message_id_for() {
251 using MessageDef =
typename FindMessageDef<PayloadT, ProcessedDefs>::type;
253 static_cast<uint8_t
>(MessageDef::prefix),
254 MessageDef::subprefix,
260 template<
typename T,
typename Tuple,
size_t Index = 0>
263 template<
typename T,
typename... Types,
size_t Index>
264 struct TypeIndex<T, std::tuple<Types...>, Index> {
265 static constexpr size_t value = []()
constexpr {
268 ((std::is_same_v<T, Types> ? (idx = current, 0) : (++current, 0)), ...);
274 static constexpr size_t type_index() {
275 return TypeIndex<T, PayloadTypes>::value;
279 template<u
int32_t ID,
size_t Index = 0,
typename Tuple = ProcessedDefs>
282 template<uint32_t ID,
size_t Index,
typename... Defs>
283 struct TypeByID<ID, Index, std::tuple<Defs...>> {
285 static constexpr bool found =
false;
288 template<uint32_t ID,
size_t Index,
typename... Defs>
289 requires (Index <
sizeof...(Defs))
290 struct TypeByID<ID, Index, std::tuple<Defs...>> {
292 using CurrentDef = std::tuple_element_t<Index, std::tuple<Defs...>>;
294 static_cast<uint8_t
>(CurrentDef::prefix),
295 CurrentDef::subprefix,
300 using type = std::conditional_t<
302 typename CurrentDef::Payload,
303 typename TypeByID<ID, Index + 1>::type
305 static constexpr bool found = (current_id == ID) ||
306 TypeByID<ID, Index + 1>::found;
324 requires is_registered_v<T>
326 return get_message_id_for<T>();
332 template<u
int32_t ID>
338 template<u
int32_t ID>
355 requires is_registered_v<T>
358 message.header.msg_type = get_message_id<T>();
364 message.header.msg_size =
static_cast<uint32_t
>(result.size);
376 template<
typename PayloadT>
377 requires is_registered_v<PayloadT>
383 auto result = sertial::Message<TimsMessage<PayloadT>>
::serialize(message);
401 requires is_registered_v<T> && (!
requires {
typename T::payload_type; })
405 auto msg_result = sertial::Message<MsgType>::deserialize(data);
410 return std::make_optional(std::move(msg_result->payload));
414 return std::optional<T>{};
424 template<
typename MsgT>
425 requires requires {
typename MsgT::payload_type; } &&
426 is_registered_v<typename MsgT::payload_type>
429 return sertial::Message<MsgT>::deserialize(data);
454 template<
typename Visitor>
455 static bool visit(uint32_t msg_id, std::span<const std::byte> data, Visitor&& visitor) {
456 return visit_impl<0>(msg_id, data, std::forward<Visitor>(visitor));
469 template<
typename Callback>
470 static bool dispatch(uint32_t msg_id, std::span<const std::byte> data, Callback&& callback) {
471 return visit(msg_id, data, std::forward<Callback>(callback));
488 static constexpr size_t size() {
495 template<
typename... Defs>
497 return std::array<uint32_t,
sizeof...(Defs)>{
499 static_cast<uint8_t
>(Defs::prefix),
517 template<std::
size_t I>
518 using type_at = std::tuple_element_t<I, PayloadTypes>;
525 return type_index<T>();
530 template<
size_t Index,
typename Visitor,
typename... Defs>
531 static bool visit_impl_helper(uint32_t msg_id, std::span<const std::byte> data,
532 Visitor&& visitor, std::tuple<Defs...>*) {
533 if constexpr (Index >=
sizeof...(Defs)) {
537 using CurrentDef = std::tuple_element_t<Index, std::tuple<Defs...>>;
538 using CurrentPayload =
typename CurrentDef::Payload;
541 static_cast<uint8_t
>(CurrentDef::prefix),
542 CurrentDef::subprefix,
546 if (msg_id == current_id) {
548 auto result = deserialize<TimsMessage<CurrentPayload>>(data);
551 std::forward<Visitor>(visitor)(*result);
558 return visit_impl_helper<Index + 1>(msg_id, data,
559 std::forward<Visitor>(visitor),
560 static_cast<std::tuple<Defs...
>*>(
nullptr));
564 template<
size_t Index,
typename Visitor>
565 static bool visit_impl(uint32_t msg_id, std::span<const std::byte> data, Visitor&& visitor) {
566 return visit_impl_helper<Index>(msg_id, data, std::forward<Visitor>(visitor),
567 static_cast<ProcessedDefs*
>(
nullptr));
584template<
typename... MessageDefs>
590template<
typename... MessageDefs>
Compile-time message type registry using MessageDefinition templates.
static constexpr auto get_all_ids_impl(std::tuple< Defs... > *)
Get list of all message IDs in the registry.
static auto serialize(TimsMessage< PayloadT > &message)
Serialize a TimsMessage<PayloadT> wrapper.
static auto serialize(T &message)
Serialize a message with automatic type registration check.
std::tuple_element_t< I, PayloadTypes > type_at
Get payload type at index I.
static constexpr bool is_registered_v
static bool dispatch(uint32_t msg_id, std::span< const std::byte > data, Callback &&callback)
Deserialize message by ID and dispatch to callback.
static constexpr size_t calc_max_size(std::tuple< Payloads... > *)
static constexpr auto message_ids()
static constexpr bool has_message_id
Check if a message ID is registered.
static constexpr size_t max_message_size
static constexpr size_t size()
Get number of registered message types.
typename TypeByID< ID, 0 >::type PayloadTypeFor
Get the payload type by message ID (compile-time)
static constexpr bool is_registered
Check if a payload type is registered.
static constexpr size_t max_buffer_size()
Get maximum buffer size needed for any message in the registry.
static constexpr size_t max_size_for_types()
Calculate maximum message size for specific payload types.
static constexpr std::size_t get_type_index()
Get type index for payload type T.
static constexpr uint32_t get_message_id()
Get the message ID for a given payload type.
static bool visit(uint32_t msg_id, std::span< const std::byte > data, Visitor &&visitor)
Visit a message by its message ID using a visitor.
typename ExtractPayloads< ProcessedDefs >::PayloadTypes PayloadTypes
static auto deserialize(std::span< const std::byte > data)
Deserialize a message with known type at compile time.
static constexpr size_t num_types
static auto deserialize(std::span< const std::byte > data)
Deserialize a TimsMessage<PayloadT> wrapper.
CommRaT - Modern C++ Real-Time Communication Framework.
constexpr uint32_t make_message_id(uint8_t prefix, uint8_t subprefix, uint16_t id)
Compile-time message ID construction.
auto serialize_message(T &message) -> typename sertial::Message< T >::Result
decltype(std::tuple_cat(std::declval< std::tuple< CurrentProcessed > >(), std::declval< RestResult >())) Result
Helper to assign auto-incremented IDs to messages marked with needs_auto_id.
typename AutoAssignIDsProcess< std::tuple<>, MessageDefs... >::Result Result
static constexpr bool check()
Message definition with compile-time ID assignment.