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