mirror of
https://github.com/MaskRay/ccls.git
synced 2024-11-29 11:01:57 +00:00
Add TypedBidiMessageQueue
This commit is contained in:
parent
528d778d9a
commit
0037a3e7f5
@ -11,6 +11,8 @@
|
|||||||
#include "language_server_api.h"
|
#include "language_server_api.h"
|
||||||
#include "test.h"
|
#include "test.h"
|
||||||
|
|
||||||
|
#include "src/typed_bidi_message_queue.h"
|
||||||
|
|
||||||
#include "third_party/tiny-process-library/process.hpp"
|
#include "third_party/tiny-process-library/process.hpp"
|
||||||
|
|
||||||
#include "third_party/doctest/doctest/doctest.h"
|
#include "third_party/doctest/doctest/doctest.h"
|
||||||
@ -1025,7 +1027,18 @@ void PreMain() {
|
|||||||
MessageRegistry::instance()->Register<In_WorkspaceSymbolRequest>();
|
MessageRegistry::instance()->Register<In_WorkspaceSymbolRequest>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct MyMessageType {
|
||||||
|
static const lsMethodId id = lsMethodId::CancelRequest;
|
||||||
|
};
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
|
// TODO: real impl
|
||||||
|
const int kQueueSize = 128;
|
||||||
|
TypedBidiMessageQueue<lsMethodId, MyMessageType> t("foo", kQueueSize);
|
||||||
|
MyMessageType mm;
|
||||||
|
t.SendMessage(&t.for_client, lsMethodId::Initialize, &mm);
|
||||||
|
t.GetMessages(&t.for_client);
|
||||||
|
|
||||||
bool loop = false;
|
bool loop = false;
|
||||||
while (loop)
|
while (loop)
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||||
|
12
indexer.cpp
12
indexer.cpp
@ -1204,6 +1204,18 @@ void emptyIndexEntityReference(CXClientData client_data,
|
|||||||
IndexedFile Parse(std::string filename,
|
IndexedFile Parse(std::string filename,
|
||||||
std::vector<std::string> args,
|
std::vector<std::string> args,
|
||||||
bool dump_ast) {
|
bool dump_ast) {
|
||||||
|
// TODO!!
|
||||||
|
// TODO!!
|
||||||
|
// TODO!!
|
||||||
|
// TODO!!: Strip useless defs from IndexedFile before returning
|
||||||
|
// TODO!!: Strip useless defs from IndexedFile before returning
|
||||||
|
// TODO!!: Strip useless defs from IndexedFile before returning
|
||||||
|
// TODO!!: Strip useless defs from IndexedFile before returning
|
||||||
|
// TODO!!: Strip useless defs from IndexedFile before returning
|
||||||
|
// TODO!!: Strip useless defs from IndexedFile before returning
|
||||||
|
// TODO!!
|
||||||
|
// TODO!!
|
||||||
|
// TODO!!
|
||||||
clang_toggleCrashRecovery(1);
|
clang_toggleCrashRecovery(1);
|
||||||
|
|
||||||
args.push_back("-std=c++11");
|
args.push_back("-std=c++11");
|
||||||
|
108
src/typed_bidi_message_queue.h
Normal file
108
src/typed_bidi_message_queue.h
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <iostream>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
#include "buffer.h"
|
||||||
|
#include "message_queue.h"
|
||||||
|
#include "../serializer.h"
|
||||||
|
|
||||||
|
// TypedBidiMessageQueue provides a type-safe server/client implementation on
|
||||||
|
// top of a couple MessageQueue instances.
|
||||||
|
template <typename TId, typename TMessage>
|
||||||
|
struct TypedBidiMessageQueue {
|
||||||
|
using Serializer = std::function<void(Writer& visitor, TMessage& message)>;
|
||||||
|
using Deserializer =
|
||||||
|
std::function<std::unique_ptr<TMessage>(Reader& visitor)>;
|
||||||
|
|
||||||
|
TypedBidiMessageQueue(const std::string& name, size_t buffer_size)
|
||||||
|
: for_server(
|
||||||
|
Buffer::CreateSharedBuffer(name + "_for_server", buffer_size),
|
||||||
|
false /*buffer_has_data*/),
|
||||||
|
for_client(
|
||||||
|
Buffer::CreateSharedBuffer(name + "_for_client", buffer_size),
|
||||||
|
true /*buffer_has_data*/) {}
|
||||||
|
|
||||||
|
void RegisterId(TId id,
|
||||||
|
const Serializer& serializer,
|
||||||
|
const Deserializer& deseriaizer) {
|
||||||
|
assert(serializers_.find(id) == serializers_.end() &&
|
||||||
|
deserializers_.find(id) == deserializers_.end() &&
|
||||||
|
"Duplicate registration");
|
||||||
|
|
||||||
|
serializers_[id] = serializer;
|
||||||
|
deserializers_[id] = deserializer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SendMessage(MessageQueue* destination, TId id, TMessage* message) {
|
||||||
|
// Create writer.
|
||||||
|
rapidjson::StringBuffer output;
|
||||||
|
rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(output);
|
||||||
|
writer.SetIndent(' ', 0);
|
||||||
|
|
||||||
|
// Serialize the message.
|
||||||
|
assert(serializers_.find(message->id) != serializers_.end() &&
|
||||||
|
"No registered serializer");
|
||||||
|
const Serializer& serializer = serializers_.find(id)->second;
|
||||||
|
serializer(writer, *message);
|
||||||
|
|
||||||
|
// Send message.
|
||||||
|
void* payload = malloc(sizeof(MessageHeader) + output.GetSize());
|
||||||
|
reinterpret_cast<MessageHeader*>(payload)->id = id;
|
||||||
|
memcpy(
|
||||||
|
(void*)(reinterpret_cast<const char*>(payload) + sizeof(MessageHeader)),
|
||||||
|
output.GetString(), output.GetSize());
|
||||||
|
destination->Enqueue(
|
||||||
|
Message(payload, sizeof(MessageHeader) + output.GetSize()));
|
||||||
|
free(payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve all messages from the given |queue|.
|
||||||
|
std::vector<std::unique_ptr<TMessage>> GetMessages(
|
||||||
|
MessageQueue* queue) const {
|
||||||
|
assert(queue == &for_server || queue == &for_client);
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<Buffer>> messages = queue->DequeueAll();
|
||||||
|
std::vector<std::unique_ptr<TMessage>> result;
|
||||||
|
result.reserve(messages.size());
|
||||||
|
|
||||||
|
for (std::unique_ptr<Buffer>& buffer : messages) {
|
||||||
|
MessageHeader* header = reinterpret_cast<MessageHeader*>(buffer->data);
|
||||||
|
|
||||||
|
// Parse message content.
|
||||||
|
rapidjson::Document document;
|
||||||
|
document.Parse(
|
||||||
|
reinterpret_cast<const char*>(buffer->data) + sizeof(MessageHeader),
|
||||||
|
buffer->capacity - sizeof(MessageHeader));
|
||||||
|
bool has_error = document.HasParseError();
|
||||||
|
auto error = document.GetParseError();
|
||||||
|
if (has_error) {
|
||||||
|
std::cerr << "[FATAL]: Unable to parse IPC message" << std::endl;
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deserialize it.
|
||||||
|
assert(deserializers_.find(header->id) != deserializers_.end() &&
|
||||||
|
"No registered deserializer");
|
||||||
|
const Deserializer& deserializer =
|
||||||
|
deserializers_.find(header->id)->second;
|
||||||
|
result.emplace_back(deserializer(document));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Messages which the server process should handle.
|
||||||
|
MessageQueue for_server;
|
||||||
|
// Messages which the client process should handle.
|
||||||
|
MessageQueue for_client;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct MessageHeader {
|
||||||
|
TId id;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unordered_map<TId, Serializer> serializers_;
|
||||||
|
std::unordered_map<TId, Deserializer> deserializers_;
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user