COMMS
Template library intended to help with implementation of communication protocols.
Loading...
Searching...
No Matches
SequenceTerminationFieldSuffix.h
1//
2// Copyright 2015 - 2026 (C). Alex Robenko. All rights reserved.
3//
4// SPDX-License-Identifier: MPL-2.0
5//
6// This Source Code Form is subject to the terms of the Mozilla Public
7// License, v. 2.0. If a copy of the MPL was not distributed with this
8// file, You can obtain one at http://mozilla.org/MPL/2.0/.
9
10#pragma once
11
12#include "comms/Assert.h"
13#include "comms/details/tag.h"
14#include "comms/ErrorStatus.h"
16
17#include <cstddef>
18#include <cstdint>
19#include <iterator>
20#include <type_traits>
21#include <utility>
22
23namespace comms
24{
25
26namespace field
27{
28
29namespace adapter
30{
31
32template <typename TTermField, typename TBase>
33class SequenceTerminationFieldSuffix : public TBase
34{
35 using BaseImpl = TBase;
36 using TermField = TTermField;
37
38 static_assert(!TermField::isVersionDependent(),
39 "Suffix fields must not be version dependent");
40
41public:
42 using ValueType = typename BaseImpl::ValueType;
43 using ElementType = typename BaseImpl::ElementType;
44
46
47 explicit SequenceTerminationFieldSuffix(const ValueType& val)
48 : BaseImpl(val)
49 {
50 }
51
52 explicit SequenceTerminationFieldSuffix(ValueType&& val)
53 : BaseImpl(std::move(val))
54 {
55 }
56
57 SequenceTerminationFieldSuffix(const SequenceTerminationFieldSuffix&) = default;
58 SequenceTerminationFieldSuffix(SequenceTerminationFieldSuffix&&) = default;
59 SequenceTerminationFieldSuffix& operator=(const SequenceTerminationFieldSuffix&) = default;
60 SequenceTerminationFieldSuffix& operator=(SequenceTerminationFieldSuffix&&) = default;
61
62 constexpr std::size_t length() const
63 {
64 return m_termField.length() + BaseImpl::length();
65 }
66
67 static constexpr std::size_t minLength()
68 {
69 return TermField::minLength() + BaseImpl::minLength();
70 }
71
72 static constexpr std::size_t maxLength()
73 {
74 return TermField::maxLength() + BaseImpl::maxLength();
75 }
76
77 template <typename TIter>
78 comms::ErrorStatus read(TIter& iter, std::size_t len)
79 {
80 using IterType = typename std::decay<decltype(iter)>::type;
81 using IterTag = typename std::iterator_traits<IterType>::iterator_category;
82 static_assert(std::is_base_of<std::random_access_iterator_tag, IterTag>::value,
83 "Only random access iterator for reading is supported with comms::option::def::SequenceTerminationFieldSuffix option");
84
85 using ReadElemTag =
86 typename comms::util::LazyShallowConditional<
87 std::is_integral<ElementType>::value && (sizeof(ElementType) == sizeof(std::uint8_t))
88 >::template Type<
89 RawDataTag,
90 FieldTag
91 >;
92
93 return readInternal(iter, len, ReadElemTag());
94 }
95
96 static constexpr bool hasReadNoStatus()
97 {
98 return false;
99 }
100
101 template <typename TIter>
102 void readNoStatus(TIter& iter) = delete;
103
104 template <typename TIter>
105 comms::ErrorStatus write(TIter& iter, std::size_t len) const
106 {
107 auto trailLen = m_termField.length();
108 auto es = BaseImpl::write(iter, len - trailLen);
109 if (es != comms::ErrorStatus::Success) {
110 return es;
111 }
112
113 return m_termField.write(iter, trailLen);
114 }
115
116 template <typename TIter>
117 void writeNoStatus(TIter& iter) const
118 {
119 BaseImpl::writeNoStatus(iter);
120 m_termField.writeNoStatus(iter);
121 }
122
123 TermField& terminationFieldSuffix()
124 {
125 return m_termField;
126 }
127
128 const TermField& terminationFieldSuffix() const
129 {
130 return m_termField;
131 }
132
133private:
134 template <typename... TParams>
135 using RawDataTag = comms::details::tag::Tag1<>;
136
137 template <typename... TParams>
138 using FieldTag = comms::details::tag::Tag2<>;
139
140 template <typename TIter, typename... TParams>
141 comms::ErrorStatus readInternal(TIter& iter, std::size_t len, FieldTag<TParams...>)
142 {
143 BaseImpl::clear();
144 while (true) {
145 auto iterCpy = iter;
146 auto es = m_termField.read(iterCpy, len);
147 if (es == comms::ErrorStatus::Success) {
148 std::advance(iter, std::distance(iter, iterCpy));
149 return es;
150 }
151
152 auto& elem = BaseImpl::createBack();
153 es = BaseImpl::readElement(elem, iter, len);
154 if (es != comms::ErrorStatus::Success) {
155 BaseImpl::value().pop_back();
156 return es;
157 }
158 }
159
161 }
162
163 template <typename TIter, typename... TParams>
164 comms::ErrorStatus readInternal(TIter& iter, std::size_t len, RawDataTag<TParams...>)
165 {
166 std::size_t consumed = 0U;
167 std::size_t termFieldLen = 0U;
168 while (consumed < len) {
169 auto iterCpy = iter + consumed;
170 auto es = m_termField.read(iterCpy, len - consumed);
171 if (es == comms::ErrorStatus::Success) {
172 termFieldLen = static_cast<std::size_t>(std::distance(iter + consumed, iterCpy));
173 break;
174 }
175
176 ++consumed;
177 }
178
179 if (len <= consumed) {
181 }
182
183 auto iterCpy = iter;
184 auto es = BaseImpl::read(iterCpy, consumed);
185 if (es != comms::ErrorStatus::Success) {
186 return es;
187 }
188
189 auto fullConsumeLen = consumed + termFieldLen;
190 COMMS_ASSERT(fullConsumeLen <= len);
191 std::advance(iter, fullConsumeLen);
193 }
194
195 TermField m_termField;
196};
197
198} // namespace adapter
199
200} // namespace field
201
202} // namespace comms
203
This file contains classes required for generic custom assertion functionality.
#define COMMS_ASSERT(expr)
Generic assert macro.
Definition Assert.h:170
This file contain definition of error statuses used by comms module.
comms::option::def::SequenceTerminationFieldSuffix< TField > SequenceTerminationFieldSuffix
Same as comms::option::def::SequenceTerminationFieldSuffix.
Definition options.h:1585
Main namespace for all classes / functions of COMMS library.
ErrorStatus
Error statuses reported by the Communication module.
Definition ErrorStatus.h:19
@ Success
Used to indicate successful outcome of the operation.
STL namespace.
Replacement to some types from standard type_traits.