2017-03-07 09:32:29 +00:00
|
|
|
#pragma once
|
|
|
|
|
2018-01-15 16:57:47 +00:00
|
|
|
#include "port.h"
|
|
|
|
|
2017-12-29 16:29:10 +00:00
|
|
|
#include <macro_map.h>
|
|
|
|
#include <optional.h>
|
|
|
|
#include <variant.h>
|
|
|
|
|
2018-01-11 07:16:33 +00:00
|
|
|
#include <cassert>
|
2017-06-14 04:00:51 +00:00
|
|
|
#include <memory>
|
2017-03-14 08:33:39 +00:00
|
|
|
#include <string>
|
2018-01-11 07:16:33 +00:00
|
|
|
#include <type_traits>
|
2017-06-14 04:00:51 +00:00
|
|
|
#include <vector>
|
2017-02-23 08:47:07 +00:00
|
|
|
|
2018-01-06 23:29:53 +00:00
|
|
|
enum class SerializeFormat { Json, MessagePack };
|
|
|
|
|
2018-01-06 21:46:41 +00:00
|
|
|
class Reader {
|
|
|
|
public:
|
|
|
|
virtual ~Reader() {}
|
2018-01-07 00:22:46 +00:00
|
|
|
virtual SerializeFormat Format() const = 0;
|
2018-01-06 21:46:41 +00:00
|
|
|
|
2018-01-11 02:43:01 +00:00
|
|
|
// virtual bool IsBool() = 0;
|
2018-01-06 21:46:41 +00:00
|
|
|
virtual bool IsNull() = 0;
|
|
|
|
virtual bool IsArray() = 0;
|
|
|
|
virtual bool IsInt() = 0;
|
2018-01-11 07:16:33 +00:00
|
|
|
virtual bool IsInt64() = 0;
|
2018-01-11 02:43:01 +00:00
|
|
|
// virtual bool IsUint64() = 0;
|
2018-01-06 21:46:41 +00:00
|
|
|
virtual bool IsString() = 0;
|
|
|
|
|
2018-01-08 04:10:16 +00:00
|
|
|
virtual void GetNull() = 0;
|
2018-01-06 21:46:41 +00:00
|
|
|
virtual bool GetBool() = 0;
|
|
|
|
virtual int GetInt() = 0;
|
|
|
|
virtual int64_t GetInt64() = 0;
|
|
|
|
virtual uint64_t GetUint64() = 0;
|
2018-01-10 06:34:58 +00:00
|
|
|
virtual double GetDouble() = 0;
|
2018-01-07 05:08:25 +00:00
|
|
|
virtual std::string GetString() = 0;
|
2018-01-06 21:46:41 +00:00
|
|
|
|
|
|
|
virtual bool HasMember(const char* x) = 0;
|
|
|
|
virtual std::unique_ptr<Reader> operator[](const char* x) = 0;
|
|
|
|
|
|
|
|
virtual void IterArray(std::function<void(Reader&)> fn) = 0;
|
|
|
|
virtual void DoMember(const char* name, std::function<void(Reader&)> fn) = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
class Writer {
|
|
|
|
public:
|
|
|
|
virtual ~Writer() {}
|
2018-01-07 00:22:46 +00:00
|
|
|
virtual SerializeFormat Format() const = 0;
|
2018-01-06 21:46:41 +00:00
|
|
|
|
|
|
|
virtual void Null() = 0;
|
|
|
|
virtual void Bool(bool x) = 0;
|
2018-01-06 22:59:05 +00:00
|
|
|
virtual void Int(int x) = 0;
|
|
|
|
virtual void Int64(int64_t x) = 0;
|
2018-01-06 21:46:41 +00:00
|
|
|
virtual void Uint64(uint64_t x) = 0;
|
2018-01-10 06:34:58 +00:00
|
|
|
virtual void Double(double x) = 0;
|
2018-01-06 21:46:41 +00:00
|
|
|
virtual void String(const char* x) = 0;
|
|
|
|
virtual void String(const char* x, size_t len) = 0;
|
2018-01-07 00:22:46 +00:00
|
|
|
virtual void StartArray(size_t) = 0;
|
2018-01-06 21:46:41 +00:00
|
|
|
virtual void EndArray() = 0;
|
2018-01-08 04:10:16 +00:00
|
|
|
virtual void StartObject() = 0;
|
2018-01-06 21:46:41 +00:00
|
|
|
virtual void EndObject() = 0;
|
|
|
|
virtual void Key(const char* name) = 0;
|
|
|
|
};
|
|
|
|
|
2017-05-12 06:08:15 +00:00
|
|
|
struct IndexFile;
|
2017-02-23 08:47:07 +00:00
|
|
|
|
2018-01-11 02:43:01 +00:00
|
|
|
#define REFLECT_MEMBER_START() \
|
|
|
|
if (!ReflectMemberStart(visitor, value)) \
|
|
|
|
return
|
|
|
|
#define REFLECT_MEMBER_START1(value) \
|
|
|
|
if (!ReflectMemberStart(visitor, value)) \
|
|
|
|
return
|
2017-09-22 01:14:57 +00:00
|
|
|
#define REFLECT_MEMBER_END() ReflectMemberEnd(visitor, value);
|
|
|
|
#define REFLECT_MEMBER_END1(value) ReflectMemberEnd(visitor, value);
|
|
|
|
#define REFLECT_MEMBER(name) ReflectMember(visitor, #name, value.name)
|
|
|
|
#define REFLECT_MEMBER2(name, value) ReflectMember(visitor, name, value)
|
|
|
|
|
2018-01-15 16:57:47 +00:00
|
|
|
// TODO Make it inline because this macro can be used in header files.
|
|
|
|
#define MAKE_REFLECT_TYPE_PROXY(type, as_type) \
|
|
|
|
ATTRIBUTE_UNUSED inline void Reflect(Reader& visitor, type& value) { \
|
|
|
|
as_type value0; \
|
|
|
|
::Reflect(visitor, value0); \
|
|
|
|
value = static_cast<type>(value0); \
|
|
|
|
} \
|
|
|
|
inline void Reflect(Writer& visitor, type& value) { \
|
|
|
|
auto value0 = static_cast<as_type>(value); \
|
|
|
|
::Reflect(visitor, value0); \
|
2017-03-25 22:13:19 +00:00
|
|
|
}
|
|
|
|
|
2017-09-22 01:14:57 +00:00
|
|
|
#define _MAPPABLE_REFLECT_MEMBER(name) REFLECT_MEMBER(name);
|
2017-03-25 23:58:11 +00:00
|
|
|
|
2017-09-22 01:14:57 +00:00
|
|
|
#define MAKE_REFLECT_EMPTY_STRUCT(type, ...) \
|
|
|
|
template <typename TVisitor> \
|
2017-03-25 23:58:11 +00:00
|
|
|
void Reflect(TVisitor& visitor, type& value) { \
|
2018-01-08 04:10:16 +00:00
|
|
|
REFLECT_MEMBER_START(); \
|
2017-09-22 01:14:57 +00:00
|
|
|
REFLECT_MEMBER_END(); \
|
2017-03-25 23:58:11 +00:00
|
|
|
}
|
|
|
|
|
2017-09-22 01:14:57 +00:00
|
|
|
#define MAKE_REFLECT_STRUCT(type, ...) \
|
|
|
|
template <typename TVisitor> \
|
|
|
|
void Reflect(TVisitor& visitor, type& value) { \
|
2018-01-08 04:10:16 +00:00
|
|
|
REFLECT_MEMBER_START(); \
|
2017-03-25 23:58:11 +00:00
|
|
|
MACRO_MAP(_MAPPABLE_REFLECT_MEMBER, __VA_ARGS__) \
|
2017-09-22 01:14:57 +00:00
|
|
|
REFLECT_MEMBER_END(); \
|
2017-03-25 23:58:11 +00:00
|
|
|
}
|
|
|
|
|
2018-01-08 04:10:16 +00:00
|
|
|
// clang-format off
|
|
|
|
// Config has many fields, we need to support at least its number of fields.
|
|
|
|
#define NUM_VA_ARGS_IMPL(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,_25,_26,_27,_28,_29,_30,N,...) N
|
|
|
|
#define NUM_VA_ARGS(...) NUM_VA_ARGS_IMPL(__VA_ARGS__,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1)
|
|
|
|
// clang-format on
|
|
|
|
|
2017-09-22 01:14:57 +00:00
|
|
|
#define _MAPPABLE_REFLECT_ARRAY(name) Reflect(visitor, value.name);
|
2017-05-20 19:31:07 +00:00
|
|
|
|
|
|
|
// Reflects the struct so it is serialized as an array instead of an object.
|
|
|
|
// This currently only supports writers.
|
2018-01-11 02:43:01 +00:00
|
|
|
#define MAKE_REFLECT_STRUCT_WRITER_AS_ARRAY(type, ...) \
|
|
|
|
inline void Reflect(Writer& visitor, type& value) { \
|
|
|
|
visitor.StartArray(NUM_VA_ARGS(__VA_ARGS__)); \
|
|
|
|
MACRO_MAP(_MAPPABLE_REFLECT_ARRAY, __VA_ARGS__) \
|
|
|
|
visitor.EndArray(); \
|
2017-05-20 19:31:07 +00:00
|
|
|
}
|
2017-03-25 23:58:11 +00:00
|
|
|
|
2017-03-07 09:32:29 +00:00
|
|
|
// API:
|
|
|
|
/*
|
|
|
|
template<typename TVisitor, typename T>
|
|
|
|
void Reflect(TVisitor& visitor, T& value) {
|
|
|
|
static_assert(false, "Missing implementation");
|
|
|
|
}
|
|
|
|
template<typename TVisitor>
|
|
|
|
void DefaultReflectMemberStart(TVisitor& visitor) {
|
|
|
|
static_assert(false, "Missing implementation");
|
|
|
|
}
|
|
|
|
template<typename TVisitor, typename T>
|
|
|
|
bool ReflectMemberStart(TVisitor& visitor, T& value) {
|
|
|
|
static_assert(false, "Missing implementation");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
template<typename TVisitor, typename T>
|
|
|
|
void ReflectMemberEnd(TVisitor& visitor, T& value) {
|
|
|
|
static_assert(false, "Missing implementation");
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
2018-01-11 08:07:51 +00:00
|
|
|
//// Elementary types
|
|
|
|
|
2018-01-08 00:06:01 +00:00
|
|
|
void Reflect(Reader& visitor, uint8_t& value);
|
|
|
|
void Reflect(Writer& visitor, uint8_t& value);
|
2018-01-11 08:07:51 +00:00
|
|
|
|
2017-05-19 07:02:01 +00:00
|
|
|
void Reflect(Reader& visitor, int16_t& value);
|
|
|
|
void Reflect(Writer& visitor, int16_t& value);
|
2018-01-11 08:07:51 +00:00
|
|
|
|
2017-05-19 07:02:01 +00:00
|
|
|
void Reflect(Reader& visitor, int32_t& value);
|
|
|
|
void Reflect(Writer& visitor, int32_t& value);
|
2018-01-11 08:07:51 +00:00
|
|
|
|
2017-04-20 04:57:44 +00:00
|
|
|
void Reflect(Reader& visitor, int64_t& value);
|
|
|
|
void Reflect(Writer& visitor, int64_t& value);
|
2018-01-11 08:07:51 +00:00
|
|
|
|
2017-05-19 07:02:01 +00:00
|
|
|
void Reflect(Reader& visitor, uint64_t& value);
|
|
|
|
void Reflect(Writer& visitor, uint64_t& value);
|
2018-01-11 08:07:51 +00:00
|
|
|
|
2018-01-10 06:34:58 +00:00
|
|
|
void Reflect(Reader& visitor, double& value);
|
|
|
|
void Reflect(Writer& visitor, double& value);
|
2018-01-11 08:07:51 +00:00
|
|
|
|
2017-03-07 18:01:23 +00:00
|
|
|
void Reflect(Reader& visitor, bool& value);
|
|
|
|
void Reflect(Writer& visitor, bool& value);
|
2018-01-06 19:26:37 +00:00
|
|
|
|
2017-03-07 18:01:23 +00:00
|
|
|
void Reflect(Reader& visitor, std::string& value);
|
|
|
|
void Reflect(Writer& visitor, std::string& value);
|
|
|
|
|
2018-01-11 08:07:51 +00:00
|
|
|
// std::monostate is used to represent JSON null
|
2018-01-10 07:57:33 +00:00
|
|
|
void Reflect(Reader& visitor, std::monostate&);
|
|
|
|
void Reflect(Writer& visitor, std::monostate&);
|
|
|
|
|
|
|
|
void Reflect(Reader& visitor, SerializeFormat& value);
|
|
|
|
void Reflect(Writer& visitor, SerializeFormat& value);
|
|
|
|
|
2018-01-11 08:07:51 +00:00
|
|
|
//// Type constructors
|
|
|
|
|
2018-01-11 08:31:47 +00:00
|
|
|
// ReflectMember optional<T> is used to represent TypeScript optional properties
|
|
|
|
// (in `key: value` context).
|
|
|
|
// Reflect optional<T> is used for a different purpose, whether an object is
|
|
|
|
// nullable (possibly in `value` context). For the nullable semantics,
|
|
|
|
// std::variant<std::monostate, T> is recommended.
|
2017-09-22 01:14:57 +00:00
|
|
|
template <typename T>
|
2018-01-06 19:26:37 +00:00
|
|
|
void Reflect(Reader& visitor, optional<T>& value) {
|
2018-01-08 04:10:16 +00:00
|
|
|
if (visitor.IsNull()) {
|
|
|
|
visitor.GetNull();
|
2018-01-06 19:26:37 +00:00
|
|
|
return;
|
2018-01-08 04:10:16 +00:00
|
|
|
}
|
2018-01-11 08:31:47 +00:00
|
|
|
T real_value;
|
2018-01-06 19:26:37 +00:00
|
|
|
Reflect(visitor, real_value);
|
|
|
|
value = real_value;
|
2017-03-07 09:32:29 +00:00
|
|
|
}
|
2017-09-22 01:14:57 +00:00
|
|
|
template <typename T>
|
2017-12-28 23:21:40 +00:00
|
|
|
void Reflect(Writer& visitor, optional<T>& value) {
|
2017-03-07 09:32:29 +00:00
|
|
|
if (value)
|
2018-01-07 05:08:25 +00:00
|
|
|
Reflect(visitor, *value);
|
2018-01-11 08:31:47 +00:00
|
|
|
else
|
2018-01-07 05:08:25 +00:00
|
|
|
visitor.Null();
|
2017-03-07 09:32:29 +00:00
|
|
|
}
|
2018-01-11 08:31:47 +00:00
|
|
|
template <typename T>
|
|
|
|
void ReflectMember(Writer& visitor, const char* name, optional<T>& value) {
|
|
|
|
// For TypeScript optional property key?: value in the spec,
|
|
|
|
// We omit both key and value if value is std::nullopt (null) for JsonWriter
|
|
|
|
// to reduce output. But keep it for other serialization formats.
|
|
|
|
if (value || visitor.Format() != SerializeFormat::Json) {
|
|
|
|
visitor.Key(name);
|
|
|
|
Reflect(visitor, value);
|
|
|
|
}
|
|
|
|
}
|
2018-01-06 19:26:37 +00:00
|
|
|
|
2018-01-11 08:07:51 +00:00
|
|
|
// Backport C++17 std::disjunction
|
2018-01-11 07:16:33 +00:00
|
|
|
namespace {
|
|
|
|
template <typename B0, typename... Bs>
|
|
|
|
struct disjunction
|
|
|
|
: std::conditional<bool(B0::value), B0, disjunction<Bs...>>::type {};
|
|
|
|
template <typename B0>
|
|
|
|
struct disjunction<B0> : B0 {};
|
|
|
|
}
|
|
|
|
|
2018-01-11 08:07:51 +00:00
|
|
|
// Helper struct to reflect std::variant
|
2018-01-10 06:34:58 +00:00
|
|
|
template <size_t N, typename... Ts>
|
|
|
|
struct ReflectVariant {
|
2018-01-11 08:07:51 +00:00
|
|
|
// If T appears in Ts..., we should set the value of std::variant<Ts...> to
|
|
|
|
// what we get from Reader.
|
2018-01-11 07:16:33 +00:00
|
|
|
template <typename T>
|
|
|
|
typename std::enable_if<disjunction<std::is_same<T, Ts>...>::value,
|
|
|
|
void>::type
|
|
|
|
ReflectTag(Reader& visitor, std::variant<Ts...>& value) {
|
|
|
|
T a;
|
|
|
|
Reflect(visitor, a);
|
|
|
|
value = a;
|
|
|
|
}
|
2018-01-11 08:07:51 +00:00
|
|
|
// This SFINAE overload is used to prevent compile error. value = a; is not
|
|
|
|
// allowed if T does not appear in Ts...
|
2018-01-11 07:16:33 +00:00
|
|
|
template <typename T>
|
|
|
|
typename std::enable_if<!disjunction<std::is_same<T, Ts>...>::value,
|
|
|
|
void>::type
|
|
|
|
ReflectTag(Reader&, std::variant<Ts...>&) {}
|
|
|
|
|
|
|
|
void operator()(Reader& visitor, std::variant<Ts...>& value) {
|
2018-01-11 08:07:51 +00:00
|
|
|
// Based on tag dispatch, call different ReflectTag helper.
|
2018-01-11 07:16:33 +00:00
|
|
|
if (visitor.IsNull())
|
|
|
|
ReflectTag<std::monostate>(visitor, value);
|
|
|
|
// It is possible that IsInt64() && IsInt(). We don't call ReflectTag<int> if
|
|
|
|
// int is not in Ts...
|
|
|
|
else if (disjunction<std::is_same<int, Ts>...>::value && visitor.IsInt())
|
|
|
|
ReflectTag<int>(visitor, value);
|
|
|
|
else if (visitor.IsInt64())
|
|
|
|
ReflectTag<int64_t>(visitor, value);
|
|
|
|
else if (visitor.IsString())
|
|
|
|
ReflectTag<std::string>(visitor, value);
|
|
|
|
else
|
|
|
|
assert(0);
|
|
|
|
}
|
|
|
|
|
2018-01-11 08:07:51 +00:00
|
|
|
// Check which type the variant contains and call corresponding Reflect.
|
2018-01-10 06:34:58 +00:00
|
|
|
void operator()(Writer& visitor, std::variant<Ts...>& value) {
|
|
|
|
if (value.index() == N - 1)
|
|
|
|
Reflect(visitor, std::get<N - 1>(value));
|
|
|
|
else
|
|
|
|
ReflectVariant<N - 1, Ts...>()(visitor, value);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-01-11 08:31:47 +00:00
|
|
|
// Writer reflection on std::variant recurses. This is induction basis.
|
2018-01-10 06:34:58 +00:00
|
|
|
template <typename... Ts>
|
2018-01-11 07:16:33 +00:00
|
|
|
struct ReflectVariant<0, Ts...> {
|
|
|
|
void operator()(Writer& visitor, std::variant<Ts...>& value) {}
|
2018-01-10 06:34:58 +00:00
|
|
|
};
|
|
|
|
|
2018-01-11 07:16:33 +00:00
|
|
|
// std::variant
|
|
|
|
template <typename TVisitor, typename... Ts>
|
|
|
|
void Reflect(TVisitor& visitor, std::variant<Ts...>& value) {
|
2018-01-10 06:34:58 +00:00
|
|
|
ReflectVariant<sizeof...(Ts), Ts...>()(visitor, value);
|
2017-12-28 23:21:40 +00:00
|
|
|
}
|
2018-01-06 19:26:37 +00:00
|
|
|
|
|
|
|
// std::vector
|
|
|
|
template <typename T>
|
|
|
|
void Reflect(Reader& visitor, std::vector<T>& values) {
|
2018-01-06 21:46:41 +00:00
|
|
|
visitor.IterArray([&](Reader& entry) {
|
2018-01-06 19:26:37 +00:00
|
|
|
T entry_value;
|
|
|
|
Reflect(entry, entry_value);
|
|
|
|
values.push_back(entry_value);
|
2018-01-06 21:46:41 +00:00
|
|
|
});
|
2018-01-06 19:26:37 +00:00
|
|
|
}
|
|
|
|
template <typename T>
|
|
|
|
void Reflect(Writer& visitor, std::vector<T>& values) {
|
2018-01-07 00:22:46 +00:00
|
|
|
visitor.StartArray(values.size());
|
2018-01-06 19:26:37 +00:00
|
|
|
for (auto& value : values)
|
|
|
|
Reflect(visitor, value);
|
|
|
|
visitor.EndArray();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Writer:
|
|
|
|
|
2018-01-08 04:10:16 +00:00
|
|
|
inline void DefaultReflectMemberStart(Writer& visitor) {
|
|
|
|
visitor.StartObject();
|
2017-03-07 09:32:29 +00:00
|
|
|
}
|
2017-09-22 01:14:57 +00:00
|
|
|
template <typename T>
|
2018-01-08 04:10:16 +00:00
|
|
|
bool ReflectMemberStart(Writer& visitor, T& value) {
|
|
|
|
visitor.StartObject();
|
2017-03-07 09:32:29 +00:00
|
|
|
return true;
|
|
|
|
}
|
2017-09-22 01:14:57 +00:00
|
|
|
template <typename T>
|
2017-03-07 09:32:29 +00:00
|
|
|
void ReflectMemberEnd(Writer& visitor, T& value) {
|
|
|
|
visitor.EndObject();
|
|
|
|
}
|
2017-09-22 01:14:57 +00:00
|
|
|
template <typename T>
|
2017-03-07 09:32:29 +00:00
|
|
|
void ReflectMember(Writer& visitor, const char* name, T& value) {
|
|
|
|
visitor.Key(name);
|
|
|
|
Reflect(visitor, value);
|
|
|
|
}
|
2017-03-08 08:09:15 +00:00
|
|
|
void ReflectMember(Writer& visitor, const char* name, std::string& value);
|
2017-03-01 08:36:11 +00:00
|
|
|
|
2017-03-07 09:32:29 +00:00
|
|
|
// Reader:
|
2018-01-06 19:26:37 +00:00
|
|
|
|
2018-01-08 04:10:16 +00:00
|
|
|
inline void DefaultReflectMemberStart(Reader& visitor) {}
|
2017-09-22 01:14:57 +00:00
|
|
|
template <typename T>
|
2018-01-08 04:10:16 +00:00
|
|
|
bool ReflectMemberStart(Reader& visitor, T& value) {
|
2017-03-07 09:32:29 +00:00
|
|
|
return true;
|
|
|
|
}
|
2017-09-22 01:14:57 +00:00
|
|
|
template <typename T>
|
2017-03-07 09:32:29 +00:00
|
|
|
void ReflectMemberEnd(Reader& visitor, T& value) {}
|
2017-09-22 01:14:57 +00:00
|
|
|
template <typename T>
|
2017-03-07 09:32:29 +00:00
|
|
|
void ReflectMember(Reader& visitor, const char* name, T& value) {
|
2018-01-06 21:46:41 +00:00
|
|
|
visitor.DoMember(name, [&](Reader& child) { Reflect(child, value); });
|
2017-03-01 08:36:11 +00:00
|
|
|
}
|
|
|
|
|
2018-01-09 06:22:24 +00:00
|
|
|
// API
|
2018-01-07 02:56:15 +00:00
|
|
|
|
2018-01-07 02:01:32 +00:00
|
|
|
std::string Serialize(SerializeFormat format, IndexFile& file);
|
2018-01-06 23:29:53 +00:00
|
|
|
std::unique_ptr<IndexFile> Deserialize(SerializeFormat format,
|
|
|
|
std::string path,
|
2017-09-22 01:14:57 +00:00
|
|
|
std::string serialized,
|
|
|
|
optional<int> expected_version);
|
2017-04-20 06:02:24 +00:00
|
|
|
|
2017-07-30 04:46:21 +00:00
|
|
|
void SetTestOutputMode();
|