cc_tools_qt
Common Environment for Protocol Analysis.
Loading...
Searching...
No Matches
ToolsFieldBase.h
1//
2// Copyright 2014 - 2025 (C). Alex Robenko. All rights reserved.
3//
4
5// This file is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// This program is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18#pragma once
19
20#include "comms/comms.h"
21
22#include <QtCore/QString>
23
24#include <cassert>
25#include <cstddef>
26#include <cstdint>
27#include <memory>
28#include <vector>
29
30COMMS_MSVC_WARNING_PUSH
31COMMS_MSVC_WARNING_DISABLE(4127) // Disable warning about constant conditional expressions
32
33namespace cc_tools_qt
34{
35
36namespace details
37{
38
39template <typename TBase, typename TField>
40class ToolsFieldBase : public TBase
41{
42 using Base = TBase;
43
44public:
45 using SerialisedSeq = typename Base::SerialisedSeq;
46 using Ptr = typename Base::Ptr;
47
48protected:
49
50 virtual ~ToolsFieldBase() noexcept = default;
51
52 using Field = TField;
53
54 explicit ToolsFieldBase(Field& fieldRef)
55 : m_field(fieldRef)
56 {
57 }
58
59 virtual const char* nameImpl() const override
60 {
61 static_assert(Field::hasName(), "The field class is expected use comms::option::def::HasName and define name() function.");
62 return m_field.name();
63 }
64
65 virtual std::size_t lengthImpl() const override
66 {
67 return m_field.length();
68 }
69
70 virtual bool validImpl() const override
71 {
72 return m_field.valid();
73 }
74
75 virtual bool isReadOnlyImpl() const override
76 {
77 return Field::hasFixedValue();
78 }
79
80 virtual bool isHiddenSerializationImpl() const override
81 {
82 return Field::hasEmptySerialization();
83 }
84
85 Field& field()
86 {
87 return m_field;
88 }
89
90 const Field& field() const
91 {
92 return m_field;
93 }
94
95 virtual SerialisedSeq getSerialisedValueImpl() const override
96 {
97 SerialisedSeq seq;
98 seq.reserve(m_field.length());
99 auto iter = std::back_inserter(seq);
100 [[maybe_unused]] auto es = m_field.write(iter, seq.max_size());
101 assert(es == comms::ErrorStatus::Success);
102 assert(seq.size() == m_field.length());
103 return seq;
104 }
105
106 virtual bool setSerialisedValueImpl(const SerialisedSeq& value) override
107 {
108 if (value.empty()) {
109 return false;
110 }
111
112 if ((!CollectionPrefixDetect<Field, IsCollection>::HasSizeFieldPrefix) &&
113 (!CollectionPrefixDetect<Field, IsCollection>::HasSerLengthFieldPrefix) &&
114 (!CollectionPrefixDetect<Field, IsCollection>::HasTrailingFieldSuffix) &&
115 (!CollectionPrefixDetect<Field, IsCollection>::HasTerminationFieldSuffix)) {
116 auto iter = &value[0];
117 auto es = m_field.read(iter, value.size());
118 return es == comms::ErrorStatus::Success;
119 }
120
121 SerialisedSeq newVal;
122 if (!writeSerialisedSize(newVal, value.size(), SerialisedSizePrefixTag())) {
123 return false;
124 }
125
126 if (!writeSerialisedLength(newVal, value.size(), SerialisedLengthPrefixTag())) {
127 return false;
128 }
129
130 auto writeIter = std::back_inserter(newVal);
131 std::copy(value.begin(), value.end(), writeIter);
132
133 if (!writeTrailSuffix(newVal, SerialisedTrailSuffixTag())) {
134 return false;
135 }
136
137 if (!writeTermSuffix(newVal, SerialisedTermSuffixTag())) {
138 return false;
139 }
140
141 auto iter = &newVal[0];
142 auto es = m_field.read(iter, newVal.size());
143 return es == comms::ErrorStatus::Success;
144 }
145
146 virtual bool canWriteImpl() const override
147 {
148 return m_field.canWrite();
149 }
150
151 virtual void resetImpl() override
152 {
153 m_field = Field();
154 }
155
156private:
157 struct HasPrefixSuffixTag {};
158 struct NoPrefixSuffixTag {};
159
160 template <typename T, bool TIsCollection>
161 struct CollectionPrefixDetect
162 {
163 static const bool HasSizeFieldPrefix = false;
164 static const bool HasSerLengthFieldPrefix = false;
165 static const bool HasTrailingFieldSuffix = false;
166 static const bool HasTerminationFieldSuffix = false;
167 };
168
169 template <typename T>
170 struct CollectionPrefixDetect<T, true>
171 {
172 static const bool HasSizeFieldPrefix = Field::hasSizeFieldPrefix();
173 static const bool HasSerLengthFieldPrefix = Field::hasSerLengthFieldPrefix();
174 static const bool HasTrailingFieldSuffix = TField::hasTrailingFieldSuffix();
175 static const bool HasTerminationFieldSuffix = Field::hasTerminationFieldSuffix();
176 };
177
178 static constexpr bool IsCollection = comms::field::isString<Field>() || comms::field::isArrayList<Field>();
179
180 using SerialisedSizePrefixTag =
181 std::conditional_t<
182 CollectionPrefixDetect<Field, IsCollection>::HasSizeFieldPrefix,
183 HasPrefixSuffixTag,
184 NoPrefixSuffixTag
185 >;
186
187 using SerialisedLengthPrefixTag =
188 std::conditional_t<
189 CollectionPrefixDetect<Field, IsCollection>::HasSerLengthFieldPrefix,
190 HasPrefixSuffixTag,
191 NoPrefixSuffixTag
192 >;
193
194 using SerialisedTrailSuffixTag =
195 std::conditional_t<
196 CollectionPrefixDetect<Field, IsCollection>::HasTrailingFieldSuffix,
197 HasPrefixSuffixTag,
198 NoPrefixSuffixTag
199 >;
200
201 using SerialisedTermSuffixTag =
202 std::conditional_t<
203 CollectionPrefixDetect<Field, IsCollection>::HasTerminationFieldSuffix,
204 HasPrefixSuffixTag,
205 NoPrefixSuffixTag
206 >;
207
208 bool writeSerialisedSize(SerialisedSeq& seq, std::size_t sizeVal, HasPrefixSuffixTag)
209 {
210 using SizePrefixField = typename Field::SizeFieldPrefix;
211
212 SizePrefixField sizePrefixField;
213 sizePrefixField.setValue(sizeVal);
214 auto writeIter = std::back_inserter(seq);
215 auto es = sizePrefixField.write(writeIter, seq.max_size() - seq.size());
216 return es == comms::ErrorStatus::Success;
217 }
218
219 bool writeSerialisedSize([[maybe_unused]] SerialisedSeq& seq, [[maybe_unused]] std::size_t sizeVal, NoPrefixSuffixTag)
220 {
221 return true;
222 }
223
224 bool writeSerialisedLength(SerialisedSeq& seq, std::size_t sizeVal, HasPrefixSuffixTag)
225 {
226 using LengthPrefixField = typename Field::SerLengthFieldPrefix;
227
228 LengthPrefixField lengthPrefixField;
229 lengthPrefixField.setValue(sizeVal);
230 auto writeIter = std::back_inserter(seq);
231 auto es = lengthPrefixField.write(writeIter, seq.max_size() - seq.size());
232 return es == comms::ErrorStatus::Success;
233 }
234
235 bool writeSerialisedLength([[maybe_unused]] SerialisedSeq& seq, [[maybe_unused]] std::size_t sizeVal, NoPrefixSuffixTag)
236 {
237 return true;
238 }
239
240 bool writeTrailSuffix(SerialisedSeq& seq, HasPrefixSuffixTag)
241 {
242 using TrailingSuffixField = typename Field::TrailingFieldSuffix;
243
244 TrailingSuffixField trailingSuffixField;
245 auto writeIter = std::back_inserter(seq);
246 auto es = trailingSuffixField.write(writeIter, seq.max_size() - seq.size());
247 return es == comms::ErrorStatus::Success;
248 }
249
250 bool writeTrailSuffix([[maybe_unused]] SerialisedSeq& seq, NoPrefixSuffixTag)
251 {
252 return true;
253 }
254
255 bool writeTermSuffix(SerialisedSeq& seq, HasPrefixSuffixTag)
256 {
257 using TermSuffixField = typename Field::TerminationFieldSuffix;
258 TermSuffixField termSuffixField;
259 auto writeIter = std::back_inserter(seq);
260 auto es = termSuffixField.write(writeIter, seq.max_size() - seq.size());
261 return es == comms::ErrorStatus::Success;
262 }
263
264 bool writeTermSuffix([[maybe_unused]] SerialisedSeq& seq, NoPrefixSuffixTag)
265 {
266 return true;
267 }
268
269 Field& m_field;
270};
271
272} // namespace details
273
274} // namespace cc_tools_qt
275
276COMMS_MSVC_WARNING_POP
Main namespace for all classes / functions of the shared library.