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