cc_tools_qt
Common Environment for Protocol Analysis.
Loading...
Searching...
No Matches
FieldWrapper.h
1//
2// Copyright 2014 - 2024 (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 <cstdint>
22#include <cstddef>
23#include <cassert>
24#include <memory>
25#include <vector>
26
27#include <QtCore/QString>
28
29#include "comms/comms.h"
30#include "cc_tools_qt/Api.h"
31
32COMMS_MSVC_WARNING_PUSH
33COMMS_MSVC_WARNING_DISABLE(4127) // Disable warning about constant conditional expressions
34
35namespace cc_tools_qt
36{
37
38namespace field_wrapper
39{
40
41class FieldWrapperHandler;
42
44class CC_API FieldWrapper
45{
46public:
47 typedef std::vector<std::uint8_t> SerialisedSeq;
48
49 typedef std::unique_ptr<FieldWrapper> BasePtr;
50
52 virtual ~FieldWrapper() noexcept;
53
54 std::size_t length() const;
55
56 int width() const;
57
58 bool valid() const;
59
60 SerialisedSeq getSerialisedValue() const;
61
62 bool setSerialisedValue(const SerialisedSeq& value);
63
64 QString getSerialisedString() const;
65
66 bool setSerialisedString(const QString& str);
67
68 void dispatch(FieldWrapperHandler& handler);
69
70 BasePtr upClone();
71
72 bool canWrite() const;
73
74 void reset();
75
76protected:
77 virtual std::size_t lengthImpl() const = 0;
78 virtual bool validImpl() const = 0;
79 virtual SerialisedSeq getSerialisedValueImpl() const = 0;
80 virtual bool setSerialisedValueImpl(const SerialisedSeq& value) = 0;
81 virtual void dispatchImpl(FieldWrapperHandler& handler) = 0;
82 virtual BasePtr upCloneImpl() = 0;
83 virtual bool canWriteImpl() const = 0;
84 virtual void resetImpl() = 0;
85};
86
87template <typename TBase, typename TField>
88class FieldWrapperT : public TBase
89{
90 using Base = TBase;
91
92 struct HasPrefixSuffixTag {};
93 struct NoPrefixSuffixTag {};
94
95public:
96 typedef typename Base::SerialisedSeq SerialisedSeq;
97 typedef typename Base::BasePtr BasePtr;
98
99 virtual ~FieldWrapperT() noexcept = default;
100
101protected:
102
103 using Field = TField;
104
105 explicit FieldWrapperT(Field& fieldRef)
106 : m_field(fieldRef)
107 {
108 }
109
110 virtual std::size_t lengthImpl() const override
111 {
112 return m_field.length();
113 }
114
115 virtual bool validImpl() const override
116 {
117 return m_field.valid();
118 }
119
120 Field& field()
121 {
122 return m_field;
123 }
124
125 const Field& field() const
126 {
127 return m_field;
128 }
129
130 virtual SerialisedSeq getSerialisedValueImpl() const override
131 {
132 SerialisedSeq seq;
133 seq.reserve(m_field.length());
134 auto iter = std::back_inserter(seq);
135 [[maybe_unused]] auto es = m_field.write(iter, seq.max_size());
136 assert(es == comms::ErrorStatus::Success);
137 assert(seq.size() == m_field.length());
138 return seq;
139 }
140
141 virtual bool setSerialisedValueImpl(const SerialisedSeq& value) override
142 {
143 if (value.empty()) {
144 return false;
145 }
146
147 if ((!CollectionPrefixDetect<Field, IsCollection>::HasSizeFieldPrefix) &&
148 (!CollectionPrefixDetect<Field, IsCollection>::HasSerLengthFieldPrefix) &&
149 (!CollectionPrefixDetect<Field, IsCollection>::HasTrailingFieldSuffix) &&
150 (!CollectionPrefixDetect<Field, IsCollection>::HasTerminationFieldSuffix)) {
151 auto iter = &value[0];
152 auto es = m_field.read(iter, value.size());
153 return es == comms::ErrorStatus::Success;
154 }
155
156 SerialisedSeq newVal;
157 if (!writeSerialisedSize(newVal, value.size(), SerialisedSizePrefixTag())) {
158 return false;
159 }
160
161 if (!writeSerialisedLength(newVal, value.size(), SerialisedLengthPrefixTag())) {
162 return false;
163 }
164
165 auto writeIter = std::back_inserter(newVal);
166 std::copy(value.begin(), value.end(), writeIter);
167
168 if (!writeTrailSuffix(newVal, SerialisedTrailSuffixTag())) {
169 return false;
170 }
171
172 if (!writeTermSuffix(newVal, SerialisedTermSuffixTag())) {
173 return false;
174 }
175
176 auto iter = &newVal[0];
177 auto es = m_field.read(iter, newVal.size());
178 return es == comms::ErrorStatus::Success;
179 }
180
181 virtual BasePtr upCloneImpl() override
182 {
183 return static_cast<Base*>(this)->clone();
184 }
185
186 virtual bool canWriteImpl() const override
187 {
188 return m_field.canWrite();
189 }
190
191 virtual void resetImpl() override
192 {
193 m_field = Field();
194 }
195
196private:
197 template <typename T, bool TIsCollection>
198 struct CollectionPrefixDetect
199 {
200 static const bool HasSizeFieldPrefix = false;
201 static const bool HasSerLengthFieldPrefix = false;
202 static const bool HasTrailingFieldSuffix = false;
203 static const bool HasTerminationFieldSuffix = false;
204 };
205
206 template <typename T>
207 struct CollectionPrefixDetect<T, true>
208 {
209 static const bool HasSizeFieldPrefix = Field::hasSizeFieldPrefix();
210 static const bool HasSerLengthFieldPrefix = Field::hasSerLengthFieldPrefix();
211 static const bool HasTrailingFieldSuffix = TField::hasTrailingFieldSuffix();
212 static const bool HasTerminationFieldSuffix = Field::hasTerminationFieldSuffix();
213 };
214
215 static constexpr bool IsCollection = comms::field::isString<Field>() || comms::field::isArrayList<Field>();
216
217 typedef typename std::conditional<
218 CollectionPrefixDetect<Field, IsCollection>::HasSizeFieldPrefix,
219 HasPrefixSuffixTag,
220 NoPrefixSuffixTag
221 >::type SerialisedSizePrefixTag;
222
223 typedef typename std::conditional<
224 CollectionPrefixDetect<Field, IsCollection>::HasSerLengthFieldPrefix,
225 HasPrefixSuffixTag,
226 NoPrefixSuffixTag
227 >::type SerialisedLengthPrefixTag;
228
229 typedef typename std::conditional<
230 CollectionPrefixDetect<Field, IsCollection>::HasTrailingFieldSuffix,
231 HasPrefixSuffixTag,
232 NoPrefixSuffixTag
233 >::type SerialisedTrailSuffixTag;
234
235 typedef typename std::conditional<
236 CollectionPrefixDetect<Field, IsCollection>::HasTerminationFieldSuffix,
237 HasPrefixSuffixTag,
238 NoPrefixSuffixTag
239 >::type SerialisedTermSuffixTag;
240
241 bool writeSerialisedSize(SerialisedSeq& seq, std::size_t sizeVal, HasPrefixSuffixTag)
242 {
243 typedef typename Field::SizeFieldPrefix SizePrefixField;
244
245 SizePrefixField sizePrefixField;
246 sizePrefixField.setValue(sizeVal);
247 auto writeIter = std::back_inserter(seq);
248 auto es = sizePrefixField.write(writeIter, seq.max_size() - seq.size());
249 return es == comms::ErrorStatus::Success;
250 }
251
252 bool writeSerialisedSize([[maybe_unused]] SerialisedSeq& seq, [[maybe_unused]] std::size_t sizeVal, NoPrefixSuffixTag)
253 {
254 return true;
255 }
256
257 bool writeSerialisedLength(SerialisedSeq& seq, std::size_t sizeVal, HasPrefixSuffixTag)
258 {
259 typedef typename Field::SerLengthFieldPrefix LengthPrefixField;
260
261 LengthPrefixField lengthPrefixField;
262 lengthPrefixField.setValue(sizeVal);
263 auto writeIter = std::back_inserter(seq);
264 auto es = lengthPrefixField.write(writeIter, seq.max_size() - seq.size());
265 return es == comms::ErrorStatus::Success;
266 }
267
268 bool writeSerialisedLength([[maybe_unused]] SerialisedSeq& seq, [[maybe_unused]] std::size_t sizeVal, NoPrefixSuffixTag)
269 {
270 return true;
271 }
272
273 bool writeTrailSuffix(SerialisedSeq& seq, HasPrefixSuffixTag)
274 {
275 typedef typename Field::TrailingFieldSuffix TrailingSuffixField;
276 TrailingSuffixField trailingSuffixField;
277 auto writeIter = std::back_inserter(seq);
278 auto es = trailingSuffixField.write(writeIter, seq.max_size() - seq.size());
279 return es == comms::ErrorStatus::Success;
280 }
281
282 bool writeTrailSuffix([[maybe_unused]] SerialisedSeq& seq, NoPrefixSuffixTag)
283 {
284 return true;
285 }
286
287 bool writeTermSuffix(SerialisedSeq& seq, HasPrefixSuffixTag)
288 {
289 typedef typename Field::TerminationFieldSuffix TermSuffixField;
290 TermSuffixField termSuffixField;
291 auto writeIter = std::back_inserter(seq);
292 auto es = termSuffixField.write(writeIter, seq.max_size() - seq.size());
293 return es == comms::ErrorStatus::Success;
294 }
295
296 bool writeTermSuffix([[maybe_unused]] SerialisedSeq& seq, NoPrefixSuffixTag)
297 {
298 return true;
299 }
300
301
302 Field& m_field;
303};
304
305typedef FieldWrapper::BasePtr FieldWrapperPtr;
306
307} // namespace field_wrapper
308
309} // namespace cc_tools_qt
310
311COMMS_MSVC_WARNING_POP
Field wrapping class.
Definition FieldWrapper.h:45
Main namespace for all classes / functions of the shared library.