COMMS
Template library intended to help with implementation of communication protocols.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
MsgIdLayer.h
Go to the documentation of this file.
1//
2// Copyright 2014 - 2025 (C). Alex Robenko. All rights reserved.
3//
4// This Source Code Form is subject to the terms of the Mozilla Public
5// License, v. 2.0. If a copy of the MPL was not distributed with this
6// file, You can obtain one at http://mozilla.org/MPL/2.0/.
7
10
11#pragma once
12
13#include "comms/Assert.h"
15#include "comms/details/tag.h"
16#include "comms/dispatch.h"
17#include "comms/fields.h"
18#include "comms/frame/details/MsgIdLayerBase.h"
19#include "comms/frame/details/MsgIdLayerOptionsParser.h"
20#include "comms/MessageBase.h"
21#include "comms/MsgFactory.h"
22#include "comms/util/Tuple.h"
24
25#include <algorithm>
26#include <array>
27#include <limits>
28#include <tuple>
29#include <utility>
30
31COMMS_MSVC_WARNING_PUSH
32COMMS_MSVC_WARNING_DISABLE(4100) // Disable warning about unreferenced parameters
33COMMS_MSVC_WARNING_DISABLE(4189) // Disable erroneous initialized but not referenced variable warning
34
35namespace comms
36{
37
38namespace frame
39{
40
65template <typename TField,
66 typename TMessage,
67 typename TAllMessages,
68 typename TNextLayer,
69 typename... TOptions>
70class MsgIdLayer : public comms::frame::details::MsgIdLayerBase<TField, TMessage, TAllMessages, TNextLayer, TOptions...>
71{
73 "TAllMessages must be of std::tuple type");
74
75 static_assert(TMessage::hasMsgIdType(),
76 "Usage of MsgIdLayer requires support for ID type. "
77 "Use comms::option::def::MsgIdType option in message interface type definition.");
78
79 using BaseImpl = comms::frame::details::MsgIdLayerBase<TField, TMessage, TAllMessages, TNextLayer, TOptions...>;
80 using ParsedOptionsInternal = details::MsgIdLayerOptionsParser<TOptions...>;
81
82public:
84 using MsgFactory = typename ParsedOptionsInternal::template MsgFactory<TMessage, TAllMessages>;
85
89 using ExtendingClass = typename ParsedOptionsInternal::ExtendingClass;
90
92 using AllMessages = TAllMessages;
93
96 using MsgPtr = typename MsgFactory::MsgPtr;
97
99 using Message = TMessage;
100
103
106
108 using Field = typename BaseImpl::Field;
109
112
114 explicit MsgIdLayer() = default;
115
117 MsgIdLayer(const MsgIdLayer&) = default;
118
120 MsgIdLayer(MsgIdLayer&&) = default;
121
123 MsgIdLayer& operator=(const MsgIdLayer&) = default;
124
127
129 ~MsgIdLayer() noexcept = default;
130
135 static constexpr bool hasExtendingClass()
136 {
137 return ParsedOptionsInternal::HasExtendingClass;
138 }
139
143 static constexpr bool hasMsgFactory()
144 {
145 return ParsedOptionsInternal::HasMsgFactory;
146 }
147
186 template <typename TMsg, typename TIter, typename TNextLayerReader, typename... TExtraValues>
188 Field& field,
189 TMsg& msg,
190 TIter& iter,
191 std::size_t size,
192 TNextLayerReader&& nextLayerReader,
193 TExtraValues... extraValues)
194 {
195 auto beforeReadIter = iter;
196 auto& thisObj = BaseImpl::thisLayer();
197 auto* msgPtr = BaseImpl::toMsgPtr(msg);
198 auto es = thisObj.doReadField(msgPtr, field, iter, size);
200 BaseImpl::updateMissingSize(field, size, extraValues...);
201 }
202
203 if (es != ErrorStatus::Success) {
204 return es;
205 }
206
207 auto fieldLen = static_cast<std::size_t>(std::distance(beforeReadIter, iter));
208
209 using Tag =
210 typename comms::util::LazyShallowConditional<
211 comms::isMessage<typename std::decay<decltype(msg)>::type>()
212 >::template Type<
213 DirectOpTag,
214 PointerOpTag
215 >;
216
217 return
218 doReadInternal(
219 field,
220 msg,
221 iter,
222 size - fieldLen,
223 std::forward<TNextLayerReader>(nextLayerReader),
224 Tag(),
225 extraValues...);
226 }
227
254 template <typename TMsg, typename TIter, typename TNextLayerWriter>
256 Field& field,
257 const TMsg& msg,
258 TIter& iter,
259 std::size_t size,
260 TNextLayerWriter&& nextLayerWriter) const
261 {
262 auto& thisObj = BaseImpl::thisLayer();
263 using MsgType = typename std::decay<decltype(msg)>::type;
264 static_assert(comms::isMessage<MsgType>(), "The message type must extend comms::Message");
265 thisObj.prepareFieldForWrite(
266 getMsgId(msg, IdRetrieveTag<MsgType>()),
267 msg,
268 field);
269
270 auto es = thisObj.doWriteField(&msg, field, iter, size);
271 if (es != ErrorStatus::Success) {
272 return es;
273 }
274
275 COMMS_ASSERT(field.length() <= size);
276
277 using Tag =
278 typename comms::util::LazyShallowConditional<
279 comms::isMessageBase<MsgType>() || MsgType::hasWrite()
280 >::template Type<
281 DirectOpTag,
282 StaticBinSearchOpTag
283 >;
284
285 return writeInternal(field, msg, iter, size - field.length(), std::forward<TNextLayerWriter>(nextLayerWriter), Tag());
286 }
287
298 MsgPtr createMsg(MsgIdParamType id, unsigned idx = 0, CreateFailureReason* reason = nullptr)
299 {
300 return m_factory.createMsg(id, idx, reason);
301 }
302
305 static constexpr bool isDispatchPolymorphic()
306 {
307 return MsgFactory::isDispatchPolymorphic();
308 }
309
312 static constexpr bool isDispatchStaticBinSearch()
313 {
314 return MsgFactory::isDispatchStaticBinSearch();
315 }
316
319 static constexpr bool isDispatchLinearSwitch()
320 {
321 return MsgFactory::isDispatchLinearSwitch();
322 }
323
324protected:
325
330 static MsgIdType getMsgIdFromField(const Field& field)
331 {
332 return static_cast<MsgIdType>(field.getValue());
333 }
334
345 template <typename TMsg>
346 static void beforeRead(const Field& field, TMsg& msg)
347 {
348 static_cast<void>(field);
349 static_cast<void>(msg);
350 }
351
359 template <typename TMsg>
360 static void prepareFieldForWrite(MsgIdParamType id, const TMsg& msg, Field& field)
361 {
362 static_cast<void>(msg);
363 static_cast<void>(field);
364 field.setValue(id);
365 }
366
367private:
368
369 template <typename... TParams>
370 using PolymorphicOpTag = comms::details::tag::Tag1<>;
371
372 template <typename... TParams>
373 using DirectOpTag = comms::details::tag::Tag2<>;
374
375 template <typename... TParams>
376 using PointerOpTag = comms::details::tag::Tag3<>;
377
378 template <typename... TParams>
379 using StaticBinSearchOpTag = comms::details::tag::Tag4<>;
380
381 template <typename TMsg>
382 using IdRetrieveTag =
383 typename comms::util::LazyShallowConditional<
384 comms::isMessageBase<TMsg>()
385 >::template Type<
386 DirectOpTag,
387 PolymorphicOpTag
388 >;
389
390 template <typename... TParams>
391 using IdParamAsIsTag = comms::details::tag::Tag5<>;
392
393 template <typename... TParams>
394 using IdParamCastTag = comms::details::tag::Tag6<>;
395
396 template <typename TId>
397 using IdParamTag =
398 typename comms::util::LazyShallowConditional<
399 std::is_base_of<MsgIdType, TId>::value
400 >::template Type<
401 IdParamAsIsTag,
402 IdParamCastTag
403 >;
404
405 template <typename... TParams>
406 using HasGenericMsgTag = comms::details::tag::Tag7<>;
407
408 template <typename... TParams>
409 using NoGenericMsgTag = comms::details::tag::Tag8<>;
410
411 template <typename TIter, typename TNextLayerReader, typename... TExtraValues>
412 class ReadRedirectionHandler
413 {
414 public:
415 using RetType = comms::ErrorStatus;
416
417 ReadRedirectionHandler(
418 TIter& iter,
419 std::size_t size,
420 TNextLayerReader&& nextLayerReader,
421 TExtraValues... extraValues)
422 : m_iter(iter),
423 m_size(size),
424 m_nextLayerReader(std::forward<TNextLayerReader>(nextLayerReader)),
425 m_extraValues(extraValues...)
426 {
427 }
428
429 template <typename TMsg>
430 RetType handle(TMsg& msg)
431 {
432 static_assert(comms::isMessageBase<TMsg>(), "Expected to be a valid message object");
433 return handleInternal(msg, m_extraValues);
434 }
435
436 RetType handle(TMessage& msg)
437 {
438 static_cast<void>(msg);
439 static constexpr bool Should_not_happen = false;
440 static_cast<void>(Should_not_happen);
441 COMMS_ASSERT(Should_not_happen);
443 }
444
445 private:
446 template <typename TMsg>
447 RetType handleInternal(TMsg& msg, std::tuple<>&)
448 {
449 return m_nextLayerReader.read(msg, m_iter, m_size);
450 }
451
452 template <typename TMsg, typename T0>
453 RetType handleInternal(TMsg& msg, std::tuple<T0>& extraValues)
454 {
455 return m_nextLayerReader.read(msg, m_iter, m_size, std::get<0>(extraValues));
456 }
457
458 template <typename TMsg, typename T0, typename T1>
459 RetType handleInternal(TMsg& msg, std::tuple<T0, T1>& extraValues)
460 {
461 return m_nextLayerReader.read(msg, m_iter, m_size, std::get<0>(extraValues), std::get<1>(extraValues));
462 }
463
464 template <typename TMsg, typename T0, typename T1, typename T2>
465 RetType handleInternal(TMsg& msg, std::tuple<T0, T1, T2>& extraValues)
466 {
467 return
468 m_nextLayerReader.read(
469 msg,
470 m_iter,
471 m_size,
472 std::get<0>(extraValues),
473 std::get<1>(extraValues),
474 std::get<2>(extraValues));
475 }
476
477 template <typename TMsg, typename T0, typename T1, typename T2, typename T3>
478 RetType handleInternal(TMsg& msg, std::tuple<T0, T1, T2, T3>& extraValues)
479 {
480 return
481 m_nextLayerReader.read(
482 msg,
483 m_iter,
484 m_size,
485 std::get<0>(extraValues),
486 std::get<1>(extraValues),
487 std::get<2>(extraValues),
488 std::get<3>(extraValues));
489 }
490
491 template <typename TMsg, typename T0, typename T1, typename T2, typename T3, typename T4>
492 RetType handleInternal(TMsg& msg, std::tuple<T0, T1, T2, T3, T4>& extraValues)
493 {
494 return
495 m_nextLayerReader.read(
496 msg,
497 m_iter,
498 m_size,
499 std::get<0>(extraValues),
500 std::get<1>(extraValues),
501 std::get<2>(extraValues),
502 std::get<3>(extraValues),
503 std::get<4>(extraValues));
504 }
505
506 template <typename TMsg, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5>
507 RetType handleInternal(TMsg& msg, std::tuple<T0, T1, T2, T3, T4, T5>& extraValues)
508 {
509 return
510 m_nextLayerReader.read(
511 msg,
512 m_iter,
513 m_size,
514 std::get<0>(extraValues),
515 std::get<1>(extraValues),
516 std::get<2>(extraValues),
517 std::get<3>(extraValues),
518 std::get<4>(extraValues),
519 std::get<5>(extraValues));
520 }
521
522 TIter& m_iter;
523 std::size_t m_size = 0U;
524 TNextLayerReader&& m_nextLayerReader;
525 std::tuple<TExtraValues...> m_extraValues;
526 };
527
528 template <typename TIter, typename TNextLayerReader, typename... TExtraValues>
529 ReadRedirectionHandler<TIter, TNextLayerReader, TExtraValues...> makeReadRedirectionHandler(
530 TIter& iter,
531 std::size_t size,
532 TNextLayerReader&& nextLayerReader,
533 TExtraValues... extraValues)
534 {
535 return ReadRedirectionHandler<TIter, TNextLayerReader, TExtraValues...>(iter, size, std::forward<TNextLayerReader>(nextLayerReader), extraValues...);
536 }
537
538 template <typename TIter, typename TNextLayerWriter>
539 class WriteRedirectionHandler
540 {
541 public:
542 using RetType = comms::ErrorStatus;
543
544 WriteRedirectionHandler(
545 TIter& iter,
546 std::size_t size,
547 TNextLayerWriter&& nextLayerWriter)
548 : m_iter(iter),
549 m_size(size),
550 m_nextLayerWriter(std::forward<TNextLayerWriter>(nextLayerWriter))
551 {
552 }
553
554 template <typename TMsg>
555 RetType handle(const TMsg& msg)
556 {
557 static_assert(comms::isMessageBase<TMsg>(), "Expected to be a valid message object");
558 return m_nextLayerWriter.write(msg, m_iter, m_size);
559 }
560
561 RetType handle(const TMessage& msg)
562 {
563 static_cast<void>(msg);
564 static constexpr bool Should_not_happen = false;
565 static_cast<void>(Should_not_happen);
566 COMMS_ASSERT(Should_not_happen);
568 }
569
570 private:
571 TIter& m_iter;
572 std::size_t m_size = 0U;
573 TNextLayerWriter&& m_nextLayerWriter;
574 };
575
576 template <typename TIter, typename TNextLayerWriter>
577 WriteRedirectionHandler<TIter, TNextLayerWriter> makeWriteRedirectionHandler(
578 TIter& iter,
579 std::size_t size,
580 TNextLayerWriter&& nextLayerWriter)
581 {
582 return WriteRedirectionHandler<TIter, TNextLayerWriter>(iter, size, std::forward<TNextLayerWriter>(nextLayerWriter));
583 }
584
585 template <typename TMsg, typename... TParams>
586 static MsgIdParamType getMsgId(const TMsg& msg, PolymorphicOpTag<TParams...>)
587 {
588 using MsgType = typename std::decay<decltype(msg)>::type;
589 static_assert(comms::isMessage<MsgType>(),
590 "The message class is expected to inherit from comms::Message");
591 static_assert(MsgType::hasGetId(),
592 "The message interface class must expose polymorphic ID retrieval functionality, "
593 "use comms::option::app::IdInfoInterface option to define it.");
594
595 return msg.getId();
596 }
597
598 template <typename TMsg, typename... TParams>
599 static constexpr MsgIdParamType getMsgId(const TMsg& msg, DirectOpTag<TParams...>)
600 {
601 using MsgType = typename std::decay<decltype(msg)>::type;
602 static_assert(comms::isMessageBase<MsgType>(),
603 "The message class is expected to inherit from comms::MessageBase");
604 static_assert(MsgType::hasStaticMsgId(),
605 "The message class must expose direct ID retrieval functionality, "
606 "use comms::option::app::StaticNumIdImpl option to define it.");
607 return msg.doGetId();
608 }
609
610 template <typename TMsg, typename TIter, typename TNextLayerReader, typename... TExtraValues>
611 comms::ErrorStatus doReadInternalDirect(
612 Field& field,
613 TMsg& msg,
614 TIter& iter,
615 std::size_t size,
616 TNextLayerReader&& nextLayerReader,
617 TExtraValues... extraValues)
618 {
619 static_assert((!details::hasMsgIndexRetriever<TExtraValues...>()) || (comms::details::allMessagesAreStrongSorted<AllMessages>()),
620 "Message type index cannot be retrieved with direct message object invocation");
621 auto& thisObj = BaseImpl::thisLayer();
622 auto id = thisObj.getMsgIdFromField(field);
623 BaseImpl::setMsgId(id, extraValues...);
624 BaseImpl::setMsgIndex(0U, extraValues...);
625
626 using MsgType = typename std::decay<decltype(msg)>::type;
627 if (id != getMsgId(msg, IdRetrieveTag<MsgType>())) {
628 return ErrorStatus::InvalidMsgId;
629 }
630
631 thisObj.beforeRead(field, msg);
632 return nextLayerReader.read(msg, iter, size, extraValues...);
633 }
634
635 template <typename TMsg, typename TIter, typename TNextLayerReader, typename... TExtraValues>
636 comms::ErrorStatus doReadInternal(
637 MsgIdParamType id,
638 unsigned idx,
639 TMsg& msg,
640 TIter& iter,
641 std::size_t size,
642 TNextLayerReader&& nextLayerReader,
643 PolymorphicOpTag<>,
644 TExtraValues... extraValues)
645 {
646 static_cast<void>(id);
647 static_cast<void>(idx);
648 return nextLayerReader.read(msg, iter, size, extraValues...);
649 }
650
651 template <typename TMsg, typename TIter, typename TNextLayerReader, typename... TExtraValues>
652 comms::ErrorStatus doReadInternal(
653 Field& field,
654 TMsg& msg,
655 TIter& iter,
656 std::size_t size,
657 TNextLayerReader&& nextLayerReader,
658 DirectOpTag<>,
659 TExtraValues... extraValues)
660 {
661 return
662 doReadInternalDirect(
663 field,
664 msg,
665 iter,
666 size,
667 std::forward<TNextLayerReader>(nextLayerReader),
668 extraValues...);
669 }
670
671 template <typename TMsg, typename TIter, typename TNextLayerReader, typename... TExtraValues>
672 comms::ErrorStatus doReadInternal(
673 Field& field,
674 TMsg& msg,
675 TIter& iter,
676 std::size_t size,
677 TNextLayerReader&& nextLayerReader,
678 PointerOpTag<>,
679 TExtraValues... extraValues)
680 {
681 using MsgType = typename std::decay<decltype(msg)>::type;
682 static_assert(comms::details::hasElementType<MsgType>(),
683 "Unsupported type of message object, expected to be either message itself or smart pointer");
684
685 using MsgElementType = typename MsgType::element_type;
686
687 using Tag =
688 typename comms::util::LazyShallowConditional<
689 MsgElementType::hasRead()
690 >::template Type<
691 PolymorphicOpTag,
692 StaticBinSearchOpTag
693 >;
694
695 auto& thisObj = BaseImpl::thisLayer();
696 const auto id = thisObj.getMsgIdFromField(field);
697 BaseImpl::setMsgId(id, extraValues...);
698
700 unsigned idx = 0;
701 CreateFailureReason failureReason = CreateFailureReason::None;
702 while (true) {
703 COMMS_ASSERT(!msg);
704 msg = createMsgInternal(id, idx, &failureReason);
705 if (!msg) {
706 break;
707 }
708
709 using IterType = typename std::decay<decltype(iter)>::type;
710 static_assert(std::is_same<typename std::iterator_traits<IterType>::iterator_category, std::random_access_iterator_tag>::value,
711 "Iterator used for reading is expected to be random access one");
712 IterType readStart = iter;
713
714 thisObj.beforeRead(field, *msg);
715 es = doReadInternal(id, idx, msg, iter, size, std::forward<TNextLayerReader>(nextLayerReader), Tag(), extraValues...);
716 if (es == comms::ErrorStatus::Success) {
717 BaseImpl::setMsgIndex(idx, extraValues...);
718 return es;
719 }
720
721 msg.reset();
722 iter = readStart;
723 ++idx;
724 }
725
726 BaseImpl::setMsgIndex(idx, extraValues...);
727 COMMS_ASSERT(!msg);
728 if (failureReason == CreateFailureReason::AllocFailure) {
730 }
731
732 COMMS_ASSERT(failureReason == CreateFailureReason::InvalidId);
733 using GenericMsgTag =
734 typename comms::util::LazyShallowConditional<
735 MsgFactory::hasGenericMessageSupport()
736 >::template Type<
737 HasGenericMsgTag,
738 NoGenericMsgTag
739 >;
740
741 return
742 createAndReadGenericMsgInternal(
743 field,
744 idx,
745 msg,
746 iter,
747 size,
748 std::forward<TNextLayerReader>(nextLayerReader),
749 es,
750 GenericMsgTag(),
751 extraValues...);
752 }
753
754 template <typename TMsg, typename TIter, typename TNextLayerReader, typename... TExtraValues>
755 comms::ErrorStatus doReadInternal(
756 MsgIdParamType id,
757 unsigned idx,
758 TMsg& msg,
759 TIter& iter,
760 std::size_t size,
761 TNextLayerReader&& nextLayerReader,
762 StaticBinSearchOpTag<>,
763 TExtraValues... extraValues)
764 {
765 auto handler =
766 makeReadRedirectionHandler(
767 iter,
768 size,
769 std::forward<TNextLayerReader>(nextLayerReader),
770 extraValues...);
771 return comms::dispatchMsgStaticBinSearch<AllMessages>(id, idx, *msg, handler);
772 }
773
774 template <typename TId, typename... TParams>
775 MsgPtr createMsgInternalTagged(TId&& id, unsigned idx, CreateFailureReason* reason, IdParamAsIsTag<TParams...>)
776 {
777 return createMsg(std::forward<TId>(id), idx, reason);
778 }
779
780 template <typename TId, typename... TParams>
781 MsgPtr createMsgInternalTagged(TId&& id, unsigned idx, CreateFailureReason* reason, IdParamCastTag<TParams...>)
782 {
783 return createMsg(static_cast<MsgIdType>(id), idx, reason);
784 }
785
786 template <typename TId>
787 MsgPtr createMsgInternal(TId&& id, unsigned idx, CreateFailureReason* reason)
788 {
789 using IdType = typename std::decay<decltype(id)>::type;
790 return createMsgInternalTagged(std::forward<TId>(id), idx, reason, IdParamTag<IdType>());
791 }
792
793 template <typename TId, typename... TParams>
794 MsgPtr createGenericMsgInternalTagged(TId&& id, unsigned idx, IdParamAsIsTag<TParams...>)
795 {
796 return m_factory.createGenericMsg(std::forward<TId>(id), idx);
797 }
798
799 template <typename TId, typename... TParams>
800 MsgPtr createGenericMsgInternalTagged(TId&& id, unsigned idx, IdParamCastTag<TParams...>)
801 {
802 return m_factory.createGenericMsg(static_cast<MsgIdType>(id), idx);
803 }
804
805 template <typename TId>
806 MsgPtr createGenericMsgInternal(TId&& id, unsigned idx)
807 {
808 using IdType = typename std::decay<decltype(id)>::type;
809 return createGenericMsgInternalTagged(std::forward<TId>(id), idx, IdParamTag<IdType>());
810 }
811
812 template <typename TMsg, typename TIter, typename TNextLayerReader, typename... TExtraValues>
813 comms::ErrorStatus createAndReadGenericMsgInternal(
814 const Field& field,
815 unsigned msgIdx,
816 TMsg& msg,
817 TIter& iter,
818 std::size_t size,
819 TNextLayerReader&& nextLayerReader,
821 NoGenericMsgTag<>,
822 TExtraValues...)
823 {
824 static_cast<void>(field);
825 static_cast<void>(msgIdx);
826 static_cast<void>(msg);
827 static_cast<void>(iter);
828 static_cast<void>(size);
829 static_cast<void>(nextLayerReader);
830 return es;
831 }
832
833 template <typename TMsg, typename TIter, typename TNextLayerReader, typename... TExtraValues>
834 comms::ErrorStatus createAndReadGenericMsgInternal(
835 const Field& field,
836 unsigned msgIdx,
837 TMsg& msg,
838 TIter& iter,
839 std::size_t size,
840 TNextLayerReader&& nextLayerReader,
842 HasGenericMsgTag<>,
843 TExtraValues... extraValues)
844 {
845 using GenericMsgType = typename MsgFactory::GenericMessage;
846
847 auto& thisObj = BaseImpl::thisLayer();
848 auto id = thisObj.getMsgIdFromField(field);
849 msg = createGenericMsgInternal(id, msgIdx);
850 if (!msg) {
851 return es;
852 }
853
854 thisObj.beforeRead(field, *msg);
855
856 using Tag =
857 typename comms::util::LazyShallowConditional<
858 GenericMsgType::hasRead()
859 >::template Type<
860 PolymorphicOpTag,
861 DirectOpTag
862 >;
863
864 return
865 readGenericMsg(
866 msg,
867 iter,
868 size,
869 std::forward<TNextLayerReader>(nextLayerReader),
870 Tag(),
871 extraValues...);
872 }
873
874 template <typename TMsg, typename TIter, typename TNextLayerReader, typename... TExtraValues>
875 comms::ErrorStatus readGenericMsg(
876 TMsg& msg,
877 TIter& iter,
878 std::size_t size,
879 TNextLayerReader&& nextLayerReader,
880 PolymorphicOpTag<>,
881 TExtraValues... extraValues)
882 {
883 return nextLayerReader.read(msg, iter, size, extraValues...);
884 }
885
886 template <typename TMsg, typename TIter, typename TNextLayerReader, typename... TExtraValues>
887 comms::ErrorStatus readGenericMsg(
888 TMsg& msg,
889 TIter& iter,
890 std::size_t size,
891 TNextLayerReader&& nextLayerReader,
892 DirectOpTag<>,
893 TExtraValues... extraValues)
894 {
895 using GenericMsgType = typename MsgFactory::GenericMessage;
896 auto& castedMsgRef = static_cast<GenericMsgType&>(*msg);
897 return nextLayerReader.read(castedMsgRef, iter, size, extraValues...);
898 }
899
900 template <typename TId, typename... TParams>
901 std::size_t msgCountInternalTagged(TId&& id, IdParamAsIsTag<TParams...>)
902 {
903 return m_factory.msgCount(std::forward<TId>(id));
904 }
905
906 template <typename TId, typename... TParams>
907 std::size_t msgCountInternalTagged(TId&& id, IdParamCastTag<TParams...>)
908 {
909 return m_factory.msgCount(static_cast<MsgIdType>(id));
910 }
911
912
913 template <typename TId>
914 std::size_t msgCountInternal(TId&& id)
915 {
916 using IdType = typename std::decay<decltype(id)>::type;
917 return msgCountInternalTagged(std::forward<TId>(id), IdParamTag<IdType>());
918 }
919
920 template <typename TMsg, typename TIter, typename TNextLayerWriter, typename... TParams>
921 ErrorStatus writeInternal(
922 Field& field,
923 const TMsg& msg,
924 TIter& iter,
925 std::size_t size,
926 TNextLayerWriter&& nextLayerWriter,
927 DirectOpTag<TParams...>) const
928 {
929 static_cast<void>(field);
930 return nextLayerWriter.write(msg, iter, size);
931 }
932
933
934 template <typename TMsg, typename TIter, typename TNextLayerWriter, typename... TParams>
935 ErrorStatus writeInternal(
936 Field& field,
937 const TMsg& msg,
938 TIter& iter,
939 std::size_t size,
940 TNextLayerWriter&& nextLayerWriter,
941 StaticBinSearchOpTag<TParams...>) const
942 {
943 auto& thisObj = BaseImpl::thisLayer();
944 auto handler = makeWriteRedirectionHandler(iter, size, std::forward<TNextLayerWriter>(nextLayerWriter));
945 auto id = thisObj.getMsgIdFromField(field);
946 return comms::dispatchMsgStaticBinSearch(id, msg, handler);
947 }
948
949 MsgFactory m_factory;
950};
951
952
953namespace details
954{
955template <typename T>
956struct MsgIdLayerCheckHelper
957{
958 static const bool Value = false;
959};
960
961template <typename TField,
962 typename TMessage,
963 typename TAllMessages,
964 typename TNextLayer,
965 typename... TOptions>
966struct MsgIdLayerCheckHelper<MsgIdLayer<TField, TMessage, TAllMessages, TNextLayer, TOptions...> >
967{
968 static const bool Value = true;
969};
970
971} // namespace details
972
976template <typename T>
977constexpr bool isMsgIdLayer()
978{
979 return details::MsgIdLayerCheckHelper<T>::Value;
980}
981
982} // namespace frame
983
984} // namespace comms
985
986COMMS_MSVC_WARNING_POP
This file contains classes required for generic custom assertion functionality.
#define COMMS_ASSERT(expr)
Generic assert macro.
Definition Assert.h:170
Contains various compiler related definitions.
Provides common base class for the custom messages with default implementation.
Contains definition of comms::MsgFactory class.
Contains various tuple type manipulation classes and functions.
typename BaseImpl::MsgIdType MsgIdType
Type used for message ID.
Definition Message.h:195
typename BaseImpl::MsgIdParamType MsgIdParamType
Type used for message ID passed as parameter or returned from function.
Definition Message.h:202
typename Base::MsgPtr MsgPtr
Smart pointer to Message which holds allocated message object.
Definition MsgFactory.h:109
Protocol layer that uses uses message ID field as a prefix to all the subsequent data written by othe...
Definition MsgIdLayer.h:71
typename Message::MsgIdParamType MsgIdParamType
Type of message ID when passed by the parameter.
Definition MsgIdLayer.h:105
static constexpr bool isDispatchStaticBinSearch()
Compile time inquiry whether static binary search dispatch is generated internally to map message ID ...
Definition MsgIdLayer.h:312
typename Message::MsgIdType MsgIdType
Type of message ID.
Definition MsgIdLayer.h:102
typename MsgFactory::MsgPtr MsgPtr
Type of smart pointer that will hold allocated message object.
Definition MsgIdLayer.h:96
TMessage Message
Type of the input message interface.
Definition MsgIdLayer.h:99
MsgIdLayer(const MsgIdLayer &)=default
Copy constructor.
static void prepareFieldForWrite(MsgIdParamType id, const TMsg &msg, Field &field)
Prepare field for writing.
Definition MsgIdLayer.h:360
typename ParsedOptionsInternal::template MsgFactory< TMessage, TAllMessages > MsgFactory
Message factory class.
Definition MsgIdLayer.h:84
static constexpr bool isDispatchPolymorphic()
Compile time inquiry whether polymorphic dispatch tables are generated internally to map message ID t...
Definition MsgIdLayer.h:305
MsgPtr createMsg(MsgIdParamType id, unsigned idx=0, CreateFailureReason *reason=nullptr)
Create message object given the ID.
Definition MsgIdLayer.h:298
static MsgIdType getMsgIdFromField(const Field &field)
Retrieve message id from the field.
Definition MsgIdLayer.h:330
static constexpr bool hasMsgFactory()
Compile time inquiry of whether custom message factory class has been provided via comms::option::app...
Definition MsgIdLayer.h:143
constexpr bool isMsgIdLayer()
Compile time check of whether the provided type is a variant of MsgIdLayer.
Definition MsgIdLayer.h:977
MsgIdLayer(MsgIdLayer &&)=default
Move constructor.
MsgIdLayer()=default
Default constructor.
comms::ErrorStatus doRead(Field &field, TMsg &msg, TIter &iter, std::size_t size, TNextLayerReader &&nextLayerReader, TExtraValues... extraValues)
Customized read functionality, invoked by read().
Definition MsgIdLayer.h:187
static constexpr bool isDispatchLinearSwitch()
Compile time inquiry whether linear switch dispatch is generated internally to map message ID to actu...
Definition MsgIdLayer.h:319
typename BaseImpl::Field Field
Type of the field object used to read/write message ID value.
Definition MsgIdLayer.h:108
typename MsgFactory::CreateFailureReason CreateFailureReason
Reason for message creation failure.
Definition MsgIdLayer.h:111
MsgIdLayer & operator=(const MsgIdLayer &)=default
Copy assignment.
ErrorStatus doWrite(Field &field, const TMsg &msg, TIter &iter, std::size_t size, TNextLayerWriter &&nextLayerWriter) const
Customized write functionality, invoked by write().
Definition MsgIdLayer.h:255
TAllMessages AllMessages
All supported message types bundled in std::tuple.
Definition MsgIdLayer.h:92
~MsgIdLayer() noexcept=default
Destructor.
typename ParsedOptionsInternal::ExtendingClass ExtendingClass
Type of real extending class.
Definition MsgIdLayer.h:89
MsgIdLayer & operator=(MsgIdLayer &&)=default
Move assignment.
static void beforeRead(const Field &field, TMsg &msg)
Extra operation before read.
Definition MsgIdLayer.h:346
Contains extra logic to help with dispatching message types and objects.
This file provides all the definitions from comms::field namespace.
comms::option::def::MsgType< TMsg > MsgType
Same as comms::option::def::MsgType.
Definition options.h:1487
comms::option::def::MsgIdType< T > MsgIdType
Same as comms::option::def::MsgIdType.
Definition options.h:1473
comms::frame::MsgIdLayer< TField, TMessage, TAllMessages, TNextLayer, TOptions... > MsgIdLayer
Alias to the comms::frame::MsgIdLayer.
Definition MsgIdLayer.h:25
Main namespace for all classes / functions of COMMS library.
ErrorStatus
Error statuses reported by the Communication module.
Definition ErrorStatus.h:17
@ MsgAllocFailure
Used to indicate that message allocation has failed.
@ Success
Used to indicate successful outcome of the operation.
@ InvalidMsgId
Used to indicate that received message has unknown id.
auto dispatchMsgStaticBinSearch(TId &&id, std::size_t index, TMsg &msg, THandler &handler) -> details::MessageInterfaceDispatchRetType< typename std::decay< decltype(handler)>::type >
Dispatch message object into appropriate handle() function in the provided handler using static binar...
Definition dispatch.h:166
constexpr bool isMessage()
Compile time check of of whether the type is a message.
Definition Message.h:542
MsgFactoryCreateFailureReason
Definition MsgFactoryCreateFailureReason.h:18
STL namespace.
Check whether provided type is a variant of std::tuple.
Definition Tuple.h:36
Replacement to some types from standard type_traits.