COMMS
Template library intended to help with implementation of communication protocols.
Loading...
Searching...
No Matches
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"
15#include "comms/cast.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
22COMMS_MSVC_WARNING_PUSH
23COMMS_MSVC_WARNING_DISABLE(4189) // Disable erroneous initialized but not referenced variable warning
24
25namespace comms
26{
27
28namespace protocol
29{
30
64template <typename TField, std::size_t TIdx, typename TNextLayer, typename... TOptions>
65class 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<
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
98public:
100 using Field = typename BaseImpl::Field;
101
105 using ExtendingClass = typename ParsedOptionsInternal::ExtendingClass;
106
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
272protected:
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
344private:
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
447namespace details
448{
449template <typename T>
450struct TransportValueLayerCheckHelper
451{
452 static const bool Value = false;
453};
454
455template <typename TField, std::size_t TIdx, typename TNextLayer>
456struct TransportValueLayerCheckHelper<TransportValueLayer<TField, TIdx, TNextLayer> >
457{
458 static const bool Value = true;
459};
460
461} // namespace details
462
466template <typename T>
467constexpr bool isTransportValueLayer()
468{
469 return details::TransportValueLayerCheckHelper<T>::Value;
470}
471
472} // namespace protocol
473
474} // namespace comms
475
476COMMS_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
Protocol layer that reads a value from transport wrapping and reassigns it to appropriate "extra tran...
Definition TransportValueLayer.h:79
Field & pseudoField()
Access to pseudo field stored internally.
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.
typename BaseImpl::Field Field
Type of the field object used to read/write "sync" value.
Definition TransportValueLayer.h:100
static std::size_t doFieldLength(const TMsg &)
Customising field length calculation.
Definition TransportValueLayer.h:255
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
const Field & pseudoField() const
Const 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
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.