59class SyncSuffixLayer :
public comms::frame::details::SyncSuffixLayerBase<TField, TNextLayer, TOptions...>
61 using BaseImpl = comms::frame::details::SyncSuffixLayerBase<TField, TNextLayer, TOptions...>;
62 using ParsedOptionsInternal = details::SyncSuffixLayerOptionsParser<TOptions...>;
66 using Field =
typename BaseImpl::Field;
70 using EscField =
typename ParsedOptionsInternal::EscField;
92 static constexpr
bool hasExtendingClass()
94 return ParsedOptionsInternal::HasExtendingClass;
101 return ParsedOptionsInternal::HasVerifyBeforeRead;
108 return ParsedOptionsInternal::HasSeekField;
140 template <
typename TMsg,
typename TIter,
typename TNextLayerReader,
typename... TExtraValues>
146 TNextLayerReader&& nextLayerReader,
147 TExtraValues... extraValues)
149 using IterType =
typename std::decay<
decltype(iter)>::type;
150 static_assert(std::is_same<typename std::iterator_traits<IterType>::iterator_category, std::random_access_iterator_tag>::value,
151 "The read operation is expected to use random access iterator");
154 typename comms::util::LazyShallowConditional<
155 ParsedOptionsInternal::HasSeekField
167 std::forward<TNextLayerReader>(nextLayerReader),
188 template <
typename TMsg,
typename TIter,
typename TNextLayerWriter>
194 TNextLayerWriter&& nextLayerWriter)
const
196 using IterType =
typename std::decay<
decltype(iter)>::type;
197 using Tag =
typename std::iterator_traits<IterType>::iterator_category;
199 return writeInternal(field, msg, iter, size, std::forward<TNextLayerWriter>(nextLayerWriter), Tag());
211 return field ==
Field();
220 template <
typename TEscField>
223 return field == TEscField();
235 static_cast<void>(field);
239 template <
typename... TParams>
240 using SeekFieldTag = comms::details::tag::Tag1<>;
242 template <
typename... TParams>
243 using InstantOpTag = comms::details::tag::Tag2<>;
245 template <
typename... TParams>
246 using VerifyBeforeReadTag = comms::details::tag::Tag3<>;
248 template <
typename... TParams>
249 using VerifyAfterReadTag = comms::details::tag::Tag4<>;
251 template <
typename... TParams>
252 using EscapeSupportedTag = comms::details::tag::Tag5<>;
254 template <
typename... TParams>
255 using NoEscapeTag = comms::details::tag::Tag6<>;
257 template <
typename TMsg,
typename TIter,
typename TReader,
typename... TExtraValues>
263 TReader&& nextLayerReader,
264 TExtraValues... extraValues)
266 auto fromIter = iter;
267 auto* msgPtr = BaseImpl::toMsgPtr(msg);
268 auto fieldLen = Field::minLength();
270 static_assert(Field::minLength() == Field::maxLength(),
"Cannot verify variable length suffix before reading rest of the message frame");
271 auto& thisObj = BaseImpl::thisLayer();
272 if (msgPtr !=
nullptr) {
273 fieldLen = thisObj.doFieldLength(*msgPtr);
275 auto toIter = fromIter + (size - fieldLen);
277 auto fieldEs = thisObj.doReadField(msgPtr, field, toIter, fieldLen);
278 if (fieldEs != ErrorStatus::Success) {
282 bool verified = thisObj.verifyFieldValue(field);
287 auto es = nextLayerReader.read(msg, iter, size - fieldLen, extraValues...);
288 if (es == ErrorStatus::Success) {
295 template <
typename TMsg,
typename TIter,
typename TReader,
typename... TExtraValues>
301 TReader&& nextLayerReader,
302 TExtraValues... extraValues)
304 auto fromIter = iter;
306 auto es = nextLayerReader.read(msg, iter, size, extraValues...);
307 if ((es == ErrorStatus::NotEnoughData) ||
308 (es == ErrorStatus::ProtocolError)) {
312 auto len =
static_cast<std::size_t
>(std::distance(fromIter, iter));
314 auto remSize = size - len;
315 auto* msgPtr = BaseImpl::toMsgPtr(msg);
316 auto& thisObj = BaseImpl::thisLayer();
317 auto fieldEs = thisObj.doReadField(msgPtr, field, iter, remSize);
318 if (fieldEs == ErrorStatus::NotEnoughData) {
319 BaseImpl::updateMissingSize(field, remSize, extraValues...);
322 if (fieldEs != ErrorStatus::Success) {
323 BaseImpl::resetMsg(msg);
327 bool verified = thisObj.verifyFieldValue(field);
335 template <
typename TMsg,
typename TIter,
typename TReader,
typename... TExtraValues>
341 TReader&& nextLayerReader,
342 TExtraValues... extraValues)
344 auto& thisObj = BaseImpl::thisLayer();
345 auto* msgPtr = BaseImpl::toMsgPtr(msg);
347 auto fromIter = iter;
348 std::size_t consumed = 0U;
349 while (consumed < size) {
351 auto remSize = size - consumed;
353 auto fieldEs = thisObj.doReadField(msgPtr, field, iterTmp, remSize);
354 if (fieldEs == ErrorStatus::NotEnoughData) {
355 BaseImpl::updateMissingSize(field, remSize, extraValues...);
356 BaseImpl::resetMsg(msg);
360 if ((fieldEs == ErrorStatus::Success) &&
361 (!fieldEscapedInternal(fromIter, iter)) &&
362 (thisObj.verifyFieldValue(field))) {
372 if (size <= consumed) {
374 return ErrorStatus::NotEnoughData;
378 return nextLayerReader.read(msg, fromIter, consumed, extraValues...);
381 template <
typename TMsg,
typename TIter,
typename TReader,
typename... TExtraValues>
387 TReader&& nextLayerReader,
389 TExtraValues... extraValues)
397 std::forward<TReader>(nextLayerReader),
401 template <
typename TMsg,
typename TIter,
typename TReader,
typename... TExtraValues>
407 TReader&& nextLayerReader,
409 TExtraValues... extraValues)
412 typename comms::util::LazyShallowConditional<
413 ParsedOptionsInternal::HasVerifyBeforeRead
425 std::forward<TReader>(nextLayerReader),
430 template <
typename TMsg,
typename TIter,
typename TReader,
typename... TExtraValues>
436 TReader&& nextLayerReader,
437 VerifyBeforeReadTag<>,
438 TExtraValues... extraValues)
446 std::forward<TReader>(nextLayerReader),
450 template <
typename TMsg,
typename TIter,
typename TReader,
typename... TExtraValues>
456 TReader&& nextLayerReader,
457 VerifyAfterReadTag<>,
458 TExtraValues... extraValues)
466 std::forward<TReader>(nextLayerReader),
470 template <
typename TMsg,
typename TIter,
typename TWriter>
476 TWriter&& nextLayerWriter)
const
478 auto fromIter = iter;
479 auto es = nextLayerWriter.write(msg, iter, size);
486 auto len =
static_cast<std::size_t
>(std::distance(fromIter, iter));
487 auto remSize = size - len;
488 auto& thisObj = BaseImpl::thisLayer();
490 thisObj.prepareFieldForWrite(field);
491 auto esTmp = thisObj.doWriteField(&msg, field, iter, remSize);
499 template <
typename TMsg,
typename TIter,
typename TWriter>
505 TWriter&& nextLayerWriter)
const
507 auto& thisObj = BaseImpl::thisLayer();
508 auto fieldLen = thisObj.doFieldLength(msg);
509 auto es = nextLayerWriter.write(msg, iter, size - fieldLen);
515 auto esTmp = thisObj.doWriteField(&msg, field, iter, fieldLen);
516 static_cast<void>(esTmp);
521 template <
typename TMsg,
typename TIter,
typename TWriter>
527 TWriter&& nextLayerWriter,
528 std::random_access_iterator_tag)
const
530 return writeInternalRandomAccess(field, msg, iter, size, std::forward<TWriter>(nextLayerWriter));
533 template <
typename TMsg,
typename TIter,
typename TWriter>
539 TWriter&& nextLayerWriter,
540 std::output_iterator_tag)
const
542 return writeInternalOutput(field, msg, iter, size, std::forward<TWriter>(nextLayerWriter));
545 template <
typename TMsg,
typename TIter>
546 ErrorStatus fieldUpdateInternal(
const TMsg* msgPtr, TIter from, TIter to, std::size_t size, Field& field)
const
549 auto len =
static_cast<std::size_t
>(std::distance(from, to));
550 auto& thisObj = BaseImpl::thisLayer();
551 if (msgPtr !=
nullptr) {
552 COMMS_ASSERT(len == (size - thisObj.doFieldLength(*msgPtr)));
557 auto remSize = size - len;
559 bool checksumValid =
false;
561 thisObj.calculateSyncSuffix(
567 if (!checksumValid) {
571 thisObj.prepareFieldForWrite(checksum, msgPtr, field);
572 return thisObj.doWriteField(msgPtr, field, to, remSize);
575 template <
typename TIter>
576 bool fieldEscapedInternal(TIter from, TIter to, NoEscapeTag<>)
578 static_cast<void>(from);
579 static_cast<void>(to);
583 template <
typename TIter>
584 bool fieldEscapedInternal(TIter from, TIter to, EscapeSupportedTag<>)
586 unsigned escCount = 0U;
587 auto& thisObj = BaseImpl::thisLayer();
590 auto dist =
static_cast<std::size_t
>(std::distance(from, to));
591 dist = std::min(dist, EscField::maxLength());
592 if (dist < EscField::minLength()) {
596 auto maxLenIter = to;
597 std::advance(maxLenIter, -
static_cast<int>(dist));
600 std::advance(iter, -
static_cast<int>(EscField::minLength()));
601 auto prevCount = escCount;
605 auto len =
static_cast<std::size_t
>(std::distance(iterTmp, to));
606 auto es = escField.read(iterTmp, len);
609 (thisObj.verifyEscFieldValue(escField))) {
614 if (iter == maxLenIter) {
618 std::advance(iter, -1);
621 if (prevCount == escCount) {
631 return (escCount & 0x1) != 0U;
634 template <
typename TIter>
635 bool fieldEscapedInternal(TIter from, TIter to)
638 typename comms::util::LazyShallowConditional<
639 std::is_same<EscField, void>::value
645 return fieldEscapedInternal(from, to, EscTag());
648 static_assert(!(hasVerifyBeforeRead() && hasSeekField()),
649 "Usage of both comms::option::def::FrameLayerVerifyBeforeRead and comms::option::def::FrameLayerSeekField at the same time are not allowed");