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 - 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::hasDoGetId(),
605 "The message class must expose direct ID retrieval functionality, "
606 "use comms::option::app::StaticNumIdImpl option to define it or "
607 "comms::option::app::HasDoGetId option to mark the class as providing one");
608 return msg.doGetId();
609 }
610
611 template <typename TMsg, typename TIter, typename TNextLayerReader, typename... TExtraValues>
612 comms::ErrorStatus doReadInternalDirect(
613 Field& field,
614 TMsg& msg,
615 TIter& iter,
616 std::size_t size,
617 TNextLayerReader&& nextLayerReader,
618 TExtraValues... extraValues)
619 {
620 static_assert((!details::hasMsgIndexRetriever<TExtraValues...>()) || (comms::details::allMessagesAreStrongSorted<AllMessages>()),
621 "Message type index cannot be retrieved with direct message object invocation");
622 auto& thisObj = BaseImpl::thisLayer();
623 auto id = thisObj.getMsgIdFromField(field);
624 BaseImpl::setMsgId(id, extraValues...);
625 BaseImpl::setMsgIndex(0U, extraValues...);
626
627 using MsgType = typename std::decay<decltype(msg)>::type;
628 if (id != getMsgId(msg, IdRetrieveTag<MsgType>())) {
629 return ErrorStatus::InvalidMsgId;
630 }
631
632 thisObj.beforeRead(field, msg);
633 return nextLayerReader.read(msg, iter, size, extraValues...);
634 }
635
636 template <typename TMsg, typename TIter, typename TNextLayerReader, typename... TExtraValues>
637 comms::ErrorStatus doReadInternal(
638 MsgIdParamType id,
639 unsigned idx,
640 TMsg& msg,
641 TIter& iter,
642 std::size_t size,
643 TNextLayerReader&& nextLayerReader,
644 PolymorphicOpTag<>,
645 TExtraValues... extraValues)
646 {
647 static_cast<void>(id);
648 static_cast<void>(idx);
649 return nextLayerReader.read(msg, iter, size, extraValues...);
650 }
651
652 template <typename TMsg, typename TIter, typename TNextLayerReader, typename... TExtraValues>
653 comms::ErrorStatus doReadInternal(
654 Field& field,
655 TMsg& msg,
656 TIter& iter,
657 std::size_t size,
658 TNextLayerReader&& nextLayerReader,
659 DirectOpTag<>,
660 TExtraValues... extraValues)
661 {
662 return
663 doReadInternalDirect(
664 field,
665 msg,
666 iter,
667 size,
668 std::forward<TNextLayerReader>(nextLayerReader),
669 extraValues...);
670 }
671
672 template <typename TMsg, typename TIter, typename TNextLayerReader, typename... TExtraValues>
673 comms::ErrorStatus doReadInternal(
674 Field& field,
675 TMsg& msg,
676 TIter& iter,
677 std::size_t size,
678 TNextLayerReader&& nextLayerReader,
679 PointerOpTag<>,
680 TExtraValues... extraValues)
681 {
682 using MsgType = typename std::decay<decltype(msg)>::type;
683 static_assert(comms::details::hasElementType<MsgType>(),
684 "Unsupported type of message object, expected to be either message itself or smart pointer");
685
686 using MsgElementType = typename MsgType::element_type;
687
688 using Tag =
689 typename comms::util::LazyShallowConditional<
690 MsgElementType::hasRead()
691 >::template Type<
692 PolymorphicOpTag,
693 StaticBinSearchOpTag
694 >;
695
696 auto& thisObj = BaseImpl::thisLayer();
697 const auto id = thisObj.getMsgIdFromField(field);
698 BaseImpl::setMsgId(id, extraValues...);
699
701 unsigned idx = 0;
702 CreateFailureReason failureReason = CreateFailureReason::None;
703 while (true) {
704 COMMS_ASSERT(!msg);
705 msg = createMsgInternal(id, idx, &failureReason);
706 if (!msg) {
707 break;
708 }
709
710 using IterType = typename std::decay<decltype(iter)>::type;
711 static_assert(std::is_same<typename std::iterator_traits<IterType>::iterator_category, std::random_access_iterator_tag>::value,
712 "Iterator used for reading is expected to be random access one");
713 IterType readStart = iter;
714
715 thisObj.beforeRead(field, *msg);
716 es = doReadInternal(id, idx, msg, iter, size, std::forward<TNextLayerReader>(nextLayerReader), Tag(), extraValues...);
717 if (es == comms::ErrorStatus::Success) {
718 BaseImpl::setMsgIndex(idx, extraValues...);
719 return es;
720 }
721
722 msg.reset();
723 iter = readStart;
724 ++idx;
725 }
726
727 BaseImpl::setMsgIndex(idx, extraValues...);
728 COMMS_ASSERT(!msg);
729 if (failureReason == CreateFailureReason::AllocFailure) {
731 }
732
733 COMMS_ASSERT(failureReason == CreateFailureReason::InvalidId);
734 using GenericMsgTag =
735 typename comms::util::LazyShallowConditional<
736 MsgFactory::hasGenericMessageSupport()
737 >::template Type<
738 HasGenericMsgTag,
739 NoGenericMsgTag
740 >;
741
742 return
743 createAndReadGenericMsgInternal(
744 field,
745 idx,
746 msg,
747 iter,
748 size,
749 std::forward<TNextLayerReader>(nextLayerReader),
750 es,
751 GenericMsgTag(),
752 extraValues...);
753 }
754
755 template <typename TMsg, typename TIter, typename TNextLayerReader, typename... TExtraValues>
756 comms::ErrorStatus doReadInternal(
757 MsgIdParamType id,
758 unsigned idx,
759 TMsg& msg,
760 TIter& iter,
761 std::size_t size,
762 TNextLayerReader&& nextLayerReader,
763 StaticBinSearchOpTag<>,
764 TExtraValues... extraValues)
765 {
766 auto handler =
767 makeReadRedirectionHandler(
768 iter,
769 size,
770 std::forward<TNextLayerReader>(nextLayerReader),
771 extraValues...);
772 return comms::dispatchMsgStaticBinSearch<AllMessages>(id, idx, *msg, handler);
773 }
774
775 template <typename TId, typename... TParams>
776 MsgPtr createMsgInternalTagged(TId&& id, unsigned idx, CreateFailureReason* reason, IdParamAsIsTag<TParams...>)
777 {
778 return createMsg(std::forward<TId>(id), idx, reason);
779 }
780
781 template <typename TId, typename... TParams>
782 MsgPtr createMsgInternalTagged(TId&& id, unsigned idx, CreateFailureReason* reason, IdParamCastTag<TParams...>)
783 {
784 return createMsg(static_cast<MsgIdType>(id), idx, reason);
785 }
786
787 template <typename TId>
788 MsgPtr createMsgInternal(TId&& id, unsigned idx, CreateFailureReason* reason)
789 {
790 using IdType = typename std::decay<decltype(id)>::type;
791 return createMsgInternalTagged(std::forward<TId>(id), idx, reason, IdParamTag<IdType>());
792 }
793
794 template <typename TId, typename... TParams>
795 MsgPtr createGenericMsgInternalTagged(TId&& id, unsigned idx, IdParamAsIsTag<TParams...>)
796 {
797 return m_factory.createGenericMsg(std::forward<TId>(id), idx);
798 }
799
800 template <typename TId, typename... TParams>
801 MsgPtr createGenericMsgInternalTagged(TId&& id, unsigned idx, IdParamCastTag<TParams...>)
802 {
803 return m_factory.createGenericMsg(static_cast<MsgIdType>(id), idx);
804 }
805
806 template <typename TId>
807 MsgPtr createGenericMsgInternal(TId&& id, unsigned idx)
808 {
809 using IdType = typename std::decay<decltype(id)>::type;
810 return createGenericMsgInternalTagged(std::forward<TId>(id), idx, IdParamTag<IdType>());
811 }
812
813 template <typename TMsg, typename TIter, typename TNextLayerReader, typename... TExtraValues>
814 comms::ErrorStatus createAndReadGenericMsgInternal(
815 const Field& field,
816 unsigned msgIdx,
817 TMsg& msg,
818 TIter& iter,
819 std::size_t size,
820 TNextLayerReader&& nextLayerReader,
822 NoGenericMsgTag<>,
823 TExtraValues...)
824 {
825 static_cast<void>(field);
826 static_cast<void>(msgIdx);
827 static_cast<void>(msg);
828 static_cast<void>(iter);
829 static_cast<void>(size);
830 static_cast<void>(nextLayerReader);
831 return es;
832 }
833
834 template <typename TMsg, typename TIter, typename TNextLayerReader, typename... TExtraValues>
835 comms::ErrorStatus createAndReadGenericMsgInternal(
836 const Field& field,
837 unsigned msgIdx,
838 TMsg& msg,
839 TIter& iter,
840 std::size_t size,
841 TNextLayerReader&& nextLayerReader,
843 HasGenericMsgTag<>,
844 TExtraValues... extraValues)
845 {
846 using GenericMsgType = typename MsgFactory::GenericMessage;
847
848 auto& thisObj = BaseImpl::thisLayer();
849 auto id = thisObj.getMsgIdFromField(field);
850 msg = createGenericMsgInternal(id, msgIdx);
851 if (!msg) {
852 return es;
853 }
854
855 thisObj.beforeRead(field, *msg);
856
857 using Tag =
858 typename comms::util::LazyShallowConditional<
859 GenericMsgType::hasRead()
860 >::template Type<
861 PolymorphicOpTag,
862 DirectOpTag
863 >;
864
865 return
866 readGenericMsg(
867 msg,
868 iter,
869 size,
870 std::forward<TNextLayerReader>(nextLayerReader),
871 Tag(),
872 extraValues...);
873 }
874
875 template <typename TMsg, typename TIter, typename TNextLayerReader, typename... TExtraValues>
876 comms::ErrorStatus readGenericMsg(
877 TMsg& msg,
878 TIter& iter,
879 std::size_t size,
880 TNextLayerReader&& nextLayerReader,
881 PolymorphicOpTag<>,
882 TExtraValues... extraValues)
883 {
884 return nextLayerReader.read(msg, iter, size, extraValues...);
885 }
886
887 template <typename TMsg, typename TIter, typename TNextLayerReader, typename... TExtraValues>
888 comms::ErrorStatus readGenericMsg(
889 TMsg& msg,
890 TIter& iter,
891 std::size_t size,
892 TNextLayerReader&& nextLayerReader,
893 DirectOpTag<>,
894 TExtraValues... extraValues)
895 {
896 using GenericMsgType = typename MsgFactory::GenericMessage;
897 auto& castedMsgRef = static_cast<GenericMsgType&>(*msg);
898 return nextLayerReader.read(castedMsgRef, iter, size, extraValues...);
899 }
900
901 template <typename TId, typename... TParams>
902 std::size_t msgCountInternalTagged(TId&& id, IdParamAsIsTag<TParams...>)
903 {
904 return m_factory.msgCount(std::forward<TId>(id));
905 }
906
907 template <typename TId, typename... TParams>
908 std::size_t msgCountInternalTagged(TId&& id, IdParamCastTag<TParams...>)
909 {
910 return m_factory.msgCount(static_cast<MsgIdType>(id));
911 }
912
913
914 template <typename TId>
915 std::size_t msgCountInternal(TId&& id)
916 {
917 using IdType = typename std::decay<decltype(id)>::type;
918 return msgCountInternalTagged(std::forward<TId>(id), IdParamTag<IdType>());
919 }
920
921 template <typename TMsg, typename TIter, typename TNextLayerWriter, typename... TParams>
922 ErrorStatus writeInternal(
923 Field& field,
924 const TMsg& msg,
925 TIter& iter,
926 std::size_t size,
927 TNextLayerWriter&& nextLayerWriter,
928 DirectOpTag<TParams...>) const
929 {
930 static_cast<void>(field);
931 return nextLayerWriter.write(msg, iter, size);
932 }
933
934
935 template <typename TMsg, typename TIter, typename TNextLayerWriter, typename... TParams>
936 ErrorStatus writeInternal(
937 Field& field,
938 const TMsg& msg,
939 TIter& iter,
940 std::size_t size,
941 TNextLayerWriter&& nextLayerWriter,
942 StaticBinSearchOpTag<TParams...>) const
943 {
944 auto& thisObj = BaseImpl::thisLayer();
945 auto handler = makeWriteRedirectionHandler(iter, size, std::forward<TNextLayerWriter>(nextLayerWriter));
946 auto id = thisObj.getMsgIdFromField(field);
947 return comms::dispatchMsgStaticBinSearch(id, msg, handler);
948 }
949
950 MsgFactory m_factory;
951};
952
953
954namespace details
955{
956template <typename T>
957struct MsgIdLayerCheckHelper
958{
959 static const bool Value = false;
960};
961
962template <typename TField,
963 typename TMessage,
964 typename TAllMessages,
965 typename TNextLayer,
966 typename... TOptions>
967struct MsgIdLayerCheckHelper<MsgIdLayer<TField, TMessage, TAllMessages, TNextLayer, TOptions...> >
968{
969 static const bool Value = true;
970};
971
972} // namespace details
973
977template <typename T>
978constexpr bool isMsgIdLayer()
979{
980 return details::MsgIdLayerCheckHelper<T>::Value;
981}
982
983} // namespace frame
984
985} // namespace comms
986
987COMMS_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:978
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:167
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.