COMMS
Template library intended to help with implementation of communication protocols.
Loading...
Searching...
No Matches
MsgSizeLayer.h
Go to the documentation of this file.
1//
2// Copyright 2014 - 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/details/tag.h"
16#include "comms/frame/details/MsgSizeLayerBase.h"
17#include "comms/frame/details/MsgSizeLayerConstNullPtrCastHelper.h"
18#include "comms/frame/details/MsgSizeLayerOptionsParser.h"
19#include "comms/MessageBase.h"
21
22#include <iterator>
23#include <type_traits>
24#include <utility>
25
26COMMS_MSVC_WARNING_PUSH
27COMMS_MSVC_WARNING_DISABLE(4189) // Disable erroneous initialized but not referenced variable warning
28
29namespace comms
30{
31
32namespace frame
33{
34
48template <typename TField, typename TNextLayer, typename... TOptions>
49class MsgSizeLayer : public comms::frame::details::MsgSizeLayerBase<TField, TNextLayer, TOptions...>
50{
51 using BaseImpl = comms::frame::details::MsgSizeLayerBase<TField, TNextLayer, TOptions...>;
52 using ParsedOptionsInternal = details::MsgSizeLayerOptionsParser<TOptions...>;
53
54public:
56 using Field = typename BaseImpl::Field;
57
61 using ExtendingClass = typename ParsedOptionsInternal::ExtendingClass;
62
64 explicit MsgSizeLayer() = default;
65
67 MsgSizeLayer(const MsgSizeLayer&) = default;
68
71
73 ~MsgSizeLayer() noexcept = default;
74
76 MsgSizeLayer& operator=(const MsgSizeLayer&) = default;
77
79 MsgSizeLayer& operator=(MsgSizeLayer&&) = default;
80
85 static constexpr bool hasExtendingClass()
86 {
87 return ParsedOptionsInternal::HasExtendingClass;
88 }
89
91 static constexpr std::size_t doFieldLength()
92 {
93 return BaseImpl::doFieldLength();
94 }
95
96 template <typename TMsg>
97 constexpr std::size_t doFieldLength(const TMsg& msg) const
98 {
99 return fieldLengthInternal(msg, LengthTag<>());
100 }
102
135 template <typename TMsg, typename TIter, typename TNextLayerReader, typename... TExtraValues>
137 Field& field,
138 TMsg& msg,
139 TIter& iter,
140 std::size_t size,
141 TNextLayerReader&& nextLayerReader,
142 TExtraValues... extraValues)
143 {
144 using IterType = typename std::decay<decltype(iter)>::type;
145 using IterTag = typename std::iterator_traits<IterType>::iterator_category;
146 static_assert(
147 std::is_base_of<std::random_access_iterator_tag, IterTag>::value,
148 "Current implementation of MsgSizeLayer requires iterator used for reading to be random-access one.");
149
150 auto begIter = iter;
151 auto* msgPtr = BaseImpl::toMsgPtr(msg);
152 auto& thisObj = BaseImpl::thisLayer();
153 auto es = thisObj.doReadField(msgPtr, field, iter, size);
154 if (es == ErrorStatus::NotEnoughData) {
155 BaseImpl::updateMissingSize(field, size, extraValues...);
156 }
157
158 if (es != ErrorStatus::Success) {
159 return es;
160 }
161
162 auto fromIter = iter;
163 auto readFieldLength = static_cast<std::size_t>(std::distance(begIter, iter));
164 std::size_t actualRemainingSize = (size - readFieldLength);
165 std::size_t requiredRemainingSize = thisObj.getRemainingSizeFromField(field);
166
167 if (actualRemainingSize < requiredRemainingSize) {
168 BaseImpl::setMissingSize(requiredRemainingSize - actualRemainingSize, extraValues...);
169 return ErrorStatus::NotEnoughData;
170 }
171
172 thisObj.beforeRead(field, msgPtr);
173 es = nextLayerReader.read(msg, iter, requiredRemainingSize, extraValues...);
174 if (es == ErrorStatus::NotEnoughData) {
175 BaseImpl::resetMsg(msg);
176 return ErrorStatus::ProtocolError;
177 }
178
179 if (es != ErrorStatus::ProtocolError) {
180 iter = fromIter;
181 std::advance(iter, requiredRemainingSize);
182 }
183
184 auto consumed =
185 static_cast<std::size_t>(std::distance(fromIter, iter));
186 if (consumed < requiredRemainingSize) {
187 auto diff = requiredRemainingSize - consumed;
188 std::advance(iter, diff);
189 }
190 return es;
191 }
192
193
213 template <typename TMsg, typename TIter, typename TNextLayerWriter>
215 Field& field,
216 const TMsg& msg,
217 TIter& iter,
218 std::size_t size,
219 TNextLayerWriter&& nextLayerWriter) const
220 {
221 using MsgType = typename std::decay<decltype(msg)>::type;
222 return writeInternal(field, msg, iter, size, std::forward<TNextLayerWriter>(nextLayerWriter), MsgLengthTag<MsgType>());
223 }
224
234 template <typename TIter, typename TNextLayerUpdater>
236 Field& field,
237 TIter& iter,
238 std::size_t size,
239 TNextLayerUpdater&& nextLayerUpdater) const
240 {
241 using LocalMsgPtr = typename BaseImpl::MsgPtr;
242 using ConstNullptrType =
243 typename details::MsgSizeLayerConstNullPtrCastHelper<
244 !std::is_void<LocalMsgPtr>::value
245 >::template Type<LocalMsgPtr>;
246 auto noMsgPtr = static_cast<ConstNullptrType>(nullptr);
247 return doUpdateInternal(noMsgPtr, field, iter, size, std::forward<TNextLayerUpdater>(nextLayerUpdater), NoMsgTypeTag<>());
248 }
249
259 template <typename TMsg, typename TIter, typename TNextLayerUpdater>
261 const TMsg& msg,
262 Field& field,
263 TIter& iter,
264 std::size_t size,
265 TNextLayerUpdater&& nextLayerUpdater) const
266 {
267 return doUpdateInternal(&msg, field, iter, size, std::forward<TNextLayerUpdater>(nextLayerUpdater), ValidMsgTypeTag<>());
268 }
269
270protected:
274 static std::size_t getRemainingSizeFromField(const Field& field)
275 {
276 return static_cast<std::size_t>(field.getValue());
277 }
278
287 template <typename TMsg>
288 static void beforeRead(const Field& field, TMsg* msg)
289 {
290 static_cast<void>(field);
291 static_cast<void>(msg);
292 }
293
302 template <typename TMsg>
303 static void prepareFieldForWrite(std::size_t size, const TMsg* msg, Field& field)
304 {
305 static_cast<void>(msg);
306 field.setValue(size);
307 }
308
309private:
310 template <typename... TParams>
311 using FixedLengthTag = typename BaseImpl::template FixedLengthTag<TParams...>;
312
313 template <typename...TParams>
314 using VarLengthTag = typename BaseImpl::template VarLengthTag<TParams...>;
315
316 template <typename... TParams>
317 using LengthTag = typename BaseImpl::template LengthTag<TParams...>;
318
319 template <typename... TParams>
320 using MsgHasLengthTag = comms::details::tag::Tag3<>;
321
322 template <typename... TParams>
323 using MsgNoLengthTag = comms::details::tag::Tag4<>;
324
325 template <typename... TParams>
326 using ValidMsgTypeTag = comms::details::tag::Tag5<>;
327
328 template <typename... TParams>
329 using NoMsgTypeTag = comms::details::tag::Tag6<>;
330
331 template<typename TMsg>
332 using MsgLengthTag =
333 typename comms::util::LazyShallowConditional<
334 details::FrameLayerHasFieldsImpl<TMsg>::Value || TMsg::hasLength()
335 >::template Type<
336 MsgHasLengthTag,
337 MsgNoLengthTag
338 >;
339
340 template <typename TMsg, typename TIter, typename TWriter>
341 ErrorStatus writeInternalHasLength(
342 Field& field,
343 const TMsg& msg,
344 TIter& iter,
345 std::size_t size,
346 TWriter&& nextLayerWriter) const
347 {
348 std::size_t lenValue = BaseImpl::nextLayer().length(msg);
349 auto& thisObj = BaseImpl::thisLayer();
350
351 thisObj.prepareFieldForWrite(lenValue, &msg, field);
352 auto es = thisObj.doWriteField(&msg, field, iter, size);
353 if (es != ErrorStatus::Success) {
354 return es;
355 }
356
357 COMMS_ASSERT(field.length() <= size);
358 return nextLayerWriter.write(msg, iter, size - field.length());
359 }
360
361 template <typename TMsg, typename TIter, typename TWriter>
362 ErrorStatus writeInternalRandomAccess(
363 Field& field,
364 const TMsg& msg,
365 TIter& iter,
366 std::size_t size,
367 TWriter&& nextLayerWriter) const
368 {
369 auto valueIter = iter;
370 auto& thisObj = BaseImpl::thisLayer();
371 thisObj.prepareFieldForWrite(0U, &msg, field);
372 auto es = thisObj.doWriteField(&msg, field, iter, size);
373 if (es != ErrorStatus::Success) {
374 return es;
375 }
376
377 auto dataIter = iter;
378
379 auto sizeLen = field.length();
380 es = nextLayerWriter.write(msg, iter, size - sizeLen);
381 if (es != ErrorStatus::Success) {
382 return es;
383 }
384
385 auto dist = static_cast<std::size_t>(std::distance(dataIter, iter));
386 thisObj.prepareFieldForWrite(dist, &msg, field);
387 COMMS_ASSERT(field.length() == sizeLen);
388 return thisObj.doWriteField(&msg, field, valueIter, sizeLen);
389 }
390
391 template <typename TMsg, typename TIter, typename TWriter>
392 ErrorStatus writeInternalOutput(
393 Field& field,
394 const TMsg& msg,
395 TIter& iter,
396 std::size_t size,
397 TWriter&& nextLayerWriter) const
398 {
399 auto& thisObj = BaseImpl::thisLayer();
400 thisObj.prepareFieldForWrite(0U, &msg, field);
401 auto es = thisObj.doWriteField(&msg, field, iter, size);
402 if (es != ErrorStatus::Success) {
403 return es;
404 }
405
406 es = nextLayerWriter.write(msg, iter, size - field.length());
407 if ((es != ErrorStatus::Success) &&
408 (es != ErrorStatus::UpdateRequired)) {
409 return es;
410 }
411
412 return ErrorStatus::UpdateRequired;
413 }
414
415 template <typename TMsg, typename TIter, typename TWriter>
416 ErrorStatus writeInternalNoLengthTagged(
417 Field& field,
418 const TMsg& msg,
419 TIter& iter,
420 std::size_t size,
421 TWriter&& nextLayerWriter,
422 std::random_access_iterator_tag) const
423 {
424 return writeInternalRandomAccess(field, msg, iter, size, std::forward<TWriter>(nextLayerWriter));
425 }
426
427 template <typename TMsg, typename TIter, typename TWriter>
428 ErrorStatus writeInternalNoLengthTagged(
429 Field& field,
430 const TMsg& msg,
431 TIter& iter,
432 std::size_t size,
433 TWriter&& nextLayerWriter,
434 std::output_iterator_tag) const
435 {
436 return writeInternalOutput(field, msg, iter, size, std::forward<TWriter>(nextLayerWriter));
437 }
438
439 template <typename TMsg, typename TIter, typename TWriter>
440 ErrorStatus writeInternalNoLength(
441 Field& field,
442 const TMsg& msg,
443 TIter& iter,
444 std::size_t size,
445 TWriter&& nextLayerWriter) const
446 {
447 static_assert(
448 (BaseImpl::MinFieldLength == BaseImpl::MaxFieldLength) ||
449 (comms::isMessageBase<typename std::decay<decltype(msg)>::type>()),
450 "Unable to perform write with size field having variable length and "
451 "no polymorphic length calculation available.");
452 using IterType = typename std::decay<decltype(iter)>::type;
453 using Tag = typename std::iterator_traits<IterType>::iterator_category;
454 return writeInternalNoLengthTagged(field, msg, iter, size, std::forward<TWriter>(nextLayerWriter), Tag());
455 }
456
457 template <typename TMsg, typename TIter, typename TWriter, typename... TParams>
458 ErrorStatus writeInternal(
459 Field& field,
460 const TMsg& msg,
461 TIter& iter,
462 std::size_t size,
463 TWriter&& nextLayerWriter,
464 MsgHasLengthTag<TParams...>) const
465 {
466 return writeInternalHasLength(field, msg, iter, size, std::forward<TWriter>(nextLayerWriter));
467 }
468
469 template <typename TMsg, typename TIter, typename TWriter, typename... TParams>
470 ErrorStatus writeInternal(
471 Field& field,
472 const TMsg& msg,
473 TIter& iter,
474 std::size_t size,
475 TWriter&& nextLayerWriter,
476 MsgNoLengthTag<TParams...>) const
477 {
478 return writeInternalNoLength(field, msg, iter, size, std::forward<TWriter>(nextLayerWriter));
479 }
480
481 template <typename TMsg, typename... TParams>
482 constexpr std::size_t fieldLengthInternal(const TMsg& msg, FixedLengthTag<TParams...>) const
483 {
484 return BaseImpl::doFieldLength(msg);
485 }
486
487 template <typename TMsg, typename... TParams>
488 std::size_t fieldLengthInternal(const TMsg& msg, VarLengthTag<TParams...>) const
489 {
490 auto& thisObj = BaseImpl::thisLayer();
491 auto remSize = BaseImpl::nextLayer().length(msg);
492 Field fieldTmp;
493 thisObj.prepareFieldForWrite(remSize, &msg, fieldTmp);
494 return fieldTmp.length();
495 }
496
497 template <typename TMsg, typename TIter, typename TNextLayerUpdater, typename TForwardTag>
498 comms::ErrorStatus doUpdateInternal(
499 const TMsg* msg,
500 Field& field,
501 TIter& iter,
502 std::size_t size,
503 TNextLayerUpdater&& nextLayerUpdater,
504 TForwardTag&& tag) const
505 {
506 std::size_t lenValue = size - Field::maxLength();
507 auto& thisObj = BaseImpl::thisLayer();
508 thisObj.prepareFieldForWrite(lenValue, msg, field);
509
510 if (field.length() != Field::maxLength()) {
511 lenValue = size - field.length();
512 thisObj.prepareFieldForWrite(lenValue, msg, field);
513 }
514
515 auto es = thisObj.doWriteField(msg, field, iter, size);
516 if (es != ErrorStatus::Success) {
517 return es;
518 }
519
520 return doUpdateForward(msg, iter, size - field.length(), std::forward<TNextLayerUpdater>(nextLayerUpdater), tag);
521 }
522
523 template <typename TMsg, typename TIter, typename TNextLayerUpdater, typename... TParams>
524 comms::ErrorStatus doUpdateForward(
525 const TMsg* msg,
526 TIter& iter,
527 std::size_t size,
528 TNextLayerUpdater&& nextLayerUpdater,
529 NoMsgTypeTag<TParams...>) const
530 {
531 static_cast<void>(msg);
532 return nextLayerUpdater.update(iter, size);
533 }
534
535 template <typename TMsg, typename TIter, typename TNextLayerUpdater, typename... TParams>
536 comms::ErrorStatus doUpdateForward(
537 const TMsg* msg,
538 TIter& iter,
539 std::size_t size,
540 TNextLayerUpdater&& nextLayerUpdater,
541 ValidMsgTypeTag<TParams...>) const
542 {
543 COMMS_ASSERT(msg != nullptr);
544 return nextLayerUpdater.update(*msg, iter, size);
545 }
546};
547
548namespace details
549{
550template <typename T>
551struct MsgSizeLayerCheckHelper
552{
553 static const bool Value = false;
554};
555
556template <typename TField, typename TNextLayer>
557struct MsgSizeLayerCheckHelper<MsgSizeLayer<TField, TNextLayer> >
558{
559 static const bool Value = true;
560};
561
562} // namespace details
563
567template <typename T>
568constexpr bool isMsgSizeLayer()
569{
570 return details::MsgSizeLayerCheckHelper<T>::Value;
571}
572
573} // namespace frame
574
575} // namespace comms
576
577COMMS_MSVC_WARNING_POP
#define COMMS_ASSERT(expr)
Generic assert macro.
Definition Assert.h:170
Contains various compiler related definitions.
Contains definition of comms::field::IntValue.
Provides common base class for the custom messages with default implementation.
Base class to all the field classes.
Definition Field.h:33
Protocol layer that uses size field as a prefix to all the subsequent data written by other (next) la...
Definition MsgSizeLayer.h:50
~MsgSizeLayer() noexcept=default
Destructor.
constexpr bool isMsgSizeLayer()
Compile time check of whether the provided type is a variant of MsgSizeLayer.
Definition MsgSizeLayer.h:568
ErrorStatus doWrite(Field &field, const TMsg &msg, TIter &iter, std::size_t size, TNextLayerWriter &&nextLayerWriter) const
Customized write functionality, invoked by write().
Definition MsgSizeLayer.h:214
MsgSizeLayer(MsgSizeLayer &&)=default
Move constructor.
comms::ErrorStatus doUpdate(const TMsg &msg, Field &field, TIter &iter, std::size_t size, TNextLayerUpdater &&nextLayerUpdater) const
Customized update functionality, invoked by update().
Definition MsgSizeLayer.h:260
typename ParsedOptionsInternal::ExtendingClass ExtendingClass
Type of real extending class.
Definition MsgSizeLayer.h:61
MsgSizeLayer(const MsgSizeLayer &)=default
Copy constructor.
typename BaseImpl::Field Field
Type of the field object used to read/write remaining size value.
Definition MsgSizeLayer.h:56
comms::ErrorStatus doRead(Field &field, TMsg &msg, TIter &iter, std::size_t size, TNextLayerReader &&nextLayerReader, TExtraValues... extraValues)
Customized read functionality, invoked by read().
Definition MsgSizeLayer.h:136
MsgSizeLayer()=default
Default constructor.
static void beforeRead(const Field &field, TMsg *msg)
Extra operation before read is forwarded to the next layer.
Definition MsgSizeLayer.h:288
static void prepareFieldForWrite(std::size_t size, const TMsg *msg, Field &field)
Prepare field for writing.
Definition MsgSizeLayer.h:303
static std::size_t getRemainingSizeFromField(const Field &field)
Retrieve remaining size (length) from the field.
Definition MsgSizeLayer.h:274
comms::ErrorStatus doUpdate(Field &field, TIter &iter, std::size_t size, TNextLayerUpdater &&nextLayerUpdater) const
Customized update functionality, invoked by update().
Definition MsgSizeLayer.h:235
comms::frame::MsgSizeLayer< TField, TNextLayer, TOptions... > MsgSizeLayer
Alias to the comms::frame::MsgSizeLayer.
Definition MsgSizeLayer.h:25
Main namespace for all classes / functions of COMMS library.
ErrorStatus
Error statuses reported by the Communication module.
Definition ErrorStatus.h:17
constexpr bool isMessageBase()
Compile time check of of whether the type is a message extending comms::MessageBase.
Definition MessageBase.h:905
Replacement to some types from standard type_traits.