1 /*
2 * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef PANDA_LIBPANDABASE_UTILS_SERIALIZER_SERIALIZER_H_
17 #define PANDA_LIBPANDABASE_UTILS_SERIALIZER_SERIALIZER_H_
18
19 #include <securec.h>
20
21 #include "utils/expected.h"
22 #include "for_each_tuple.h"
23 #include "tuple_to_struct.h"
24 #include "struct_to_tuple.h"
25 #include "concepts.h"
26 #include <vector>
27 #include <string>
28 #include <unordered_map>
29 #include <cstring>
30
31 namespace ark::serializer {
32
ToUintPtr(const uint8_t *p)33 inline uintptr_t ToUintPtr(const uint8_t *p)
34 {
35 return reinterpret_cast<uintptr_t>(p);
36 }
37
ToUint8tPtr(uintptr_t v)38 inline const uint8_t *ToUint8tPtr(uintptr_t v)
39 {
40 return reinterpret_cast<const uint8_t *>(v);
41 }
42
43 template <typename T>
44 // NOLINTNEXTLINE(google-runtime-references)
45 inline auto TypeToBuffer(const T &value, std::vector<uint8_t> &buffer)
46 -> std::enable_if_t<std::is_pod_v<T>, Expected<size_t, const char *>>
47 {
48 const auto *ptr = reinterpret_cast<const uint8_t *>(&value);
49 std::copy(ptr, ToUint8tPtr(ToUintPtr(ptr) + sizeof(value)), std::back_inserter(buffer));
50 return sizeof(value);
51 }
52
53 template <class VecT>
54 // NOLINTNEXTLINE(google-runtime-references)
55 inline auto TypeToBuffer(const VecT &vec, std::vector<uint8_t> &buffer)
56 -> std::enable_if_t<is_vectorable_v<VecT> && std::is_pod_v<typename VecT::value_type>,
57 Expected<size_t, const char *>>
58 {
59 using Type = typename VecT::value_type;
60 // pack size
61 uint32_t size = vec.size() * sizeof(Type);
62 auto ret = TypeToBuffer(size, buffer);
63 if (!ret) {
64 return ret;
65 }
66
67 // pack data
68 const auto *ptr = reinterpret_cast<const uint8_t *>(vec.data());
69 const uint8_t *ptrEnd = ToUint8tPtr(ToUintPtr(ptr) + size);
70 std::copy(ptr, ptrEnd, std::back_inserter(buffer));
71 return ret.Value() + size;
72 }
73
74 template <class UnMap>
75 auto TypeToBuffer(const UnMap &map, std::vector<uint8_t> &buffer)
76 -> std::enable_if_t<is_hash_mappable_v<UnMap>, Expected<size_t, const char *>>
77 {
78 // pack size
79 auto ret = TypeToBuffer(static_cast<uint32_t>(map.size()), buffer);
80 if (!ret) {
81 return ret;
82 }
83
84 for (const auto &[key, value] : map) {
85 // pack key
86 auto k = TypeToBuffer(key, buffer);
87 if (!k) {
88 return k;
89 }
90 ret.Value() += k.Value();
91
92 // pack value
93 auto v = TypeToBuffer(value, buffer);
94 if (!v) {
95 return v;
96 }
97 ret.Value() += v.Value();
98 }
99
100 return ret;
101 }
102
103 template <typename T>
BufferToType(const uint8_t *data, size_t size, T &out)104 Expected<size_t, const char *> BufferToType(const uint8_t *data, size_t size, T &out)
105 {
106 static_assert(std::is_pod<T>::value, "Type is not supported");
107
108 if (sizeof(out) > size) {
109 return Unexpected("Cannot deserialize POD type, the buffer is too small.");
110 }
111
112 auto *ptr = reinterpret_cast<uint8_t *>(&out);
113 memcpy_s(ptr, sizeof(out), data, sizeof(out));
114 return sizeof(out);
115 }
116
117 // NOLINTNEXTLINE(google-runtime-references)
BufferToTypeUnpackString(const uint8_t *data, size_t size, std::string &out, uint32_t strSize, size_t value)118 inline Expected<size_t, const char *> BufferToTypeUnpackString(const uint8_t *data, size_t size, std::string &out,
119 uint32_t strSize, size_t value)
120 {
121 if (size < strSize) {
122 return Unexpected("Cannot deserialize string, the buffer is too small.");
123 }
124
125 out.resize(strSize);
126 memcpy_s(out.data(), strSize, data, strSize);
127 return value + strSize;
128 }
129
130 // NOLINTNEXTLINE(google-runtime-references)
BufferToType(const uint8_t *data, size_t size, std::string &out)131 inline Expected<size_t, const char *> BufferToType(const uint8_t *data, size_t size, std::string &out)
132 {
133 // unpack size
134 uint32_t strSize = 0;
135 auto r = BufferToType(data, size, strSize);
136 if (!r || strSize == 0) {
137 return r;
138 }
139 ASSERT(r.Value() <= size);
140 data = ToUint8tPtr(ToUintPtr(data) + r.Value());
141 size -= r.Value();
142 return BufferToTypeUnpackString(data, size, out, strSize, r.Value());
143 }
144
145 template <typename T>
BufferToType(const uint8_t *data, size_t size, std::vector<T> &vector)146 Expected<size_t, const char *> BufferToType(const uint8_t *data, size_t size, std::vector<T> &vector)
147 {
148 static_assert(std::is_pod<T>::value, "Type is not supported");
149
150 // unpack size
151 uint32_t vectorSize = 0;
152 auto r = BufferToType(data, size, vectorSize);
153 if (!r || vectorSize == 0) {
154 return r;
155 }
156 ASSERT(r.Value() <= size);
157 data = ToUint8tPtr(ToUintPtr(data) + r.Value());
158 size -= r.Value();
159 // unpack data
160 if (size < vectorSize || (vectorSize % sizeof(T))) {
161 return Unexpected("Cannot deserialize vector, the buffer is too small.");
162 }
163
164 vector.resize(vectorSize / sizeof(T));
165 memcpy_s(vector.data(), vectorSize, data, vectorSize);
166
167 return r.Value() + vectorSize;
168 }
169
170 template <typename K, typename V>
BufferToType(const uint8_t *data, size_t size, std::unordered_map<K, V> &out)171 Expected<size_t, const char *> BufferToType(const uint8_t *data, size_t size, std::unordered_map<K, V> &out)
172 {
173 size_t backupSize = size;
174 uint32_t count = 0;
175 auto r = BufferToType(data, size, count);
176 if (!r) {
177 return r;
178 }
179 ASSERT(r.Value() <= size);
180 data = ToUint8tPtr(ToUintPtr(data) + r.Value());
181 size -= r.Value();
182
183 for (uint32_t i = 0; i < count; ++i) {
184 K key {};
185 auto v = serializer::BufferToType(data, size, key);
186 if (!v) {
187 return v;
188 }
189 ASSERT(v.Value() <= size);
190 data = ToUint8tPtr(ToUintPtr(data) + v.Value());
191 size -= v.Value();
192
193 V value {};
194 v = serializer::BufferToType(data, size, value);
195 if (!v) {
196 return v;
197 }
198 ASSERT(v.Value() <= size);
199 data = ToUint8tPtr(ToUintPtr(data) + v.Value());
200 size -= v.Value();
201
202 auto ret = out.emplace(std::make_pair(std::move(key), std::move(value)));
203 if (!ret.second) {
204 return Unexpected("Cannot emplace KeyValue to map.");
205 }
206 }
207 return backupSize - size;
208 }
209
210 namespace internal {
211
212 class Serializer {
213 public:
214 // NOLINTNEXTLINE(google-runtime-references)
Serializer(std::vector<uint8_t> &buffer)215 explicit Serializer(std::vector<uint8_t> &buffer) : buffer_(buffer) {}
216
217 template <typename T>
operator ()(const T &value)218 void operator()(const T &value)
219 {
220 TypeToBuffer(value, buffer_);
221 }
222
223 virtual ~Serializer() = default;
224
225 NO_COPY_SEMANTIC(Serializer);
226 NO_MOVE_SEMANTIC(Serializer);
227
228 private:
229 std::vector<uint8_t> &buffer_;
230 };
231
232 class Deserializer {
233 public:
Deserializer(const uint8_t *data, size_t size)234 Deserializer(const uint8_t *data, size_t size) : data_(data), size_(size) {}
235
IsError() const236 bool IsError() const
237 {
238 return error_ != nullptr;
239 }
240
GetError() const241 const char *GetError() const
242 {
243 return error_;
244 }
245
GetEndPosition() const246 size_t GetEndPosition() const
247 {
248 return pos_;
249 }
250
251 template <typename T>
operator ()(T &value)252 void operator()(T &value)
253 {
254 if (error_ != nullptr) {
255 return;
256 }
257
258 ASSERT(pos_ < size_);
259 const uint8_t *ptr = ToUint8tPtr(ToUintPtr(data_) + pos_);
260 auto ret = BufferToType(ptr, size_ - pos_, value);
261 if (!ret) {
262 error_ = ret.Error();
263 return;
264 }
265 pos_ += ret.Value();
266 }
267
268 virtual ~Deserializer() = default;
269
270 NO_COPY_SEMANTIC(Deserializer);
271 NO_MOVE_SEMANTIC(Deserializer);
272
273 private:
274 const uint8_t *data_;
275 size_t size_;
276 size_t pos_ = 0;
277 const char *error_ = nullptr;
278 };
279
280 } // namespace internal
281
282 template <size_t N, typename Struct>
283 bool StructToBuffer(Struct &&str, std::vector<uint8_t> &buffer)
284 {
285 internal::ForEachTuple(internal::StructToTuple<N>(std::forward<Struct>(str)), internal::Serializer(buffer));
286 return true;
287 }
288
289 template <size_t N, typename Struct>
290 Expected<size_t, const char *> RawBufferToStruct(const uint8_t *data, size_t size, Struct &out)
291 {
292 using S = std::remove_reference_t<Struct>;
293 using TupleType = decltype(internal::StructToTuple<N, S>({}));
294
295 TupleType tuple;
296 internal::Deserializer deserializer(data, size);
297 internal::ForEachTuple(tuple, deserializer);
298 if (deserializer.IsError()) {
299 return Unexpected(deserializer.GetError());
300 }
301
302 out = std::move(internal::TupleToStruct<S>(tuple));
303 return deserializer.GetEndPosition();
304 }
305
306 template <size_t N, typename Struct>
307 bool BufferToStruct(const uint8_t *data, size_t size, Struct &out)
308 {
309 auto r = RawBufferToStruct<N>(data, size, out);
310 if (!r) {
311 return false;
312 }
313 return r.Value() == size;
314 }
315
316 template <size_t N, typename Struct>
317 bool BufferToStruct(const std::vector<uint8_t> &buffer, Struct &out)
318 {
319 return BufferToStruct<N>(buffer.data(), buffer.size(), out);
320 }
321
322 } // namespace ark::serializer
323
324 #endif // PANDA_LIBPANDABASE_UTILS_SERIALIZER_SERIALIZER_H_
325