1 /*
2 * Copyright (c) 2021 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_SERIALIZER_SERIALIZER_H_
17 #define PANDA_LIBPANDABASE_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 panda::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, /* out */ 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, /* out */ 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 *ptr_end = ToUint8tPtr(ToUintPtr(ptr) + size);
70 std::copy(ptr, ptr_end, std::back_inserter(buffer));
71 return ret.Value() + size;
72 }
73
74 template <class UnMap>
75 // NOLINTNEXTLINE(google-runtime-references)
76 inline auto TypeToBuffer(const UnMap &map, /* out */ std::vector<uint8_t> &buffer)
77 -> std::enable_if_t<is_hash_mappable_v<UnMap>, Expected<size_t, const char *>>
78 {
79 // pack size
80 auto ret = TypeToBuffer(static_cast<uint32_t>(map.size()), buffer);
81 if (!ret) {
82 return ret;
83 }
84
85 // At the moment, we can't use: [key, value]
86 // because clang-format-8 can't correctly detect the source code language.
87 // https://bugs.llvm.org/show_bug.cgi?id=37433
88 //
89 for (const auto &it : map) {
90 // pack key
91 auto k = TypeToBuffer(it.first, buffer);
92 if (!k) {
93 return k;
94 }
95 ret.Value() += k.Value();
96
97 // pack value
98 auto v = TypeToBuffer(it.second, buffer);
99 if (!v) {
100 return v;
101 }
102 ret.Value() += v.Value();
103 }
104
105 return ret;
106 }
107
108 template <typename T>
BufferToType(const uint8_t * data,size_t size,T & value)109 Expected<size_t, const char *> BufferToType(const uint8_t *data, size_t size, /* out */ T &value)
110 {
111 static_assert(std::is_pod<T>::value, "Type is not supported");
112
113 if (sizeof(value) > size) {
114 return Unexpected("Cannot deserialize POD type, the buffer is too small.");
115 }
116
117 auto *ptr = reinterpret_cast<uint8_t *>(&value);
118 (void)memcpy_s(ptr, sizeof(value), data, sizeof(value));
119 return sizeof(value);
120 }
121
122 // NOLINTNEXTLINE(google-runtime-references)
BufferToType(const uint8_t * data,size_t size,std::string & str)123 inline Expected<size_t, const char *> BufferToType(const uint8_t *data, size_t size, /* out */ std::string &str)
124 {
125 // unpack size
126 uint32_t str_size = 0;
127 auto r = BufferToType(data, size, str_size);
128 if (!r || str_size == 0) {
129 return r;
130 }
131 ASSERT(r.Value() <= size);
132 data = ToUint8tPtr(ToUintPtr(data) + r.Value());
133 size -= r.Value();
134
135 // unpack string
136 if (size < str_size) {
137 return Unexpected("Cannot deserialize string, the buffer is too small.");
138 }
139
140 str.resize(str_size);
141 (void)memcpy_s(str.data(), str_size, data, str_size);
142 return r.Value() + str_size;
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, /* out */ std::vector<T> &vector)
147 {
148 static_assert(std::is_pod<T>::value, "Type is not supported");
149
150 // unpack size
151 uint32_t vector_size = 0;
152 auto r = BufferToType(data, size, vector_size);
153 if (!r || vector_size == 0) {
154 return r;
155 }
156 ASSERT(r.Value() <= size);
157 data = ToUint8tPtr(ToUintPtr(data) + r.Value());
158 size -= r.Value();
159
160 // unpack data
161 if (size < vector_size || (vector_size % sizeof(T))) {
162 return Unexpected("Cannot deserialize vector, the buffer is too small.");
163 }
164
165 vector.resize(vector_size / sizeof(T));
166 (void)memcpy_s(vector.data(), vector_size, data, vector_size);
167
168 return r.Value() + vector_size;
169 }
170
171 template <typename K, typename V>
BufferToType(const uint8_t * data,size_t size,std::unordered_map<K,V> & map)172 Expected<size_t, const char *> BufferToType(const uint8_t *data, size_t size, /* out */ std::unordered_map<K, V> &map)
173 {
174 size_t backup_size = size;
175 uint32_t count = 0;
176 auto r = BufferToType(data, size, count);
177 if (!r) {
178 return r;
179 }
180 ASSERT(r.Value() <= size);
181 data = ToUint8tPtr(ToUintPtr(data) + r.Value());
182 size -= r.Value();
183
184 for (uint32_t i = 0; i < count; ++i) {
185 K key {};
186 auto v = serializer::BufferToType(data, size, key);
187 if (!v) {
188 return v;
189 }
190 ASSERT(v.Value() <= size);
191 data = ToUint8tPtr(ToUintPtr(data) + v.Value());
192 size -= v.Value();
193
194 V value {};
195 v = serializer::BufferToType(data, size, value);
196 if (!v) {
197 return v;
198 }
199 ASSERT(v.Value() <= size);
200 data = ToUint8tPtr(ToUintPtr(data) + v.Value());
201 size -= v.Value();
202
203 auto ret = map.emplace(std::make_pair(std::move(key), std::move(value)));
204 if (!ret.second) {
205 return Unexpected("Cannot emplace KeyValue to map.");
206 }
207 }
208 return backup_size - size;
209 }
210
211 namespace internal {
212
213 class Serializer {
214 public:
215 // NOLINTNEXTLINE(google-runtime-references)
Serializer(std::vector<uint8_t> & buffer)216 explicit Serializer(std::vector<uint8_t> &buffer) : buffer_(buffer) {}
217
218 template <typename T>
operator()219 void operator()(const T &value)
220 {
221 TypeToBuffer(value, buffer_);
222 }
223
224 virtual ~Serializer() = default;
225
226 NO_COPY_SEMANTIC(Serializer);
227 NO_MOVE_SEMANTIC(Serializer);
228
229 private:
230 std::vector<uint8_t> &buffer_;
231 };
232
233 class Deserializer {
234 public:
Deserializer(const uint8_t * data,size_t size)235 Deserializer(const uint8_t *data, size_t size) : data_(data), size_(size) {}
236
IsError()237 bool IsError() const
238 {
239 return error_ != nullptr;
240 }
241
GetError()242 const char *GetError() const
243 {
244 return error_;
245 }
246
GetEndPosition()247 size_t GetEndPosition() const
248 {
249 return pos_;
250 }
251
252 template <typename T>
operator()253 void operator()(T &value)
254 {
255 if (error_ != nullptr) {
256 return;
257 }
258
259 ASSERT(pos_ < size_);
260 const uint8_t *ptr = ToUint8tPtr(ToUintPtr(data_) + pos_);
261 auto ret = BufferToType(ptr, size_ - pos_, value);
262 if (!ret) {
263 error_ = ret.Error();
264 return;
265 }
266 pos_ += ret.Value();
267 }
268
269 virtual ~Deserializer() = default;
270
271 NO_COPY_SEMANTIC(Deserializer);
272 NO_MOVE_SEMANTIC(Deserializer);
273
274 private:
275 const uint8_t *data_;
276 size_t size_;
277 size_t pos_ = 0;
278 const char *error_ = nullptr;
279 };
280
281 } // namespace internal
282
283 template <size_t N, typename Struct>
StructToBuffer(Struct && str,std::vector<uint8_t> & buffer)284 bool StructToBuffer(Struct &&str, /* out */ std::vector<uint8_t> &buffer) // NOLINT(google-runtime-references)
285 {
286 internal::ForEachTuple(internal::StructToTuple<N>(std::forward<Struct>(str)), internal::Serializer(buffer));
287 return true;
288 }
289
290 template <size_t N, typename Struct>
RawBufferToStruct(const uint8_t * data,size_t size,Struct & str)291 Expected<size_t, const char *> RawBufferToStruct(const uint8_t *data, size_t size, /* out */ Struct &str)
292 {
293 using S = std::remove_reference_t<Struct>;
294 using TupleType = decltype(internal::StructToTuple<N, S>({}));
295
296 TupleType tuple;
297 internal::Deserializer deserializer(data, size);
298 internal::ForEachTuple(tuple, deserializer);
299 if (deserializer.IsError()) {
300 return Unexpected(deserializer.GetError());
301 }
302
303 str = std::move(internal::TupleToStruct<S>(tuple));
304 return deserializer.GetEndPosition();
305 }
306
307 template <size_t N, typename Struct>
BufferToStruct(const uint8_t * data,size_t size,Struct & str)308 bool BufferToStruct(const uint8_t *data, size_t size, /* out */ Struct &str)
309 {
310 auto r = RawBufferToStruct<N>(data, size, str);
311 if (!r) {
312 return false;
313 }
314 return r.Value() == size;
315 }
316
317 template <size_t N, typename Struct>
BufferToStruct(const std::vector<uint8_t> & buffer,Struct & str)318 bool BufferToStruct(const std::vector<uint8_t> &buffer, /* out */ Struct &str)
319 {
320 return BufferToStruct<N>(buffer.data(), buffer.size(), str);
321 }
322
323 } // namespace panda::serializer
324
325 #endif // PANDA_LIBPANDABASE_SERIALIZER_SERIALIZER_H_
326