// Copyright 2017-2018 ccls Authors // SPDX-License-Identifier: Apache-2.0 #pragma once #include "maybe.hh" #include #include #include #include #include #include #include #include #include #include namespace llvm { class CachedHashStringRef; class StringRef; } namespace ccls { enum class SerializeFormat { Binary, Json }; struct JsonNull {}; class Reader { public: virtual ~Reader(); virtual SerializeFormat Format() const = 0; virtual bool IsBool() = 0; virtual bool IsNull() = 0; virtual bool IsInt() = 0; virtual bool IsInt64() = 0; virtual bool IsUInt64() = 0; virtual bool IsDouble() = 0; virtual bool IsString() = 0; virtual void GetNull() = 0; virtual bool GetBool() = 0; virtual uint8_t GetUInt8() = 0; virtual int GetInt() = 0; virtual uint32_t GetUInt32() = 0; virtual int64_t GetInt64() = 0; virtual uint64_t GetUInt64() = 0; virtual double GetDouble() = 0; virtual const char *GetString() = 0; virtual bool HasMember(const char *x) = 0; virtual std::unique_ptr operator[](const char *x) = 0; virtual void IterArray(std::function fn) = 0; virtual void Member(const char *name, std::function fn) = 0; }; class Writer { public: virtual ~Writer(); virtual SerializeFormat Format() const = 0; virtual void Null() = 0; virtual void Bool(bool x) = 0; virtual void Int(int x) = 0; virtual void Int64(int64_t x) = 0; virtual void UInt8(uint8_t x) = 0; virtual void UInt32(uint32_t x) = 0; virtual void UInt64(uint64_t x) = 0; virtual void Double(double x) = 0; virtual void String(const char *x) = 0; virtual void String(const char *x, size_t len) = 0; virtual void StartArray(size_t) = 0; virtual void EndArray() = 0; virtual void StartObject() = 0; virtual void EndObject() = 0; virtual void Key(const char *name) = 0; }; struct IndexFile; #define REFLECT_MEMBER_START() ReflectMemberStart(vis) #define REFLECT_MEMBER_END() ReflectMemberEnd(vis); #define REFLECT_MEMBER(name) ReflectMember(vis, #name, v.name) #define REFLECT_MEMBER2(name, v) ReflectMember(vis, name, v) #define MAKE_REFLECT_TYPE_PROXY(type_name) \ MAKE_REFLECT_TYPE_PROXY2(type_name, std::underlying_type_t) #define MAKE_REFLECT_TYPE_PROXY2(type, as_type) \ LLVM_ATTRIBUTE_UNUSED inline void Reflect(Reader &vis, type &v) { \ as_type value0; \ ::ccls::Reflect(vis, value0); \ v = static_cast(value0); \ } \ LLVM_ATTRIBUTE_UNUSED inline void Reflect(Writer &vis, type &v) { \ auto value0 = static_cast(v); \ ::ccls::Reflect(vis, value0); \ } #define _MAPPABLE_REFLECT_MEMBER(name) REFLECT_MEMBER(name); #define MAKE_REFLECT_EMPTY_STRUCT(type, ...) \ template void Reflect(TVisitor &vis, type &v) { \ REFLECT_MEMBER_START(); \ REFLECT_MEMBER_END(); \ } #define MAKE_REFLECT_STRUCT(type, ...) \ template void Reflect(TVisitor &vis, type &v) { \ REFLECT_MEMBER_START(); \ MACRO_MAP(_MAPPABLE_REFLECT_MEMBER, __VA_ARGS__) \ REFLECT_MEMBER_END(); \ } // 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 #define _MAPPABLE_REFLECT_ARRAY(name) Reflect(vis, v.name); // Reflects the struct so it is serialized as an array instead of an object. // This currently only supports writers. #define MAKE_REFLECT_STRUCT_WRITER_AS_ARRAY(type, ...) \ inline void Reflect(Writer &vis, type &v) { \ vis.StartArray(NUM_VA_ARGS(__VA_ARGS__)); \ MACRO_MAP(_MAPPABLE_REFLECT_ARRAY, __VA_ARGS__) \ vis.EndArray(); \ } //// Elementary types void Reflect(Reader &vis, uint8_t &v); void Reflect(Writer &vis, uint8_t &v); void Reflect(Reader &vis, short &v); void Reflect(Writer &vis, short &v); void Reflect(Reader &vis, unsigned short &v); void Reflect(Writer &vis, unsigned short &v); void Reflect(Reader &vis, int &v); void Reflect(Writer &vis, int &v); void Reflect(Reader &vis, unsigned &v); void Reflect(Writer &vis, unsigned &v); void Reflect(Reader &vis, long &v); void Reflect(Writer &vis, long &v); void Reflect(Reader &vis, unsigned long &v); void Reflect(Writer &vis, unsigned long &v); void Reflect(Reader &vis, long long &v); void Reflect(Writer &vis, long long &v); void Reflect(Reader &vis, unsigned long long &v); void Reflect(Writer &vis, unsigned long long &v); void Reflect(Reader &vis, double &v); void Reflect(Writer &vis, double &v); void Reflect(Reader &vis, bool &v); void Reflect(Writer &vis, bool &v); void Reflect(Reader &vis, std::string &v); void Reflect(Writer &vis, std::string &v); void Reflect(Reader &vis, std::string_view &v); void Reflect(Writer &vis, std::string_view &v); void Reflect(Reader &vis, const char *&v); void Reflect(Writer &vis, const char *&v); void Reflect(Reader &vis, JsonNull &v); void Reflect(Writer &vis, JsonNull &v); void Reflect(Reader &vis, SerializeFormat &v); void Reflect(Writer &vis, SerializeFormat &v); //// Type constructors // ReflectMember std::optional is used to represent TypeScript optional // properties (in `key: value` context). Reflect std::optional is used for a // different purpose, whether an object is nullable (possibly in `value` // context). template void Reflect(Reader &vis, std::optional &v) { if (vis.IsNull()) { vis.GetNull(); return; } T val; Reflect(vis, val); v = std::move(val); } template void Reflect(Writer &vis, std::optional &v) { if (v) { if (vis.Format() != SerializeFormat::Json) vis.UInt8(1); Reflect(vis, *v); } else vis.Null(); } // The same as std::optional template void Reflect(Reader &vis, Maybe &v) { if (vis.IsNull()) { vis.GetNull(); return; } T val; Reflect(vis, val); v = std::move(val); } template void Reflect(Writer &vis, Maybe &v) { if (v) { if (vis.Format() != SerializeFormat::Json) vis.UInt8(1); Reflect(vis, *v); } else vis.Null(); } template void ReflectMember(Writer &vis, const char *name, std::optional &v) { // For TypeScript std::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 (v || vis.Format() != SerializeFormat::Json) { vis.Key(name); Reflect(vis, v); } } // The same as std::optional template void ReflectMember(Writer &vis, const char *name, Maybe &v) { if (v.Valid() || vis.Format() != SerializeFormat::Json) { vis.Key(name); Reflect(vis, v); } } template void Reflect(Reader &vis, std::pair &v) { vis.Member("L", [&]() { Reflect(vis, v.first); }); vis.Member("R", [&]() { Reflect(vis, v.second); }); } template void Reflect(Writer &vis, std::pair &v) { vis.StartObject(); ReflectMember(vis, "L", v.first); ReflectMember(vis, "R", v.second); vis.EndObject(); } // std::vector template void Reflect(Reader &vis, std::vector &vs) { vis.IterArray([&](Reader &entry) { T entry_value; Reflect(entry, entry_value); vs.push_back(std::move(entry_value)); }); } template void Reflect(Writer &vis, std::vector &vs) { vis.StartArray(vs.size()); for (auto &v : vs) Reflect(vis, v); vis.EndArray(); } // ReflectMember inline bool ReflectMemberStart(Reader &vis) { return false; } inline bool ReflectMemberStart(Writer &vis) { vis.StartObject(); return true; } inline void ReflectMemberEnd(Reader &vis) {} inline void ReflectMemberEnd(Writer &vis) { vis.EndObject(); } template void ReflectMember(Reader &vis, const char *name, T &v) { vis.Member(name, [&]() { Reflect(vis, v); }); } template void ReflectMember(Writer &vis, const char *name, T &v) { vis.Key(name); Reflect(vis, v); } // API const char *Intern(llvm::StringRef str); llvm::CachedHashStringRef InternH(llvm::StringRef str); std::string Serialize(SerializeFormat format, IndexFile &file); std::unique_ptr Deserialize(SerializeFormat format, const std::string &path, const std::string &serialized_index_content, const std::string &file_content, std::optional expected_version); } // namespace ccls