CommRaT 2.0.0
C++20 Real-Time Messaging Framework
Loading...
Searching...
No Matches
typed_mailbox.hpp
Go to the documentation of this file.
1
18#pragma once
19
20#include "mailbox.hpp"
21#include "../messaging/message_registry.hpp"
22#include <type_traits>
23
24namespace commrat {
25
81template<typename Registry, typename... AllowedPayloadTypes>
83private:
84 // SendOnlyTypes extracted from template magic if needed
85 // For now, this is the base implementation
86 // Extract MessageDefinition types for allowed payloads
87 template<typename PayloadT>
88 struct FindMessageDef {
89 // TODO: Extract MessageDefinition from Registry for this PayloadT
90 // For now, use MessageDefinition with UserDefined prefix
92 };
93
94 // Create underlying mailbox with all MessageDefinitions from registry
95 // (We'll add type validation in send/receive methods)
96 template<typename... MessageDefs>
97 static auto extract_mailbox_type(MessageRegistry<MessageDefs...>*) -> Mailbox<MessageDefs...>;
98
99 using UnderlyingMailbox = decltype(extract_mailbox_type(static_cast<Registry*>(nullptr)));
100
101 UnderlyingMailbox mailbox_;
102
103 // Compile-time validation helpers
104 template<typename PayloadT>
105 static constexpr bool is_allowed_type = (std::is_same_v<PayloadT, AllowedPayloadTypes> || ...);
106
107 // For base TypedMailbox: sendable = allowed (no send-only types)
108 template<typename PayloadT>
109 static constexpr bool is_sendable_type = is_allowed_type<PayloadT>;
110
111 template<typename PayloadT>
112 static constexpr bool is_registered_type = Registry::template is_registered<PayloadT>;
113
114public:
115 // ========================================================================
116 // Type Information
117 // ========================================================================
118
125 static constexpr size_t max_message_size =
126 Registry::template max_size_for_types<AllowedPayloadTypes...>();
127
128 static constexpr size_t num_allowed_types = sizeof...(AllowedPayloadTypes);
129
133 template<typename PayloadT>
134 static constexpr bool is_allowed() {
135 return is_allowed_type<PayloadT>;
136 }
137
138 // ========================================================================
139 // Construction and Lifecycle
140 // ========================================================================
141
146 explicit TypedMailbox(const MailboxConfig& config)
147 : mailbox_(config) {
148
149 static_assert(sizeof...(AllowedPayloadTypes) > 0,
150 "TypedMailbox requires at least one allowed payload type");
151
152 // Validate all allowed types are registered in the registry
153 static_assert((is_registered_type<AllowedPayloadTypes> && ...),
154 "All allowed types must be registered in the message registry");
155 }
156
157 ~TypedMailbox() = default;
158
159 // Non-copyable, movable
160 TypedMailbox(const TypedMailbox&) = delete;
162 TypedMailbox(TypedMailbox&&) noexcept = default;
163 TypedMailbox& operator=(TypedMailbox&&) noexcept = default;
164
165 // ========================================================================
166 // Lifecycle Management
167 // ========================================================================
168
169 auto start() -> MailboxResult<void> {
170 return mailbox_.start();
171 }
172
173 void stop() {
174 mailbox_.stop();
175 }
176
177 bool is_running() const {
178 return mailbox_.is_running();
179 }
180
181 uint32_t mailbox_id() const {
182 return mailbox_.mailbox_id();
183 }
184
185 // ========================================================================
186 // Type-Safe Send Operations
187 // ========================================================================
188
201 template<typename PayloadT>
202 auto send(PayloadT& message, uint32_t dest_mailbox)
204
205 static_assert(is_sendable_type<PayloadT>,
206 "Message type not sendable from this mailbox. "
207 "Check that PayloadT is in AllowedPayloadTypes or SendOnlyTypes.");
208
209 static_assert(is_registered_type<PayloadT>,
210 "Message type not registered in the message registry.");
211
212 // Create TimsMessage wrapper (const → non-const copy for underlying Mailbox)
213 TimsMessage<PayloadT> tims_msg{
214 .header = {
215 .msg_type = Registry::template get_message_id<PayloadT>(),
216 .msg_size = 0, // Will be set by serialization
217 .timestamp = 0, // Will be set by TiMS with current time
218 .seq_number = 0, // Will be set by TiMS
219 .flags = 0
220 },
221 .payload = message
222 };
223
224 return mailbox_.send(tims_msg, dest_mailbox);
225 }
226
236 template<typename PayloadT>
237 auto send(PayloadT& message, uint32_t dest_mailbox, uint64_t timestamp)
239
240 static_assert(is_sendable_type<PayloadT>,
241 "Message type not sendable from this mailbox. "
242 "Check that PayloadT is in AllowedPayloadTypes or SendOnlyTypes.");
243
244 static_assert(is_registered_type<PayloadT>,
245 "Message type not registered in the message registry.");
246
247 // Create TimsMessage wrapper with explicit timestamp
248 TimsMessage<PayloadT> tims_msg{
249 .header = {
250 .msg_type = Registry::template get_message_id<PayloadT>(),
251 .msg_size = 0, // Will be set by serialization
252 .timestamp = timestamp, // USER-PROVIDED timestamp
253 .seq_number = 0, // Will be set by TiMS
254 .flags = 0
255 },
256 .payload = message
257 };
258
259 return mailbox_.send(tims_msg, dest_mailbox);
260 }
261
265 template<typename PayloadT>
266 auto send(const TimsMessage<PayloadT>& tims_message, uint32_t dest_mailbox)
268
269 static_assert(is_sendable_type<PayloadT>,
270 "Message type not sendable from this mailbox.");
271
272 static_assert(is_registered_type<PayloadT>,
273 "Message type not registered in the message registry.");
274
275 return mailbox_.send(tims_message, dest_mailbox);
276 }
277
278 // ========================================================================
279 // Type-Safe Receive Operations
280 // ========================================================================
281
288 template<typename PayloadT>
290 static_assert(is_allowed_type<PayloadT>,
291 "Message type not allowed in this typed mailbox. "
292 "Check that PayloadT is in the AllowedPayloadTypes list.");
293 static_assert(is_registered_type<PayloadT>,
294 "Message type not registered in the message registry.");
295 return mailbox_.template receive<PayloadT>();
296 }
297
305 template<typename PayloadT>
306 auto receive_for(std::chrono::milliseconds timeout) -> MailboxResult<TimsMessage<PayloadT>> {
307 static_assert(is_allowed_type<PayloadT>,
308 "Message type not allowed in this typed mailbox.");
309 static_assert(is_registered_type<PayloadT>,
310 "Message type not registered in the message registry.");
311 return mailbox_.template receive_for<PayloadT>(timeout);
312 }
313
320 template<typename PayloadT>
322 static_assert(is_allowed_type<PayloadT>,
323 "Message type not allowed in this typed mailbox.");
324 static_assert(is_registered_type<PayloadT>,
325 "Message type not registered in the message registry.");
326 return mailbox_.template try_receive<PayloadT>();
327 }
328
335 template<typename Visitor>
336 auto receive_any(Visitor&& visitor) -> MailboxResult<void> {
337 return mailbox_.receive_any(std::forward<Visitor>(visitor));
338 }
339
347 template<typename Visitor>
348 auto receive_any_for(std::chrono::milliseconds timeout, Visitor&& visitor) -> MailboxResult<void> {
349 return mailbox_.receive_any_for(timeout, std::forward<Visitor>(visitor));
350 }
351
352 // ========================================================================
353 // Send Operations
354 // ========================================================================
355
379 // ========================================================================
380 // Access to Underlying Mailbox
381 // ========================================================================
382
389 auto& get_underlying_mailbox() { return mailbox_; }
390 const auto& get_underlying_mailbox() const { return mailbox_; }
391};
392
393// ============================================================================
394// Specialization with SendOnlyTypes Support
395// ============================================================================
396
402template<typename... Ts>
404 using Types = std::tuple<Ts...>;
405};
406
407template<typename... Ts>
409 using Types = std::tuple<Ts...>;
410};
411
426template<typename Registry, typename... SendOnlyTypesInner>
427class TypedMailbox<Registry, SendOnlyTypes<SendOnlyTypesInner...>> {
428private:
429 template<typename... MessageDefs>
430 static auto extract_mailbox_type(MessageRegistry<MessageDefs...>*) -> Mailbox<MessageDefs...>;
431
432 using UnderlyingMailbox = decltype(extract_mailbox_type(static_cast<Registry*>(nullptr)));
433 UnderlyingMailbox mailbox_;
434
435 // Type checking
436 template<typename PayloadT>
437 static constexpr bool is_send_only_type = (std::is_same_v<PayloadT, SendOnlyTypesInner> || ...);
438
439 template<typename PayloadT>
440 static constexpr bool is_registered_type = Registry::template is_registered<PayloadT>;
441
442public:
443 // Minimal buffer (no receive types)
444 static constexpr size_t max_message_size = 64; // Minimal size for headers only
445
446 explicit TypedMailbox(const MailboxConfig& config)
447 : mailbox_(MailboxConfig{
448 .mailbox_id = config.mailbox_id,
449 .message_slots = config.message_slots,
451 .send_priority = config.send_priority,
452 .realtime = config.realtime,
453 .mailbox_name = config.mailbox_name
454 }) {}
455
456 // Send operations (allow send-only types)
457 template<typename PayloadT>
458 auto send(PayloadT& message, uint32_t dest_mailbox) -> MailboxResult<void> {
459 static_assert(is_send_only_type<PayloadT>,
460 "Message type not in SendOnlyTypes list.");
461 static_assert(is_registered_type<PayloadT>,
462 "Message type not registered in registry.");
463
464 TimsMessage<PayloadT> tims_msg{
465 .header = {
466 .msg_type = Registry::template get_message_id<PayloadT>(),
467 .msg_size = 0,
468 .timestamp = 0,
469 .seq_number = 0,
470 .flags = 0
471 },
472 .payload = message
473 };
474 return mailbox_.send(tims_msg, dest_mailbox);
475 }
476
477 template<typename PayloadT>
478 auto send(PayloadT& message, uint32_t dest_mailbox, uint64_t timestamp) -> MailboxResult<void> {
479 static_assert(is_send_only_type<PayloadT>, "Message type not in SendOnlyTypes list.");
480 static_assert(is_registered_type<PayloadT>, "Type not registered.");
481
482 TimsMessage<PayloadT> tims_msg{
483 .header = {
484 .msg_type = Registry::template get_message_id<PayloadT>(),
485 .msg_size = 0,
486 .timestamp = timestamp,
487 .seq_number = 0,
488 .flags = 0
489 },
490 .payload = message
491 };
492 return mailbox_.send(tims_msg, dest_mailbox);
493 }
494
495 // No receive operations (compile error if attempted)
496 template<typename PayloadT>
498
499 template<typename PayloadT>
500 auto receive_timed(int64_t timeout_ns) -> MailboxResult<TimsMessage<PayloadT>> = delete;
501
502 // receive_any also not allowed (no receive types)
503 template<typename Visitor>
504 auto receive_any(Visitor&& visitor) -> MailboxResult<void> = delete;
505
506 // Lifecycle
507 auto create() -> MailboxResult<void> { return mailbox_.create(); }
508 auto destroy() -> MailboxResult<void> { return mailbox_.destroy(); }
509 auto start() -> MailboxResult<void> { return mailbox_.start(); }
510 void stop() { mailbox_.stop(); }
511 auto get_id() const -> uint32_t { return mailbox_.get_id(); }
512};
513
530template<typename Registry, typename... ReceiveTypesInner, typename... SendOnlyTypesInner>
531class TypedMailbox<Registry, ReceiveTypes<ReceiveTypesInner...>, SendOnlyTypes<SendOnlyTypesInner...>> {
532private:
533 template<typename... MessageDefs>
534 static auto extract_mailbox_type(MessageRegistry<MessageDefs...>*) -> Mailbox<MessageDefs...>;
535
536 using UnderlyingMailbox = decltype(extract_mailbox_type(static_cast<Registry*>(nullptr)));
537 UnderlyingMailbox mailbox_;
538
539 // Type checking
540 template<typename PayloadT>
541 static constexpr bool is_receive_type = (std::is_same_v<PayloadT, ReceiveTypesInner> || ...);
542
543 template<typename PayloadT>
544 static constexpr bool is_send_only_type = (std::is_same_v<PayloadT, SendOnlyTypesInner> || ...);
545
546 template<typename PayloadT>
547 static constexpr bool is_sendable_type = is_receive_type<PayloadT> || is_send_only_type<PayloadT>;
548
549 template<typename PayloadT>
550 static constexpr bool is_registered_type = Registry::template is_registered<PayloadT>;
551
552public:
553 // Buffer sized for receive types only!
554 static constexpr size_t max_message_size =
555 Registry::template max_size_for_types<ReceiveTypesInner...>();
556
557 explicit TypedMailbox(const MailboxConfig& config)
558 : mailbox_(MailboxConfig{
559 .mailbox_id = config.mailbox_id,
560 .message_slots = config.message_slots,
561 .max_message_size = max_message_size, // Optimized!
562 .send_priority = config.send_priority,
563 .realtime = config.realtime,
564 .mailbox_name = config.mailbox_name
565 }) {}
566
567 // Send operations (allow receive + send-only types)
568 template<typename PayloadT>
569 auto send(PayloadT& message, uint32_t dest_mailbox) -> MailboxResult<void> {
570 static_assert(is_sendable_type<PayloadT>,
571 "Message type not sendable from this mailbox.");
572 static_assert(is_registered_type<PayloadT>,
573 "Message type not registered in registry.");
574
575 TimsMessage<PayloadT> tims_msg{
576 .header = {
577 .msg_type = Registry::template get_message_id<PayloadT>(),
578 .msg_size = 0,
579 .timestamp = 0,
580 .seq_number = 0,
581 .flags = 0
582 },
583 .payload = message
584 };
585 return mailbox_.send(tims_msg, dest_mailbox);
586 }
587
588 template<typename PayloadT>
589 auto send(PayloadT& message, uint32_t dest_mailbox, uint64_t timestamp) -> MailboxResult<void> {
590 static_assert(is_sendable_type<PayloadT>, "Message type not sendable.");
591 static_assert(is_registered_type<PayloadT>, "Type not registered.");
592
593 TimsMessage<PayloadT> tims_msg{
594 .header = {
595 .msg_type = Registry::template get_message_id<PayloadT>(),
596 .msg_size = 0,
597 .timestamp = timestamp,
598 .seq_number = 0,
599 .flags = 0
600 },
601 .payload = message
602 };
603 return mailbox_.send(tims_msg, dest_mailbox);
604 }
605
606 // Receive operations (only receive types allowed)
607 template<typename PayloadT>
609 static_assert(is_receive_type<PayloadT>,
610 "Message type not receivable. Only ReceiveTypes can be received.");
611 static_assert(is_registered_type<PayloadT>, "Type not registered.");
612 return mailbox_.template receive<PayloadT>();
613 }
614
615 template<typename PayloadT>
617 static_assert(is_receive_type<PayloadT>, "Only ReceiveTypes can be received.");
618 static_assert(is_registered_type<PayloadT>, "Type not registered.");
619 return mailbox_.template receive_timed<PayloadT>(timeout_ns);
620 }
621
622 // receive_any for ReceiveTypes
623 template<typename Visitor>
624 auto receive_any(Visitor&& visitor) -> MailboxResult<void> {
625 return mailbox_.receive_any(std::forward<Visitor>(visitor));
626 }
627
628 // Lifecycle
629 auto start() -> MailboxResult<void> { return mailbox_.start(); }
630 void stop() { mailbox_.stop(); }
631 auto& get_underlying_mailbox() { return mailbox_; }
632 const auto& get_underlying_mailbox() const { return mailbox_; }
633};
634
635// ============================================================================
636// Convenience Type Aliases
637// ============================================================================
638
647template<typename Registry, typename PayloadT>
649
660template<typename Registry, typename... CommandTypes>
661using CommandMailbox = TypedMailbox<Registry, CommandTypes...>;
662
673template<typename Registry, typename... DataTypes>
674using DataMailbox = TypedMailbox<Registry, DataTypes...>;
675
676} // namespace commrat
Strongly-typed mailbox for message-based communication.
Definition mailbox.hpp:177
Compile-time message type registry using MessageDefinition templates.
Build a complete registry with automatic Module and Mailbox aliases.
auto send(PayloadT &message, uint32_t dest_mailbox, uint64_t timestamp) -> MailboxResult< void >
auto send(PayloadT &message, uint32_t dest_mailbox, uint64_t timestamp) -> MailboxResult< void >
auto send(PayloadT &message, uint32_t dest_mailbox) -> MailboxResult< void >
auto receive_timed(int64_t timeout_ns) -> MailboxResult< TimsMessage< PayloadT > >=delete
auto receive() -> MailboxResult< TimsMessage< PayloadT > >=delete
auto receive_any(Visitor &&visitor) -> MailboxResult< void >=delete
Type-restricted mailbox with optimized buffer sizing.
auto send(const TimsMessage< PayloadT > &tims_message, uint32_t dest_mailbox) -> MailboxResult< void >
Send a TimsMessage (type-restricted)
static constexpr size_t max_message_size
Maximum message size for allowed types only.
static constexpr bool is_allowed()
Check if a payload type is allowed in this mailbox.
TypedMailbox & operator=(const TypedMailbox &)=delete
const auto & get_underlying_mailbox() const
TypedMailbox(const MailboxConfig &config)
Construct a typed mailbox.
auto receive_for(std::chrono::milliseconds timeout) -> MailboxResult< TimsMessage< PayloadT > >
Receive with timeout for specific payload type.
auto start() -> MailboxResult< void >
static constexpr size_t num_allowed_types
TypedMailbox(const TypedMailbox &)=delete
auto receive() -> MailboxResult< TimsMessage< PayloadT > >
Blocking receive for specific payload type.
auto send(PayloadT &message, uint32_t dest_mailbox, uint64_t timestamp) -> MailboxResult< void >
Send a message with explicit timestamp (type-restricted)
uint32_t mailbox_id() const
auto & get_underlying_mailbox()
Receive any allowed message using a visitor.
auto send(PayloadT &message, uint32_t dest_mailbox) -> MailboxResult< void >
Send a message (type-restricted)
TypedMailbox(TypedMailbox &&) noexcept=default
auto receive_any_for(std::chrono::milliseconds timeout, Visitor &&visitor) -> MailboxResult< void >
Receive any allowed message type with timeout.
auto receive_any(Visitor &&visitor) -> MailboxResult< void >
Blocking receive any allowed message type using visitor pattern.
auto try_receive() -> MailboxResult< TimsMessage< PayloadT > >
Non-blocking receive (type-restricted)
CommRaT - Modern C++ Real-Time Communication Framework.
Message definition with compile-time ID assignment.
Tag type to mark send-only types in template parameter.
std::tuple< Ts... > Types
std::tuple< Ts... > Types