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::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.