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 - 2025 (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
14#include "comms/cast.h"
15#include "comms/details/tag.h"
16#include "comms/frame/details/TransportValueLayerOptionsParser.h"
17#include "comms/frame/details/TransportValueLayerBase.h"
19
20COMMS_MSVC_WARNING_PUSH
21COMMS_MSVC_WARNING_DISABLE(4189) // Disable erroneous initialized but not referenced variable warning
22
23namespace comms
24{
25
26namespace frame
27{
28
62template <typename TField, std::size_t TIdx, typename TNextLayer, typename... TOptions>
63class TransportValueLayer : public comms::frame::details::TransportValueLayerBase<TField, TIdx, TNextLayer, TOptions...>
64{
65 using BaseImpl = comms::frame::details::TransportValueLayerBase<TField, TIdx, TNextLayer, TOptions...>;
66 using ParsedOptionsInternal = comms::frame::details::TransportValueLayerOptionsParser<TOptions...>;
67
68public:
70 using Field = typename BaseImpl::Field;
71
75 using ExtendingClass = typename ParsedOptionsInternal::ExtendingClass;
76
79
82
85
87 ~TransportValueLayer() noexcept = default;
88
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
334 template <typename... TParams>
335 static constexpr std::size_t doFieldLengthInternal(PseudoValueTag<TParams...>)
336 {
337 return 0U;
338 }
339
340 template <typename... TParams>
341 static constexpr std::size_t doFieldLengthInternal(NormalValueTag<TParams...>)
342 {
343 return BaseImpl::doFieldLength();
344 }
345
346 template <typename TMsg, typename TIter, typename... TExtraValues>
347 comms::ErrorStatus readFieldInternal(
348 Field& field,
349 TMsg& msg,
350 TIter& iter,
351 std::size_t& len,
352 PseudoValueTag<>,
353 TExtraValues...)
354 {
355 static_cast<void>(msg);
356 static_cast<void>(iter);
357 static_cast<void>(len);
358 field = BaseImpl::pseudoField();
360 }
361
362 template <typename TMsg, typename TIter, typename... TExtraValues>
363 comms::ErrorStatus readFieldInternal(
364 Field& field,
365 TMsg& msg,
366 TIter& iter,
367 std::size_t& len,
368 NormalValueTag<>,
369 TExtraValues... extraValues)
370 {
371 auto& thisObj = BaseImpl::thisLayer();
372 auto* msgPtr = BaseImpl::toMsgPtr(msg);
373 auto beforeReadIter = iter;
374
375 auto es = thisObj.doReadField(msgPtr, field, iter, len);
377 BaseImpl::updateMissingSize(field, len, extraValues...);
378 }
379 else {
380 auto fieldLen = static_cast<std::size_t>(std::distance(beforeReadIter, iter));
381 len -= fieldLen;
382 }
383 return es;
384 }
385
386 template <typename TMsg, typename TIter, typename... TParams>
387 comms::ErrorStatus writeFieldInternal(
388 Field& field,
389 const TMsg& msg,
390 TIter& iter,
391 std::size_t& len,
392 PseudoValueTag<TParams...>) const
393 {
394 static_cast<void>(msg);
395 static_cast<void>(iter);
396 static_cast<void>(len);
397 field = BaseImpl::pseudoField();
399 }
400
401 template <typename TMsg, typename TIter, typename... TParams>
402 comms::ErrorStatus writeFieldInternal(
403 Field& field,
404 const TMsg& msg,
405 TIter& iter,
406 std::size_t& len,
407 NormalValueTag<TParams...>) const
408 {
409 auto& thisObj = BaseImpl::thisLayer();
410 auto es = thisObj.doWriteField(&msg, field, iter, len);
411 if (es == comms::ErrorStatus::Success) {
412 COMMS_ASSERT(field.length() <= len);
413 len -= field.length();
414 }
415 return es;
416 }
417};
418
419namespace details
420{
421template <typename T>
422struct TransportValueLayerCheckHelper
423{
424 static const bool Value = false;
425};
426
427template <typename TField, std::size_t TIdx, typename TNextLayer>
428struct TransportValueLayerCheckHelper<TransportValueLayer<TField, TIdx, TNextLayer> >
429{
430 static const bool Value = true;
431};
432
433} // namespace details
434
438template <typename T>
439constexpr bool isTransportValueLayer()
440{
441 return details::TransportValueLayerCheckHelper<T>::Value;
442}
443
444} // namespace frame
445
446} // namespace comms
447
448COMMS_MSVC_WARNING_POP
#define COMMS_ASSERT(expr)
Generic assert macro.
Definition Assert.h:170
Contains various compiler related definitions.
Contains definition of various casts.
Protocol layer that reads a value from transport wrapping and reassigns it to appropriate "extra tran...
Definition TransportValueLayer.h:64
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:70
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
typename ParsedOptionsInternal::ExtendingClass ExtendingClass
Type of real extending class.
Definition TransportValueLayer.h:75
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:439
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:25
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.