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