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 LIBPANDABASE_SERIALIZER_SERIALIZER_H 17#define 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 31namespace panda::serializer { 32 33inline uintptr_t ToUintPtr(const uint8_t *p) 34{ 35 return reinterpret_cast<uintptr_t>(p); 36} 37 38inline const uint8_t *ToUint8tPtr(uintptr_t v) 39{ 40 return reinterpret_cast<const uint8_t *>(v); 41} 42 43template <typename T> 44// NOLINTNEXTLINE(google-runtime-references) 45inline 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 53template <class VecT> 54// NOLINTNEXTLINE(google-runtime-references) 55inline 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 74template <class UnMap> 75// NOLINTNEXTLINE(google-runtime-references) 76inline 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 109template <typename T> 110Expected<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) 124inline 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 // 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 memcpy_s(str.data(), str_size, data, str_size); 142 return r.Value() + str_size; 143} 144 145template <typename T> 146Expected<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 // unpack data 160 if (size < vector_size || (vector_size % sizeof(T))) { 161 return Unexpected("Cannot deserialize vector, the buffer is too small."); 162 } 163 164 vector.resize(vector_size / sizeof(T)); 165 memcpy_s(vector.data(), vector_size, data, vector_size); 166 167 return r.Value() + vector_size; 168} 169 170template <typename K, typename V> 171Expected<size_t, const char *> BufferToType(const uint8_t *data, size_t size, /* out */ std::unordered_map<K, V> &map) 172{ 173 size_t backup_size = 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 = map.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 backup_size - size; 208} 209 210namespace internal { 211 212class Serializer { 213public: 214 // NOLINTNEXTLINE(google-runtime-references) 215 explicit Serializer(std::vector<uint8_t> &buffer) : buffer_(buffer) {} 216 217 template <typename T> 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 228private: 229 std::vector<uint8_t> &buffer_; 230}; 231 232class Deserializer { 233public: 234 Deserializer(const uint8_t *data, size_t size) : data_(data), size_(size) {} 235 236 bool IsError() const 237 { 238 return error_ != nullptr; 239 } 240 241 const char *GetError() const 242 { 243 return error_; 244 } 245 246 size_t GetEndPosition() const 247 { 248 return pos_; 249 } 250 251 template <typename T> 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 273private: 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 282template <size_t N, typename Struct> 283bool StructToBuffer(Struct &&str, /* out */ std::vector<uint8_t> &buffer) // NOLINT(google-runtime-references) 284{ 285 internal::ForEachTuple(internal::StructToTuple<N>(std::forward<Struct>(str)), internal::Serializer(buffer)); 286 return true; 287} 288 289template <size_t N, typename Struct> 290Expected<size_t, const char *> RawBufferToStruct(const uint8_t *data, size_t size, /* out */ Struct &str) 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 str = std::move(internal::TupleToStruct<S>(tuple)); 303 return deserializer.GetEndPosition(); 304} 305 306template <size_t N, typename Struct> 307bool BufferToStruct(const uint8_t *data, size_t size, /* out */ Struct &str) 308{ 309 auto r = RawBufferToStruct<N>(data, size, str); 310 if (!r) { 311 return false; 312 } 313 return r.Value() == size; 314} 315 316template <size_t N, typename Struct> 317bool BufferToStruct(const std::vector<uint8_t> &buffer, /* out */ Struct &str) 318{ 319 return BufferToStruct<N>(buffer.data(), buffer.size(), str); 320} 321 322} // namespace panda::serializer 323 324#endif // LIBPANDABASE_SERIALIZER_SERIALIZER_H 325