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