From 04e80544b985c16a81b3b7bf3237b5551af564d0 Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Sun, 2 Dec 2018 15:53:33 -0800 Subject: [PATCH] Refactor serializer Delete virtual bases Reader & Writer Delete unused MAKE_REFLECT_STRUCT_WRITER_AS_ARRAY Merge serializers/{json,binary}.hh into serializer.{hh,cc} MAKE_REFLECT_STRUCT => REFLECT_STRUCT MAKE_REFLECT_TYPE_PROXY => REFLECT_UNDERLYING --- src/config.hh | 24 +- src/indexer.cc | 154 ++++--- src/indexer.hh | 28 +- src/lsp.cc | 31 +- src/lsp.hh | 11 +- src/main.cc | 2 +- src/message_handler.cc | 76 ++-- src/message_handler.hh | 76 ++-- src/messages/ccls_call.cc | 12 +- src/messages/ccls_info.cc | 12 +- src/messages/ccls_inheritance.cc | 10 +- src/messages/ccls_member.cc | 10 +- src/messages/ccls_navigate.cc | 5 +- src/messages/ccls_reload.cc | 4 +- src/messages/ccls_vars.cc | 4 +- src/messages/initialize.cc | 95 ++--- src/messages/textDocument_code.cc | 14 +- src/messages/textDocument_completion.cc | 12 +- src/messages/textDocument_document.cc | 18 +- src/messages/textDocument_foldingRange.cc | 4 +- src/messages/textDocument_hover.cc | 8 +- src/messages/textDocument_references.cc | 9 +- src/messages/textDocument_signatureHelp.cc | 7 +- src/messages/workspace.cc | 2 +- src/pipeline.cc | 15 +- src/pipeline.hh | 10 +- src/position.cc | 71 ++-- src/position.hh | 19 +- src/project.cc | 1 - src/query.cc | 3 +- src/serializer.cc | 392 ++++++++++-------- src/serializer.hh | 453 +++++++++++++-------- src/serializers/binary.hh | 139 ------- src/serializers/json.hh | 120 ------ 34 files changed, 875 insertions(+), 976 deletions(-) delete mode 100644 src/serializers/binary.hh delete mode 100644 src/serializers/json.hh diff --git a/src/config.hh b/src/config.hh index 1185697f..b0f5ff4f 100644 --- a/src/config.hh +++ b/src/config.hh @@ -259,28 +259,28 @@ struct Config { int maxNum = 2000; } xref; }; -MAKE_REFLECT_STRUCT(Config::Clang, excludeArgs, extraArgs, pathMappings, +REFLECT_STRUCT(Config::Clang, excludeArgs, extraArgs, pathMappings, resourceDir); -MAKE_REFLECT_STRUCT(Config::ClientCapability, hierarchicalDocumentSymbolSupport, +REFLECT_STRUCT(Config::ClientCapability, hierarchicalDocumentSymbolSupport, snippetSupport); -MAKE_REFLECT_STRUCT(Config::CodeLens, localVariables); -MAKE_REFLECT_STRUCT(Config::Completion::Include, blacklist, maxPathSize, +REFLECT_STRUCT(Config::CodeLens, localVariables); +REFLECT_STRUCT(Config::Completion::Include, blacklist, maxPathSize, suffixWhitelist, whitelist); -MAKE_REFLECT_STRUCT(Config::Completion, caseSensitivity, detailedLabel, +REFLECT_STRUCT(Config::Completion, caseSensitivity, detailedLabel, dropOldRequests, duplicateOptional, filterAndSort, include, maxNum); -MAKE_REFLECT_STRUCT(Config::Diagnostics, blacklist, onChange, onOpen, onSave, +REFLECT_STRUCT(Config::Diagnostics, blacklist, onChange, onOpen, onSave, spellChecking, whitelist) -MAKE_REFLECT_STRUCT(Config::Highlight, largeFileSize, lsRanges, blacklist, +REFLECT_STRUCT(Config::Highlight, largeFileSize, lsRanges, blacklist, whitelist) -MAKE_REFLECT_STRUCT(Config::Index, blacklist, comments, initialBlacklist, +REFLECT_STRUCT(Config::Index, blacklist, comments, initialBlacklist, initialWhitelist, multiVersion, multiVersionBlacklist, multiVersionWhitelist, onChange, threads, trackDependency, whitelist); -MAKE_REFLECT_STRUCT(Config::Session, maxNum); -MAKE_REFLECT_STRUCT(Config::WorkspaceSymbol, caseSensitivity, maxNum, sort); -MAKE_REFLECT_STRUCT(Config::Xref, maxNum); -MAKE_REFLECT_STRUCT(Config, compilationDatabaseCommand, +REFLECT_STRUCT(Config::Session, maxNum); +REFLECT_STRUCT(Config::WorkspaceSymbol, caseSensitivity, maxNum, sort); +REFLECT_STRUCT(Config::Xref, maxNum); +REFLECT_STRUCT(Config, compilationDatabaseCommand, compilationDatabaseDirectory, cacheDirectory, cacheFormat, clang, client, codeLens, completion, diagnostics, highlight, index, session, workspaceSymbol, xref); diff --git a/src/indexer.cc b/src/indexer.cc index ea9f3ca4..584dd20a 100644 --- a/src/indexer.cc +++ b/src/indexer.cc @@ -20,7 +20,6 @@ limitations under the License. #include "pipeline.hh" #include "platform.hh" #include "sema_manager.hh" -#include "serializer.hh" #include #include @@ -1185,7 +1184,7 @@ public: } // namespace const int IndexFile::kMajorVersion = 19; -const int IndexFile::kMinorVersion = 0; +const int IndexFile::kMinorVersion = 1; IndexFile::IndexFile(llvm::sys::fs::UniqueID UniqueID, const std::string &path, const std::string &contents) @@ -1377,90 +1376,85 @@ Index(SemaManager *manager, WorkingFiles *wfiles, VFS *vfs, } } // namespace idx -void Reflect(Reader &vis, SymbolRef &v) { - if (vis.Format() == SerializeFormat::Json) { - std::string t = vis.GetString(); - char *s = const_cast(t.c_str()); - v.range = Range::FromString(s); - s = strchr(s, '|'); - v.usr = strtoull(s + 1, &s, 10); - v.kind = static_cast(strtol(s + 1, &s, 10)); - v.role = static_cast(strtol(s + 1, &s, 10)); - } else { - Reflect(vis, v.range); - Reflect(vis, v.usr); - Reflect(vis, v.kind); - Reflect(vis, v.role); - } +void Reflect(JsonReader &vis, SymbolRef &v) { + std::string t = vis.GetString(); + char *s = const_cast(t.c_str()); + v.range = Range::FromString(s); + s = strchr(s, '|'); + v.usr = strtoull(s + 1, &s, 10); + v.kind = static_cast(strtol(s + 1, &s, 10)); + v.role = static_cast(strtol(s + 1, &s, 10)); } -void Reflect(Writer &vis, SymbolRef &v) { - if (vis.Format() == SerializeFormat::Json) { - char buf[99]; - snprintf(buf, sizeof buf, "%s|%" PRIu64 "|%d|%d", - v.range.ToString().c_str(), v.usr, int(v.kind), int(v.role)); - std::string s(buf); - Reflect(vis, s); - } else { - Reflect(vis, v.range); - Reflect(vis, v.usr); - Reflect(vis, v.kind); - Reflect(vis, v.role); - } +void Reflect(JsonReader &vis, Use &v) { + std::string t = vis.GetString(); + char *s = const_cast(t.c_str()); + v.range = Range::FromString(s); + s = strchr(s, '|'); + v.role = static_cast(strtol(s + 1, &s, 10)); + v.file_id = static_cast(strtol(s + 1, &s, 10)); +} +void Reflect(JsonReader &vis, DeclRef &v) { + std::string t = vis.GetString(); + char *s = const_cast(t.c_str()); + v.range = Range::FromString(s); + s = strchr(s, '|') + 1; + v.extent = Range::FromString(s); + s = strchr(s, '|'); + v.role = static_cast(strtol(s + 1, &s, 10)); + v.file_id = static_cast(strtol(s + 1, &s, 10)); } -void Reflect(Reader &vis, Use &v) { - if (vis.Format() == SerializeFormat::Json) { - std::string t = vis.GetString(); - char *s = const_cast(t.c_str()); - v.range = Range::FromString(s); - s = strchr(s, '|'); - v.role = static_cast(strtol(s + 1, &s, 10)); - v.file_id = static_cast(strtol(s + 1, &s, 10)); - } else { - Reflect(vis, v.range); - Reflect(vis, v.role); - Reflect(vis, v.file_id); - } +void Reflect(JsonWriter &vis, SymbolRef &v) { + char buf[99]; + snprintf(buf, sizeof buf, "%s|%" PRIu64 "|%d|%d", v.range.ToString().c_str(), + v.usr, int(v.kind), int(v.role)); + std::string s(buf); + Reflect(vis, s); } -void Reflect(Writer &vis, Use &v) { - if (vis.Format() == SerializeFormat::Json) { - char buf[99]; - snprintf(buf, sizeof buf, "%s|%d|%d", v.range.ToString().c_str(), - int(v.role), v.file_id); - std::string s(buf); - Reflect(vis, s); - } else { - Reflect(vis, v.range); - Reflect(vis, v.role); - Reflect(vis, v.file_id); - } +void Reflect(JsonWriter &vis, Use &v) { + char buf[99]; + snprintf(buf, sizeof buf, "%s|%d|%d", v.range.ToString().c_str(), int(v.role), + v.file_id); + std::string s(buf); + Reflect(vis, s); +} +void Reflect(JsonWriter &vis, DeclRef &v) { + char buf[99]; + snprintf(buf, sizeof buf, "%s|%s|%d|%d", v.range.ToString().c_str(), + v.extent.ToString().c_str(), int(v.role), v.file_id); + std::string s(buf); + Reflect(vis, s); } -void Reflect(Reader &vis, DeclRef &v) { - if (vis.Format() == SerializeFormat::Json) { - std::string t = vis.GetString(); - char *s = const_cast(t.c_str()); - v.range = Range::FromString(s); - s = strchr(s, '|') + 1; - v.extent = Range::FromString(s); - s = strchr(s, '|'); - v.role = static_cast(strtol(s + 1, &s, 10)); - v.file_id = static_cast(strtol(s + 1, &s, 10)); - } else { - Reflect(vis, static_cast(v)); - Reflect(vis, v.extent); - } +void Reflect(BinaryReader &vis, SymbolRef &v) { + Reflect(vis, v.range); + Reflect(vis, v.usr); + Reflect(vis, v.kind); + Reflect(vis, v.role); } -void Reflect(Writer &vis, DeclRef &v) { - if (vis.Format() == SerializeFormat::Json) { - char buf[99]; - snprintf(buf, sizeof buf, "%s|%s|%d|%d", v.range.ToString().c_str(), - v.extent.ToString().c_str(), int(v.role), v.file_id); - std::string s(buf); - Reflect(vis, s); - } else { - Reflect(vis, static_cast(v)); - Reflect(vis, v.extent); - } +void Reflect(BinaryReader &vis, Use &v) { + Reflect(vis, v.range); + Reflect(vis, v.role); + Reflect(vis, v.file_id); +} +void Reflect(BinaryReader &vis, DeclRef &v) { + Reflect(vis, static_cast(v)); + Reflect(vis, v.extent); +} + +void Reflect(BinaryWriter &vis, SymbolRef &v) { + Reflect(vis, v.range); + Reflect(vis, v.usr); + Reflect(vis, v.kind); + Reflect(vis, v.role); +} +void Reflect(BinaryWriter &vis, Use &v) { + Reflect(vis, v.range); + Reflect(vis, v.role); + Reflect(vis, v.file_id); +} +void Reflect(BinaryWriter &vis, DeclRef &v) { + Reflect(vis, static_cast(v)); + Reflect(vis, v.extent); } } // namespace ccls diff --git a/src/indexer.hh b/src/indexer.hh index 8e55f666..88598510 100644 --- a/src/indexer.hh +++ b/src/indexer.hh @@ -46,7 +46,7 @@ using Usr = uint64_t; // The order matters. In FindSymbolsAtLocation, we want Var/Func ordered in // front of others. enum class Kind : uint8_t { Invalid, File, Type, Func, Var }; -MAKE_REFLECT_TYPE_PROXY(Kind); +REFLECT_UNDERLYING_B(Kind); enum class Role : uint16_t { None = 0, @@ -61,7 +61,7 @@ enum class Role : uint16_t { Implicit = 1 << 8, All = (1 << 9) - 1, }; -MAKE_REFLECT_TYPE_PROXY(Role); +REFLECT_UNDERLYING_B(Role); inline uint16_t operator&(Role lhs, Role rhs) { return uint16_t(lhs) & uint16_t(rhs); } @@ -130,12 +130,18 @@ struct DeclRef : Use { Range extent; }; -void Reflect(Reader &visitor, SymbolRef &value); -void Reflect(Writer &visitor, SymbolRef &value); -void Reflect(Reader &visitor, Use &value); -void Reflect(Writer &visitor, Use &value); -void Reflect(Reader &visitor, DeclRef &value); -void Reflect(Writer &visitor, DeclRef &value); +void Reflect(JsonReader &visitor, SymbolRef &value); +void Reflect(JsonReader &visitor, Use &value); +void Reflect(JsonReader &visitor, DeclRef &value); +void Reflect(JsonWriter &visitor, SymbolRef &value); +void Reflect(JsonWriter &visitor, Use &value); +void Reflect(JsonWriter &visitor, DeclRef &value); +void Reflect(BinaryReader &visitor, SymbolRef &value); +void Reflect(BinaryReader &visitor, Use &value); +void Reflect(BinaryReader &visitor, DeclRef &value); +void Reflect(BinaryWriter &visitor, SymbolRef &value); +void Reflect(BinaryWriter &visitor, Use &value); +void Reflect(BinaryWriter &visitor, DeclRef &value); template struct NameMixin { std::string_view Name(bool qualified) const { @@ -174,7 +180,7 @@ struct FuncDef : NameMixin { std::vector GetBases() const { return bases; } }; -MAKE_REFLECT_STRUCT(FuncDef, detailed_name, hover, comments, spell, bases, vars, +REFLECT_STRUCT(FuncDef, detailed_name, hover, comments, spell, bases, vars, callees, qual_name_offset, short_name_offset, short_name_size, kind, parent_kind, storage); @@ -211,7 +217,7 @@ struct TypeDef : NameMixin { std::vector GetBases() const { return bases; } }; -MAKE_REFLECT_STRUCT(TypeDef, detailed_name, hover, comments, spell, bases, +REFLECT_STRUCT(TypeDef, detailed_name, hover, comments, spell, bases, funcs, types, vars, alias_of, qual_name_offset, short_name_offset, short_name_size, kind, parent_kind); @@ -255,7 +261,7 @@ struct VarDef : NameMixin { std::vector GetBases() const { return {}; } }; -MAKE_REFLECT_STRUCT(VarDef, detailed_name, hover, comments, spell, type, +REFLECT_STRUCT(VarDef, detailed_name, hover, comments, spell, type, qual_name_offset, short_name_offset, short_name_size, kind, parent_kind, storage); diff --git a/src/lsp.cc b/src/lsp.cc index 3a95a9d8..caf7eec8 100644 --- a/src/lsp.cc +++ b/src/lsp.cc @@ -16,29 +16,30 @@ limitations under the License. #include "lsp.hh" #include "log.hh" -#include "serializers/json.hh" + +#include #include #include namespace ccls { -void Reflect(Reader &visitor, RequestId &value) { - if (visitor.IsInt64()) { - value.type = RequestId::kInt; - value.value = int(visitor.GetInt64()); - } else if (visitor.IsInt()) { - value.type = RequestId::kInt; - value.value = visitor.GetInt(); - } else if (visitor.IsString()) { - value.type = RequestId::kString; - value.value = atoll(visitor.GetString()); +void Reflect(JsonReader &vis, RequestId &v) { + if (vis.m->IsInt64()) { + v.type = RequestId::kInt; + v.value = int(vis.m->GetInt64()); + } else if (vis.m->IsInt()) { + v.type = RequestId::kInt; + v.value = vis.m->GetInt(); + } else if (vis.m->IsString()) { + v.type = RequestId::kString; + v.value = atoll(vis.m->GetString()); } else { - value.type = RequestId::kNone; - value.value = -1; + v.type = RequestId::kNone; + v.value = -1; } } -void Reflect(Writer &visitor, RequestId &value) { +void Reflect(JsonWriter &visitor, RequestId &value) { switch (value.type) { case RequestId::kNone: visitor.Null(); @@ -48,7 +49,7 @@ void Reflect(Writer &visitor, RequestId &value) { break; case RequestId::kString: auto s = std::to_string(value.value); - visitor.String(s.c_str(), s.length()); + visitor.String(s.c_str(), s.size()); break; } } diff --git a/src/lsp.hh b/src/lsp.hh index 9677aea5..fecf9da2 100644 --- a/src/lsp.hh +++ b/src/lsp.hh @@ -35,8 +35,8 @@ struct RequestId { bool Valid() const { return type != kNone; } }; -void Reflect(Reader &visitor, RequestId &value); -void Reflect(Writer &visitor, RequestId &value); +void Reflect(JsonReader &visitor, RequestId &value); +void Reflect(JsonWriter &visitor, RequestId &value); struct InMessage { RequestId id; @@ -80,11 +80,6 @@ struct DocumentUri { std::string raw_uri; }; -template -void Reflect(TVisitor &visitor, DocumentUri &value) { - Reflect(visitor, value.raw_uri); -} - struct Position { int line = 0; int character = 0; @@ -220,7 +215,7 @@ struct WorkspaceFolder { }; enum class MessageType : int { Error = 1, Warning = 2, Info = 3, Log = 4 }; -MAKE_REFLECT_TYPE_PROXY(MessageType) +REFLECT_UNDERLYING(MessageType) struct Diagnostic { lsRange range; diff --git a/src/main.cc b/src/main.cc index 8dc5f95f..9a4ea630 100644 --- a/src/main.cc +++ b/src/main.cc @@ -17,7 +17,6 @@ limitations under the License. #include "pipeline.hh" #include "platform.hh" #include "serializer.hh" -#include "serializers/json.hh" #include "test.hh" #include "working_files.hh" @@ -29,6 +28,7 @@ limitations under the License. #include #include +#include #include #include diff --git a/src/message_handler.cc b/src/message_handler.cc index e7f25d2c..238baf0b 100644 --- a/src/message_handler.cc +++ b/src/message_handler.cc @@ -19,7 +19,9 @@ limitations under the License. #include "pipeline.hh" #include "project.hh" #include "query.hh" -#include "serializers/json.hh" + +#include +#include #include #include @@ -29,35 +31,35 @@ using namespace clang; MAKE_HASHABLE(ccls::SymbolIdx, t.usr, t.kind); namespace ccls { -MAKE_REFLECT_STRUCT(CodeActionParam::Context, diagnostics); -MAKE_REFLECT_STRUCT(CodeActionParam, textDocument, range, context); -void Reflect(Reader &, EmptyParam &) {} -MAKE_REFLECT_STRUCT(TextDocumentParam, textDocument); -MAKE_REFLECT_STRUCT(DidOpenTextDocumentParam, textDocument); -MAKE_REFLECT_STRUCT(TextDocumentContentChangeEvent, range, rangeLength, text); -MAKE_REFLECT_STRUCT(TextDocumentDidChangeParam, textDocument, contentChanges); -MAKE_REFLECT_STRUCT(TextDocumentPositionParam, textDocument, position); -MAKE_REFLECT_STRUCT(RenameParam, textDocument, position, newName); +REFLECT_STRUCT(CodeActionParam::Context, diagnostics); +REFLECT_STRUCT(CodeActionParam, textDocument, range, context); +void Reflect(JsonReader &, EmptyParam &) {} +REFLECT_STRUCT(TextDocumentParam, textDocument); +REFLECT_STRUCT(DidOpenTextDocumentParam, textDocument); +REFLECT_STRUCT(TextDocumentContentChangeEvent, range, rangeLength, text); +REFLECT_STRUCT(TextDocumentDidChangeParam, textDocument, contentChanges); +REFLECT_STRUCT(TextDocumentPositionParam, textDocument, position); +REFLECT_STRUCT(RenameParam, textDocument, position, newName); // completion -MAKE_REFLECT_TYPE_PROXY(CompletionTriggerKind); -MAKE_REFLECT_STRUCT(CompletionContext, triggerKind, triggerCharacter); -MAKE_REFLECT_STRUCT(CompletionParam, textDocument, position, context); +REFLECT_UNDERLYING(CompletionTriggerKind); +REFLECT_STRUCT(CompletionContext, triggerKind, triggerCharacter); +REFLECT_STRUCT(CompletionParam, textDocument, position, context); // formatting -MAKE_REFLECT_STRUCT(FormattingOptions, tabSize, insertSpaces); -MAKE_REFLECT_STRUCT(DocumentFormattingParam, textDocument, options); -MAKE_REFLECT_STRUCT(DocumentOnTypeFormattingParam, textDocument, position, - ch, options); -MAKE_REFLECT_STRUCT(DocumentRangeFormattingParam, textDocument, range, options); +REFLECT_STRUCT(FormattingOptions, tabSize, insertSpaces); +REFLECT_STRUCT(DocumentFormattingParam, textDocument, options); +REFLECT_STRUCT(DocumentOnTypeFormattingParam, textDocument, position, ch, + options); +REFLECT_STRUCT(DocumentRangeFormattingParam, textDocument, range, options); // workspace -MAKE_REFLECT_TYPE_PROXY(FileChangeType); -MAKE_REFLECT_STRUCT(DidChangeWatchedFilesParam::Event, uri, type); -MAKE_REFLECT_STRUCT(DidChangeWatchedFilesParam, changes); -MAKE_REFLECT_STRUCT(DidChangeWorkspaceFoldersParam::Event, added, removed); -MAKE_REFLECT_STRUCT(DidChangeWorkspaceFoldersParam, event); -MAKE_REFLECT_STRUCT(WorkspaceSymbolParam, query, folders); +REFLECT_UNDERLYING(FileChangeType); +REFLECT_STRUCT(DidChangeWatchedFilesParam::Event, uri, type); +REFLECT_STRUCT(DidChangeWatchedFilesParam, changes); +REFLECT_STRUCT(DidChangeWorkspaceFoldersParam::Event, added, removed); +REFLECT_STRUCT(DidChangeWorkspaceFoldersParam, event); +REFLECT_STRUCT(WorkspaceSymbolParam, query, folders); namespace { struct CclsSemanticHighlightSymbol { @@ -75,15 +77,15 @@ struct CclsSemanticHighlight { DocumentUri uri; std::vector symbols; }; -MAKE_REFLECT_STRUCT(CclsSemanticHighlightSymbol, id, parentKind, kind, storage, - ranges, lsRanges); -MAKE_REFLECT_STRUCT(CclsSemanticHighlight, uri, symbols); +REFLECT_STRUCT(CclsSemanticHighlightSymbol, id, parentKind, kind, storage, + ranges, lsRanges); +REFLECT_STRUCT(CclsSemanticHighlight, uri, symbols); struct CclsSetSkippedRanges { DocumentUri uri; std::vector skippedRanges; }; -MAKE_REFLECT_STRUCT(CclsSetSkippedRanges, uri, skippedRanges); +REFLECT_STRUCT(CclsSetSkippedRanges, uri, skippedRanges); struct ScanLineEvent { Position pos; @@ -114,8 +116,9 @@ void ReplyOnce::NotReady(bool file) { Error(ErrorCode::InternalError, "not indexed"); } -void MessageHandler::Bind(const char *method, void (MessageHandler::*handler)(Reader &)) { - method2notification[method] = [this, handler](Reader &reader) { +void MessageHandler::Bind(const char *method, + void (MessageHandler::*handler)(JsonReader &)) { + method2notification[method] = [this, handler](JsonReader &reader) { (this->*handler)(reader); }; } @@ -123,7 +126,7 @@ void MessageHandler::Bind(const char *method, void (MessageHandler::*handler)(Re template void MessageHandler::Bind(const char *method, void (MessageHandler::*handler)(Param &)) { - method2notification[method] = [this, handler](Reader &reader) { + method2notification[method] = [this, handler](JsonReader &reader) { Param param{}; Reflect(reader, param); (this->*handler)(param); @@ -131,9 +134,10 @@ void MessageHandler::Bind(const char *method, } void MessageHandler::Bind(const char *method, - void (MessageHandler::*handler)(Reader &, + void (MessageHandler::*handler)(JsonReader &, ReplyOnce &)) { - method2request[method] = [this, handler](Reader &reader, ReplyOnce &reply) { + method2request[method] = [this, handler](JsonReader &reader, + ReplyOnce &reply) { (this->*handler)(reader, reply); }; } @@ -142,7 +146,8 @@ template void MessageHandler::Bind(const char *method, void (MessageHandler::*handler)(Param &, ReplyOnce &)) { - method2request[method] = [this, handler](Reader &reader, ReplyOnce &reply) { + method2request[method] = [this, handler](JsonReader &reader, + ReplyOnce &reply) { Param param{}; Reflect(reader, param); (this->*handler)(param, reply); @@ -214,7 +219,8 @@ void MessageHandler::Run(InMessage &msg) { it->second(reader, reply); } catch (std::invalid_argument &ex) { reply.Error(ErrorCode::InvalidParams, - "invalid params of " + msg.method + ": " + ex.what()); + "invalid params of " + msg.method + ": expected " + + ex.what() + " for " + reader.GetPath()); } catch (...) { reply.Error(ErrorCode::InternalError, "failed to process " + msg.method); } diff --git a/src/message_handler.hh b/src/message_handler.hh index d60e44b0..a0b6f1ce 100644 --- a/src/message_handler.hh +++ b/src/message_handler.hh @@ -32,8 +32,8 @@ struct WorkingFile; struct WorkingFiles; namespace pipeline { -void Reply(RequestId id, const std::function &fn); -void ReplyError(RequestId id, const std::function &fn); +void Reply(RequestId id, const std::function &fn); +void ReplyError(RequestId id, const std::function &fn); } struct CodeActionParam { @@ -63,11 +63,11 @@ struct TextDocumentEdit { VersionedTextDocumentIdentifier textDocument; std::vector edits; }; -MAKE_REFLECT_STRUCT(TextDocumentEdit, textDocument, edits); +REFLECT_STRUCT(TextDocumentEdit, textDocument, edits); struct WorkspaceEdit { std::vector documentChanges; }; -MAKE_REFLECT_STRUCT(WorkspaceEdit, documentChanges); +REFLECT_STRUCT(WorkspaceEdit, documentChanges); // completion enum class CompletionTriggerKind { @@ -175,32 +175,39 @@ struct WorkspaceSymbolParam { // ccls extensions std::vector folders; }; -MAKE_REFLECT_STRUCT(WorkspaceFolder, uri, name); +REFLECT_STRUCT(WorkspaceFolder, uri, name); -MAKE_REFLECT_TYPE_PROXY(ErrorCode); -MAKE_REFLECT_STRUCT(ResponseError, code, message); -MAKE_REFLECT_STRUCT(Position, line, character); -MAKE_REFLECT_STRUCT(lsRange, start, end); -MAKE_REFLECT_STRUCT(Location, uri, range); -MAKE_REFLECT_TYPE_PROXY(SymbolKind); -MAKE_REFLECT_STRUCT(TextDocumentIdentifier, uri); -MAKE_REFLECT_STRUCT(TextDocumentItem, uri, languageId, version, text); -MAKE_REFLECT_STRUCT(TextEdit, range, newText); -MAKE_REFLECT_STRUCT(VersionedTextDocumentIdentifier, uri, version); -MAKE_REFLECT_STRUCT(Diagnostic, range, severity, code, source, message); -MAKE_REFLECT_STRUCT(ShowMessageParam, type, message); -MAKE_REFLECT_TYPE_PROXY(LanguageId); +inline void Reflect(JsonReader &visitor, DocumentUri &value) { + Reflect(visitor, value.raw_uri); +} +inline void Reflect(JsonWriter &visitor, DocumentUri &value) { + Reflect(visitor, value.raw_uri); +} + +REFLECT_UNDERLYING(ErrorCode); +REFLECT_STRUCT(ResponseError, code, message); +REFLECT_STRUCT(Position, line, character); +REFLECT_STRUCT(lsRange, start, end); +REFLECT_STRUCT(Location, uri, range); +REFLECT_UNDERLYING_B(SymbolKind); +REFLECT_STRUCT(TextDocumentIdentifier, uri); +REFLECT_STRUCT(TextDocumentItem, uri, languageId, version, text); +REFLECT_STRUCT(TextEdit, range, newText); +REFLECT_STRUCT(VersionedTextDocumentIdentifier, uri, version); +REFLECT_STRUCT(Diagnostic, range, severity, code, source, message); +REFLECT_STRUCT(ShowMessageParam, type, message); +REFLECT_UNDERLYING_B(LanguageId); struct ReplyOnce { RequestId id; template void operator()(Res &&result) const { if (id.Valid()) - pipeline::Reply(id, [&](Writer &w) { Reflect(w, result); }); + pipeline::Reply(id, [&](JsonWriter &w) { Reflect(w, result); }); } void Error(ErrorCode code, std::string message) const { ResponseError err{code, std::move(message)}; if (id.Valid()) - pipeline::ReplyError(id, [&](Writer &w) { Reflect(w, err); }); + pipeline::ReplyError(id, [&](JsonWriter &w) { Reflect(w, err); }); } void NotReady(bool file); }; @@ -213,33 +220,34 @@ struct MessageHandler { VFS *vfs = nullptr; WorkingFiles *wfiles = nullptr; - llvm::StringMap> method2notification; - llvm::StringMap> method2request; + llvm::StringMap> method2notification; + llvm::StringMap> + method2request; MessageHandler(); void Run(InMessage &msg); QueryFile *FindFile(const std::string &path, int *out_file_id = nullptr); private: - void Bind(const char *method, void (MessageHandler::*handler)(Reader &)); + void Bind(const char *method, void (MessageHandler::*handler)(JsonReader &)); template void Bind(const char *method, void (MessageHandler::*handler)(Param &)); void Bind(const char *method, - void (MessageHandler::*handler)(Reader &, ReplyOnce &)); + void (MessageHandler::*handler)(JsonReader &, ReplyOnce &)); template void Bind(const char *method, void (MessageHandler::*handler)(Param &, ReplyOnce &)); - void ccls_call(Reader &, ReplyOnce &); + void ccls_call(JsonReader &, ReplyOnce &); void ccls_fileInfo(TextDocumentParam &, ReplyOnce &); void ccls_info(EmptyParam &, ReplyOnce &); - void ccls_inheritance(Reader &, ReplyOnce &); - void ccls_member(Reader &, ReplyOnce &); - void ccls_navigate(Reader &, ReplyOnce &); - void ccls_reload(Reader &); - void ccls_vars(Reader &, ReplyOnce &); + void ccls_inheritance(JsonReader &, ReplyOnce &); + void ccls_member(JsonReader &, ReplyOnce &); + void ccls_navigate(JsonReader &, ReplyOnce &); + void ccls_reload(JsonReader &); + void ccls_vars(JsonReader &, ReplyOnce &); void exit(EmptyParam &); - void initialize(Reader &, ReplyOnce &); + void initialize(JsonReader &, ReplyOnce &); void shutdown(EmptyParam &, ReplyOnce &); void textDocument_codeAction(CodeActionParam &, ReplyOnce &); void textDocument_codeLens(TextDocumentParam &, ReplyOnce &); @@ -251,7 +259,7 @@ private: void textDocument_didSave(TextDocumentParam &); void textDocument_documentHighlight(TextDocumentPositionParam &, ReplyOnce &); void textDocument_documentLink(TextDocumentParam &, ReplyOnce &); - void textDocument_documentSymbol(Reader &, ReplyOnce &); + void textDocument_documentSymbol(JsonReader &, ReplyOnce &); void textDocument_foldingRange(TextDocumentParam &, ReplyOnce &); void textDocument_formatting(DocumentFormattingParam &, ReplyOnce &); void textDocument_hover(TextDocumentPositionParam &, ReplyOnce &); @@ -260,14 +268,14 @@ private: ReplyOnce &); void textDocument_rangeFormatting(DocumentRangeFormattingParam &, ReplyOnce &); - void textDocument_references(Reader &, ReplyOnce &); + void textDocument_references(JsonReader &, ReplyOnce &); void textDocument_rename(RenameParam &, ReplyOnce &); void textDocument_signatureHelp(TextDocumentPositionParam &, ReplyOnce &); void textDocument_typeDefinition(TextDocumentPositionParam &, ReplyOnce &); void workspace_didChangeConfiguration(EmptyParam &); void workspace_didChangeWatchedFiles(DidChangeWatchedFilesParam &); void workspace_didChangeWorkspaceFolders(DidChangeWorkspaceFoldersParam &); - void workspace_executeCommand(Reader &, ReplyOnce &); + void workspace_executeCommand(JsonReader &, ReplyOnce &); void workspace_symbol(WorkspaceSymbolParam &, ReplyOnce &); }; diff --git a/src/messages/ccls_call.cc b/src/messages/ccls_call.cc index f1e07b74..5a0e6d8e 100644 --- a/src/messages/ccls_call.cc +++ b/src/messages/ccls_call.cc @@ -30,7 +30,7 @@ enum class CallType : uint8_t { Derived = 2, All = 1 | 2 }; -MAKE_REFLECT_TYPE_PROXY(CallType); +REFLECT_UNDERLYING(CallType); bool operator&(CallType lhs, CallType rhs) { return uint8_t(lhs) & uint8_t(rhs); @@ -52,8 +52,8 @@ struct Param : TextDocumentPositionParam { int levels = 1; bool hierarchy = false; }; -MAKE_REFLECT_STRUCT(Param, textDocument, position, id, callee, callType, - qualified, levels, hierarchy); +REFLECT_STRUCT(Param, textDocument, position, id, callee, callType, qualified, + levels, hierarchy); struct Out_cclsCall { Usr usr; @@ -69,8 +69,8 @@ struct Out_cclsCall { } bool operator<(const Out_cclsCall &o) const { return location < o.location; } }; -MAKE_REFLECT_STRUCT(Out_cclsCall, id, name, location, callType, numChildren, - children); +REFLECT_STRUCT(Out_cclsCall, id, name, location, callType, numChildren, + children); bool Expand(MessageHandler *m, Out_cclsCall *entry, bool callee, CallType call_type, bool qualified, int levels) { @@ -182,7 +182,7 @@ std::optional BuildInitial(MessageHandler *m, Usr root_usr, } } // namespace -void MessageHandler::ccls_call(Reader &reader, ReplyOnce &reply) { +void MessageHandler::ccls_call(JsonReader &reader, ReplyOnce &reply) { Param param; Reflect(reader, param); std::optional result; diff --git a/src/messages/ccls_info.cc b/src/messages/ccls_info.cc index c48dd519..9befa32f 100644 --- a/src/messages/ccls_info.cc +++ b/src/messages/ccls_info.cc @@ -19,8 +19,8 @@ limitations under the License. #include "query.hh" namespace ccls { -MAKE_REFLECT_STRUCT(QueryFile::Def, path, args, language, skipped_ranges, - dependencies); +REFLECT_STRUCT(QueryFile::Def, path, args, language, skipped_ranges, + dependencies); namespace { struct Out_cclsInfo { @@ -34,10 +34,10 @@ struct Out_cclsInfo { int entries; } project; }; -MAKE_REFLECT_STRUCT(Out_cclsInfo::DB, files, funcs, types, vars); -MAKE_REFLECT_STRUCT(Out_cclsInfo::Pipeline, pendingIndexRequests); -MAKE_REFLECT_STRUCT(Out_cclsInfo::Project, entries); -MAKE_REFLECT_STRUCT(Out_cclsInfo, db, pipeline, project); +REFLECT_STRUCT(Out_cclsInfo::DB, files, funcs, types, vars); +REFLECT_STRUCT(Out_cclsInfo::Pipeline, pendingIndexRequests); +REFLECT_STRUCT(Out_cclsInfo::Project, entries); +REFLECT_STRUCT(Out_cclsInfo, db, pipeline, project); } // namespace void MessageHandler::ccls_info(EmptyParam &, ReplyOnce &reply) { diff --git a/src/messages/ccls_inheritance.cc b/src/messages/ccls_inheritance.cc index 6be44fe4..b7520ddf 100644 --- a/src/messages/ccls_inheritance.cc +++ b/src/messages/ccls_inheritance.cc @@ -36,8 +36,8 @@ struct Param : TextDocumentPositionParam { bool hierarchy = false; }; -MAKE_REFLECT_STRUCT(Param, textDocument, position, id, kind, derived, qualified, - levels, hierarchy); +REFLECT_STRUCT(Param, textDocument, position, id, kind, derived, qualified, + levels, hierarchy); struct Out_cclsInheritance { Usr usr; @@ -51,8 +51,8 @@ struct Out_cclsInheritance { // Empty if the |levels| limit is reached. std::vector children; }; -MAKE_REFLECT_STRUCT(Out_cclsInheritance, id, kind, name, location, numChildren, - children); +REFLECT_STRUCT(Out_cclsInheritance, id, kind, name, location, numChildren, + children); bool Expand(MessageHandler *m, Out_cclsInheritance *entry, bool derived, bool qualified, int levels); @@ -165,7 +165,7 @@ void Inheritance(MessageHandler *m, Param ¶m, ReplyOnce &reply) { } } // namespace -void MessageHandler::ccls_inheritance(Reader &reader, ReplyOnce &reply) { +void MessageHandler::ccls_inheritance(JsonReader &reader, ReplyOnce &reply) { Param param; Reflect(reader, param); Inheritance(this, param, reply); diff --git a/src/messages/ccls_member.cc b/src/messages/ccls_member.cc index cae89c86..d94a3d88 100644 --- a/src/messages/ccls_member.cc +++ b/src/messages/ccls_member.cc @@ -42,8 +42,8 @@ struct Param : TextDocumentPositionParam { bool hierarchy = false; }; -MAKE_REFLECT_STRUCT(Param, textDocument, position, id, qualified, levels, kind, - hierarchy); +REFLECT_STRUCT(Param, textDocument, position, id, qualified, levels, kind, + hierarchy); struct Out_cclsMember { Usr usr; @@ -57,8 +57,8 @@ struct Out_cclsMember { // Empty if the |levels| limit is reached. std::vector children; }; -MAKE_REFLECT_STRUCT(Out_cclsMember, id, name, fieldName, location, numChildren, - children); +REFLECT_STRUCT(Out_cclsMember, id, name, fieldName, location, numChildren, + children); bool Expand(MessageHandler *m, Out_cclsMember *entry, bool qualified, int levels, Kind memberKind); @@ -263,7 +263,7 @@ std::optional BuildInitial(MessageHandler *m, Kind kind, } } // namespace -void MessageHandler::ccls_member(Reader &reader, ReplyOnce &reply) { +void MessageHandler::ccls_member(JsonReader &reader, ReplyOnce &reply) { Param param; Reflect(reader, param); std::optional result; diff --git a/src/messages/ccls_navigate.cc b/src/messages/ccls_navigate.cc index d097aa96..d09d57a8 100644 --- a/src/messages/ccls_navigate.cc +++ b/src/messages/ccls_navigate.cc @@ -23,7 +23,7 @@ struct Param { Position position; std::string direction; }; -MAKE_REFLECT_STRUCT(Param, textDocument, position, direction); +REFLECT_STRUCT(Param, textDocument, position, direction); Maybe FindParent(QueryFile *file, Pos pos) { Maybe parent; @@ -38,8 +38,7 @@ Maybe FindParent(QueryFile *file, Pos pos) { } } // namespace -void MessageHandler::ccls_navigate(Reader &reader, - ReplyOnce &reply) { +void MessageHandler::ccls_navigate(JsonReader &reader, ReplyOnce &reply) { Param param; Reflect(reader, param); QueryFile *file = FindFile(param.textDocument.uri.GetPath()); diff --git a/src/messages/ccls_reload.cc b/src/messages/ccls_reload.cc index 0ca2d446..3a4268c4 100644 --- a/src/messages/ccls_reload.cc +++ b/src/messages/ccls_reload.cc @@ -29,10 +29,10 @@ struct Param { std::vector whitelist; std::vector blacklist; }; -MAKE_REFLECT_STRUCT(Param, dependencies, whitelist, blacklist); +REFLECT_STRUCT(Param, dependencies, whitelist, blacklist); } // namespace -void MessageHandler::ccls_reload(Reader &reader) { +void MessageHandler::ccls_reload(JsonReader &reader) { Param param; Reflect(reader, param); // Send index requests for every file. diff --git a/src/messages/ccls_vars.cc b/src/messages/ccls_vars.cc index bf0cbbf9..03941491 100644 --- a/src/messages/ccls_vars.cc +++ b/src/messages/ccls_vars.cc @@ -25,10 +25,10 @@ struct Param : TextDocumentPositionParam { // 4: parameter unsigned kind = ~0u; }; -MAKE_REFLECT_STRUCT(Param, textDocument, position, kind); +REFLECT_STRUCT(Param, textDocument, position, kind); } // namespace -void MessageHandler::ccls_vars(Reader &reader, ReplyOnce &reply) { +void MessageHandler::ccls_vars(JsonReader &reader, ReplyOnce &reply) { Param param; Reflect(reader, param); QueryFile *file = FindFile(param.textDocument.uri.GetPath()); diff --git a/src/messages/initialize.cc b/src/messages/initialize.cc index 0f8f6ca8..474f01ed 100644 --- a/src/messages/initialize.cc +++ b/src/messages/initialize.cc @@ -21,12 +21,14 @@ limitations under the License. #include "pipeline.hh" #include "platform.hh" #include "project.hh" -#include "serializers/json.hh" #include "working_files.hh" #include #include +#include +#include + #include #include #include @@ -39,7 +41,7 @@ extern std::string g_init_options; namespace { enum class TextDocumentSyncKind { None = 0, Full = 1, Incremental = 2 }; -MAKE_REFLECT_TYPE_PROXY(TextDocumentSyncKind) +REFLECT_UNDERLYING(TextDocumentSyncKind) struct ServerCap { struct SaveOptions { @@ -104,37 +106,36 @@ struct ServerCap { } workspaceFolders; } workspace; }; -MAKE_REFLECT_STRUCT(ServerCap::CodeActionOptions, codeActionKinds); -MAKE_REFLECT_STRUCT(ServerCap::CodeLensOptions, resolveProvider); -MAKE_REFLECT_STRUCT(ServerCap::CompletionOptions, resolveProvider, - triggerCharacters); -MAKE_REFLECT_STRUCT(ServerCap::DocumentLinkOptions, resolveProvider); -MAKE_REFLECT_STRUCT(ServerCap::DocumentOnTypeFormattingOptions, - firstTriggerCharacter, moreTriggerCharacter); -MAKE_REFLECT_STRUCT(ServerCap::ExecuteCommandOptions, commands); -MAKE_REFLECT_STRUCT(ServerCap::SaveOptions, includeText); -MAKE_REFLECT_STRUCT(ServerCap::SignatureHelpOptions, triggerCharacters); -MAKE_REFLECT_STRUCT(ServerCap::TextDocumentSyncOptions, openClose, change, - willSave, willSaveWaitUntil, save); -MAKE_REFLECT_STRUCT(ServerCap::Workspace::WorkspaceFolders, supported, - changeNotifications); -MAKE_REFLECT_STRUCT(ServerCap::Workspace, workspaceFolders); -MAKE_REFLECT_STRUCT(ServerCap, textDocumentSync, hoverProvider, - completionProvider, signatureHelpProvider, - definitionProvider, implementationProvider, - typeDefinitionProvider, referencesProvider, - documentHighlightProvider, documentSymbolProvider, - workspaceSymbolProvider, codeActionProvider, - codeLensProvider, documentFormattingProvider, - documentRangeFormattingProvider, - documentOnTypeFormattingProvider, renameProvider, - documentLinkProvider, foldingRangeProvider, - executeCommandProvider, workspace); +REFLECT_STRUCT(ServerCap::CodeActionOptions, codeActionKinds); +REFLECT_STRUCT(ServerCap::CodeLensOptions, resolveProvider); +REFLECT_STRUCT(ServerCap::CompletionOptions, resolveProvider, + triggerCharacters); +REFLECT_STRUCT(ServerCap::DocumentLinkOptions, resolveProvider); +REFLECT_STRUCT(ServerCap::DocumentOnTypeFormattingOptions, + firstTriggerCharacter, moreTriggerCharacter); +REFLECT_STRUCT(ServerCap::ExecuteCommandOptions, commands); +REFLECT_STRUCT(ServerCap::SaveOptions, includeText); +REFLECT_STRUCT(ServerCap::SignatureHelpOptions, triggerCharacters); +REFLECT_STRUCT(ServerCap::TextDocumentSyncOptions, openClose, change, willSave, + willSaveWaitUntil, save); +REFLECT_STRUCT(ServerCap::Workspace::WorkspaceFolders, supported, + changeNotifications); +REFLECT_STRUCT(ServerCap::Workspace, workspaceFolders); +REFLECT_STRUCT(ServerCap, textDocumentSync, hoverProvider, completionProvider, + signatureHelpProvider, definitionProvider, + implementationProvider, typeDefinitionProvider, + referencesProvider, documentHighlightProvider, + documentSymbolProvider, workspaceSymbolProvider, + codeActionProvider, codeLensProvider, documentFormattingProvider, + documentRangeFormattingProvider, + documentOnTypeFormattingProvider, renameProvider, + documentLinkProvider, foldingRangeProvider, + executeCommandProvider, workspace); struct DynamicReg { bool dynamicRegistration = false; }; -MAKE_REFLECT_STRUCT(DynamicReg, dynamicRegistration); +REFLECT_STRUCT(DynamicReg, dynamicRegistration); // Workspace specific client capabilities. struct WorkspaceClientCap { @@ -154,10 +155,10 @@ struct WorkspaceClientCap { DynamicReg executeCommand; }; -MAKE_REFLECT_STRUCT(WorkspaceClientCap::WorkspaceEdit, documentChanges); -MAKE_REFLECT_STRUCT(WorkspaceClientCap, applyEdit, workspaceEdit, - didChangeConfiguration, didChangeWatchedFiles, symbol, - executeCommand); +REFLECT_STRUCT(WorkspaceClientCap::WorkspaceEdit, documentChanges); +REFLECT_STRUCT(WorkspaceClientCap, applyEdit, workspaceEdit, + didChangeConfiguration, didChangeWatchedFiles, symbol, + executeCommand); // Text document specific client capabilities. struct TextDocumentClientCap { @@ -178,18 +179,18 @@ struct TextDocumentClientCap { } documentSymbol; }; -MAKE_REFLECT_STRUCT(TextDocumentClientCap::Completion::CompletionItem, - snippetSupport); -MAKE_REFLECT_STRUCT(TextDocumentClientCap::Completion, completionItem); -MAKE_REFLECT_STRUCT(TextDocumentClientCap::DocumentSymbol, - hierarchicalDocumentSymbolSupport); -MAKE_REFLECT_STRUCT(TextDocumentClientCap, completion, documentSymbol); +REFLECT_STRUCT(TextDocumentClientCap::Completion::CompletionItem, + snippetSupport); +REFLECT_STRUCT(TextDocumentClientCap::Completion, completionItem); +REFLECT_STRUCT(TextDocumentClientCap::DocumentSymbol, + hierarchicalDocumentSymbolSupport); +REFLECT_STRUCT(TextDocumentClientCap, completion, documentSymbol); struct ClientCap { WorkspaceClientCap workspace; TextDocumentClientCap textDocument; }; -MAKE_REFLECT_STRUCT(ClientCap, workspace, textDocument); +REFLECT_STRUCT(ClientCap, workspace, textDocument); struct InitializeParam { // The rootUri of the workspace. Is null if no @@ -211,12 +212,12 @@ struct InitializeParam { std::vector workspaceFolders; }; -void Reflect(Reader &reader, InitializeParam::Trace &value) { - if (!reader.IsString()) { +void Reflect(JsonReader &reader, InitializeParam::Trace &value) { + if (!reader.m->IsString()) { value = InitializeParam::Trace::Off; return; } - std::string v = reader.GetString(); + std::string v = reader.m->GetString(); if (v == "off") value = InitializeParam::Trace::Off; else if (v == "messages") @@ -225,13 +226,13 @@ void Reflect(Reader &reader, InitializeParam::Trace &value) { value = InitializeParam::Trace::Verbose; } -MAKE_REFLECT_STRUCT(InitializeParam, rootUri, initializationOptions, - capabilities, trace, workspaceFolders); +REFLECT_STRUCT(InitializeParam, rootUri, initializationOptions, capabilities, + trace, workspaceFolders); struct InitializeResult { ServerCap capabilities; }; -MAKE_REFLECT_STRUCT(InitializeResult, capabilities); +REFLECT_STRUCT(InitializeResult, capabilities); void *Indexer(void *arg_) { MessageHandler *h; @@ -341,7 +342,7 @@ void Initialize(MessageHandler *m, InitializeParam ¶m, ReplyOnce &reply) { m->manager->sessions.SetCapacity(g_config->session.maxNum); } -void MessageHandler::initialize(Reader &reader, ReplyOnce &reply) { +void MessageHandler::initialize(JsonReader &reader, ReplyOnce &reply) { InitializeParam param; Reflect(reader, param); if (!param.rootUri) { diff --git a/src/messages/textDocument_code.cc b/src/messages/textDocument_code.cc index b96db1ae..4d288f03 100644 --- a/src/messages/textDocument_code.cc +++ b/src/messages/textDocument_code.cc @@ -16,10 +16,12 @@ limitations under the License. #include "message_handler.hh" #include "pipeline.hh" #include "query.hh" -#include "serializers/json.hh" #include +#include +#include + #include namespace ccls { @@ -29,7 +31,7 @@ struct CodeAction { const char *kind = "quickfix"; WorkspaceEdit edit; }; -MAKE_REFLECT_STRUCT(CodeAction, title, kind, edit); +REFLECT_STRUCT(CodeAction, title, kind, edit); } void MessageHandler::textDocument_codeAction(CodeActionParam ¶m, ReplyOnce &reply) { @@ -72,9 +74,9 @@ struct CodeLens { lsRange range; std::optional command; }; -MAKE_REFLECT_STRUCT(Cmd_xref, usr, kind, field); -MAKE_REFLECT_STRUCT(Command, title, command, arguments); -MAKE_REFLECT_STRUCT(CodeLens, range, command); +REFLECT_STRUCT(Cmd_xref, usr, kind, field); +REFLECT_STRUCT(Command, title, command, arguments); +REFLECT_STRUCT(CodeLens, range, command); template std::string ToString(T &v) { @@ -174,7 +176,7 @@ void MessageHandler::textDocument_codeLens(TextDocumentParam ¶m, reply(result); } -void MessageHandler::workspace_executeCommand(Reader &reader, +void MessageHandler::workspace_executeCommand(JsonReader &reader, ReplyOnce &reply) { Command param; Reflect(reader, param); diff --git a/src/messages/textDocument_completion.cc b/src/messages/textDocument_completion.cc index 4691189f..77116990 100644 --- a/src/messages/textDocument_completion.cc +++ b/src/messages/textDocument_completion.cc @@ -32,11 +32,11 @@ namespace ccls { using namespace clang; using namespace llvm; -MAKE_REFLECT_TYPE_PROXY(InsertTextFormat); -MAKE_REFLECT_TYPE_PROXY(CompletionItemKind); +REFLECT_UNDERLYING(InsertTextFormat); +REFLECT_UNDERLYING(CompletionItemKind); -void Reflect(Writer &vis, CompletionItem &v) { - REFLECT_MEMBER_START(); +void Reflect(JsonWriter &vis, CompletionItem &v) { + ReflectMemberStart(vis); REFLECT_MEMBER(label); REFLECT_MEMBER(kind); REFLECT_MEMBER(detail); @@ -49,7 +49,7 @@ void Reflect(Writer &vis, CompletionItem &v) { REFLECT_MEMBER(textEdit); if (v.additionalTextEdits.size()) REFLECT_MEMBER(additionalTextEdits); - REFLECT_MEMBER_END(); + ReflectMemberEnd(vis); } namespace { @@ -57,7 +57,7 @@ struct CompletionList { bool isIncomplete = false; std::vector items; }; -MAKE_REFLECT_STRUCT(CompletionList, isIncomplete, items); +REFLECT_STRUCT(CompletionList, isIncomplete, items); #if LLVM_VERSION_MAJOR < 8 void DecorateIncludePaths(const std::smatch &match, diff --git a/src/messages/textDocument_document.cc b/src/messages/textDocument_document.cc index e65a6c77..32271c2f 100644 --- a/src/messages/textDocument_document.cc +++ b/src/messages/textDocument_document.cc @@ -22,7 +22,7 @@ limitations under the License. MAKE_HASHABLE(ccls::SymbolIdx, t.usr, t.kind); namespace ccls { -MAKE_REFLECT_STRUCT(SymbolInformation, name, kind, location, containerName); +REFLECT_STRUCT(SymbolInformation, name, kind, location, containerName); namespace { struct DocumentHighlight { @@ -38,7 +38,7 @@ struct DocumentHighlight { return !(range == o.range) ? range < o.range : kind < o.kind; } }; -MAKE_REFLECT_STRUCT(DocumentHighlight, range, kind, role); +REFLECT_STRUCT(DocumentHighlight, range, kind, role); } // namespace void MessageHandler::textDocument_documentHighlight( @@ -85,7 +85,7 @@ struct DocumentLink { lsRange range; DocumentUri target; }; -MAKE_REFLECT_STRUCT(DocumentLink, range, target); +REFLECT_STRUCT(DocumentLink, range, target); } // namespace void MessageHandler::textDocument_documentLink(TextDocumentParam ¶m, @@ -118,7 +118,7 @@ struct DocumentSymbolParam : TextDocumentParam { int startLine = -1; int endLine = -1; }; -MAKE_REFLECT_STRUCT(DocumentSymbolParam, textDocument, all, startLine, endLine); +REFLECT_STRUCT(DocumentSymbolParam, textDocument, all, startLine, endLine); struct DocumentSymbol { std::string name; @@ -128,10 +128,10 @@ struct DocumentSymbol { lsRange selectionRange; std::vector> children; }; -void Reflect(Writer &vis, std::unique_ptr &v); -MAKE_REFLECT_STRUCT(DocumentSymbol, name, detail, kind, range, selectionRange, - children); -void Reflect(Writer &vis, std::unique_ptr &v) { +void Reflect(JsonWriter &vis, std::unique_ptr &v); +REFLECT_STRUCT(DocumentSymbol, name, detail, kind, range, selectionRange, + children); +void Reflect(JsonWriter &vis, std::unique_ptr &v) { Reflect(vis, *v); } @@ -159,7 +159,7 @@ void Uniquify(std::vector> &cs) { } } // namespace -void MessageHandler::textDocument_documentSymbol(Reader &reader, +void MessageHandler::textDocument_documentSymbol(JsonReader &reader, ReplyOnce &reply) { DocumentSymbolParam param; Reflect(reader, param); diff --git a/src/messages/textDocument_foldingRange.cc b/src/messages/textDocument_foldingRange.cc index 9f07b7a7..67fb0c0a 100644 --- a/src/messages/textDocument_foldingRange.cc +++ b/src/messages/textDocument_foldingRange.cc @@ -25,8 +25,8 @@ struct FoldingRange { int startLine, startCharacter, endLine, endCharacter; std::string kind = "region"; }; -MAKE_REFLECT_STRUCT(FoldingRange, startLine, startCharacter, endLine, - endCharacter, kind); +REFLECT_STRUCT(FoldingRange, startLine, startCharacter, endLine, endCharacter, + kind); } // namespace void MessageHandler::textDocument_foldingRange(TextDocumentParam ¶m, diff --git a/src/messages/textDocument_hover.cc b/src/messages/textDocument_hover.cc index eec1edfb..7a3e0341 100644 --- a/src/messages/textDocument_hover.cc +++ b/src/messages/textDocument_hover.cc @@ -27,19 +27,19 @@ struct Hover { std::optional range; }; -void Reflect(Writer &vis, MarkedString &v) { +void Reflect(JsonWriter &vis, MarkedString &v) { // If there is a language, emit a `{language:string, value:string}` object. If // not, emit a string. if (v.language) { - REFLECT_MEMBER_START(); + vis.StartObject(); REFLECT_MEMBER(language); REFLECT_MEMBER(value); - REFLECT_MEMBER_END(); + vis.EndObject(); } else { Reflect(vis, v.value); } } -MAKE_REFLECT_STRUCT(Hover, contents, range); +REFLECT_STRUCT(Hover, contents, range); const char *LanguageIdentifier(LanguageId lang) { switch (lang) { diff --git a/src/messages/textDocument_references.cc b/src/messages/textDocument_references.cc index e8f8eeb4..8c784553 100644 --- a/src/messages/textDocument_references.cc +++ b/src/messages/textDocument_references.cc @@ -36,12 +36,13 @@ struct ReferenceParam : public TextDocumentPositionParam { // Include references with all |Role| bits set. Role role = Role::None; }; -MAKE_REFLECT_STRUCT(ReferenceParam::Context, includeDeclaration); -MAKE_REFLECT_STRUCT(ReferenceParam, textDocument, position, context, folders, - base, excludeRole, role); +REFLECT_STRUCT(ReferenceParam::Context, includeDeclaration); +REFLECT_STRUCT(ReferenceParam, textDocument, position, context, folders, base, + excludeRole, role); } // namespace -void MessageHandler::textDocument_references(Reader &reader, ReplyOnce &reply) { +void MessageHandler::textDocument_references(JsonReader &reader, + ReplyOnce &reply) { ReferenceParam param; Reflect(reader, param); QueryFile *file = FindFile(param.textDocument.uri.GetPath()); diff --git a/src/messages/textDocument_signatureHelp.cc b/src/messages/textDocument_signatureHelp.cc index 21238898..b15def2a 100644 --- a/src/messages/textDocument_signatureHelp.cc +++ b/src/messages/textDocument_signatureHelp.cc @@ -36,10 +36,9 @@ struct SignatureHelp { int activeSignature = 0; int activeParameter = 0; }; -MAKE_REFLECT_STRUCT(ParameterInformation, label); -MAKE_REFLECT_STRUCT(SignatureInformation, label, documentation, parameters); -MAKE_REFLECT_STRUCT(SignatureHelp, signatures, activeSignature, - activeParameter); +REFLECT_STRUCT(ParameterInformation, label); +REFLECT_STRUCT(SignatureInformation, label, documentation, parameters); +REFLECT_STRUCT(SignatureHelp, signatures, activeSignature, activeParameter); std::string BuildOptional(const CodeCompletionString &CCS, std::vector &ls_params) { diff --git a/src/messages/workspace.cc b/src/messages/workspace.cc index d4b4da58..5661a5d6 100644 --- a/src/messages/workspace.cc +++ b/src/messages/workspace.cc @@ -30,7 +30,7 @@ limitations under the License. #include namespace ccls { -MAKE_REFLECT_STRUCT(SymbolInformation, name, kind, location, containerName); +REFLECT_STRUCT(SymbolInformation, name, kind, location, containerName); void MessageHandler::workspace_didChangeConfiguration(EmptyParam &) { for (const std::string &folder : g_config->workspaceFolders) diff --git a/src/pipeline.cc b/src/pipeline.cc index c7f8aa7c..ab6fd2e1 100644 --- a/src/pipeline.cc +++ b/src/pipeline.cc @@ -25,7 +25,6 @@ limitations under the License. #include "project.hh" #include "query.hh" #include "sema_manager.hh" -#include "serializers/json.hh" #include #include @@ -49,7 +48,7 @@ struct PublishDiagnosticParam { DocumentUri uri; std::vector diagnostics; }; -MAKE_REFLECT_STRUCT(PublishDiagnosticParam, uri, diagnostics); +REFLECT_STRUCT(PublishDiagnosticParam, uri, diagnostics); } // namespace void VFS::Clear() { @@ -457,8 +456,8 @@ void LaunchStdin() { assert(!document->HasParseError()); JsonReader reader{document.get()}; - if (!reader.HasMember("jsonrpc") || - std::string(reader["jsonrpc"]->GetString()) != "2.0") + if (!reader.m->HasMember("jsonrpc") || + std::string((*reader.m)["jsonrpc"].GetString()) != "2.0") return; RequestId id; std::string method; @@ -610,7 +609,7 @@ std::optional LoadIndexedContent(const std::string &path) { return ReadContent(GetCachePath(path)); } -void Notify(const char *method, const std::function &fn) { +void Notify(const char *method, const std::function &fn) { rapidjson::StringBuffer output; rapidjson::Writer w(output); w.StartObject(); @@ -626,7 +625,7 @@ void Notify(const char *method, const std::function &fn) { } static void Reply(RequestId id, const char *key, - const std::function &fn) { + const std::function &fn) { rapidjson::StringBuffer output; rapidjson::Writer w(output); w.StartObject(); @@ -652,11 +651,11 @@ static void Reply(RequestId id, const char *key, for_stdout->PushBack(output.GetString()); } -void Reply(RequestId id, const std::function &fn) { +void Reply(RequestId id, const std::function &fn) { Reply(id, "result", fn); } -void ReplyError(RequestId id, const std::function &fn) { +void ReplyError(RequestId id, const std::function &fn) { Reply(id, "error", fn); } } // namespace pipeline diff --git a/src/pipeline.hh b/src/pipeline.hh index c75a371f..e70d9dd8 100644 --- a/src/pipeline.hh +++ b/src/pipeline.hh @@ -51,16 +51,16 @@ void Index(const std::string &path, const std::vector &args, std::optional LoadIndexedContent(const std::string& path); -void Notify(const char *method, const std::function &fn); +void Notify(const char *method, const std::function &fn); template void Notify(const char *method, T &result) { - Notify(method, [&](Writer &w) { Reflect(w, result); }); + Notify(method, [&](JsonWriter &w) { Reflect(w, result); }); } -void Reply(RequestId id, const std::function &fn); +void Reply(RequestId id, const std::function &fn); -void ReplyError(RequestId id, const std::function &fn); +void ReplyError(RequestId id, const std::function &fn); template void ReplyError(RequestId id, T &result) { - ReplyError(id, [&](Writer &w) { Reflect(w, result); }); + ReplyError(id, [&](JsonWriter &w) { Reflect(w, result); }); } } // namespace pipeline } // namespace ccls diff --git a/src/position.cc b/src/position.cc index b82d3097..8211ff98 100644 --- a/src/position.cc +++ b/src/position.cc @@ -17,6 +17,9 @@ limitations under the License. #include "serializer.hh" +#include +#include + #include #include #include @@ -69,45 +72,39 @@ std::string Range::ToString() { return buf; } -// Position -void Reflect(Reader &visitor, Pos &value) { - if (visitor.Format() == SerializeFormat::Json) { - value = Pos::FromString(visitor.GetString()); - } else { - Reflect(visitor, value.line); - Reflect(visitor, value.column); - } -} -void Reflect(Writer &visitor, Pos &value) { - if (visitor.Format() == SerializeFormat::Json) { - std::string output = value.ToString(); - visitor.String(output.c_str(), output.size()); - } else { - Reflect(visitor, value.line); - Reflect(visitor, value.column); - } +void Reflect(JsonReader &vis, Pos &v) { v = Pos::FromString(vis.GetString()); } +void Reflect(JsonReader &vis, Range &v) { + v = Range::FromString(vis.GetString()); } -// Range -void Reflect(Reader &visitor, Range &value) { - if (visitor.Format() == SerializeFormat::Json) { - value = Range::FromString(visitor.GetString()); - } else { - Reflect(visitor, value.start.line); - Reflect(visitor, value.start.column); - Reflect(visitor, value.end.line); - Reflect(visitor, value.end.column); - } +void Reflect(JsonWriter &vis, Pos &v) { + std::string output = v.ToString(); + vis.String(output.c_str(), output.size()); } -void Reflect(Writer &visitor, Range &value) { - if (visitor.Format() == SerializeFormat::Json) { - std::string output = value.ToString(); - visitor.String(output.c_str(), output.size()); - } else { - Reflect(visitor, value.start.line); - Reflect(visitor, value.start.column); - Reflect(visitor, value.end.line); - Reflect(visitor, value.end.column); - } +void Reflect(JsonWriter &vis, Range &v) { + std::string output = v.ToString(); + vis.String(output.c_str(), output.size()); +} + +void Reflect(BinaryReader &visitor, Pos &value) { + Reflect(visitor, value.line); + Reflect(visitor, value.column); +} +void Reflect(BinaryReader &visitor, Range &value) { + Reflect(visitor, value.start.line); + Reflect(visitor, value.start.column); + Reflect(visitor, value.end.line); + Reflect(visitor, value.end.column); +} + +void Reflect(BinaryWriter &vis, Pos &v) { + Reflect(vis, v.line); + Reflect(vis, v.column); +} +void Reflect(BinaryWriter &vis, Range &v) { + Reflect(vis, v.start.line); + Reflect(vis, v.start.column); + Reflect(vis, v.end.line); + Reflect(vis, v.end.column); } } // namespace ccls diff --git a/src/position.hh b/src/position.hh index 11075e90..d5bf241b 100644 --- a/src/position.hh +++ b/src/position.hh @@ -63,12 +63,19 @@ struct Range { }; // Reflection -class Reader; -class Writer; -void Reflect(Reader &visitor, Pos &value); -void Reflect(Writer &visitor, Pos &value); -void Reflect(Reader &visitor, Range &value); -void Reflect(Writer &visitor, Range &value); +struct JsonReader; +struct JsonWriter; +struct BinaryReader; +struct BinaryWriter; + +void Reflect(JsonReader &visitor, Pos &value); +void Reflect(JsonReader &visitor, Range &value); +void Reflect(JsonWriter &visitor, Pos &value); +void Reflect(JsonWriter &visitor, Range &value); +void Reflect(BinaryReader &visitor, Pos &value); +void Reflect(BinaryReader &visitor, Range &value); +void Reflect(BinaryWriter &visitor, Pos &value); +void Reflect(BinaryWriter &visitor, Range &value); } // namespace ccls namespace std { diff --git a/src/project.cc b/src/project.cc index c2c23a6c..5a2de3da 100644 --- a/src/project.cc +++ b/src/project.cc @@ -20,7 +20,6 @@ limitations under the License. #include "log.hh" #include "pipeline.hh" #include "platform.hh" -#include "serializers/json.hh" #include "utils.hh" #include "working_files.hh" diff --git a/src/query.cc b/src/query.cc index 036cba60..0906ee24 100644 --- a/src/query.cc +++ b/src/query.cc @@ -18,7 +18,8 @@ limitations under the License. #include "indexer.hh" #include "pipeline.hh" #include "serializer.hh" -#include "serializers/json.hh" + +#include #include #include diff --git a/src/serializer.cc b/src/serializer.cc index 11c75197..c754f83a 100644 --- a/src/serializer.cc +++ b/src/serializer.cc @@ -19,8 +19,9 @@ limitations under the License. #include "indexer.hh" #include "log.hh" #include "message_handler.hh" -#include "serializers/binary.hh" -#include "serializers/json.hh" + +#include +#include #include #include @@ -33,181 +34,198 @@ using namespace llvm; bool gTestOutputMode = false; namespace ccls { -Reader::~Reader() {} -BinaryReader::~BinaryReader() {} -JsonReader::~JsonReader() {} -Writer::~Writer() {} -BinaryWriter::~BinaryWriter() {} -JsonWriter::~JsonWriter() {} - -void Reflect(Reader &vis, uint8_t &v) { v = vis.GetUInt8(); } -void Reflect(Writer &vis, uint8_t &v) { vis.UInt8(v); } - -void Reflect(Reader &vis, short &v) { - if (!vis.IsInt()) - throw std::invalid_argument("short"); - v = (short)vis.GetInt(); +void JsonReader::IterArray(std::function fn) { + if (!m->IsArray()) + throw std::invalid_argument("array"); + // Use "0" to indicate any element for now. + path_.push_back("0"); + for (auto &entry : m->GetArray()) { + auto saved = m; + m = &entry; + fn(); + m = saved; + } + path_.pop_back(); } -void Reflect(Writer &vis, short &v) { vis.Int(v); } - -void Reflect(Reader &vis, unsigned short &v) { - if (!vis.IsInt()) - throw std::invalid_argument("unsigned short"); - v = (unsigned short)vis.GetInt(); +void JsonReader::Member(const char *name, std::function fn) { + path_.push_back(name); + auto it = m->FindMember(name); + if (it != m->MemberEnd()) { + auto saved = m; + m = &it->value; + fn(); + m = saved; + } + path_.pop_back(); } -void Reflect(Writer &vis, unsigned short &v) { vis.Int(v); } - -void Reflect(Reader &vis, int &v) { - if (!vis.IsInt()) - throw std::invalid_argument("int"); - v = vis.GetInt(); -} -void Reflect(Writer &vis, int &v) { vis.Int(v); } - -void Reflect(Reader &vis, unsigned &v) { - if (!vis.IsUInt64()) - throw std::invalid_argument("unsigned"); - v = vis.GetUInt32(); -} -void Reflect(Writer &vis, unsigned &v) { vis.UInt32(v); } - -void Reflect(Reader &vis, long &v) { - if (!vis.IsInt64()) - throw std::invalid_argument("long"); - v = long(vis.GetInt64()); -} -void Reflect(Writer &vis, long &v) { vis.Int64(v); } - -void Reflect(Reader &vis, unsigned long &v) { - if (!vis.IsUInt64()) - throw std::invalid_argument("unsigned long"); - v = (unsigned long)vis.GetUInt64(); -} -void Reflect(Writer &vis, unsigned long &v) { vis.UInt64(v); } - -void Reflect(Reader &vis, long long &v) { - if (!vis.IsInt64()) - throw std::invalid_argument("long long"); - v = vis.GetInt64(); -} -void Reflect(Writer &vis, long long &v) { vis.Int64(v); } - -void Reflect(Reader &vis, unsigned long long &v) { - if (!vis.IsUInt64()) - throw std::invalid_argument("unsigned long long"); - v = vis.GetUInt64(); -} -void Reflect(Writer &vis, unsigned long long &v) { vis.UInt64(v); } - -void Reflect(Reader &vis, double &v) { - if (!vis.IsDouble()) - throw std::invalid_argument("double"); - v = vis.GetDouble(); -} -void Reflect(Writer &vis, double &v) { vis.Double(v); } - -void Reflect(Reader &vis, bool &v) { - if (!vis.IsBool()) - throw std::invalid_argument("bool"); - v = vis.GetBool(); -} -void Reflect(Writer &vis, bool &v) { vis.Bool(v); } - -void Reflect(Reader &vis, std::string &v) { - if (!vis.IsString()) - throw std::invalid_argument("std::string"); - v = vis.GetString(); -} -void Reflect(Writer &vis, std::string &v) { - vis.String(v.c_str(), (rapidjson::SizeType)v.size()); +bool JsonReader::IsNull() { return m->IsNull(); } +std::string JsonReader::GetString() { return m->GetString(); } +std::string JsonReader::GetPath() const { + std::string ret; + for (auto &t : path_) + if (t[0] == '0') { + ret += '['; + ret += t; + ret += ']'; + } else { + ret += '/'; + ret += t; + } + return ret; } -void Reflect(Reader &, std::string_view &) { assert(0); } -void Reflect(Writer &vis, std::string_view &data) { +void JsonWriter::StartArray() { m->StartArray(); } +void JsonWriter::EndArray() { m->EndArray(); } +void JsonWriter::StartObject() { m->StartObject(); } +void JsonWriter::EndObject() { m->EndObject(); } +void JsonWriter::Key(const char *name) { m->Key(name); } +void JsonWriter::Null() { m->Null(); } +void JsonWriter::Int(int v) { m->Int(v); } +void JsonWriter::String(const char *s) { m->String(s); } +void JsonWriter::String(const char *s, size_t len) { m->String(s, len); } + +// clang-format off +void Reflect(JsonReader &vis, bool &v ) { if (!vis.m->IsBool()) throw std::invalid_argument("bool"); v = vis.m->GetBool(); } +void Reflect(JsonReader &vis, unsigned char &v ) { if (!vis.m->IsInt()) throw std::invalid_argument("uint8_t"); v = (uint8_t)vis.m->GetInt(); } +void Reflect(JsonReader &vis, short &v ) { if (!vis.m->IsInt()) throw std::invalid_argument("short"); v = (short)vis.m->GetInt(); } +void Reflect(JsonReader &vis, unsigned short &v ) { if (!vis.m->IsInt()) throw std::invalid_argument("unsigned short"); v = (unsigned short)vis.m->GetInt(); } +void Reflect(JsonReader &vis, int &v ) { if (!vis.m->IsInt()) throw std::invalid_argument("int"); v = vis.m->GetInt(); } +void Reflect(JsonReader &vis, unsigned &v ) { if (!vis.m->IsUint64()) throw std::invalid_argument("unsigned"); v = (unsigned)vis.m->GetUint64(); } +void Reflect(JsonReader &vis, long &v ) { if (!vis.m->IsInt64()) throw std::invalid_argument("long"); v = (long)vis.m->GetInt64(); } +void Reflect(JsonReader &vis, unsigned long &v ) { if (!vis.m->IsUint64()) throw std::invalid_argument("unsigned long"); v = (unsigned long)vis.m->GetUint64(); } +void Reflect(JsonReader &vis, long long &v ) { if (!vis.m->IsInt64()) throw std::invalid_argument("long long"); v = vis.m->GetInt64(); } +void Reflect(JsonReader &vis, unsigned long long &v) { if (!vis.m->IsUint64()) throw std::invalid_argument("unsigned long long"); v = vis.m->GetUint64(); } +void Reflect(JsonReader &vis, double &v ) { if (!vis.m->IsDouble()) throw std::invalid_argument("double"); v = vis.m->GetDouble(); } +void Reflect(JsonReader &vis, const char *&v ) { if (!vis.m->IsString()) throw std::invalid_argument("string"); v = Intern(vis.GetString()); } +void Reflect(JsonReader &vis, std::string &v ) { if (!vis.m->IsString()) throw std::invalid_argument("string"); v = vis.GetString(); } + +void Reflect(JsonWriter &vis, bool &v ) { vis.m->Bool(v); } +void Reflect(JsonWriter &vis, unsigned char &v ) { vis.m->Int(v); } +void Reflect(JsonWriter &vis, short &v ) { vis.m->Int(v); } +void Reflect(JsonWriter &vis, unsigned short &v ) { vis.m->Int(v); } +void Reflect(JsonWriter &vis, int &v ) { vis.m->Int(v); } +void Reflect(JsonWriter &vis, unsigned &v ) { vis.m->Uint64(v); } +void Reflect(JsonWriter &vis, long &v ) { vis.m->Int64(v); } +void Reflect(JsonWriter &vis, unsigned long &v ) { vis.m->Uint64(v); } +void Reflect(JsonWriter &vis, long long &v ) { vis.m->Int64(v); } +void Reflect(JsonWriter &vis, unsigned long long &v) { vis.m->Uint64(v); } +void Reflect(JsonWriter &vis, double &v ) { vis.m->Double(v); } +void Reflect(JsonWriter &vis, const char *&v ) { vis.String(v); } +void Reflect(JsonWriter &vis, std::string &v ) { vis.String(v.c_str(), v.size()); } + +void Reflect(BinaryReader &vis, bool &v ) { v = vis.Get(); } +void Reflect(BinaryReader &vis, unsigned char &v ) { v = vis.Get(); } +void Reflect(BinaryReader &vis, short &v ) { v = (short)vis.VarInt(); } +void Reflect(BinaryReader &vis, unsigned short &v ) { v = (unsigned short)vis.VarUInt(); } +void Reflect(BinaryReader &vis, int &v ) { v = (int)vis.VarInt(); } +void Reflect(BinaryReader &vis, unsigned &v ) { v = (unsigned)vis.VarUInt(); } +void Reflect(BinaryReader &vis, long &v ) { v = (long)vis.VarInt(); } +void Reflect(BinaryReader &vis, unsigned long &v ) { v = (unsigned long)vis.VarUInt(); } +void Reflect(BinaryReader &vis, long long &v ) { v = vis.VarInt(); } +void Reflect(BinaryReader &vis, unsigned long long &v) { v = vis.VarUInt(); } +void Reflect(BinaryReader &vis, double &v ) { v = vis.Get(); } +void Reflect(BinaryReader &vis, const char *&v ) { v = Intern(vis.GetString()); } +void Reflect(BinaryReader &vis, std::string &v ) { v = vis.GetString(); } + +void Reflect(BinaryWriter &vis, bool &v ) { vis.Pack(v); } +void Reflect(BinaryWriter &vis, unsigned char &v ) { vis.Pack(v); } +void Reflect(BinaryWriter &vis, short &v ) { vis.VarInt(v); } +void Reflect(BinaryWriter &vis, unsigned short &v ) { vis.VarUInt(v); } +void Reflect(BinaryWriter &vis, int &v ) { vis.VarInt(v); } +void Reflect(BinaryWriter &vis, unsigned &v ) { vis.VarUInt(v); } +void Reflect(BinaryWriter &vis, long &v ) { vis.VarInt(v); } +void Reflect(BinaryWriter &vis, unsigned long &v ) { vis.VarUInt(v); } +void Reflect(BinaryWriter &vis, long long &v ) { vis.VarInt(v); } +void Reflect(BinaryWriter &vis, unsigned long long &v) { vis.VarUInt(v); } +void Reflect(BinaryWriter &vis, double &v ) { vis.Pack(v); } +void Reflect(BinaryWriter &vis, const char *&v ) { vis.String(v); } +void Reflect(BinaryWriter &vis, std::string &v ) { vis.String(v.c_str(), v.size()); } +// clang-format on + +void Reflect(JsonWriter &vis, std::string_view &data) { if (data.empty()) vis.String(""); else vis.String(&data[0], (rapidjson::SizeType)data.size()); } -void Reflect(Reader &vis, const char *&v) { - const char *str = vis.GetString(); - v = Intern(str); -} -void Reflect(Writer &vis, const char *&v) { vis.String(v); } +void Reflect(JsonReader &vis, JsonNull &v) {} +void Reflect(JsonWriter &vis, JsonNull &v) { vis.m->Null(); } -void Reflect(Reader &vis, JsonNull &v) { - assert(vis.Format() == SerializeFormat::Json); - vis.GetNull(); -} - -void Reflect(Writer &vis, JsonNull &v) { vis.Null(); } - -// std::unordered_map template -void Reflect(Reader &vis, std::unordered_map &map) { - vis.IterArray([&](Reader &entry) { +void Reflect(JsonReader &vis, std::unordered_map &v) { + vis.IterArray([&]() { V val; - Reflect(entry, val); - auto usr = val.usr; - map[usr] = std::move(val); + Reflect(vis, val); + v[val.usr] = std::move(val); }); } template -void Reflect(Writer &vis, std::unordered_map &map) { - std::vector> xs(map.begin(), map.end()); +void Reflect(JsonWriter &vis, std::unordered_map &v) { + // Determinism + std::vector> xs(v.begin(), v.end()); std::sort(xs.begin(), xs.end(), [](const auto &a, const auto &b) { return a.first < b.first; }); - vis.StartArray(xs.size()); + vis.StartArray(); for (auto &it : xs) Reflect(vis, it.second); vis.EndArray(); } +template +void Reflect(BinaryReader &vis, std::unordered_map &v) { + for (auto n = vis.VarUInt(); n; n--) { + V val; + Reflect(vis, val); + v[val.usr] = std::move(val); + } +} +template +void Reflect(BinaryWriter &vis, std::unordered_map &v) { + vis.VarUInt(v.size()); + for (auto &it : v) + Reflect(vis, it.second); +} // Used by IndexFile::dependencies. -void Reflect(Reader &vis, DenseMap &v) { +void Reflect(JsonReader &vis, DenseMap &v) { std::string name; - if (vis.Format() == SerializeFormat::Json) { - auto &vis1 = static_cast(vis); - for (auto it = vis1.m().MemberBegin(); it != vis1.m().MemberEnd(); ++it) - v[InternH(it->name.GetString())] = it->value.GetInt64(); - } else { - vis.IterArray([&](Reader &entry) { - Reflect(entry, name); - Reflect(entry, v[InternH(name)]); - }); + for (auto it = vis.m->MemberBegin(); it != vis.m->MemberEnd(); ++it) + v[InternH(it->name.GetString())] = it->value.GetInt64(); +} +void Reflect(JsonWriter &vis, DenseMap &v) { + vis.StartObject(); + for (auto &it : v) { + vis.m->Key(it.first.val().data()); // llvm 8 -> data() + vis.m->Int64(it.second); + } + vis.EndObject(); +} +void Reflect(BinaryReader &vis, DenseMap &v) { + std::string name; + for (auto n = vis.VarUInt(); n; n--) { + Reflect(vis, name); + Reflect(vis, v[InternH(name)]); } } -void Reflect(Writer &vis, DenseMap &v) { - if (vis.Format() == SerializeFormat::Json) { - auto &vis1 = static_cast(vis); - vis.StartObject(); - for (auto &it : v) { - vis1.m().Key(it.first.val().data()); // llvm 8 -> data() - vis1.m().Int64(it.second); - } - vis.EndObject(); - } else { - vis.StartArray(v.size()); - for (auto &it : v) { - std::string key = it.first.val().str(); - Reflect(vis, key); - Reflect(vis, it.second); - } - vis.EndArray(); +void Reflect(BinaryWriter &vis, DenseMap &v) { + std::string key; + vis.VarUInt(v.size()); + for (auto &it : v) { + key = it.first.val().str(); + Reflect(vis, key); + Reflect(vis, it.second); } } -// TODO: Move this to indexer.cc -void Reflect(Reader &vis, IndexInclude &v) { - REFLECT_MEMBER_START(); +template void Reflect(Vis &vis, IndexInclude &v) { + ReflectMemberStart(vis); REFLECT_MEMBER(line); REFLECT_MEMBER(resolved_path); - REFLECT_MEMBER_END(); + ReflectMemberEnd(vis); } -void Reflect(Writer &vis, IndexInclude &v) { - REFLECT_MEMBER_START(); +void Reflect(JsonWriter &vis, IndexInclude &v) { + ReflectMemberStart(vis); REFLECT_MEMBER(line); if (gTestOutputMode) { std::string basename = llvm::sys::path::filename(v.resolved_path); @@ -217,23 +235,34 @@ void Reflect(Writer &vis, IndexInclude &v) { } else { REFLECT_MEMBER(resolved_path); } - REFLECT_MEMBER_END(); + ReflectMemberEnd(vis); } -template void ReflectHoverAndComments(Reader &vis, Def &def) { +template +void ReflectHoverAndComments(JsonReader &vis, Def &def) { ReflectMember(vis, "hover", def.hover); ReflectMember(vis, "comments", def.comments); } - -template void ReflectHoverAndComments(Writer &vis, Def &def) { +template +void ReflectHoverAndComments(JsonWriter &vis, Def &def) { // Don't emit empty hover and comments in JSON test mode. if (!gTestOutputMode || def.hover[0]) ReflectMember(vis, "hover", def.hover); if (!gTestOutputMode || def.comments[0]) ReflectMember(vis, "comments", def.comments); } +template +void ReflectHoverAndComments(BinaryReader &vis, Def &def) { + Reflect(vis, def.hover); + Reflect(vis, def.comments); +} +template +void ReflectHoverAndComments(BinaryWriter &vis, Def &def) { + Reflect(vis, def.hover); + Reflect(vis, def.comments); +} -template void ReflectShortName(Reader &vis, Def &def) { +template void ReflectShortName(JsonReader &vis, Def &def) { if (gTestOutputMode) { std::string short_name; ReflectMember(vis, "short_name", short_name); @@ -246,8 +275,7 @@ template void ReflectShortName(Reader &vis, Def &def) { ReflectMember(vis, "short_name_size", def.short_name_size); } } - -template void ReflectShortName(Writer &vis, Def &def) { +template void ReflectShortName(JsonWriter &vis, Def &def) { if (gTestOutputMode) { std::string_view short_name(def.detailed_name + def.short_name_offset, def.short_name_size); @@ -257,9 +285,17 @@ template void ReflectShortName(Writer &vis, Def &def) { ReflectMember(vis, "short_name_size", def.short_name_size); } } +template void ReflectShortName(BinaryReader &vis, Def &def) { + Reflect(vis, def.short_name_offset); + Reflect(vis, def.short_name_size); +} +template void ReflectShortName(BinaryWriter &vis, Def &def) { + Reflect(vis, def.short_name_offset); + Reflect(vis, def.short_name_size); +} -template void Reflect(TVisitor &vis, IndexFunc &v) { - REFLECT_MEMBER_START(); +template void Reflect1(TVisitor &vis, IndexFunc &v) { + ReflectMemberStart(vis); REFLECT_MEMBER2("usr", v.usr); REFLECT_MEMBER2("detailed_name", v.def.detailed_name); REFLECT_MEMBER2("qual_name_offset", v.def.qual_name_offset); @@ -276,11 +312,15 @@ template void Reflect(TVisitor &vis, IndexFunc &v) { REFLECT_MEMBER2("declarations", v.declarations); REFLECT_MEMBER2("derived", v.derived); REFLECT_MEMBER2("uses", v.uses); - REFLECT_MEMBER_END(); + ReflectMemberEnd(vis); } +void Reflect(JsonReader &vis, IndexFunc &v) { Reflect1(vis, v); } +void Reflect(JsonWriter &vis, IndexFunc &v) { Reflect1(vis, v); } +void Reflect(BinaryReader &vis, IndexFunc &v) { Reflect1(vis, v); } +void Reflect(BinaryWriter &vis, IndexFunc &v) { Reflect1(vis, v); } -template void Reflect(TVisitor &vis, IndexType &v) { - REFLECT_MEMBER_START(); +template void Reflect1(TVisitor &vis, IndexType &v) { + ReflectMemberStart(vis); REFLECT_MEMBER2("usr", v.usr); REFLECT_MEMBER2("detailed_name", v.def.detailed_name); REFLECT_MEMBER2("qual_name_offset", v.def.qual_name_offset); @@ -299,11 +339,15 @@ template void Reflect(TVisitor &vis, IndexType &v) { REFLECT_MEMBER2("derived", v.derived); REFLECT_MEMBER2("instances", v.instances); REFLECT_MEMBER2("uses", v.uses); - REFLECT_MEMBER_END(); + ReflectMemberEnd(vis); } +void Reflect(JsonReader &vis, IndexType &v) { Reflect1(vis, v); } +void Reflect(JsonWriter &vis, IndexType &v) { Reflect1(vis, v); } +void Reflect(BinaryReader &vis, IndexType &v) { Reflect1(vis, v); } +void Reflect(BinaryWriter &vis, IndexType &v) { Reflect1(vis, v); } -template void Reflect(TVisitor &vis, IndexVar &v) { - REFLECT_MEMBER_START(); +template void Reflect1(TVisitor &vis, IndexVar &v) { + ReflectMemberStart(vis); REFLECT_MEMBER2("usr", v.usr); REFLECT_MEMBER2("detailed_name", v.def.detailed_name); REFLECT_MEMBER2("qual_name_offset", v.def.qual_name_offset); @@ -317,16 +361,16 @@ template void Reflect(TVisitor &vis, IndexVar &v) { REFLECT_MEMBER2("declarations", v.declarations); REFLECT_MEMBER2("uses", v.uses); - REFLECT_MEMBER_END(); + ReflectMemberEnd(vis); } +void Reflect(JsonReader &vis, IndexVar &v) { Reflect1(vis, v); } +void Reflect(JsonWriter &vis, IndexVar &v) { Reflect1(vis, v); } +void Reflect(BinaryReader &vis, IndexVar &v) { Reflect1(vis, v); } +void Reflect(BinaryWriter &vis, IndexVar &v) { Reflect1(vis, v); } // IndexFile -bool ReflectMemberStart(Writer &vis, IndexFile &v) { - vis.StartObject(); - return true; -} -template void Reflect(TVisitor &vis, IndexFile &v) { - REFLECT_MEMBER_START(); +template void Reflect1(TVisitor &vis, IndexFile &v) { + ReflectMemberStart(vis); if (!gTestOutputMode) { REFLECT_MEMBER(mtime); REFLECT_MEMBER(language); @@ -340,15 +384,19 @@ template void Reflect(TVisitor &vis, IndexFile &v) { REFLECT_MEMBER(usr2func); REFLECT_MEMBER(usr2type); REFLECT_MEMBER(usr2var); - REFLECT_MEMBER_END(); + ReflectMemberEnd(vis); } +void ReflectFile(JsonReader &vis, IndexFile &v) { Reflect1(vis, v); } +void ReflectFile(JsonWriter &vis, IndexFile &v) { Reflect1(vis, v); } +void ReflectFile(BinaryReader &vis, IndexFile &v) { Reflect1(vis, v); } +void ReflectFile(BinaryWriter &vis, IndexFile &v) { Reflect1(vis, v); } -void Reflect(Reader &vis, SerializeFormat &v) { +void Reflect(JsonReader &vis, SerializeFormat &v) { v = vis.GetString()[0] == 'j' ? SerializeFormat::Json : SerializeFormat::Binary; } -void Reflect(Writer &vis, SerializeFormat &v) { +void Reflect(JsonWriter &vis, SerializeFormat &v) { switch (v) { case SerializeFormat::Binary: vis.String("binary"); @@ -390,7 +438,7 @@ std::string Serialize(SerializeFormat format, IndexFile &file) { int minor = IndexFile::kMinorVersion; Reflect(writer, major); Reflect(writer, minor); - Reflect(writer, file); + ReflectFile(writer, file); return writer.Take(); } case SerializeFormat::Json: { @@ -406,7 +454,7 @@ std::string Serialize(SerializeFormat format, IndexFile &file) { output.Put(c); output.Put('\n'); } - Reflect(json_writer, file); + ReflectFile(json_writer, file); return output.GetString(); } } @@ -436,7 +484,7 @@ Deserialize(SerializeFormat format, const std::string &path, throw std::invalid_argument("Invalid version"); file = std::make_unique(sys::fs::UniqueID(0, 0), path, file_content); - Reflect(reader, *file); + ReflectFile(reader, *file); } catch (std::invalid_argument &e) { LOG_S(INFO) << "failed to deserialize '" << path << "': " << e.what(); return nullptr; @@ -462,7 +510,7 @@ Deserialize(SerializeFormat format, const std::string &path, file_content); JsonReader json_reader{&reader}; try { - Reflect(json_reader, *file); + ReflectFile(json_reader, *file); } catch (std::invalid_argument &e) { LOG_S(INFO) << "'" << path << "': failed to deserialize " << json_reader.GetPath() << "." << e.what(); diff --git a/src/serializer.hh b/src/serializer.hh index dc469d30..de5c24ac 100644 --- a/src/serializer.hh +++ b/src/serializer.hh @@ -20,6 +20,7 @@ limitations under the License. #include #include +#include #include #include @@ -40,159 +41,208 @@ enum class SerializeFormat { Binary, Json }; struct JsonNull {}; -class Reader { -public: - virtual ~Reader(); - virtual SerializeFormat Format() const = 0; +struct JsonReader { + rapidjson::Value *m; + std::vector path_; - 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; + JsonReader(rapidjson::Value *m) : m(m) {} + void StartObject() {} + void EndObject() {} + void IterArray(std::function fn); + void Member(const char *name, std::function fn); + bool IsNull(); + std::string GetString(); + std::string GetPath() const; }; -class Writer { -public: - virtual ~Writer(); - virtual SerializeFormat Format() const = 0; +struct JsonWriter { + using W = + rapidjson::Writer, + rapidjson::UTF8, rapidjson::CrtAllocator, 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; + W *m; + + JsonWriter(W *m) : m(m) {} + void StartArray(); + void EndArray(); + void StartObject(); + void EndObject(); + void Key(const char *name); + void Null(); + void Int(int v); + void String(const char *s); + void String(const char *s, size_t len); +}; + +struct BinaryReader { + const char *p_; + + BinaryReader(std::string_view buf) : p_(buf.data()) {} + template T Get() { + T ret; + memcpy(&ret, p_, sizeof(T)); + p_ += sizeof(T); + return ret; + } + uint64_t VarUInt() { + auto x = *reinterpret_cast(p_++); + if (x < 253) + return x; + if (x == 253) + return Get(); + if (x == 254) + return Get(); + return Get(); + } + int64_t VarInt() { + uint64_t x = VarUInt(); + return int64_t(x >> 1 ^ -(x & 1)); + } + const char *GetString() { + const char *ret = p_; + while (*p_) + p_++; + p_++; + return ret; + } +}; + +struct BinaryWriter { + std::string buf_; + + template void Pack(T x) { + auto i = buf_.size(); + buf_.resize(i + sizeof(x)); + memcpy(buf_.data() + i, &x, sizeof(x)); + } + + void VarUInt(uint64_t n) { + if (n < 253) + Pack(n); + else if (n < 65536) { + Pack(253); + Pack(n); + } else if (n < 4294967296) { + Pack(254); + Pack(n); + } else { + Pack(255); + Pack(n); + } + } + void VarInt(int64_t n) { VarUInt(uint64_t(n) << 1 ^ n >> 63); } + std::string Take() { return std::move(buf_); } + + void String(const char *x) { String(x, strlen(x)); } + void String(const char *x, size_t len) { + auto i = buf_.size(); + buf_.resize(i + len + 1); + memcpy(buf_.data() + i, x, len); + } }; 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); \ +#define REFLECT_UNDERLYING(T) \ + LLVM_ATTRIBUTE_UNUSED inline void Reflect(JsonReader &vis, T &v) { \ + std::underlying_type_t v0; \ + ::ccls::Reflect(vis, v0); \ + v = static_cast(v0); \ } \ - LLVM_ATTRIBUTE_UNUSED inline void Reflect(Writer &vis, type &v) { \ - auto value0 = static_cast(v); \ - ::ccls::Reflect(vis, value0); \ + LLVM_ATTRIBUTE_UNUSED inline void Reflect(JsonWriter &vis, T &v) { \ + auto v0 = static_cast>(v); \ + ::ccls::Reflect(vis, v0); \ + } + +#define REFLECT_UNDERLYING_B(T) \ + REFLECT_UNDERLYING(T) \ + LLVM_ATTRIBUTE_UNUSED inline void Reflect(BinaryReader &vis, T &v) { \ + std::underlying_type_t v0; \ + ::ccls::Reflect(vis, v0); \ + v = static_cast(v0); \ + } \ + LLVM_ATTRIBUTE_UNUSED inline void Reflect(BinaryWriter &vis, T &v) { \ + auto v0 = static_cast>(v); \ + ::ccls::Reflect(vis, v0); \ } #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(); \ +#define REFLECT_STRUCT(type, ...) \ + template void Reflect(Vis &vis, type &v) { \ + ReflectMemberStart(vis); \ MACRO_MAP(_MAPPABLE_REFLECT_MEMBER, __VA_ARGS__) \ - REFLECT_MEMBER_END(); \ + ReflectMemberEnd(vis); \ } -// 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(); \ - } +void Reflect(JsonReader &vis, bool &v); +void Reflect(JsonReader &vis, unsigned char &v); +void Reflect(JsonReader &vis, short &v); +void Reflect(JsonReader &vis, unsigned short &v); +void Reflect(JsonReader &vis, int &v); +void Reflect(JsonReader &vis, unsigned &v); +void Reflect(JsonReader &vis, long &v); +void Reflect(JsonReader &vis, unsigned long &v); +void Reflect(JsonReader &vis, long long &v); +void Reflect(JsonReader &vis, unsigned long long &v); +void Reflect(JsonReader &vis, double &v); +void Reflect(JsonReader &vis, const char *&v); +void Reflect(JsonReader &vis, std::string &v); -//// Elementary types +void Reflect(JsonWriter &vis, bool &v); +void Reflect(JsonWriter &vis, unsigned char &v); +void Reflect(JsonWriter &vis, short &v); +void Reflect(JsonWriter &vis, unsigned short &v); +void Reflect(JsonWriter &vis, int &v); +void Reflect(JsonWriter &vis, unsigned &v); +void Reflect(JsonWriter &vis, long &v); +void Reflect(JsonWriter &vis, unsigned long &v); +void Reflect(JsonWriter &vis, long long &v); +void Reflect(JsonWriter &vis, unsigned long long &v); +void Reflect(JsonWriter &vis, double &v); +void Reflect(JsonWriter &vis, const char *&v); +void Reflect(JsonWriter &vis, std::string &v); -void Reflect(Reader &vis, uint8_t &v); -void Reflect(Writer &vis, uint8_t &v); +void Reflect(BinaryReader &vis, bool &v); +void Reflect(BinaryReader &vis, unsigned char &v); +void Reflect(BinaryReader &vis, short &v); +void Reflect(BinaryReader &vis, unsigned short &v); +void Reflect(BinaryReader &vis, int &v); +void Reflect(BinaryReader &vis, unsigned &v); +void Reflect(BinaryReader &vis, long &v); +void Reflect(BinaryReader &vis, unsigned long &v); +void Reflect(BinaryReader &vis, long long &v); +void Reflect(BinaryReader &vis, unsigned long long &v); +void Reflect(BinaryReader &vis, double &v); +void Reflect(BinaryReader &vis, const char *&v); +void Reflect(BinaryReader &vis, std::string &v); -void Reflect(Reader &vis, short &v); -void Reflect(Writer &vis, short &v); +void Reflect(BinaryWriter &vis, bool &v); +void Reflect(BinaryWriter &vis, unsigned char &v); +void Reflect(BinaryWriter &vis, short &v); +void Reflect(BinaryWriter &vis, unsigned short &v); +void Reflect(BinaryWriter &vis, int &v); +void Reflect(BinaryWriter &vis, unsigned &v); +void Reflect(BinaryWriter &vis, long &v); +void Reflect(BinaryWriter &vis, unsigned long &v); +void Reflect(BinaryWriter &vis, long long &v); +void Reflect(BinaryWriter &vis, unsigned long long &v); +void Reflect(BinaryWriter &vis, double &v); +void Reflect(BinaryWriter &vis, const char *&v); +void Reflect(BinaryWriter &vis, std::string &v); -void Reflect(Reader &vis, unsigned short &v); -void Reflect(Writer &vis, unsigned short &v); +void Reflect(JsonReader &vis, JsonNull &v); +void Reflect(JsonWriter &vis, JsonNull &v); -void Reflect(Reader &vis, int &v); -void Reflect(Writer &vis, int &v); +void Reflect(JsonReader &vis, SerializeFormat &v); +void Reflect(JsonWriter &vis, SerializeFormat &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); +void Reflect(JsonWriter &vis, std::string_view &v); //// Type constructors @@ -200,109 +250,154 @@ void Reflect(Writer &vis, SerializeFormat &v); // 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); +template void Reflect(JsonReader &vis, std::optional &v) { + if (!vis.IsNull()) { + v.emplace(); Reflect(vis, *v); - } else + } +} +template void Reflect(JsonWriter &vis, std::optional &v) { + if (v) + Reflect(vis, *v); + else vis.Null(); } +template void Reflect(BinaryReader &vis, std::optional &v) { + if (*vis.p_++) { + v.emplace(); + Reflect(vis, *v); + } +} +template void Reflect(BinaryWriter &vis, std::optional &v) { + if (v) { + vis.Pack(1); + Reflect(vis, *v); + } else { + vis.Pack(0); + } +} // 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); +template void Reflect(JsonReader &vis, Maybe &v) { + if (!vis.IsNull()) Reflect(vis, *v); - } else +} +template void Reflect(JsonWriter &vis, Maybe &v) { + if (v) + Reflect(vis, *v); + else vis.Null(); } +template void Reflect(BinaryReader &vis, Maybe &v) { + if (*vis.p_++) + Reflect(vis, *v); +} +template void Reflect(BinaryWriter &vis, Maybe &v) { + if (v) { + vis.Pack(1); + Reflect(vis, *v); + } else { + vis.Pack(0); + } +} template -void ReflectMember(Writer &vis, const char *name, std::optional &v) { +void ReflectMember(JsonWriter &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) { + if (v) { vis.Key(name); - Reflect(vis, v); + Reflect(vis, *v); } } +template +void ReflectMember(BinaryWriter &vis, const char *, std::optional &v) { + 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) { +void ReflectMember(JsonWriter &vis, const char *name, Maybe &v) { + if (v.Valid()) { vis.Key(name); Reflect(vis, v); } } +template +void ReflectMember(BinaryWriter &vis, const char *, Maybe &v) { + Reflect(vis, v); +} template -void Reflect(Reader &vis, std::pair &v) { +void Reflect(JsonReader &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) { +void Reflect(JsonWriter &vis, std::pair &v) { vis.StartObject(); ReflectMember(vis, "L", v.first); ReflectMember(vis, "R", v.second); vis.EndObject(); } +template +void Reflect(BinaryReader &vis, std::pair &v) { + Reflect(vis, v.first); + Reflect(vis, v.second); +} +template +void Reflect(BinaryWriter &vis, std::pair &v) { + Reflect(vis, v.first); + Reflect(vis, v.second); +} // 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(JsonReader &vis, std::vector &v) { + vis.IterArray([&]() { + v.emplace_back(); + Reflect(vis, v.back()); }); } -template void Reflect(Writer &vis, std::vector &vs) { - vis.StartArray(vs.size()); - for (auto &v : vs) - Reflect(vis, v); +template void Reflect(JsonWriter &vis, std::vector &v) { + vis.StartArray(); + for (auto &it : v) + Reflect(vis, it); vis.EndArray(); } +template void Reflect(BinaryReader &vis, std::vector &v) { + for (auto n = vis.VarUInt(); n; n--) { + v.emplace_back(); + Reflect(vis, v.back()); + } +} +template void Reflect(BinaryWriter &vis, std::vector &v) { + vis.VarUInt(v.size()); + for (auto &it : v) + Reflect(vis, it); +} // ReflectMember -inline bool ReflectMemberStart(Reader &vis) { return false; } -inline bool ReflectMemberStart(Writer &vis) { - vis.StartObject(); - return true; -} +template void ReflectMemberStart(T &) {} +inline void ReflectMemberStart(JsonWriter &vis) { vis.StartObject(); } -inline void ReflectMemberEnd(Reader &vis) {} -inline void ReflectMemberEnd(Writer &vis) { vis.EndObject(); } +template void ReflectMemberEnd(T &) {} +inline void ReflectMemberEnd(JsonWriter &vis) { vis.EndObject(); } -template void ReflectMember(Reader &vis, const char *name, T &v) { +template void ReflectMember(JsonReader &vis, const char *name, T &v) { vis.Member(name, [&]() { Reflect(vis, v); }); } -template void ReflectMember(Writer &vis, const char *name, T &v) { +template void ReflectMember(JsonWriter &vis, const char *name, T &v) { vis.Key(name); Reflect(vis, v); } +template void ReflectMember(BinaryReader &vis, const char *, T &v) { + Reflect(vis, v); +} +template void ReflectMember(BinaryWriter &vis, const char *, T &v) { + Reflect(vis, v); +} // API diff --git a/src/serializers/binary.hh b/src/serializers/binary.hh deleted file mode 100644 index e995ec44..00000000 --- a/src/serializers/binary.hh +++ /dev/null @@ -1,139 +0,0 @@ -/* Copyright 2017-2018 ccls Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -==============================================================================*/ - -#pragma once - -#include "serializer.hh" - -#include - -namespace ccls { -class BinaryReader : public Reader { - const char *p_; - - template T Get() { - T ret; - memcpy(&ret, p_, sizeof(T)); - p_ += sizeof(T); - return ret; - } - - uint64_t VarUInt() { - auto x = *reinterpret_cast(p_++); - if (x < 253) - return x; - if (x == 253) - return Get(); - if (x == 254) - return Get(); - return Get(); - } - int64_t VarInt() { - uint64_t x = VarUInt(); - return int64_t(x >> 1 ^ -(x & 1)); - } - -public: - BinaryReader(std::string_view buf) : p_(buf.data()) {} - virtual ~BinaryReader(); - SerializeFormat Format() const override { return SerializeFormat::Binary; } - - bool IsBool() override { return true; } - // Abuse how the function is called in serializer.h - bool IsNull() override { return !*p_++; } - bool IsInt() override { return true; } - bool IsInt64() override { return true; } - bool IsUInt64() override { return true; } - bool IsDouble() override { return true; } - bool IsString() override { return true; } - - void GetNull() override {} - bool GetBool() override { return Get(); } - int GetInt() override { return VarInt(); } - int64_t GetInt64() override { return VarInt(); } - uint8_t GetUInt8() override { return Get(); } - uint32_t GetUInt32() override { return VarUInt(); } - uint64_t GetUInt64() override { return VarUInt(); } - double GetDouble() override { return Get(); } - const char *GetString() override { - const char *ret = p_; - while (*p_) - p_++; - p_++; - return ret; - } - - bool HasMember(const char *x) override { return true; } - std::unique_ptr operator[](const char *x) override { return {}; } - - void IterArray(std::function fn) override { - for (auto n = VarUInt(); n; n--) - fn(*this); - } - - void Member(const char *, std::function fn) override { fn(); } -}; - -class BinaryWriter : public Writer { - std::string buf_; - - template void Pack(T x) { - auto i = buf_.size(); - buf_.resize(i + sizeof(x)); - memcpy(buf_.data() + i, &x, sizeof(x)); - } - - void VarUInt(uint64_t n) { - if (n < 253) - Pack(n); - else if (n < 65536) { - Pack(253); - Pack(n); - } else if (n < 4294967296) { - Pack(254); - Pack(n); - } else { - Pack(255); - Pack(n); - } - } - void VarInt(int64_t n) { VarUInt(uint64_t(n) << 1 ^ n >> 63); } - -public: - virtual ~BinaryWriter(); - SerializeFormat Format() const override { return SerializeFormat::Binary; } - std::string Take() { return std::move(buf_); } - - void Null() override { Pack(uint8_t(0)); } - void Bool(bool x) override { Pack(x); } - void Int(int x) override { VarInt(x); } - void Int64(int64_t x) override { VarInt(x); } - void UInt8(uint8_t x) override { Pack(x); } - void UInt32(uint32_t x) override { VarUInt(x); } - void UInt64(uint64_t x) override { VarUInt(x); } - void Double(double x) override { Pack(x); } - void String(const char *x) override { String(x, strlen(x)); } - void String(const char *x, size_t len) override { - auto i = buf_.size(); - buf_.resize(i + len + 1); - memcpy(buf_.data() + i, x, len); - } - void StartArray(size_t n) override { VarUInt(n); } - void EndArray() override {} - void StartObject() override {} - void EndObject() override {} - void Key(const char *name) override {} -}; -} // namespace ccls diff --git a/src/serializers/json.hh b/src/serializers/json.hh deleted file mode 100644 index a1d29b72..00000000 --- a/src/serializers/json.hh +++ /dev/null @@ -1,120 +0,0 @@ -/* Copyright 2017-2018 ccls Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -==============================================================================*/ - -#pragma once - -#include "serializer.hh" - -#include -#include - -namespace ccls { -class JsonReader : public Reader { - rapidjson::GenericValue> *m_; - std::vector path_; - -public: - JsonReader(rapidjson::GenericValue> *m) : m_(m) {} - virtual ~JsonReader(); - SerializeFormat Format() const override { return SerializeFormat::Json; } - rapidjson::GenericValue> &m() { return *m_; } - - bool IsBool() override { return m_->IsBool(); } - bool IsNull() override { return m_->IsNull(); } - bool IsInt() override { return m_->IsInt(); } - bool IsInt64() override { return m_->IsInt64(); } - bool IsUInt64() override { return m_->IsUint64(); } - bool IsDouble() override { return m_->IsDouble(); } - bool IsString() override { return m_->IsString(); } - - void GetNull() override {} - bool GetBool() override { return m_->GetBool(); } - int GetInt() override { return m_->GetInt(); } - int64_t GetInt64() override { return m_->GetInt64(); } - uint8_t GetUInt8() override { return uint8_t(m_->GetInt()); } - uint32_t GetUInt32() override { return uint32_t(m_->GetUint64()); } - uint64_t GetUInt64() override { return m_->GetUint64(); } - double GetDouble() override { return m_->GetDouble(); } - const char *GetString() override { return m_->GetString(); } - - bool HasMember(const char *x) override { return m_->HasMember(x); } - std::unique_ptr operator[](const char *x) override { - auto &sub = (*m_)[x]; - return std::unique_ptr(new JsonReader(&sub)); - } - - void IterArray(std::function fn) override { - if (!m_->IsArray()) - throw std::invalid_argument("array"); - // Use "0" to indicate any element for now. - path_.push_back("0"); - for (auto &entry : m_->GetArray()) { - auto saved = m_; - m_ = &entry; - fn(*this); - m_ = saved; - } - path_.pop_back(); - } - - void Member(const char *name, std::function fn) override { - path_.push_back(name); - auto it = m_->FindMember(name); - if (it != m_->MemberEnd()) { - auto saved = m_; - m_ = &it->value; - fn(); - m_ = saved; - } - path_.pop_back(); - } - - std::string GetPath() const { - std::string ret; - for (auto &t : path_) { - ret += '/'; - ret += t; - } - ret.pop_back(); - return ret; - } -}; - -class JsonWriter : public Writer { - rapidjson::Writer *m_; - -public: - JsonWriter(rapidjson::Writer *m) : m_(m) {} - virtual ~JsonWriter(); - SerializeFormat Format() const override { return SerializeFormat::Json; } - rapidjson::Writer &m() { return *m_; } - - void Null() override { m_->Null(); } - void Bool(bool x) override { m_->Bool(x); } - void Int(int x) override { m_->Int(x); } - void Int64(int64_t x) override { m_->Int64(x); } - void UInt8(uint8_t x) override { m_->Int(x); } - void UInt32(uint32_t x) override { m_->Uint64(x); } - void UInt64(uint64_t x) override { m_->Uint64(x); } - void Double(double x) override { m_->Double(x); } - void String(const char *x) override { m_->String(x); } - void String(const char *x, size_t len) override { m_->String(x, len); } - void StartArray(size_t) override { m_->StartArray(); } - void EndArray() override { m_->EndArray(); } - void StartObject() override { m_->StartObject(); } - void EndObject() override { m_->EndObject(); } - void Key(const char *name) override { m_->Key(name); } -}; -} // namespace ccls