COMMS
Template library intended to help with implementation of communication protocols.
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 
20 #include "comms/CompileControl.h"
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"
29 #include "comms/util/type_traits.h"
30 #include "comms/dispatch.h"
31 #include "comms/fields.h"
32 
33 
34 COMMS_MSVC_WARNING_PUSH
35 COMMS_MSVC_WARNING_DISABLE(4100) // Disable warning about unreferenced parameters
36 COMMS_MSVC_WARNING_DISABLE(4189) // Disable erroneous initialized but not referenced variable warning
37 
38 namespace comms
39 {
40 
41 namespace protocol
42 {
43 
66 template <typename TField,
67  typename TMessage,
68  typename TAllMessages,
69  typename TNextLayer,
70  typename... TOptions>
71 class 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 
100 public:
101  // @brief Message factory class
102  using MsgFactory = typename ParsedOptionsInternal::template MsgFactory<TMessage, TAllMessages>;
103 
108 
110  using AllMessages = TAllMessages;
111 
114  using MsgPtr = typename MsgFactory::MsgPtr;
115 
117  using Message = TMessage;
118 
120  using MsgIdType = typename Message::MsgIdType;
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 
341 protected:
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 
384 private:
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 
967 namespace details
968 {
969 template <typename T>
970 struct MsgIdLayerCheckHelper
971 {
972  static const bool Value = false;
973 };
974 
975 template <typename TField,
976  typename TMessage,
977  typename TAllMessages,
978  typename TNextLayer,
979  typename... TOptions>
980 struct MsgIdLayerCheckHelper<MsgIdLayer<TField, TMessage, TAllMessages, TNextLayer, TOptions...> >
981 {
982  static const bool Value = true;
983 };
984 
985 } // namespace details
986 
990 template <typename T>
991 constexpr bool isMsgIdLayer()
992 {
993  return details::MsgIdLayerCheckHelper<T>::Value;
994 }
995 
996 } // namespace protocol
997 
998 } // namespace comms
999 
1000 COMMS_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::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
MsgIdLayer & operator=(const MsgIdLayer &)=default
Copy assignment.
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
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
MsgIdLayer & operator=(MsgIdLayer &&)=default
Move assignment.
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
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::ExtendingClass< T > ExtendingClass
Same as comms::option::def::ExtendingClass.
Definition: options.h:1822
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
Check whether provided type is a variant of std::tuple.
Definition: Tuple.h:35
Replacement to some types from standard type_traits.