Embedded Template Library 1.0
Loading...
Searching...
No Matches
message_router.h
1/******************************************************************************
2The MIT License(MIT)
3
4Embedded Template Library.
5https://github.com/ETLCPP/etl
6https://www.etlcpp.com
7
8Copyright(c) 2017 John Wellbelove
9
10Permission is hereby granted, free of charge, to any person obtaining a copy
11of this software and associated documentation files(the "Software"), to deal
12in the Software without restriction, including without limitation the rights
13to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
14copies of the Software, and to permit persons to whom the Software is
15furnished to do so, subject to the following conditions :
16
17The above copyright notice and this permission notice shall be included in all
18copies or substantial portions of the Software.
19
20THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
23AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26SOFTWARE.
27******************************************************************************/
28
29#ifndef ETL_MESSAGE_ROUTER_INCLUDED
30#define ETL_MESSAGE_ROUTER_INCLUDED
31
32#include "platform.h"
33#include "alignment.h"
34#include "array.h"
35#include "error_handler.h"
36#include "exception.h"
37#include "largest.h"
38#include "message.h"
39#include "message_packet.h"
40#include "message_types.h"
41#include "nullptr.h"
42#include "placement_new.h"
43#include "shared_message.h"
44#include "successor.h"
45#include "type_list.h"
46#include "type_traits.h"
47
48#include <stdint.h>
49
50namespace etl
51{
52 //***************************************************************************
54 //***************************************************************************
55 class message_router_exception : public etl::exception
56 {
57 public:
58
59 message_router_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
60 : etl::exception(reason_, file_name_, line_number_)
61 {
62 }
63 };
64
65 //***************************************************************************
67 //***************************************************************************
68 class message_router_illegal_id : public etl::message_router_exception
69 {
70 public:
71
72 message_router_illegal_id(string_type file_name_, numeric_type line_number_)
73 : message_router_exception(ETL_ERROR_TEXT("message router:illegal id", ETL_MESSAGE_ROUTER_FILE_ID"A"), file_name_, line_number_)
74 {
75 }
76 };
77
78 namespace private_message_router
79 {
80 //***************************************************************************
81 // Traits for a message router.
82 // message packet type
83 // message type_list
84 // sorted message type_list.
85 //***************************************************************************
86 template <typename... TMessageTypes>
87 class traits
88 {
89#if ETL_USING_CPP11
90
91 private:
92
93 using message_id_sequence = etl::index_sequence<TMessageTypes::ID...>;
94
95 public:
96
97 using message_packet = etl::message_packet<TMessageTypes...>;
98 using message_types = etl::type_list<TMessageTypes...>;
99 using sorted_message_types = etl::type_list_sort_t<message_types, etl::compare_message_id_less>;
100
101 static_assert(etl::type_list_is_unique<message_types>::value, "All TMessageTypes must be unique");
102 static_assert(etl::type_list_all_of<message_types, etl::is_message_type>::value,
103 "All TMessageTypes must satisfy the condition etl::is_message_type");
104 static_assert(etl::index_sequence_is_unique<message_id_sequence>::value, "All message IDs must be unique");
105#endif
106 };
107
108 //***************************************************************************
109 // Specialisation of traits for no message types.
110 // message packet type
111 // message type_list
112 // sorted message type_list.
113 //***************************************************************************
114 template <>
115 class traits<>
116 {
117 public:
118
119#if ETL_USING_CPP11
121 using message_types = etl::type_list<>;
122 using sorted_message_types = etl::type_list<>;
123#endif
124 };
125 } // namespace private_message_router
126
127 //***************************************************************************
129 //***************************************************************************
130 class imessage_router;
131
133
134 //***************************************************************************
136 //***************************************************************************
137 class imessage_router : public etl::successor<imessage_router>
138 {
139 public:
140
141 virtual ~imessage_router() {}
142 virtual void receive(const etl::imessage&) = 0;
143 virtual bool accepts(etl::message_id_t) const = 0;
144 virtual bool is_null_router() const = 0;
145 virtual bool is_producer() const = 0;
146 virtual bool is_consumer() const = 0;
147
148 //********************************************
149 virtual void receive(etl::message_router_id_t destination_router_id, const etl::imessage& message)
150 {
151 if ((destination_router_id == get_message_router_id()) || (destination_router_id == imessage_router::ALL_MESSAGE_ROUTERS))
152 {
153 receive(message);
154 }
155 }
156
157 //********************************************
158 virtual void receive(etl::shared_message shared_msg)
159 {
160 receive(shared_msg.get_message());
161 }
162
163 //********************************************
164 virtual void receive(etl::message_router_id_t destination_router_id, etl::shared_message shared_msg)
165 {
166 if ((destination_router_id == get_message_router_id()) || (destination_router_id == imessage_router::ALL_MESSAGE_ROUTERS))
167 {
168 receive(shared_msg);
169 }
170 }
171
172 //********************************************
173 bool accepts(const etl::imessage& msg) const
174 {
175 return accepts(msg.get_message_id());
176 }
177
178 //********************************************
179 etl::message_router_id_t get_message_router_id() const
180 {
181 return message_router_id;
182 }
183
184 enum
185 {
186 NULL_MESSAGE_ROUTER = 255,
187 MESSAGE_BUS = 254,
188 ALL_MESSAGE_ROUTERS = 253,
189 MESSAGE_BROKER = 252,
190 MESSAGE_ROUTER = 251,
191 MAX_MESSAGE_ROUTER = 249
192 };
193
194 protected:
195
196 imessage_router(etl::message_router_id_t id_)
197 : message_router_id(id_)
199 }
200
201 imessage_router(etl::message_router_id_t id_, imessage_router& successor_)
202 : successor(successor_)
203 , message_router_id(id_)
204 {
205 }
206
207 private:
208
209 // Disabled.
210 imessage_router(const imessage_router&);
211 imessage_router& operator=(const imessage_router&);
212
213 etl::message_router_id_t message_router_id;
214 };
215
216 //***************************************************************************
218 //***************************************************************************
219 class null_message_router
220 : public imessage_router
222 {
223 public:
224
225 //********************************************
226 null_message_router()
227 : imessage_router(imessage_router::NULL_MESSAGE_ROUTER)
228 {
229 }
230
231 //********************************************
232 null_message_router(etl::imessage_router& successor_)
233 : imessage_router(imessage_router::NULL_MESSAGE_ROUTER, successor_)
234 {
235 }
236
237 //********************************************
238 using etl::imessage_router::receive;
239
240 void receive(const etl::imessage& msg) ETL_OVERRIDE
241 {
242 if (has_successor())
243 {
244 get_successor().receive(msg);
245 }
246 }
247
248 //********************************************
249 using etl::imessage_router::accepts;
250
251 bool accepts(etl::message_id_t id) const ETL_OVERRIDE
252 {
253 if (has_successor())
254 {
255 return get_successor().accepts(id);
256 }
257 else
258 {
259 return false;
260 }
261 }
262
263 //********************************************
264 ETL_DEPRECATED
265 bool is_null_router() const ETL_OVERRIDE
266 {
267 return true;
268 }
269
270 //********************************************
271 bool is_producer() const ETL_OVERRIDE
272 {
273 return false;
274 }
275
276 //********************************************
277 bool is_consumer() const ETL_OVERRIDE
278 {
279 return false;
280 }
281
282 //********************************************
283 static null_message_router& instance()
284 {
285 static null_message_router nmr;
286 return nmr;
287 }
288 };
289
290 //***********************************************
293 {
294 return etl::null_message_router::instance();
295 }
296
297 //***************************************************************************
300 //***************************************************************************
301 class message_producer
302 : public imessage_router
304 {
305 public:
306
307 //********************************************
308 message_producer()
309 : imessage_router(etl::imessage_router::MESSAGE_ROUTER)
310 {
311 }
312
313 //********************************************
314 message_producer(etl::imessage_router& successor_)
315 : imessage_router(imessage_router::NULL_MESSAGE_ROUTER, successor_)
316 {
317 }
318
319 //********************************************
320 message_producer(etl::message_router_id_t id_)
321 : imessage_router(id_)
322 {
323 ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
324 }
325
326 //********************************************
327 message_producer(etl::message_router_id_t id_, etl::imessage_router& successor_)
328 : imessage_router(id_, successor_)
329 {
330 ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
331 }
332
333 //********************************************
334 using etl::imessage_router::receive;
335
336 void receive(const etl::imessage& msg) ETL_OVERRIDE
337 {
338 if (has_successor())
339 {
340 get_successor().receive(msg);
341 }
342 }
343
344 //********************************************
345 using etl::imessage_router::accepts;
346
347 bool accepts(etl::message_id_t id) const ETL_OVERRIDE
348 {
349 if (has_successor())
350 {
351 return get_successor().accepts(id);
352 }
353 else
354 {
355 return false;
356 }
357 }
358
359 //********************************************
360 ETL_DEPRECATED
361 bool is_null_router() const ETL_OVERRIDE
362 {
363 return false;
364 }
365
366 //********************************************
367 bool is_producer() const ETL_OVERRIDE
368 {
369 return true;
370 }
371
372 //********************************************
373 bool is_consumer() const ETL_OVERRIDE
374 {
375 return false;
376 }
377 };
378
379 //***************************************************************************
381 //***************************************************************************
382 template <typename T>
383 struct is_message_router : public etl::bool_constant< etl::is_base_of< etl::imessage_router, typename etl::remove_cvref<T>::type>::value>
384 {
385 };
386
387 //***************************************************************************
389 //***************************************************************************
390 template <typename TRouter, typename TMessage>
391 static typename etl::enable_if< etl::is_message_router<TRouter>::value && etl::is_message<TMessage>::value, void>::type
392 send_message(TRouter& destination, const TMessage& message)
393 {
394 destination.receive(message);
395 }
396
397 //***************************************************************************
399 //***************************************************************************
400 template <typename TRouter>
401 static typename etl::enable_if<etl::is_message_router<TRouter>::value, void>::type send_message(TRouter& destination, etl::shared_message message)
402 {
403 destination.receive(message);
404 }
405
406 //***************************************************************************
408 //***************************************************************************
409 template <typename TRouter, typename TMessage>
410 static typename etl::enable_if< etl::is_message_router<TRouter>::value && etl::is_message<TMessage>::value, void>::type
411 send_message(TRouter& destination, etl::message_router_id_t id, const TMessage& message)
412 {
413 destination.receive(id, message);
414 }
415
416 //***************************************************************************
418 //***************************************************************************
419 template <typename TRouter>
420 static typename etl::enable_if<etl::is_message_router<TRouter>::value, void>::type send_message(TRouter& destination, etl::message_router_id_t id,
421 etl::shared_message message)
422 {
423 destination.receive(id, message);
424 }
425
426 //*************************************************************************************************
427 // For C++11 and above.
428 //*************************************************************************************************
429#if ETL_USING_CPP11 && !defined(ETL_MESSAGE_ROUTER_FORCE_CPP03_IMPLEMENTATION)
430 //***************************************************************************
431 // The definition for all message types.
432 //***************************************************************************
433 template <typename TDerived, typename... TMessageTypes>
434 class message_router
435 : public imessage_router
436 , public private_message_router::traits<TMessageTypes...>
437 {
438 public:
439
440 using typename private_message_router::traits<TMessageTypes...>::message_packet;
441 using typename private_message_router::traits<TMessageTypes...>::message_types;
442 using typename private_message_router::traits< TMessageTypes...>::sorted_message_types;
443
444 //**********************************************
446 //**********************************************
447 message_router()
448 : imessage_router(etl::imessage_router::MESSAGE_ROUTER)
449 {
450 }
451
452 //**********************************************
455 //**********************************************
456 message_router(etl::imessage_router& successor_)
457 : imessage_router(etl::imessage_router::MESSAGE_ROUTER, successor_)
458 {
459 }
460
461 //**********************************************
463 //**********************************************
464 message_router(etl::message_router_id_t id_)
465 : imessage_router(id_)
466 {
467 ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
468 }
469
470 //**********************************************
472 //**********************************************
473 message_router(etl::message_router_id_t id_, etl::imessage_router& successor_)
474 : imessage_router(id_, successor_)
475 {
476 ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
477 }
478
479 //**********************************************
481 //**********************************************
482 using etl::imessage_router::receive;
483
484 //**********************************************
489 //***********************************************
490 void receive(const etl::imessage& msg) ETL_OVERRIDE
491 {
492 const etl::message_id_t id = msg.get_message_id();
493
494 // The IDs are sorted, so an ID less than the first is not handled by this
495 // router.
496 if (id >= Message_Id_Start)
497 {
498 const size_t index = get_dispatch_index_from_message_id(id);
499
500 // If the index is less than Number_Of_Messages, then we have a handler
501 // for this message type, so dispatch it.
502 if (index < Number_Of_Messages)
503 {
504 dispatch(msg, index);
505 return;
506 }
508
509 // We don't have a handler for this message type, so pass it to a
510 // successor if there is one, or call on_receive_unknown() if there isn't.
511 if (has_successor())
512 {
513 get_successor().receive(msg);
514 }
515 else
516 {
518 static_cast<TDerived*>(this)->on_receive_unknown(msg);
520 }
521 }
522
523 //**********************************************
527 //**********************************************
528 template < typename TMessage, typename etl::enable_if<etl::is_one_of<TMessage, TMessageTypes...>::value, int>::type = 0>
529 void receive(const TMessage& msg)
530 {
532 static_cast<TDerived*>(this)->on_receive(msg);
534 }
535
536 //**********************************************
541 //**********************************************
542 template <typename TMessage,
543 typename etl::enable_if< etl::is_message<TMessage>::value && !etl::is_one_of<TMessage, TMessageTypes...>::value, int>::type = 0>
544 void receive(const TMessage& msg)
545 {
546 if (has_successor())
547 {
548 get_successor().receive(msg);
549 }
550 else
551 {
553 static_cast<TDerived*>(this)->on_receive_unknown(msg);
555 }
556 }
557
558 //**********************************************
560 //**********************************************
561 using imessage_router::accepts;
562
563 //**********************************************
566 //***********************************************
567 bool accepts(etl::message_id_t id) const ETL_OVERRIDE
568 {
569 if (id >= Message_Id_Start)
570 {
571 const size_t index = get_dispatch_index_from_message_id(id);
572
573 if (index < Number_Of_Messages)
574 {
575 return true;
576 }
577 }
578
579 return has_successor() ? get_successor().accepts(id) : false;
580 }
581
582 //********************************************
583 ETL_DEPRECATED
584 bool is_null_router() const ETL_OVERRIDE
585 {
586 return false;
587 }
588
589 //********************************************
590 bool is_producer() const ETL_OVERRIDE
591 {
592 return true;
593 }
594
595 //********************************************
596 bool is_consumer() const ETL_OVERRIDE
597 {
598 return true;
599 }
600
601 private:
602
603 static constexpr size_t Number_Of_Messages = sizeof...(TMessageTypes);
604 static constexpr etl::message_id_t Message_Id_Start = etl::type_list_type_at_index_t<sorted_message_types, 0>::ID;
605
606 //**********************************************
607 // Checks that the message ids are contiguous.
608 //**********************************************
609 template <size_t Index, bool Last = (Index + 1U >= Number_Of_Messages)>
610 struct contiguous_impl;
611
612 template <size_t Index>
613 struct contiguous_impl<Index, true> : etl::true_type
614 {
615 };
616
617 template <size_t Index>
618 struct contiguous_impl<Index, false>
619 : etl::bool_constant< (etl::type_list_type_at_index_t<sorted_message_types, Index>::ID + 1U
620 == etl::type_list_type_at_index_t<sorted_message_types, Index + 1U>::ID)
621 && contiguous_impl<Index + 1U>::value>
622 {
623 };
624
625 // The message ids are contiguous if there are 0 or 1 message types, or if
626 // each message id is one greater than the previous message id.
627 static constexpr bool Message_Ids_Are_Contiguous = (Number_Of_Messages <= 1U) ? true : contiguous_impl<0U>::value;
628
629 using handler_ptr = void (*)(TDerived&,
630 const etl::imessage&);
633 using message_dispatch_table_t = etl::array<handler_ptr,
634 Number_Of_Messages>;
637 using message_id_table_t = etl::array<etl::message_id_t,
638 Number_Of_Messages>;
641
642 //**********************************************
643 // Call for a single message type
644 //**********************************************
645 template <typename TMessage>
646 static void call_on_receive(TDerived& derived, const imessage& msg)
647 {
648 derived.on_receive(static_cast<const TMessage&>(msg));
649 }
650
651 //**********************************************
652 // Get the handler for a single message type at the index in the sorted
653 // type_list. This will be called for each message type to generate the
654 // dispatch table.
655 //**********************************************
656 template <size_t Index>
657 static constexpr handler_ptr get_message_handler()
658 {
659 return &call_on_receive< etl::type_list_type_at_index_t<sorted_message_types, Index>>;
660 }
661
662 //**********************************************
663 // Generate the dispatch table at compile time.
664 // This will create an array of handler pointers, one for each message type.
665 //**********************************************
666 template <size_t... Indices>
667 static constexpr message_dispatch_table_t make_message_dispatch_table(etl::index_sequence<Indices...>)
668 {
669 return message_dispatch_table_t{{get_message_handler<Indices>()...}};
670 }
671
672 //**********************************************
673 // Get the message id for a single message type at an index in the sorted
674 // type_list. This will be called for each message type to generate the
675 // message id table.
676 //**********************************************
677 template <size_t Index>
678 static constexpr etl::message_id_t get_message_id_from_index()
679 {
680 return etl::type_list_type_at_index_t<sorted_message_types, Index>::ID;
681 }
682
683 //**********************************************
684 // Generate the message id table at compile time.
685 // This will create an array of message ids, one for each message type.
686 //**********************************************
687 template <size_t... Indices>
688 static constexpr message_id_table_t make_message_id_table(etl::index_sequence<Indices...>)
689 {
690 return message_id_table_t{{get_message_id_from_index<Indices>()...}};
691 }
692
693 //**********************************************
694 // Get the dispatch index for a message id.
695 // This will be used at runtime to find the handler for a message id.
696 // If the message ids are contiguous, we can calculate the index directly.
697 // If they are not contiguous, we need to do a binary search. This will
698 // return Number_Of_Messages if the message id is not found, which indicates
699 // that the message should be passed to the successor.
700 //**********************************************
701 static size_t get_dispatch_index_from_message_id(etl::message_id_t id)
702 {
703 if ETL_IF_CONSTEXPR (Message_Ids_Are_Contiguous)
704 {
705 // The IDs are contiguous, so we can calculate the index directly.
706 return static_cast<size_t>(id - Message_Id_Start);
707 }
708 else
709 {
710 // The IDs are not contiguous, so we need to do a binary search.
711 size_t left = 0;
712 size_t right = Number_Of_Messages;
713
714 while (left < right)
715 {
716 size_t mid = (left + right) / 2;
717
718 if (message_id_table[mid] == id)
719 {
720 return mid;
721 }
722 else if (message_id_table[mid] < id)
723 {
724 left = mid + 1;
725 }
726 else
727 {
728 right = mid;
729 }
730 }
731 }
732
733 return Number_Of_Messages; // Not found
734 }
735
736 //**********************************************
737 // Dispatch the message to the appropriate handler based on the index in the
738 // dispatch table.
739 //**********************************************
740 void dispatch(const etl::imessage& msg, size_t index)
741 {
742 message_dispatch_table[index](static_cast<TDerived&>(*this), msg);
743 }
744
745 //**********************************************
746 // The dispatch table is generated at compile time. The dispatch table
747 // contains pointers to the on_receive handlers for each message type.
748 //**********************************************
749 static ETL_INLINE_VAR constexpr message_dispatch_table_t message_dispatch_table =
750 etl::message_router<TDerived, TMessageTypes...>::make_message_dispatch_table(
751 etl::make_index_sequence< etl::message_router< TDerived, TMessageTypes...>::Number_Of_Messages>{});
752
753 //**********************************************
754 // The message id table is generated at compile time. The message id table
755 // contains the corresponding message ids for each message type.
756 //**********************************************
757 static ETL_INLINE_VAR constexpr message_id_table_t message_id_table = etl::message_router<TDerived, TMessageTypes...>::make_message_id_table(
758 etl::make_index_sequence< etl::message_router< TDerived, TMessageTypes...>::Number_Of_Messages>{});
759 };
760
761 #if ETL_USING_CPP11 && !ETL_USING_CPP17
762 template <typename TDerived, typename... TMessageTypes>
763 constexpr const typename etl::message_router< TDerived, TMessageTypes...>::message_dispatch_table_t
764 etl::message_router<TDerived, TMessageTypes...>::message_dispatch_table;
765
766 template <typename TDerived, typename... TMessageTypes>
767 constexpr const typename etl::message_router< TDerived, TMessageTypes...>::message_id_table_t
768 etl::message_router<TDerived, TMessageTypes...>::message_id_table;
769 #endif
770
771 //***************************************************************************
772 // The definition of a message_router for zero message types.
773 //***************************************************************************
774 template <typename TDerived>
775 class message_router<TDerived>
776 : public imessage_router
778 {
779 public:
780
781 //**********************************************
783 //**********************************************
784 message_router()
785 : imessage_router(etl::imessage_router::MESSAGE_ROUTER)
786 {
787 }
788
789 //**********************************************
792 //**********************************************
793 message_router(etl::imessage_router& successor_)
794 : imessage_router(etl::imessage_router::MESSAGE_ROUTER, successor_)
795 {
796 }
797
798 //**********************************************
800 //**********************************************
801 message_router(etl::message_router_id_t id_)
802 : imessage_router(id_)
803 {
804 ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
805 }
806
807 //**********************************************
809 //**********************************************
810 message_router(etl::message_router_id_t id_, etl::imessage_router& successor_)
811 : imessage_router(id_, successor_)
812 {
813 ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
814 }
815
816 //**********************************************
818 using etl::imessage_router::receive;
819
820 //**********************************************
825 //***********************************************
826 void receive(const etl::imessage& msg) ETL_OVERRIDE
827 {
829 if (has_successor())
830 {
831 get_successor().receive(msg);
832 }
834 }
835
836 //**********************************************
838 //**********************************************
839 using imessage_router::accepts;
840
841 //**********************************************
843 //***********************************************
844 bool accepts(etl::message_id_t id) const ETL_OVERRIDE
845 {
846 if (has_successor())
847 {
848 return get_successor().accepts(id);
849 }
850 else
851 {
852 return false;
853 }
854 }
855
856 //********************************************
857 ETL_DEPRECATED
858 bool is_null_router() const ETL_OVERRIDE
859 {
860 return false;
861 }
862
863 //********************************************
864 bool is_producer() const ETL_OVERRIDE
865 {
866 return true;
867 }
868
869 //********************************************
870 bool is_consumer() const ETL_OVERRIDE
871 {
872 return true;
873 }
874 };
875
876 //***************************************************************************
879 //***************************************************************************
880 template <typename TDerived, typename TList>
881 struct message_router_from_type_list;
882
883 template <typename TDerived, typename... TMessageTypes>
884 struct message_router_from_type_list<TDerived, etl::type_list<TMessageTypes...>>
885 {
886 using type = etl::message_router<TDerived, TMessageTypes...>;
887 };
888
889 template <typename TDerived, typename TTypeList>
890 using message_router_from_type_list_t = typename message_router_from_type_list<TDerived, TTypeList>::type;
891
892#else
893 #include "private/message_router_cpp03.h"
894#endif
895} // namespace etl
896
897#endif
This is the base of all message routers.
Definition message_router.h:138
Definition message.h:75
Definition message_packet.h:42
Base exception class for message router.
Definition message_router.h:56
Router id is out of the legal range.
Definition message_router.h:69
Definition message_router.h:46
Definition message.h:94
Definition message_router.h:88
Definition shared_message.h:50
ETL_NODISCARD etl::imessage & get_message()
Get a reference to the contained message.
Definition shared_message.h:192
Adds successor traits to a class.
Definition successor.h:73
bool has_successor() const
Definition successor.h:184
successor_type & get_successor() const
Definition successor.h:174
#define ETL_ASSERT(b, e)
Definition error_handler.h:511
Definition exception.h:59
bitset_ext
Definition absolute.h:40
etl::imessage_router & get_null_message_router()
null message router functionality.
Definition message_router.h:292
uint_least8_t message_id_t
Allow alternative type for message id.
Definition message_types.h:40
Definition type_traits.h:97
Is T ultimately derived from etl::imessage_router?
Definition message_router.h:384