63class SyncSuffixLayer :
public comms::frame::details::SyncSuffixLayerBase<TField, TNextLayer, TOptions...>
65 using BaseImpl = comms::frame::details::SyncSuffixLayerBase<TField, TNextLayer, TOptions...>;
66 using ParsedOptionsInternal = details::SyncSuffixLayerOptionsParser<TOptions...>;
70 using Field =
typename BaseImpl::Field;
74 using EscField =
typename ParsedOptionsInternal::EscField;
96 static constexpr
bool hasExtendingClass()
98 return ParsedOptionsInternal::HasExtendingClass;
105 return ParsedOptionsInternal::HasVerifyBeforeRead;
112 return ParsedOptionsInternal::HasSeekField;
144 template <
typename TMsg,
typename TIter,
typename TNextLayerReader,
typename... TExtraValues>
150 TNextLayerReader&& nextLayerReader,
151 TExtraValues... extraValues)
153 using IterType =
typename std::decay<
decltype(iter)>::type;
154 static_assert(std::is_same<typename std::iterator_traits<IterType>::iterator_category, std::random_access_iterator_tag>::value,
155 "The read operation is expected to use random access iterator");
158 typename comms::util::LazyShallowConditional<
159 ParsedOptionsInternal::HasSeekField
171 std::forward<TNextLayerReader>(nextLayerReader),
192 template <
typename TMsg,
typename TIter,
typename TNextLayerWriter>
198 TNextLayerWriter&& nextLayerWriter)
const
200 using IterType =
typename std::decay<
decltype(iter)>::type;
201 using Tag =
typename std::iterator_traits<IterType>::iterator_category;
203 return writeInternal(field, msg, iter, size, std::forward<TNextLayerWriter>(nextLayerWriter), Tag());
215 return field ==
Field();
224 template <
typename TEscField>
227 return field == TEscField();
239 static_cast<void>(field);
243 template <
typename... TParams>
244 using SeekFieldTag = comms::details::tag::Tag1<>;
246 template <
typename... TParams>
247 using InstantOpTag = comms::details::tag::Tag2<>;
249 template <
typename... TParams>
250 using VerifyBeforeReadTag = comms::details::tag::Tag3<>;
252 template <
typename... TParams>
253 using VerifyAfterReadTag = comms::details::tag::Tag4<>;
255 template <
typename... TParams>
256 using EscapeSupportedTag = comms::details::tag::Tag5<>;
258 template <
typename... TParams>
259 using NoEscapeTag = comms::details::tag::Tag6<>;
261 template <
typename TMsg,
typename TIter,
typename TReader,
typename... TExtraValues>
267 TReader&& nextLayerReader,
268 TExtraValues... extraValues)
270 auto fromIter = iter;
271 auto* msgPtr = BaseImpl::toMsgPtr(msg);
272 auto fieldLen = Field::minLength();
274 static_assert(Field::minLength() == Field::maxLength(),
"Cannot verify variable length suffix before reading rest of the message frame");
275 auto& thisObj = BaseImpl::thisLayer();
276 if (msgPtr !=
nullptr) {
277 fieldLen = thisObj.doFieldLength(*msgPtr);
279 auto toIter = fromIter + (size - fieldLen);
281 auto fieldEs = thisObj.doReadField(msgPtr, field, toIter, fieldLen);
282 if (fieldEs != ErrorStatus::Success) {
286 bool verified = thisObj.verifyFieldValue(field);
291 auto es = nextLayerReader.read(msg, iter, size - fieldLen, extraValues...);
292 if (es == ErrorStatus::Success) {
299 template <
typename TMsg,
typename TIter,
typename TReader,
typename... TExtraValues>
305 TReader&& nextLayerReader,
306 TExtraValues... extraValues)
308 auto fromIter = iter;
310 auto es = nextLayerReader.read(msg, iter, size, extraValues...);
311 if ((es == ErrorStatus::NotEnoughData) ||
312 (es == ErrorStatus::ProtocolError)) {
316 auto len =
static_cast<std::size_t
>(std::distance(fromIter, iter));
318 auto remSize = size - len;
319 auto* msgPtr = BaseImpl::toMsgPtr(msg);
320 auto& thisObj = BaseImpl::thisLayer();
321 auto fieldEs = thisObj.doReadField(msgPtr, field, iter, remSize);
322 if (fieldEs == ErrorStatus::NotEnoughData) {
323 BaseImpl::updateMissingSize(field, remSize, extraValues...);
326 if (fieldEs != ErrorStatus::Success) {
327 BaseImpl::resetMsg(msg);
331 bool verified = thisObj.verifyFieldValue(field);
339 template <
typename TMsg,
typename TIter,
typename TReader,
typename... TExtraValues>
345 TReader&& nextLayerReader,
346 TExtraValues... extraValues)
348 auto& thisObj = BaseImpl::thisLayer();
349 auto* msgPtr = BaseImpl::toMsgPtr(msg);
351 auto fromIter = iter;
352 std::size_t consumed = 0U;
353 while (consumed < size) {
355 auto remSize = size - consumed;
357 auto fieldEs = thisObj.doReadField(msgPtr, field, iterTmp, remSize);
358 if (fieldEs == ErrorStatus::NotEnoughData) {
359 BaseImpl::updateMissingSize(field, remSize, extraValues...);
360 BaseImpl::resetMsg(msg);
364 if ((fieldEs == ErrorStatus::Success) &&
365 (!fieldEscapedInternal(fromIter, iter)) &&
366 (thisObj.verifyFieldValue(field))) {
376 if (size <= consumed) {
378 return ErrorStatus::NotEnoughData;
382 return nextLayerReader.read(msg, fromIter, consumed, extraValues...);
385 template <
typename TMsg,
typename TIter,
typename TReader,
typename... TExtraValues>
391 TReader&& nextLayerReader,
393 TExtraValues... extraValues)
401 std::forward<TReader>(nextLayerReader),
405 template <
typename TMsg,
typename TIter,
typename TReader,
typename... TExtraValues>
411 TReader&& nextLayerReader,
413 TExtraValues... extraValues)
416 typename comms::util::LazyShallowConditional<
417 ParsedOptionsInternal::HasVerifyBeforeRead
429 std::forward<TReader>(nextLayerReader),
434 template <
typename TMsg,
typename TIter,
typename TReader,
typename... TExtraValues>
440 TReader&& nextLayerReader,
441 VerifyBeforeReadTag<>,
442 TExtraValues... extraValues)
450 std::forward<TReader>(nextLayerReader),
454 template <
typename TMsg,
typename TIter,
typename TReader,
typename... TExtraValues>
460 TReader&& nextLayerReader,
461 VerifyAfterReadTag<>,
462 TExtraValues... extraValues)
470 std::forward<TReader>(nextLayerReader),
474 template <
typename TMsg,
typename TIter,
typename TWriter>
480 TWriter&& nextLayerWriter)
const
482 auto fromIter = iter;
483 auto es = nextLayerWriter.write(msg, iter, size);
490 auto len =
static_cast<std::size_t
>(std::distance(fromIter, iter));
491 auto remSize = size - len;
492 auto& thisObj = BaseImpl::thisLayer();
494 thisObj.prepareFieldForWrite(field);
495 auto esTmp = thisObj.doWriteField(&msg, field, iter, remSize);
503 template <
typename TMsg,
typename TIter,
typename TWriter>
509 TWriter&& nextLayerWriter)
const
511 auto& thisObj = BaseImpl::thisLayer();
512 auto fieldLen = thisObj.doFieldLength(msg);
513 auto es = nextLayerWriter.write(msg, iter, size - fieldLen);
519 auto esTmp = thisObj.doWriteField(&msg, field, iter, fieldLen);
520 static_cast<void>(esTmp);
525 template <
typename TMsg,
typename TIter,
typename TWriter>
531 TWriter&& nextLayerWriter,
532 std::random_access_iterator_tag)
const
534 return writeInternalRandomAccess(field, msg, iter, size, std::forward<TWriter>(nextLayerWriter));
537 template <
typename TMsg,
typename TIter,
typename TWriter>
543 TWriter&& nextLayerWriter,
544 std::output_iterator_tag)
const
546 return writeInternalOutput(field, msg, iter, size, std::forward<TWriter>(nextLayerWriter));
549 template <
typename TMsg,
typename TIter>
550 ErrorStatus fieldUpdateInternal(
const TMsg* msgPtr, TIter from, TIter to, std::size_t size, Field& field)
const
553 auto len =
static_cast<std::size_t
>(std::distance(from, to));
554 auto& thisObj = BaseImpl::thisLayer();
555 if (msgPtr !=
nullptr) {
556 COMMS_ASSERT(len == (size - thisObj.doFieldLength(*msgPtr)));
561 auto remSize = size - len;
563 bool checksumValid =
false;
565 thisObj.calculateSyncSuffix(
571 if (!checksumValid) {
575 thisObj.prepareFieldForWrite(checksum, msgPtr, field);
576 return thisObj.doWriteField(msgPtr, field, to, remSize);
579 template <
typename TIter>
580 bool fieldEscapedInternal(TIter from, TIter to, NoEscapeTag<>)
582 static_cast<void>(from);
583 static_cast<void>(to);
587 template <
typename TIter>
588 bool fieldEscapedInternal(TIter from, TIter to, EscapeSupportedTag<>)
590 unsigned escCount = 0U;
591 auto& thisObj = BaseImpl::thisLayer();
594 auto dist =
static_cast<std::size_t
>(std::distance(from, to));
595 dist = std::min(dist, EscField::maxLength());
596 if (dist < EscField::minLength()) {
600 auto maxLenIter = to;
601 std::advance(maxLenIter, -
static_cast<int>(dist));
604 std::advance(iter, -
static_cast<int>(EscField::minLength()));
605 auto prevCount = escCount;
609 auto len =
static_cast<std::size_t
>(std::distance(iterTmp, to));
610 auto es = escField.read(iterTmp, len);
613 (thisObj.verifyEscFieldValue(escField))) {
618 if (iter == maxLenIter) {
622 std::advance(iter, -1);
625 if (prevCount == escCount) {
635 return (escCount & 0x1) != 0U;
638 template <
typename TIter>
639 bool fieldEscapedInternal(TIter from, TIter to)
642 typename comms::util::LazyShallowConditional<
643 std::is_same<EscField, void>::value
649 return fieldEscapedInternal(from, to, EscTag());
652 static_assert(!(hasVerifyBeforeRead() && hasSeekField()),
653 "Usage of both comms::option::def::FrameLayerVerifyBeforeRead and comms::option::def::FrameLayerSeekField at the same time are not allowed");