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
20#include <iterator>
21
22COMMS_MSVC_WARNING_PUSH
23COMMS_MSVC_WARNING_DISABLE(4189) // Disable erroneous initialized but not referenced variable warning
24
25namespace comms
26{
27
28namespace frame
29{
30
64template <typename TField, std::size_t TIdx, typename TNextLayer, typename... TOptions>
65class TransportValueLayer : public comms::frame::details::TransportValueLayerBase<TField, TIdx, TNextLayer, TOptions...>
66{
67 using BaseImpl = comms::frame::details::TransportValueLayerBase<TField, TIdx, TNextLayer, TOptions...>;
68 using ParsedOptionsInternal = comms::frame::details::TransportValueLayerOptionsParser<TOptions...>;
69
70public:
72 using Field = typename BaseImpl::Field;
73
76
79
82
84 ~TransportValueLayer() noexcept = default;
85
88 static constexpr bool hasExtendingClass()
89 {
90 return ParsedOptionsInternal::HasExtendingClass;
91 }
92
95 static constexpr bool hasPseudoValue()
96 {
97 return ParsedOptionsInternal::HasPseudoValue;
98 }
99
133 template <typename TMsg, typename TIter, typename TNextLayerReader, typename... TExtraValues>
135 Field& field,
136 TMsg& msg,
137 TIter& iter,
138 std::size_t size,
139 TNextLayerReader&& nextLayerReader,
140 TExtraValues... extraValues)
141 {
142 auto es = readFieldInternal(field, msg, iter, size, ValueTag<>(), extraValues...);
143 if (es != comms::ErrorStatus::Success) {
144 return es;
145 }
146
147 static constexpr bool ForcedReadUntilDataSplit =
148 BaseImpl::ParsedOptions::HasForceReadUntilDataSplit;
149
150 if (ForcedReadUntilDataSplit) {
151 es = nextLayerReader.read(msg, iter, size, extraValues...);
152
153 if (es != comms::ErrorStatus::Success) {
154 return es;
155 }
156 }
157
158 auto& thisObj = BaseImpl::thisLayer();
159 auto* msgPtr = BaseImpl::toMsgPtr(msg);
160 bool success = thisObj.reassignFieldValueToMsg(field, msgPtr);
161 if (!success) {
163 }
164
165 if (!ForcedReadUntilDataSplit) {
166 es = nextLayerReader.read(msg, iter, size, extraValues...);
167 }
168
169 return es;
170 }
171
189 template <typename TMsg, typename TIter, typename TNextLayerWriter>
191 Field& field,
192 const TMsg& msg,
193 TIter& iter,
194 std::size_t size,
195 TNextLayerWriter&& nextLayerWriter) const
196 {
197 auto& thisObj = BaseImpl::thisLayer();
198 thisObj.prepareFieldForWrite(msg, field);
199
200 auto es = writeFieldInternal(field, msg, iter, size, ValueTag<>());
201 if (es != ErrorStatus::Success) {
202 return es;
203 }
204
205 return nextLayerWriter.write(msg, iter, size);
206 }
207
211 static constexpr std::size_t doFieldLength()
212 {
213 return doFieldLengthInternal(ValueTag<>());
214 }
215
219 template <typename TMsg>
220 static std::size_t doFieldLength(const TMsg&)
221 {
222 return doFieldLength();
223 }
224
225#ifdef FOR_DOXYGEN_DOC_ONLY
231
236 const Field& pseudoField() const;
237#endif
238
239protected:
249 template <typename TMsg>
250 static void reassignFieldValue(TMsg& msg, const Field& field)
251 {
252 using MsgType = typename std::decay<decltype(msg)>::type;
253 static_assert(MsgType::hasTransportFields(),
254 "Message interface class hasn't defined transport fields, "
255 "use comms::option::def::ExtraTransportFields option.");
256 static_assert(TIdx < std::tuple_size<typename MsgType::TransportFields>::value,
257 "TIdx is too big, exceeds the amount of transport fields defined in interface class");
258
259 auto& allTransportFields = msg.transportFields();
260 auto& transportField = std::get<TIdx>(allTransportFields);
261
262 using FieldType = typename std::decay<decltype(transportField)>::type;
263 transportField = comms::field_cast<FieldType>(field);
264 }
265
278 template <typename TMsg>
279 bool reassignFieldValueToMsg(const Field& field, TMsg* msgPtr)
280 {
281 if (msgPtr == nullptr) {
282 return false;
283 }
284
285 auto& thisObj = BaseImpl::thisLayer();
286 thisObj.reassignFieldValue(*msgPtr, field);
287 return true;
288 }
289
297 template <typename TMsg>
298 static void prepareFieldForWrite(const TMsg& msg, Field& field)
299 {
300 using MsgType = typename std::decay<decltype(msg)>::type;
301 static_assert(MsgType::hasTransportFields(),
302 "Message interface class hasn't defined transport fields, "
303 "use comms::option::def::ExtraTransportFields option.");
304 static_assert(TIdx < std::tuple_size<typename MsgType::TransportFields>::value,
305 "TIdx is too big, exceeds the amount of transport fields defined in interface class");
306
307 auto& transportField = std::get<TIdx>(msg.transportFields());
308 field = comms::field_cast<Field>(transportField);
309 }
310
311private:
312
313 template <typename... TParams>
314 using PseudoValueTag = comms::details::tag::Tag1<>;
315
316 template <typename... TParams>
317 using NormalValueTag = comms::details::tag::Tag2<>;
318
319 template <typename...>
320 using ValueTag =
321 typename comms::util::LazyShallowConditional<
322 ParsedOptionsInternal::HasPseudoValue
323 >::template Type<
324 PseudoValueTag,
325 NormalValueTag
326 >;
327
328 template <typename... TParams>
329 static constexpr std::size_t doFieldLengthInternal(PseudoValueTag<TParams...>)
330 {
331 return 0U;
332 }
333
334 template <typename... TParams>
335 static constexpr std::size_t doFieldLengthInternal(NormalValueTag<TParams...>)
336 {
337 return BaseImpl::doFieldLength();
338 }
339
340 template <typename TMsg, typename TIter, typename... TExtraValues>
341 comms::ErrorStatus readFieldInternal(
342 Field& field,
343 TMsg& msg,
344 TIter& iter,
345 std::size_t& len,
346 PseudoValueTag<>,
347 TExtraValues...)
348 {
349 static_cast<void>(msg);
350 static_cast<void>(iter);
351 static_cast<void>(len);
352 field = BaseImpl::pseudoField();
354 }
355
356 template <typename TMsg, typename TIter, typename... TExtraValues>
357 comms::ErrorStatus readFieldInternal(
358 Field& field,
359 TMsg& msg,
360 TIter& iter,
361 std::size_t& len,
362 NormalValueTag<>,
363 TExtraValues... extraValues)
364 {
365 auto& thisObj = BaseImpl::thisLayer();
366 auto* msgPtr = BaseImpl::toMsgPtr(msg);
367 auto beforeReadIter = iter;
368
369 auto es = thisObj.doReadField(msgPtr, field, iter, len);
371 BaseImpl::updateMissingSize(field, len, extraValues...);
372 }
373 else {
374 auto fieldLen = static_cast<std::size_t>(std::distance(beforeReadIter, iter));
375 len -= fieldLen;
376 }
377 return es;
378 }
379
380 template <typename TMsg, typename TIter, typename... TParams>
381 comms::ErrorStatus writeFieldInternal(
382 Field& field,
383 const TMsg& msg,
384 TIter& iter,
385 std::size_t& len,
386 PseudoValueTag<TParams...>) const
387 {
388 static_cast<void>(msg);
389 static_cast<void>(iter);
390 static_cast<void>(len);
391 field = BaseImpl::pseudoField();
393 }
394
395 template <typename TMsg, typename TIter, typename... TParams>
396 comms::ErrorStatus writeFieldInternal(
397 Field& field,
398 const TMsg& msg,
399 TIter& iter,
400 std::size_t& len,
401 NormalValueTag<TParams...>) const
402 {
403 auto& thisObj = BaseImpl::thisLayer();
404 auto es = thisObj.doWriteField(&msg, field, iter, len);
405 if (es == comms::ErrorStatus::Success) {
406 COMMS_ASSERT(field.length() <= len);
407 len -= field.length();
408 }
409 return es;
410 }
411};
412
413namespace details
414{
415template <typename T>
416struct TransportValueLayerCheckHelper
417{
418 static const bool Value = false;
419};
420
421template <typename TField, std::size_t TIdx, typename TNextLayer>
422struct TransportValueLayerCheckHelper<TransportValueLayer<TField, TIdx, TNextLayer> >
423{
424 static const bool Value = true;
425};
426
427} // namespace details
428
432template <typename T>
433constexpr bool isTransportValueLayer()
434{
435 return details::TransportValueLayerCheckHelper<T>::Value;
436}
437
438} // namespace frame
439
440} // namespace comms
441
442COMMS_MSVC_WARNING_POP
#define COMMS_ASSERT(expr)
Generic assert macro.
Definition Assert.h:168
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:66
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:134
static constexpr bool hasPseudoValue()
Compile time inquiry of whether the comms::option::def::PseudoValue option has been used.
Definition TransportValueLayer.h:95
typename BaseImpl::Field Field
Type of the field object used to read/write "sync" value.
Definition TransportValueLayer.h:72
TransportValueLayer(TransportValueLayer &&)=default
Move constructor.
~TransportValueLayer() noexcept=default
Destructor.
static constexpr std::size_t doFieldLength()
Customising field length calculation.
Definition TransportValueLayer.h:211
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:250
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:298
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:220
constexpr bool isTransportValueLayer()
Compile time check of whether the provided type is a variant of TransportValueLayer.
Definition TransportValueLayer.h:433
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:279
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:190
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.