COMMS
Template library intended to help with implementation of communication protocols.
Loading...
Searching...
No Matches
MsgIdLayer.h
Go to the documentation of this file.
1//
2// Copyright 2014 - 2024 (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 <array>
14#include <tuple>
15#include <algorithm>
16#include <utility>
17#include <tuple>
18#include <limits>
19
21#include "comms/Assert.h"
22#include "comms/MessageBase.h"
23#include "comms/MsgFactory.h"
24#include "comms/details/tag.h"
25#include "comms/protocol/details/ProtocolLayerBase.h"
26#include "comms/protocol/details/MsgIdLayerOptionsParser.h"
27#include "comms/protocol/details/ProtocolLayerExtendingClassHelper.h"
28#include "comms/util/Tuple.h"
30#include "comms/dispatch.h"
31#include "comms/fields.h"
32
33
34COMMS_MSVC_WARNING_PUSH
35COMMS_MSVC_WARNING_DISABLE(4100) // Disable warning about unreferenced parameters
36COMMS_MSVC_WARNING_DISABLE(4189) // Disable erroneous initialized but not referenced variable warning
37
38namespace comms
39{
40
41namespace protocol
42{
43
66template <typename TField,
67 typename TMessage,
68 typename TAllMessages,
69 typename TNextLayer,
70 typename... TOptions>
71class MsgIdLayer : public
73 TField,
74 TNextLayer,
75 details::ProtocolLayerExtendingClassT<
76 MsgIdLayer<TField, TMessage, TAllMessages, TNextLayer, TOptions...>,
77 details::MsgIdLayerOptionsParser<TOptions...>
78 >
79 >
80{
82 "TAllMessages must be of std::tuple type");
83
84 using BaseImpl =
86 TField,
87 TNextLayer,
88 details::ProtocolLayerExtendingClassT<
89 MsgIdLayer<TField, TMessage, TAllMessages, TNextLayer, TOptions...>,
90 details::MsgIdLayerOptionsParser<TOptions...>
91 >
92 >;
93
94 static_assert(TMessage::hasMsgIdType(),
95 "Usage of MsgIdLayer requires support for ID type. "
96 "Use comms::option::def::MsgIdType option in message interface type definition.");
97
98 using ParsedOptionsInternal = details::MsgIdLayerOptionsParser<TOptions...>;
99
100public:
101 // @brief Message factory class
102 using MsgFactory = typename ParsedOptionsInternal::template MsgFactory<TMessage, TAllMessages>;
103
107 using ExtendingClass = typename ParsedOptionsInternal::ExtendingClass;
108
110 using AllMessages = TAllMessages;
111
114 using MsgPtr = typename MsgFactory::MsgPtr;
115
117 using Message = TMessage;
118
121
124
126 using Field = typename BaseImpl::Field;
127
130
132 explicit MsgIdLayer() = default;
133
135 MsgIdLayer(const MsgIdLayer&) = default;
136
138 MsgIdLayer(MsgIdLayer&&) = default;
139
141 MsgIdLayer& operator=(const MsgIdLayer&) = default;
142
145
147 ~MsgIdLayer() noexcept = default;
148
153 static constexpr bool hasExtendingClass()
154 {
155 return ParsedOptionsInternal::HasExtendingClass;
156 }
157
161 static constexpr bool hasMsgFactory()
162 {
163 return ParsedOptionsInternal::HasMsgFactory;
164 }
165
204 template <typename TMsg, typename TIter, typename TNextLayerReader, typename... TExtraValues>
206 Field& field,
207 TMsg& msg,
208 TIter& iter,
209 std::size_t size,
210 TNextLayerReader&& nextLayerReader,
211 TExtraValues... extraValues)
212 {
213 auto beforeReadIter = iter;
214 auto& thisObj = BaseImpl::thisLayer();
215 auto* msgPtr = BaseImpl::toMsgPtr(msg);
216 auto es = thisObj.doReadField(msgPtr, field, iter, size);
218 BaseImpl::updateMissingSize(field, size, extraValues...);
219 }
220
221 if (es != ErrorStatus::Success) {
222 return es;
223 }
224
225 auto fieldLen = static_cast<std::size_t>(std::distance(beforeReadIter, iter));
226
227 using Tag =
228 typename comms::util::LazyShallowConditional<
229 comms::isMessageBase<typename std::decay<decltype(msg)>::type>()
230 >::template Type<
231 DirectOpTag,
232 PointerOpTag
233 >;
234
235 return
236 doReadInternal(
237 field,
238 msg,
239 iter,
240 size - fieldLen,
241 std::forward<TNextLayerReader>(nextLayerReader),
242 Tag(),
243 extraValues...);
244 }
245
272 template <typename TMsg, typename TIter, typename TNextLayerWriter>
274 Field& field,
275 const TMsg& msg,
276 TIter& iter,
277 std::size_t size,
278 TNextLayerWriter&& nextLayerWriter) const
279 {
280 auto& thisObj = BaseImpl::thisLayer();
281 using MsgType = typename std::decay<decltype(msg)>::type;
282 thisObj.prepareFieldForWrite(
283 getMsgId(msg, IdRetrieveTag<MsgType>()),
284 msg,
285 field);
286
287 auto es = thisObj.doWriteField(&msg, field, iter, size);
288 if (es != ErrorStatus::Success) {
289 return es;
290 }
291
292 COMMS_ASSERT(field.length() <= size);
293
294 using Tag =
295 typename comms::util::LazyShallowConditional<
296 comms::isMessageBase<MsgType>() || MsgType::hasWrite()
297 >::template Type<
298 DirectOpTag,
299 StaticBinSearchOpTag
300 >;
301
302 return writeInternal(field, msg, iter, size - field.length(), std::forward<TNextLayerWriter>(nextLayerWriter), Tag());
303 }
304
315 MsgPtr createMsg(MsgIdParamType id, unsigned idx = 0, CreateFailureReason* reason = nullptr)
316 {
317 return factory_.createMsg(id, idx, reason);
318 }
319
322 static constexpr bool isDispatchPolymorphic()
323 {
324 return MsgFactory::isDispatchPolymorphic();
325 }
326
329 static constexpr bool isDispatchStaticBinSearch()
330 {
331 return MsgFactory::isDispatchStaticBinSearch();
332 }
333
336 static constexpr bool isDispatchLinearSwitch()
337 {
338 return MsgFactory::isDispatchLinearSwitch();
339 }
340
341protected:
342
347 static MsgIdType getMsgIdFromField(const Field& field)
348 {
349 return static_cast<MsgIdType>(field.getValue());
350 }
351
362 template <typename TMsg>
363 static void beforeRead(const Field& field, TMsg& msg)
364 {
365 static_cast<void>(field);
366 static_cast<void>(msg);
367 }
368
376 template <typename TMsg>
377 static void prepareFieldForWrite(MsgIdParamType id, const TMsg& msg, Field& field)
378 {
379 static_cast<void>(msg);
380 static_cast<void>(field);
381 field.setValue(id);
382 }
383
384private:
385
386 template <typename... TParams>
387 using PolymorphicOpTag = comms::details::tag::Tag1<>;
388
389 template <typename... TParams>
390 using DirectOpTag = comms::details::tag::Tag2<>;
391
392 template <typename... TParams>
393 using PointerOpTag = comms::details::tag::Tag3<>;
394
395 template <typename... TParams>
396 using StaticBinSearchOpTag = comms::details::tag::Tag4<>;
397
398 template <typename TMsg>
399 using IdRetrieveTag =
400 typename comms::util::LazyShallowConditional<
401 details::protocolLayerHasDoGetId<TMsg>()
402 >::template Type<
403 DirectOpTag,
404 PolymorphicOpTag
405 >;
406
407 template <typename... TParams>
408 using IdParamAsIsTag = comms::details::tag::Tag5<>;
409
410 template <typename... TParams>
411 using IdParamCastTag = comms::details::tag::Tag6<>;
412
413 template <typename TId>
414 using IdParamTag =
415 typename comms::util::LazyShallowConditional<
416 std::is_base_of<MsgIdType, TId>::value
417 >::template Type<
418 IdParamAsIsTag,
419 IdParamCastTag
420 >;
421
422 template <typename... TParams>
423 using HasGenericMsgTag = comms::details::tag::Tag7<>;
424
425 template <typename... TParams>
426 using NoGenericMsgTag = comms::details::tag::Tag8<>;
427
428 template <typename TIter, typename TNextLayerReader, typename... TExtraValues>
429 class ReadRedirectionHandler
430 {
431 public:
432 using RetType = comms::ErrorStatus;
433
434 ReadRedirectionHandler(
435 TIter& iter,
436 std::size_t size,
437 TNextLayerReader&& nextLayerReader,
438 TExtraValues... extraValues)
439 : m_iter(iter),
440 m_size(size),
441 m_nextLayerReader(std::forward<TNextLayerReader>(nextLayerReader)),
442 m_extraValues(extraValues...)
443 {
444 }
445
446 template <typename TMsg>
447 RetType handle(TMsg& msg)
448 {
449 static_assert(comms::isMessageBase<TMsg>(), "Expected to be a valid message object");
450 return handleInternal(msg, m_extraValues);
451 }
452
453 RetType handle(TMessage& msg)
454 {
455 static_cast<void>(msg);
456 static constexpr bool Should_not_happen = false;
457 static_cast<void>(Should_not_happen);
458 COMMS_ASSERT(Should_not_happen);
460 }
461
462 private:
463 template <typename TMsg>
464 RetType handleInternal(TMsg& msg, std::tuple<>&)
465 {
466 return m_nextLayerReader.read(msg, m_iter, m_size);
467 }
468
469 template <typename TMsg, typename T0>
470 RetType handleInternal(TMsg& msg, std::tuple<T0>& extraValues)
471 {
472 return m_nextLayerReader.read(msg, m_iter, m_size, std::get<0>(extraValues));
473 }
474
475 template <typename TMsg, typename T0, typename T1>
476 RetType handleInternal(TMsg& msg, std::tuple<T0, T1>& extraValues)
477 {
478 return m_nextLayerReader.read(msg, m_iter, m_size, std::get<0>(extraValues), std::get<1>(extraValues));
479 }
480
481 template <typename TMsg, typename T0, typename T1, typename T2>
482 RetType handleInternal(TMsg& msg, std::tuple<T0, T1, T2>& extraValues)
483 {
484 return
485 m_nextLayerReader.read(
486 msg,
487 m_iter,
488 m_size,
489 std::get<0>(extraValues),
490 std::get<1>(extraValues),
491 std::get<2>(extraValues));
492 }
493
494 template <typename TMsg, typename T0, typename T1, typename T2, typename T3>
495 RetType handleInternal(TMsg& msg, std::tuple<T0, T1, T2, T3>& extraValues)
496 {
497 return
498 m_nextLayerReader.read(
499 msg,
500 m_iter,
501 m_size,
502 std::get<0>(extraValues),
503 std::get<1>(extraValues),
504 std::get<2>(extraValues),
505 std::get<3>(extraValues));
506 }
507
508 template <typename TMsg, typename T0, typename T1, typename T2, typename T3, typename T4>
509 RetType handleInternal(TMsg& msg, std::tuple<T0, T1, T2, T3, T4>& extraValues)
510 {
511 return
512 m_nextLayerReader.read(
513 msg,
514 m_iter,
515 m_size,
516 std::get<0>(extraValues),
517 std::get<1>(extraValues),
518 std::get<2>(extraValues),
519 std::get<3>(extraValues),
520 std::get<4>(extraValues));
521 }
522
523 template <typename TMsg, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5>
524 RetType handleInternal(TMsg& msg, std::tuple<T0, T1, T2, T3, T4, T5>& extraValues)
525 {
526 return
527 m_nextLayerReader.read(
528 msg,
529 m_iter,
530 m_size,
531 std::get<0>(extraValues),
532 std::get<1>(extraValues),
533 std::get<2>(extraValues),
534 std::get<3>(extraValues),
535 std::get<4>(extraValues),
536 std::get<5>(extraValues));
537 }
538
539 TIter& m_iter;
540 std::size_t m_size = 0U;
541 TNextLayerReader&& m_nextLayerReader;
542 std::tuple<TExtraValues...> m_extraValues;
543 };
544
545 template <typename TIter, typename TNextLayerReader, typename... TExtraValues>
546 ReadRedirectionHandler<TIter, TNextLayerReader, TExtraValues...> makeReadRedirectionHandler(
547 TIter& iter,
548 std::size_t size,
549 TNextLayerReader&& nextLayerReader,
550 TExtraValues... extraValues)
551 {
552 return ReadRedirectionHandler<TIter, TNextLayerReader, TExtraValues...>(iter, size, std::forward<TNextLayerReader>(nextLayerReader), extraValues...);
553 }
554
555 template <typename TIter, typename TNextLayerWriter>
556 class WriteRedirectionHandler
557 {
558 public:
559 using RetType = comms::ErrorStatus;
560
561 WriteRedirectionHandler(
562 TIter& iter,
563 std::size_t size,
564 TNextLayerWriter&& nextLayerWriter)
565 : m_iter(iter),
566 m_size(size),
567 m_nextLayerWriter(std::forward<TNextLayerWriter>(nextLayerWriter))
568 {
569 }
570
571 template <typename TMsg>
572 RetType handle(const TMsg& msg)
573 {
574 static_assert(comms::isMessageBase<TMsg>(), "Expected to be a valid message object");
575 return m_nextLayerWriter.write(msg, m_iter, m_size);
576 }
577
578 RetType handle(const TMessage& msg)
579 {
580 static_cast<void>(msg);
581 static constexpr bool Should_not_happen = false;
582 static_cast<void>(Should_not_happen);
583 COMMS_ASSERT(Should_not_happen);
585 }
586
587 private:
588 TIter& m_iter;
589 std::size_t m_size = 0U;
590 TNextLayerWriter&& m_nextLayerWriter;
591 };
592
593 template <typename TIter, typename TNextLayerWriter>
594 WriteRedirectionHandler<TIter, TNextLayerWriter> makeWriteRedirectionHandler(
595 TIter& iter,
596 std::size_t size,
597 TNextLayerWriter&& nextLayerWriter)
598 {
599 return WriteRedirectionHandler<TIter, TNextLayerWriter>(iter, size, std::forward<TNextLayerWriter>(nextLayerWriter));
600 }
601
602 template <typename TMsg, typename... TParams>
603 static MsgIdParamType getMsgId(const TMsg& msg, PolymorphicOpTag<TParams...>)
604 {
605 using MsgType = typename std::decay<decltype(msg)>::type;
606 static_assert(comms::isMessage<MsgType>(),
607 "The message class is expected to inherit from comms::Message");
608 static_assert(MsgType::hasGetId(),
609 "The message interface class must expose polymorphic ID retrieval functionality, "
610 "use comms::option::app::IdInfoInterface option to define it.");
611
612 return msg.getId();
613 }
614
615 template <typename TMsg, typename... TParams>
616 static constexpr MsgIdParamType getMsgId(const TMsg& msg, DirectOpTag<TParams...>)
617 {
618 return msg.doGetId();
619 }
620
621 template <typename TMsg, typename TIter, typename TNextLayerReader, typename... TExtraValues>
622 comms::ErrorStatus doReadInternalDirect(
623 Field& field,
624 TMsg& msg,
625 TIter& iter,
626 std::size_t size,
627 TNextLayerReader&& nextLayerReader,
628 TExtraValues... extraValues)
629 {
630 using MsgType = typename std::decay<decltype(msg)>::type;
631 static_assert(details::protocolLayerHasDoGetId<MsgType>(),
632 "Explicit message type is expected to expose compile type message ID by "
633 "using \"StaticNumIdImpl\" option");
634
635 auto& thisObj = BaseImpl::thisLayer();
636 auto id = thisObj.getMsgIdFromField(field);
637 BaseImpl::setMsgId(id, extraValues...);
638 if (id != MsgType::doGetId()) {
639 return ErrorStatus::InvalidMsgId;
640 }
641
642 thisObj.beforeRead(field, msg);
643 return nextLayerReader.read(msg, iter, size, extraValues...);
644 }
645
646 template <typename TMsg, typename TIter, typename TNextLayerReader, typename... TExtraValues>
647 comms::ErrorStatus doReadInternal(
648 MsgIdParamType id,
649 unsigned idx,
650 TMsg& msg,
651 TIter& iter,
652 std::size_t size,
653 TNextLayerReader&& nextLayerReader,
654 PolymorphicOpTag<>,
655 TExtraValues... extraValues)
656 {
657 static_cast<void>(id);
658 static_cast<void>(idx);
659 return nextLayerReader.read(msg, iter, size, extraValues...);
660 }
661
662 template <typename TMsg, typename TIter, typename TNextLayerReader, typename... TExtraValues>
663 comms::ErrorStatus doReadInternal(
664 Field& field,
665 TMsg& msg,
666 TIter& iter,
667 std::size_t size,
668 TNextLayerReader&& nextLayerReader,
669 DirectOpTag<>,
670 TExtraValues... extraValues)
671 {
672 return
673 doReadInternalDirect(
674 field,
675 msg,
676 iter,
677 size,
678 std::forward<TNextLayerReader>(nextLayerReader),
679 extraValues...);
680 }
681
682 template <typename TMsg, typename TIter, typename TNextLayerReader, typename... TExtraValues>
683 comms::ErrorStatus doReadInternal(
684 Field& field,
685 TMsg& msg,
686 TIter& iter,
687 std::size_t size,
688 TNextLayerReader&& nextLayerReader,
689 PointerOpTag<>,
690 TExtraValues... extraValues)
691 {
692 using MsgType = typename std::decay<decltype(msg)>::type;
693 static_assert(comms::details::hasElementType<MsgType>(),
694 "Unsupported type of message object, expected to be either message itself or smart pointer");
695
696 using MsgElementType = typename MsgType::element_type;
697
698// static_assert(std::has_virtual_destructor<MsgElementType>::value,
699// "Message object is (dynamically) allocated and held by the pointer to the base class. "
700// "However, there is no virtual desctructor to perform proper destruction.");
701
702 using Tag =
703 typename comms::util::LazyShallowConditional<
704 MsgElementType::hasRead()
705 >::template Type<
706 PolymorphicOpTag,
707 StaticBinSearchOpTag
708 >;
709
710 auto& thisObj = BaseImpl::thisLayer();
711 const auto id = thisObj.getMsgIdFromField(field);
712 BaseImpl::setMsgId(id, extraValues...);
713
715 unsigned idx = 0;
716 CreateFailureReason failureReason = CreateFailureReason::None;
717 while (true) {
718 COMMS_ASSERT(!msg);
719 msg = createMsgInternal(id, idx, &failureReason);
720 if (!msg) {
721 break;
722 }
723
724 using IterType = typename std::decay<decltype(iter)>::type;
725 static_assert(std::is_same<typename std::iterator_traits<IterType>::iterator_category, std::random_access_iterator_tag>::value,
726 "Iterator used for reading is expected to be random access one");
727 IterType readStart = iter;
728
729 thisObj.beforeRead(field, *msg);
730 es = doReadInternal(id, idx, msg, iter, size, std::forward<TNextLayerReader>(nextLayerReader), Tag(), extraValues...);
731 if (es == comms::ErrorStatus::Success) {
732 BaseImpl::setMsgIndex(idx, extraValues...);
733 return es;
734 }
735
736 msg.reset();
737 iter = readStart;
738 ++idx;
739 }
740
741 BaseImpl::setMsgIndex(idx, extraValues...);
742 COMMS_ASSERT(!msg);
743 if (failureReason == CreateFailureReason::AllocFailure) {
745 }
746
747 COMMS_ASSERT(failureReason == CreateFailureReason::InvalidId);
748 using GenericMsgTag =
749 typename comms::util::LazyShallowConditional<
750 MsgFactory::hasGenericMessageSupport()
751 >::template Type<
752 HasGenericMsgTag,
753 NoGenericMsgTag
754 >;
755
756 return createAndReadGenericMsgInternal(
757 field,
758 idx,
759 msg,
760 iter,
761 size,
762 std::forward<TNextLayerReader>(nextLayerReader),
763 es,
764 GenericMsgTag(),
765 extraValues...);
766 }
767
768 template <typename TMsg, typename TIter, typename TNextLayerReader, typename... TExtraValues>
769 comms::ErrorStatus doReadInternal(
770 MsgIdParamType id,
771 unsigned idx,
772 TMsg& msg,
773 TIter& iter,
774 std::size_t size,
775 TNextLayerReader&& nextLayerReader,
776 StaticBinSearchOpTag<>,
777 TExtraValues... extraValues)
778 {
779 auto handler =
780 makeReadRedirectionHandler(
781 iter,
782 size,
783 std::forward<TNextLayerReader>(nextLayerReader),
784 extraValues...);
785 return comms::dispatchMsgStaticBinSearch<AllMessages>(id, idx, *msg, handler);
786 }
787
788 template <typename TId, typename... TParams>
789 MsgPtr createMsgInternalTagged(TId&& id, unsigned idx, CreateFailureReason* reason, IdParamAsIsTag<TParams...>)
790 {
791 return createMsg(std::forward<TId>(id), idx, reason);
792 }
793
794 template <typename TId, typename... TParams>
795 MsgPtr createMsgInternalTagged(TId&& id, unsigned idx, CreateFailureReason* reason, IdParamCastTag<TParams...>)
796 {
797 return createMsg(static_cast<MsgIdType>(id), idx, reason);
798 }
799
800 template <typename TId>
801 MsgPtr createMsgInternal(TId&& id, unsigned idx, CreateFailureReason* reason)
802 {
803 using IdType = typename std::decay<decltype(id)>::type;
804 return createMsgInternalTagged(std::forward<TId>(id), idx, reason, IdParamTag<IdType>());
805 }
806
807 template <typename TId, typename... TParams>
808 MsgPtr createGenericMsgInternalTagged(TId&& id, unsigned idx, IdParamAsIsTag<TParams...>)
809 {
810 return factory_.createGenericMsg(std::forward<TId>(id), idx);
811 }
812
813 template <typename TId, typename... TParams>
814 MsgPtr createGenericMsgInternalTagged(TId&& id, unsigned idx, IdParamCastTag<TParams...>)
815 {
816 return factory_.createGenericMsg(static_cast<MsgIdType>(id), idx);
817 }
818
819 template <typename TId>
820 MsgPtr createGenericMsgInternal(TId&& id, unsigned idx)
821 {
822 using IdType = typename std::decay<decltype(id)>::type;
823 return createGenericMsgInternalTagged(std::forward<TId>(id), idx, IdParamTag<IdType>());
824 }
825
826 template <typename TMsg, typename TIter, typename TNextLayerReader, typename... TExtraValues>
827 comms::ErrorStatus createAndReadGenericMsgInternal(
828 const Field& field,
829 unsigned msgIdx,
830 TMsg& msg,
831 TIter& iter,
832 std::size_t size,
833 TNextLayerReader&& nextLayerReader,
835 NoGenericMsgTag<>,
836 TExtraValues...)
837 {
838 static_cast<void>(field);
839 static_cast<void>(msgIdx);
840 static_cast<void>(msg);
841 static_cast<void>(iter);
842 static_cast<void>(size);
843 static_cast<void>(nextLayerReader);
844 return es;
845 }
846
847 template <typename TMsg, typename TIter, typename TNextLayerReader, typename... TExtraValues>
848 comms::ErrorStatus createAndReadGenericMsgInternal(
849 const Field& field,
850 unsigned msgIdx,
851 TMsg& msg,
852 TIter& iter,
853 std::size_t size,
854 TNextLayerReader&& nextLayerReader,
856 HasGenericMsgTag<>,
857 TExtraValues... extraValues)
858 {
859 using GenericMsgType = typename MsgFactory::GenericMessage;
860
861 auto& thisObj = BaseImpl::thisLayer();
862 auto id = thisObj.getMsgIdFromField(field);
863 msg = createGenericMsgInternal(id, msgIdx);
864 if (!msg) {
865 return es;
866 }
867
868 thisObj.beforeRead(field, *msg);
869
870 using Tag =
871 typename comms::util::LazyShallowConditional<
872 GenericMsgType::hasRead()
873 >::template Type<
874 PolymorphicOpTag,
875 DirectOpTag
876 >;
877
878 return
879 readGenericMsg(
880 msg,
881 iter,
882 size,
883 std::forward<TNextLayerReader>(nextLayerReader),
884 Tag(),
885 extraValues...);
886 }
887
888 template <typename TMsg, typename TIter, typename TNextLayerReader, typename... TExtraValues>
889 comms::ErrorStatus readGenericMsg(
890 TMsg& msg,
891 TIter& iter,
892 std::size_t size,
893 TNextLayerReader&& nextLayerReader,
894 PolymorphicOpTag<>,
895 TExtraValues... extraValues)
896 {
897 return nextLayerReader.read(msg, iter, size, extraValues...);
898 }
899
900 template <typename TMsg, typename TIter, typename TNextLayerReader, typename... TExtraValues>
901 comms::ErrorStatus readGenericMsg(
902 TMsg& msg,
903 TIter& iter,
904 std::size_t size,
905 TNextLayerReader&& nextLayerReader,
906 DirectOpTag<>,
907 TExtraValues... extraValues)
908 {
909 using GenericMsgType = typename MsgFactory::GenericMessage;
910 auto& castedMsgRef = static_cast<GenericMsgType&>(*msg);
911 return nextLayerReader.read(castedMsgRef, iter, size, extraValues...);
912 }
913
914 template <typename TId, typename... TParams>
915 std::size_t msgCountInternalTagged(TId&& id, IdParamAsIsTag<TParams...>)
916 {
917 return factory_.msgCount(std::forward<TId>(id));
918 }
919
920 template <typename TId, typename... TParams>
921 std::size_t msgCountInternalTagged(TId&& id, IdParamCastTag<TParams...>)
922 {
923 return factory_.msgCount(static_cast<MsgIdType>(id));
924 }
925
926
927 template <typename TId>
928 std::size_t msgCountInternal(TId&& id)
929 {
930 using IdType = typename std::decay<decltype(id)>::type;
931 return msgCountInternalTagged(std::forward<TId>(id), IdParamTag<IdType>());
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 DirectOpTag<TParams...>) const
942 {
943 static_cast<void>(field);
944 return nextLayerWriter.write(msg, iter, size);
945 }
946
947
948 template <typename TMsg, typename TIter, typename TNextLayerWriter, typename... TParams>
949 ErrorStatus writeInternal(
950 Field& field,
951 const TMsg& msg,
952 TIter& iter,
953 std::size_t size,
954 TNextLayerWriter&& nextLayerWriter,
955 StaticBinSearchOpTag<TParams...>) const
956 {
957 auto& thisObj = BaseImpl::thisLayer();
958 auto handler = makeWriteRedirectionHandler(iter, size, std::forward<TNextLayerWriter>(nextLayerWriter));
959 auto id = thisObj.getMsgIdFromField(field);
960 return comms::dispatchMsgStaticBinSearch(id, msg, handler);
961 }
962
963 MsgFactory factory_;
964};
965
966
967namespace details
968{
969template <typename T>
970struct MsgIdLayerCheckHelper
971{
972 static const bool Value = false;
973};
974
975template <typename TField,
976 typename TMessage,
977 typename TAllMessages,
978 typename TNextLayer,
979 typename... TOptions>
980struct MsgIdLayerCheckHelper<MsgIdLayer<TField, TMessage, TAllMessages, TNextLayer, TOptions...> >
981{
982 static const bool Value = true;
983};
984
985} // namespace details
986
990template <typename T>
991constexpr bool isMsgIdLayer()
992{
993 return details::MsgIdLayerCheckHelper<T>::Value;
994}
995
996} // namespace protocol
997
998} // namespace comms
999
1000COMMS_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:196
typename BaseImpl::MsgIdParamType MsgIdParamType
Type used for message ID passed as parameter or returned from function.
Definition Message.h:203
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:80
static void prepareFieldForWrite(MsgIdParamType id, const TMsg &msg, Field &field)
Prepare field for writing.
Definition MsgIdLayer.h:377
static MsgIdType getMsgIdFromField(const Field &field)
Retrieve message id from the field.
Definition MsgIdLayer.h:347
typename Message::MsgIdParamType MsgIdParamType
Type of message ID when passed by the parameter.
Definition MsgIdLayer.h:123
typename MsgFactory::CreateFailureReason CreateFailureReason
Reason for message creation failure.
Definition MsgIdLayer.h:129
static constexpr bool hasMsgFactory()
Compile time inquiry of whether custom message factory class has been provided via comms::option::app...
Definition MsgIdLayer.h:161
typename MsgFactory::MsgPtr MsgPtr
Type of smart pointer that will hold allocated message object.
Definition MsgIdLayer.h:114
MsgIdLayer(MsgIdLayer &&)=default
Move constructor.
typename Message::MsgIdType MsgIdType
Type of message ID.
Definition MsgIdLayer.h:120
~MsgIdLayer() noexcept=default
Destructor.
TMessage Message
Type of the input message interface.
Definition MsgIdLayer.h:117
MsgIdLayer & operator=(MsgIdLayer &&)=default
Move assignment.
static constexpr bool isDispatchStaticBinSearch()
Compile time inquiry whether static binary search dispatch is generated internally to map message ID ...
Definition MsgIdLayer.h:329
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:273
static constexpr bool isDispatchPolymorphic()
Compile time inquiry whether polymorphic dispatch tables are generated internally to map message ID t...
Definition MsgIdLayer.h:322
constexpr bool isMsgIdLayer()
Compile time check of whether the provided type is a variant of MsgIdLayer.
Definition MsgIdLayer.h:991
MsgIdLayer()=default
Default constructor.
MsgPtr createMsg(MsgIdParamType id, unsigned idx=0, CreateFailureReason *reason=nullptr)
Create message object given the ID.
Definition MsgIdLayer.h:315
MsgIdLayer(const MsgIdLayer &)=default
Copy constructor.
static void beforeRead(const Field &field, TMsg &msg)
Extra operation before read.
Definition MsgIdLayer.h:363
TAllMessages AllMessages
All supported message types bundled in std::tuple.
Definition MsgIdLayer.h:110
typename BaseImpl::Field Field
Type of the field object used to read/write message ID value.
Definition MsgIdLayer.h:126
MsgIdLayer & operator=(const MsgIdLayer &)=default
Copy assignment.
typename ParsedOptionsInternal::ExtendingClass ExtendingClass
Type of real extending class.
Definition MsgIdLayer.h:107
static constexpr bool isDispatchLinearSwitch()
Compile time inquiry whether linear switch dispatch is generated internally to map message ID to actu...
Definition MsgIdLayer.h:336
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:205
Base class for all the middle (non MsgDataLayer) protocol transport layers.
Definition ProtocolLayerBase.h:61
TField Field
Type of the field used for this layer.
Definition ProtocolLayerBase.h:64
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:1459
comms::option::def::MsgIdType< T > MsgIdType
Same as comms::option::def::MsgIdType.
Definition options.h:1448
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 isMessageBase()
Compile time check of of whether the type is a message extending comms::MessageBase.
Definition MessageBase.h:899
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.