COMMS
Template library intended to help with implementation of communication protocols.
TransportValueLayer.h
Go to the documentation of this file.
1 //
2 // Copyright 2017 - 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 "ProtocolLayerBase.h"
14 #include "comms/CompileControl.h"
15 #include "comms/cast.h"
16 #include "comms/util/type_traits.h"
17 #include "comms/details/tag.h"
18 #include "comms/protocol/details/TransportValueLayerAdapter.h"
19 #include "comms/protocol/details/TransportValueLayerOptionsParser.h"
20 #include "comms/protocol/details/ProtocolLayerExtendingClassHelper.h"
21 
22 COMMS_MSVC_WARNING_PUSH
23 COMMS_MSVC_WARNING_DISABLE(4189) // Disable erroneous initialized but not referenced variable warning
24 
25 namespace comms
26 {
27 
28 namespace protocol
29 {
30 
64 template <typename TField, std::size_t TIdx, typename TNextLayer, typename... TOptions>
65 class TransportValueLayer : public
66  details::TransportValueLayerAdapterT<
67  ProtocolLayerBase<
68  TField,
69  TNextLayer,
70  details::ProtocolLayerExtendingClassT<
71  TransportValueLayer<TField, TIdx, TNextLayer, TOptions...>,
72  details::TransportValueLayerOptionsParser<TOptions...>
73  >,
74  typename details::TransportValueLayerOptionsParser<TOptions...>::
75  template ForceReadUntilDataSplitIfNeeded<TNextLayer>
76  >,
77  TOptions...
78  >
79 {
80  using ThisClass = TransportValueLayer<TField, TIdx, TNextLayer, TOptions...>;
81  using BaseImpl =
82  details::TransportValueLayerAdapterT<
84  TField,
85  TNextLayer,
86  details::ProtocolLayerExtendingClassT<
87  ThisClass,
88  details::TransportValueLayerOptionsParser<TOptions...>
89  >,
90  typename details::TransportValueLayerOptionsParser<TOptions...>::
91  template ForceReadUntilDataSplitIfNeeded<TNextLayer>
92  >,
93  TOptions...
94  >;
95 
96  using ParsedOptionsInternal = details::TransportValueLayerOptionsParser<TOptions...>;
97 
98 public:
100  using Field = typename BaseImpl::Field;
101 
106 
108  TransportValueLayer() = default;
109 
112 
115 
117  ~TransportValueLayer() noexcept = default;
118 
123  static constexpr bool hasExtendingClass()
124  {
125  return ParsedOptionsInternal::HasExtendingClass;
126  }
127 
130  static constexpr bool hasPseudoValue()
131  {
132  return ParsedOptionsInternal::HasPseudoValue;
133  }
134 
168  template <typename TMsg, typename TIter, typename TNextLayerReader, typename... TExtraValues>
170  Field& field,
171  TMsg& msg,
172  TIter& iter,
173  std::size_t size,
174  TNextLayerReader&& nextLayerReader,
175  TExtraValues... extraValues)
176  {
177  auto es = readFieldInternal(field, msg, iter, size, ValueTag<>(), extraValues...);
178  if (es != comms::ErrorStatus::Success) {
179  return es;
180  }
181 
182  static constexpr bool ForcedReadUntilDataSplit =
183  BaseImpl::ParsedOptions::HasForceReadUntilDataSplit;
184 
185  if (ForcedReadUntilDataSplit) {
186  es = nextLayerReader.read(msg, iter, size, extraValues...);
187 
188  if (es != comms::ErrorStatus::Success) {
189  return es;
190  }
191  }
192 
193  auto& thisObj = BaseImpl::thisLayer();
194  auto* msgPtr = BaseImpl::toMsgPtr(msg);
195  bool success = thisObj.reassignFieldValueToMsg(field, msgPtr);
196  if (!success) {
198  }
199 
200  if (!ForcedReadUntilDataSplit) {
201  es = nextLayerReader.read(msg, iter, size, extraValues...);
202  }
203 
204  return es;
205  }
206 
224  template <typename TMsg, typename TIter, typename TNextLayerWriter>
226  Field& field,
227  const TMsg& msg,
228  TIter& iter,
229  std::size_t size,
230  TNextLayerWriter&& nextLayerWriter) const
231  {
232  auto& thisObj = BaseImpl::thisLayer();
233  thisObj.prepareFieldForWrite(msg, field);
234 
235  auto es = writeFieldInternal(field, msg, iter, size, ValueTag<>());
236  if (es != ErrorStatus::Success) {
237  return es;
238  }
239 
240  return nextLayerWriter.write(msg, iter, size);
241  }
242 
246  static constexpr std::size_t doFieldLength()
247  {
248  return doFieldLengthInternal(ValueTag<>());
249  }
250 
254  template <typename TMsg>
255  static std::size_t doFieldLength(const TMsg&)
256  {
257  return doFieldLength();
258  }
259 
260 #ifdef FOR_DOXYGEN_DOC_ONLY
265 
269  const Field& pseudoField() const;
270 #endif
271 
272 protected:
282  template <typename TMsg>
283  static void reassignFieldValue(TMsg& msg, const Field& field)
284  {
285  using MsgType = typename std::decay<decltype(msg)>::type;
286  static_assert(MsgType::hasTransportFields(),
287  "Message interface class hasn't defined transport fields, "
288  "use comms::option::def::ExtraTransportFields option.");
289  static_assert(TIdx < std::tuple_size<typename MsgType::TransportFields>::value,
290  "TIdx is too big, exceeds the amount of transport fields defined in interface class");
291 
292  auto& allTransportFields = msg.transportFields();
293  auto& transportField = std::get<TIdx>(allTransportFields);
294 
295  using FieldType = typename std::decay<decltype(transportField)>::type;
296  transportField = comms::field_cast<FieldType>(field);
297  }
298 
311  template <typename TMsg>
312  bool reassignFieldValueToMsg(const Field& field, TMsg* msgPtr)
313  {
314  if (msgPtr == nullptr) {
315  return false;
316  }
317 
318  auto& thisObj = BaseImpl::thisLayer();
319  thisObj.reassignFieldValue(*msgPtr, field);
320  return true;
321  }
322 
330  template <typename TMsg>
331  static void prepareFieldForWrite(const TMsg& msg, Field& field)
332  {
333  using MsgType = typename std::decay<decltype(msg)>::type;
334  static_assert(MsgType::hasTransportFields(),
335  "Message interface class hasn't defined transport fields, "
336  "use comms::option::def::ExtraTransportFields option.");
337  static_assert(TIdx < std::tuple_size<typename MsgType::TransportFields>::value,
338  "TIdx is too big, exceeds the amount of transport fields defined in interface class");
339 
340  auto& transportField = std::get<TIdx>(msg.transportFields());
341  field = comms::field_cast<Field>(transportField);
342  }
343 
344 private:
345 
346  template <typename... TParams>
347  using PseudoValueTag = comms::details::tag::Tag1<>;
348 
349  template <typename... TParams>
350  using NormalValueTag = comms::details::tag::Tag2<>;
351 
352  template <typename...>
353  using ValueTag =
354  typename comms::util::LazyShallowConditional<
355  ParsedOptionsInternal::HasPseudoValue
356  >::template Type<
357  PseudoValueTag,
358  NormalValueTag
359  >;
360 
361 
362  template <typename... TParams>
363  static constexpr std::size_t doFieldLengthInternal(PseudoValueTag<TParams...>)
364  {
365  return 0U;
366  }
367 
368  template <typename... TParams>
369  static constexpr std::size_t doFieldLengthInternal(NormalValueTag<TParams...>)
370  {
371  return BaseImpl::doFieldLength();
372  }
373 
374  template <typename TMsg, typename TIter, typename... TExtraValues>
375  comms::ErrorStatus readFieldInternal(
376  Field& field,
377  TMsg& msg,
378  TIter& iter,
379  std::size_t& len,
380  PseudoValueTag<>,
381  TExtraValues...)
382  {
383  static_cast<void>(msg);
384  static_cast<void>(iter);
385  static_cast<void>(len);
386  field = BaseImpl::pseudoField();
388  }
389 
390  template <typename TMsg, typename TIter, typename... TExtraValues>
391  comms::ErrorStatus readFieldInternal(
392  Field& field,
393  TMsg& msg,
394  TIter& iter,
395  std::size_t& len,
396  NormalValueTag<>,
397  TExtraValues... extraValues)
398  {
399  auto& thisObj = BaseImpl::thisLayer();
400  auto* msgPtr = BaseImpl::toMsgPtr(msg);
401  auto beforeReadIter = iter;
402 
403  auto es = thisObj.doReadField(msgPtr, field, iter, len);
405  BaseImpl::updateMissingSize(field, len, extraValues...);
406  }
407  else {
408  auto fieldLen = static_cast<std::size_t>(std::distance(beforeReadIter, iter));
409  len -= fieldLen;
410  }
411  return es;
412  }
413 
414  template <typename TMsg, typename TIter, typename... TParams>
415  comms::ErrorStatus writeFieldInternal(
416  Field& field,
417  const TMsg& msg,
418  TIter& iter,
419  std::size_t& len,
420  PseudoValueTag<TParams...>) const
421  {
422  static_cast<void>(msg);
423  static_cast<void>(iter);
424  static_cast<void>(len);
425  field = BaseImpl::pseudoField();
427  }
428 
429  template <typename TMsg, typename TIter, typename... TParams>
430  comms::ErrorStatus writeFieldInternal(
431  Field& field,
432  const TMsg& msg,
433  TIter& iter,
434  std::size_t& len,
435  NormalValueTag<TParams...>) const
436  {
437  auto& thisObj = BaseImpl::thisLayer();
438  auto es = thisObj.doWriteField(&msg, field, iter, len);
439  if (es == comms::ErrorStatus::Success) {
440  COMMS_ASSERT(field.length() <= len);
441  len -= field.length();
442  }
443  return es;
444  }
445 };
446 
447 namespace details
448 {
449 template <typename T>
450 struct TransportValueLayerCheckHelper
451 {
452  static const bool Value = false;
453 };
454 
455 template <typename TField, std::size_t TIdx, typename TNextLayer>
456 struct TransportValueLayerCheckHelper<TransportValueLayer<TField, TIdx, TNextLayer> >
457 {
458  static const bool Value = true;
459 };
460 
461 } // namespace details
462 
466 template <typename T>
467 constexpr bool isTransportValueLayer()
468 {
469  return details::TransportValueLayerCheckHelper<T>::Value;
470 }
471 
472 } // namespace protocol
473 
474 } // namespace comms
475 
476 COMMS_MSVC_WARNING_POP
#define COMMS_ASSERT(expr)
Generic assert macro.
Definition: Assert.h:170
Contains various compiler related definitions.
Contains definition of comms::protocol::ProtocolLayerBase.
Contains definition of various casts.
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
Protocol layer that reads a value from transport wrapping and reassigns it to appropriate "extra tran...
Definition: TransportValueLayer.h:79
comms::ErrorStatus doRead(Field &field, TMsg &msg, TIter &iter, std::size_t size, TNextLayerReader &&nextLayerReader, TExtraValues... extraValues)
Customized read functionality, invoked by read().
Definition: TransportValueLayer.h:169
TransportValueLayer(TransportValueLayer &&)=default
Move constructor.
static constexpr bool hasPseudoValue()
Compile time inquiry of whether the comms::option::def::PseudoValue option has been used.
Definition: TransportValueLayer.h:130
~TransportValueLayer() noexcept=default
Destructor.
static std::size_t doFieldLength(const TMsg &)
Customising field length calculation.
Definition: TransportValueLayer.h:255
const Field & pseudoField() const
Const access to pseudo field stored internally.
bool reassignFieldValueToMsg(const Field &field, TMsg *msgPtr)
Re-assign the value from the input field to appropriate transport field in the message object.
Definition: TransportValueLayer.h:312
comms::ErrorStatus doWrite(Field &field, const TMsg &msg, TIter &iter, std::size_t size, TNextLayerWriter &&nextLayerWriter) const
Customized write functionality, invoked by write().
Definition: TransportValueLayer.h:225
TransportValueLayer()=default
Default constructor.
typename ParsedOptionsInternal::ExtendingClass ExtendingClass
Type of real extending class.
Definition: TransportValueLayer.h:105
static void prepareFieldForWrite(const TMsg &msg, Field &field)
Prepare field for writing.
Definition: TransportValueLayer.h:331
constexpr bool isTransportValueLayer()
Compile time check of whether the provided type is a variant of TransportValueLayer.
Definition: TransportValueLayer.h:467
static constexpr std::size_t doFieldLength()
Customising field length calculation.
Definition: TransportValueLayer.h:246
Field & pseudoField()
Access to pseudo field stored internally.
TransportValueLayer(const TransportValueLayer &)=default
Copy constructor.
static void reassignFieldValue(TMsg &msg, const Field &field)
Re-assign the value from the input field to appropriate transport field in the message object.
Definition: TransportValueLayer.h:283
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::FieldType< TMsg > FieldType
Same as comms::option::def::FieldType.
Definition: options.h:1463
Main namespace for all classes / functions of COMMS library.
ErrorStatus
Error statuses reported by the Communication module.
Definition: ErrorStatus.h:17
@ Success
Used to indicate successful outcome of the operation.
Replacement to some types from standard type_traits.