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 - 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
16#include "comms/cast.h"
17#include "comms/details/tag.h"
18#include "comms/frame/details/TransportValueLayerOptionsParser.h"
19#include "comms/frame/details/TransportValueLayerBase.h"
21
22#include <cstddef>
23#include <iterator>
24#include <tuple>
25#include <type_traits>
26
27COMMS_MSVC_WARNING_PUSH
28COMMS_MSVC_WARNING_DISABLE(4189) // Disable erroneous initialized but not referenced variable warning
29
30namespace comms
31{
32
33namespace frame
34{
35
69template <typename TField, std::size_t TIdx, typename TNextLayer, typename... TOptions>
70class TransportValueLayer : public comms::frame::details::TransportValueLayerBase<TField, TIdx, TNextLayer, TOptions...>
71{
72 using BaseImpl = comms::frame::details::TransportValueLayerBase<TField, TIdx, TNextLayer, TOptions...>;
73 using ParsedOptionsInternal = comms::frame::details::TransportValueLayerOptionsParser<TOptions...>;
74
75public:
77 using Field = typename BaseImpl::Field;
78
81
84
87
89 ~TransportValueLayer() noexcept = default;
90
93 static constexpr bool hasExtendingClass()
94 {
95 return ParsedOptionsInternal::HasExtendingClass;
96 }
97
100 static constexpr bool hasPseudoValue()
101 {
102 return ParsedOptionsInternal::HasPseudoValue;
103 }
104
138 template <typename TMsg, typename TIter, typename TNextLayerReader, typename... TExtraValues>
140 Field& field,
141 TMsg& msg,
142 TIter& iter,
143 std::size_t size,
144 TNextLayerReader&& nextLayerReader,
145 TExtraValues... extraValues)
146 {
147 auto es = readFieldInternal(field, msg, iter, size, ValueTag<>(), extraValues...);
148 if (es != comms::ErrorStatus::Success) {
149 return es;
150 }
151
152 static constexpr bool ForcedReadUntilDataSplit =
153 BaseImpl::ParsedOptions::HasForceReadUntilDataSplit;
154
155 if (ForcedReadUntilDataSplit) {
156 es = nextLayerReader.read(msg, iter, size, extraValues...);
157
158 if (es != comms::ErrorStatus::Success) {
159 return es;
160 }
161 }
162
163 auto& thisObj = BaseImpl::thisLayer();
164 auto* msgPtr = BaseImpl::toMsgPtr(msg);
165 bool success = thisObj.reassignFieldValueToMsg(field, msgPtr);
166 if (!success) {
168 }
169
170 if (!ForcedReadUntilDataSplit) {
171 es = nextLayerReader.read(msg, iter, size, extraValues...);
172 }
173
174 return es;
175 }
176
194 template <typename TMsg, typename TIter, typename TNextLayerWriter>
196 Field& field,
197 const TMsg& msg,
198 TIter& iter,
199 std::size_t size,
200 TNextLayerWriter&& nextLayerWriter) const
201 {
202 auto& thisObj = BaseImpl::thisLayer();
203 thisObj.prepareFieldForWrite(msg, field);
204
205 auto es = writeFieldInternal(field, msg, iter, size, ValueTag<>());
206 if (es != ErrorStatus::Success) {
207 return es;
208 }
209
210 return nextLayerWriter.write(msg, iter, size);
211 }
212
216 static constexpr std::size_t doFieldLength()
217 {
218 return doFieldLengthInternal(ValueTag<>());
219 }
220
224 template <typename TMsg>
225 static std::size_t doFieldLength(const TMsg&)
226 {
227 return doFieldLength();
228 }
229
230#ifdef FOR_DOXYGEN_DOC_ONLY
236
241 const Field& pseudoField() const;
242#endif
243
244protected:
254 template <typename TMsg>
255 static void reassignFieldValue(TMsg& msg, const Field& field)
256 {
257 using MsgType = typename std::decay<decltype(msg)>::type;
258 static_assert(MsgType::hasTransportFields(),
259 "Message interface class hasn't defined transport fields, "
260 "use comms::option::def::ExtraTransportFields option.");
261 static_assert(TIdx < std::tuple_size<typename MsgType::TransportFields>::value,
262 "TIdx is too big, exceeds the amount of transport fields defined in interface class");
263
264 auto& allTransportFields = msg.transportFields();
265 auto& transportField = std::get<TIdx>(allTransportFields);
266
267 using FieldType = typename std::decay<decltype(transportField)>::type;
268 transportField = comms::field_cast<FieldType>(field);
269 }
270
283 template <typename TMsg>
284 bool reassignFieldValueToMsg(const Field& field, TMsg* msgPtr)
285 {
286 if (msgPtr == nullptr) {
287 return false;
288 }
289
290 auto& thisObj = BaseImpl::thisLayer();
291 thisObj.reassignFieldValue(*msgPtr, field);
292 return true;
293 }
294
302 template <typename TMsg>
303 static void prepareFieldForWrite(const TMsg& msg, Field& field)
304 {
305 using MsgType = typename std::decay<decltype(msg)>::type;
306 static_assert(MsgType::hasTransportFields(),
307 "Message interface class hasn't defined transport fields, "
308 "use comms::option::def::ExtraTransportFields option.");
309 static_assert(TIdx < std::tuple_size<typename MsgType::TransportFields>::value,
310 "TIdx is too big, exceeds the amount of transport fields defined in interface class");
311
312 auto& transportField = std::get<TIdx>(msg.transportFields());
313 field = comms::field_cast<Field>(transportField);
314 }
315
316private:
317
318 template <typename... TParams>
319 using PseudoValueTag = comms::details::tag::Tag1<>;
320
321 template <typename... TParams>
322 using NormalValueTag = comms::details::tag::Tag2<>;
323
324 template <typename...>
325 using ValueTag =
326 typename comms::util::LazyShallowConditional<
327 ParsedOptionsInternal::HasPseudoValue
328 >::template Type<
329 PseudoValueTag,
330 NormalValueTag
331 >;
332
333 template <typename... TParams>
334 static constexpr std::size_t doFieldLengthInternal(PseudoValueTag<TParams...>)
335 {
336 return 0U;
337 }
338
339 template <typename... TParams>
340 static constexpr std::size_t doFieldLengthInternal(NormalValueTag<TParams...>)
341 {
342 return BaseImpl::doFieldLength();
343 }
344
345 template <typename TMsg, typename TIter, typename... TExtraValues>
346 comms::ErrorStatus readFieldInternal(
347 Field& field,
348 TMsg& msg,
349 TIter& iter,
350 std::size_t& len,
351 PseudoValueTag<>,
352 TExtraValues...)
353 {
354 static_cast<void>(msg);
355 static_cast<void>(iter);
356 static_cast<void>(len);
357 field = BaseImpl::pseudoField();
359 }
360
361 template <typename TMsg, typename TIter, typename... TExtraValues>
362 comms::ErrorStatus readFieldInternal(
363 Field& field,
364 TMsg& msg,
365 TIter& iter,
366 std::size_t& len,
367 NormalValueTag<>,
368 TExtraValues... extraValues)
369 {
370 auto& thisObj = BaseImpl::thisLayer();
371 auto* msgPtr = BaseImpl::toMsgPtr(msg);
372 auto beforeReadIter = iter;
373
374 auto es = thisObj.doReadField(msgPtr, field, iter, len);
376 BaseImpl::updateMissingSize(field, len, extraValues...);
377 }
378 else {
379 auto fieldLen = static_cast<std::size_t>(std::distance(beforeReadIter, iter));
380 len -= fieldLen;
381 }
382 return es;
383 }
384
385 template <typename TMsg, typename TIter, typename... TParams>
386 comms::ErrorStatus writeFieldInternal(
387 Field& field,
388 const TMsg& msg,
389 TIter& iter,
390 std::size_t& len,
391 PseudoValueTag<TParams...>) const
392 {
393 static_cast<void>(msg);
394 static_cast<void>(iter);
395 static_cast<void>(len);
396 field = BaseImpl::pseudoField();
398 }
399
400 template <typename TMsg, typename TIter, typename... TParams>
401 comms::ErrorStatus writeFieldInternal(
402 Field& field,
403 const TMsg& msg,
404 TIter& iter,
405 std::size_t& len,
406 NormalValueTag<TParams...>) const
407 {
408 auto& thisObj = BaseImpl::thisLayer();
409 auto es = thisObj.doWriteField(&msg, field, iter, len);
410 if (es == comms::ErrorStatus::Success) {
411 COMMS_ASSERT(field.length() <= len);
412 len -= field.length();
413 }
414 return es;
415 }
416};
417
418namespace details
419{
420template <typename T>
421struct TransportValueLayerCheckHelper
422{
423 static const bool Value = false;
424};
425
426template <typename TField, std::size_t TIdx, typename TNextLayer>
427struct TransportValueLayerCheckHelper<TransportValueLayer<TField, TIdx, TNextLayer> >
428{
429 static const bool Value = true;
430};
431
432} // namespace details
433
437template <typename T>
438constexpr bool isTransportValueLayer()
439{
440 return details::TransportValueLayerCheckHelper<T>::Value;
441}
442
443} // namespace frame
444
445} // namespace comms
446
447COMMS_MSVC_WARNING_POP
#define COMMS_ASSERT(expr)
Generic assert macro.
Definition Assert.h:170
Contains various compiler related definitions.
Contains definition of various casts.
Frame layer that reads a value from transport wrapping and reassigns it to appropriate "extra transpo...
Definition TransportValueLayer.h:71
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:139
static constexpr bool hasPseudoValue()
Compile time inquiry of whether the comms::option::def::PseudoValue option has been used.
Definition TransportValueLayer.h:100
typename BaseImpl::Field Field
Type of the field object used to read/write "sync" value.
Definition TransportValueLayer.h:77
TransportValueLayer(TransportValueLayer &&)=default
Move constructor.
~TransportValueLayer() noexcept=default
Destructor.
static constexpr std::size_t doFieldLength()
Customising field length calculation.
Definition TransportValueLayer.h:216
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:255
TransportValueLayer(const TransportValueLayer &)=default
Copy constructor.
const Field & pseudoField() const
Const access to pseudo field stored internally.
static void prepareFieldForWrite(const TMsg &msg, Field &field)
Prepare field for writing.
Definition TransportValueLayer.h:303
TransportValueLayer()=default
Default constructor.
Field & pseudoField()
Access to pseudo field stored internally.
static std::size_t doFieldLength(const TMsg &)
Customising field length calculation.
Definition TransportValueLayer.h:225
constexpr bool isTransportValueLayer()
Compile time check of whether the provided type is a variant of TransportValueLayer.
Definition TransportValueLayer.h:438
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:284
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:195
comms::frame::TransportValueLayer< TField, TIdx, TNextLayer, TOptions... > TransportValueLayer
Alias to the comms::frame::TransportValueLayer.
Definition TransportValueLayer.h:27
Main namespace for all classes / functions of COMMS library.
ErrorStatus
Error statuses reported by the Communication module.
Definition ErrorStatus.h:19
@ Success
Used to indicate successful outcome of the operation.
Replacement to some types from standard type_traits.