298 lines
8.6 KiB
C++
298 lines
8.6 KiB
C++
//
|
|
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2022
|
|
//
|
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|
//
|
|
#pragma once
|
|
|
|
#include "td/utils/common.h"
|
|
#include "td/utils/FlatHashSet.h"
|
|
#include "td/utils/misc.h"
|
|
#include "td/utils/SharedSlice.h"
|
|
#include "td/utils/Slice.h"
|
|
#include "td/utils/SliceBuilder.h"
|
|
#include "td/utils/StackAllocator.h"
|
|
#include "td/utils/Status.h"
|
|
#include "td/utils/tl_parsers.h"
|
|
#include "td/utils/tl_storers.h"
|
|
#include "td/utils/Variant.h"
|
|
|
|
#include <type_traits>
|
|
#include <utility>
|
|
|
|
#define BEGIN_STORE_FLAGS() \
|
|
do { \
|
|
::td::uint32 flags_store = 0; \
|
|
::td::uint32 bit_offset_store = 0
|
|
|
|
#define STORE_FLAG(flag) \
|
|
static_assert(std::is_same<decltype(flag), bool>::value, "flag must be bool"); \
|
|
flags_store |= (flag) << bit_offset_store; \
|
|
bit_offset_store++
|
|
|
|
#define END_STORE_FLAGS() \
|
|
CHECK(bit_offset_store < 31); \
|
|
::td::store(flags_store, storer); \
|
|
} \
|
|
while (false)
|
|
|
|
#define BEGIN_PARSE_FLAGS() \
|
|
do { \
|
|
::td::uint32 flags_parse; \
|
|
::td::uint32 bit_offset_parse = 0; \
|
|
::td::parse(flags_parse, parser)
|
|
|
|
#define PARSE_FLAG(flag) \
|
|
static_assert(std::is_same<decltype(flag), bool>::value, "flag must be bool"); \
|
|
flag = ((flags_parse >> bit_offset_parse) & 1) != 0; \
|
|
bit_offset_parse++
|
|
|
|
#define END_PARSE_FLAGS() \
|
|
CHECK(bit_offset_parse < 31); \
|
|
if ((flags_parse & ~((1 << bit_offset_parse) - 1)) != 0) { \
|
|
parser.set_error(PSTRING() << "Invalid flags " << flags_parse << " left, current bit is " << bit_offset_parse); \
|
|
} \
|
|
} \
|
|
while (false)
|
|
|
|
namespace td {
|
|
|
|
template <class StorerT>
|
|
void store(bool x, StorerT &storer) {
|
|
storer.store_binary(static_cast<int32>(x));
|
|
}
|
|
template <class ParserT>
|
|
void parse(bool &x, ParserT &parser) {
|
|
x = parser.fetch_int() != 0;
|
|
}
|
|
|
|
template <class StorerT>
|
|
void store(int32 x, StorerT &storer) {
|
|
storer.store_binary(x);
|
|
}
|
|
template <class ParserT>
|
|
void parse(int32 &x, ParserT &parser) {
|
|
x = parser.fetch_int();
|
|
}
|
|
|
|
template <class StorerT>
|
|
void store(uint32 x, StorerT &storer) {
|
|
storer.store_binary(x);
|
|
}
|
|
template <class ParserT>
|
|
void parse(uint32 &x, ParserT &parser) {
|
|
x = static_cast<uint32>(parser.fetch_int());
|
|
}
|
|
|
|
template <class StorerT>
|
|
void store(int64 x, StorerT &storer) {
|
|
storer.store_binary(x);
|
|
}
|
|
template <class ParserT>
|
|
void parse(int64 &x, ParserT &parser) {
|
|
x = parser.fetch_long();
|
|
}
|
|
template <class StorerT>
|
|
void store(uint64 x, StorerT &storer) {
|
|
storer.store_binary(x);
|
|
}
|
|
template <class ParserT>
|
|
void parse(uint64 &x, ParserT &parser) {
|
|
x = static_cast<uint64>(parser.fetch_long());
|
|
}
|
|
|
|
template <class StorerT>
|
|
void store(double x, StorerT &storer) {
|
|
storer.store_binary(x);
|
|
}
|
|
template <class ParserT>
|
|
void parse(double &x, ParserT &parser) {
|
|
x = parser.fetch_double();
|
|
}
|
|
|
|
template <class StorerT>
|
|
void store(Slice x, StorerT &storer) {
|
|
storer.store_string(x);
|
|
}
|
|
template <class StorerT>
|
|
void store(const string &x, StorerT &storer) {
|
|
storer.store_string(x);
|
|
}
|
|
template <class StorerT>
|
|
void store(const SecureString &x, StorerT &storer) {
|
|
storer.store_string(x.as_slice());
|
|
}
|
|
template <class ParserT>
|
|
void parse(string &x, ParserT &parser) {
|
|
x = parser.template fetch_string<string>();
|
|
}
|
|
|
|
template <class ParserT>
|
|
void parse(SecureString &x, ParserT &parser) {
|
|
x = parser.template fetch_string<SecureString>();
|
|
}
|
|
|
|
template <class T, class StorerT>
|
|
void store(const vector<T> &vec, StorerT &storer) {
|
|
storer.store_binary(narrow_cast<int32>(vec.size()));
|
|
for (auto &val : vec) {
|
|
store(val, storer);
|
|
}
|
|
}
|
|
template <class T, class StorerT>
|
|
void store(const vector<T *> &vec, StorerT &storer) {
|
|
storer.store_binary(narrow_cast<int32>(vec.size()));
|
|
for (auto &val : vec) {
|
|
store(*val, storer);
|
|
}
|
|
}
|
|
template <class T, class ParserT>
|
|
void parse(vector<T> &vec, ParserT &parser) {
|
|
uint32 size = parser.fetch_int();
|
|
if (parser.get_left_len() < size) {
|
|
parser.set_error("Wrong vector length");
|
|
return;
|
|
}
|
|
vec = vector<T>(size);
|
|
for (auto &val : vec) {
|
|
parse(val, parser);
|
|
}
|
|
}
|
|
|
|
template <class T, class StorerT>
|
|
void store(const unique_ptr<T> &ptr, StorerT &storer) {
|
|
CHECK(ptr != nullptr);
|
|
store(*ptr, storer);
|
|
}
|
|
template <class T, class ParserT>
|
|
void parse(unique_ptr<T> &ptr, ParserT &parser) {
|
|
CHECK(ptr == nullptr);
|
|
ptr = make_unique<T>();
|
|
parse(*ptr, parser);
|
|
}
|
|
|
|
template <class Key, class Hash, class KeyEqual, class StorerT>
|
|
void store(const FlatHashSet<Key, Hash, KeyEqual> &s, StorerT &storer) {
|
|
storer.store_binary(narrow_cast<int32>(s.size()));
|
|
for (auto &val : s) {
|
|
store(val, storer);
|
|
}
|
|
}
|
|
template <class Key, class Hash, class KeyEqual, class ParserT>
|
|
void parse(FlatHashSet<Key, Hash, KeyEqual> &s, ParserT &parser) {
|
|
uint32 size = parser.fetch_int();
|
|
if (parser.get_left_len() < size) {
|
|
parser.set_error("Wrong set length");
|
|
return;
|
|
}
|
|
s.clear();
|
|
for (uint32 i = 0; i < size; i++) {
|
|
Key val;
|
|
parse(val, parser);
|
|
s.insert(std::move(val));
|
|
}
|
|
}
|
|
|
|
template <class U, class V, class StorerT>
|
|
void store(const std::pair<U, V> &pair, StorerT &storer) {
|
|
store(pair.first, storer);
|
|
store(pair.second, storer);
|
|
}
|
|
template <class U, class V, class ParserT>
|
|
void parse(std::pair<U, V> &pair, ParserT &parser) {
|
|
parse(pair.first, parser);
|
|
parse(pair.second, parser);
|
|
}
|
|
|
|
template <class T, class StorerT>
|
|
std::enable_if_t<std::is_enum<T>::value> store(const T &val, StorerT &storer) {
|
|
store(static_cast<int32>(val), storer);
|
|
}
|
|
template <class T, class ParserT>
|
|
std::enable_if_t<std::is_enum<T>::value> parse(T &val, ParserT &parser) {
|
|
int32 result;
|
|
parse(result, parser);
|
|
val = static_cast<T>(result);
|
|
}
|
|
|
|
template <class T, class StorerT>
|
|
std::enable_if_t<!std::is_enum<T>::value> store(const T &val, StorerT &storer) {
|
|
val.store(storer);
|
|
}
|
|
template <class T, class ParserT>
|
|
std::enable_if_t<!std::is_enum<T>::value> parse(T &val, ParserT &parser) {
|
|
val.parse(parser);
|
|
}
|
|
|
|
template <class... Types, class StorerT>
|
|
void store(const Variant<Types...> &variant, StorerT &storer) {
|
|
store(variant.get_offset(), storer);
|
|
variant.visit([&storer](auto &&value) {
|
|
using td::store;
|
|
store(value, storer);
|
|
});
|
|
}
|
|
template <class... Types, class ParserT>
|
|
void parse(Variant<Types...> &variant, ParserT &parser) {
|
|
auto type_offset = parser.fetch_int();
|
|
if (type_offset < 0 || type_offset >= static_cast<int32>(sizeof...(Types))) {
|
|
return parser.set_error("Invalid type");
|
|
}
|
|
variant.for_each([type_offset, &parser, &variant](int offset, auto *ptr) {
|
|
using T = std::decay_t<decltype(*ptr)>;
|
|
if (offset == type_offset) {
|
|
variant = T();
|
|
parse(variant.template get<T>(), parser);
|
|
}
|
|
});
|
|
}
|
|
|
|
template <class T>
|
|
string serialize(const T &object) {
|
|
TlStorerCalcLength calc_length;
|
|
store(object, calc_length);
|
|
size_t length = calc_length.get_length();
|
|
|
|
string key(length, '\0');
|
|
if (!is_aligned_pointer<4>(key.data())) {
|
|
auto ptr = StackAllocator::alloc(length);
|
|
MutableSlice data = ptr.as_slice();
|
|
TlStorerUnsafe storer(data.ubegin());
|
|
store(object, storer);
|
|
CHECK(storer.get_buf() == data.uend());
|
|
key.assign(data.begin(), data.size());
|
|
} else {
|
|
MutableSlice data = key;
|
|
TlStorerUnsafe storer(data.ubegin());
|
|
store(object, storer);
|
|
CHECK(storer.get_buf() == data.uend());
|
|
}
|
|
return key;
|
|
}
|
|
|
|
template <class T>
|
|
SecureString serialize_secure(const T &object) {
|
|
TlStorerCalcLength calc_length;
|
|
store(object, calc_length);
|
|
size_t length = calc_length.get_length();
|
|
|
|
SecureString key(length, '\0');
|
|
CHECK(is_aligned_pointer<4>(key.data()));
|
|
MutableSlice data = key.as_mutable_slice();
|
|
TlStorerUnsafe storer(data.ubegin());
|
|
store(object, storer);
|
|
CHECK(storer.get_buf() == data.uend());
|
|
return key;
|
|
}
|
|
|
|
template <class T>
|
|
TD_WARN_UNUSED_RESULT Status unserialize(T &object, Slice data) {
|
|
TlParser parser(data);
|
|
parse(object, parser);
|
|
parser.fetch_end();
|
|
return parser.get_status();
|
|
}
|
|
|
|
} // namespace td
|