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