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