2018-04-04 22:34:18 +08:00
|
|
|
#include <experimental/optional>
|
|
|
|
#include <sstream>
|
|
|
|
|
|
|
|
#include "gtest/gtest.h"
|
|
|
|
|
2018-05-04 16:35:31 +08:00
|
|
|
#include "capnp/message.h"
|
2018-04-04 22:34:18 +08:00
|
|
|
#include "utils/serialization.hpp"
|
|
|
|
|
|
|
|
using std::experimental::optional;
|
|
|
|
using std::string_literals::operator""s;
|
|
|
|
|
2018-05-04 16:35:31 +08:00
|
|
|
void CheckOptionalInt(const std::experimental::optional<int> &x1) {
|
|
|
|
::capnp::MallocMessageBuilder message;
|
|
|
|
std::experimental::optional<int> y1;
|
|
|
|
{
|
|
|
|
auto builder =
|
|
|
|
message.initRoot<utils::capnp::Optional<utils::capnp::BoxInt32>>();
|
|
|
|
auto save = [](utils::capnp::BoxInt32::Builder *builder, int value) {
|
|
|
|
builder->setValue(value);
|
|
|
|
};
|
|
|
|
utils::SaveOptional<utils::capnp::BoxInt32, int>(x1, &builder, save);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
auto reader =
|
|
|
|
message.getRoot<utils::capnp::Optional<utils::capnp::BoxInt32>>();
|
|
|
|
auto load = [](const utils::capnp::BoxInt32::Reader &reader) -> int {
|
|
|
|
return reader.getValue();
|
|
|
|
};
|
|
|
|
y1 = utils::LoadOptional<utils::capnp::BoxInt32, int>(reader, load);
|
|
|
|
}
|
|
|
|
|
|
|
|
EXPECT_EQ(x1, y1);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(Serialization, CapnpOptional) {
|
|
|
|
std::experimental::optional<int> x1 = {};
|
|
|
|
std::experimental::optional<int> x2 = 42;
|
|
|
|
|
|
|
|
CheckOptionalInt(x1);
|
|
|
|
CheckOptionalInt(x2);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(Serialization, CapnpOptionalNonCopyable) {
|
|
|
|
std::experimental::optional<std::unique_ptr<int>> data =
|
|
|
|
std::make_unique<int>(5);
|
|
|
|
::capnp::MallocMessageBuilder message;
|
|
|
|
{
|
|
|
|
auto builder = message.initRoot<utils::capnp::Optional<
|
|
|
|
utils::capnp::UniquePtr<utils::capnp::BoxInt32>>>();
|
2018-05-16 19:48:56 +08:00
|
|
|
auto save = [](auto *ptr_builder, const auto &data) {
|
|
|
|
auto save_int = [](auto *int_builder, int value) {
|
|
|
|
int_builder->setValue(value);
|
2018-05-04 16:35:31 +08:00
|
|
|
};
|
2018-05-16 19:48:56 +08:00
|
|
|
utils::SaveUniquePtr<utils::capnp::BoxInt32, int>(data, ptr_builder,
|
2018-05-04 16:35:31 +08:00
|
|
|
save_int);
|
|
|
|
};
|
|
|
|
utils::SaveOptional<utils::capnp::UniquePtr<utils::capnp::BoxInt32>,
|
|
|
|
std::unique_ptr<int>>(data, &builder, save);
|
|
|
|
}
|
|
|
|
std::experimental::optional<std::unique_ptr<int>> element;
|
|
|
|
{
|
|
|
|
auto reader = message.getRoot<utils::capnp::Optional<
|
|
|
|
utils::capnp::UniquePtr<utils::capnp::BoxInt32>>>();
|
2018-05-16 19:48:56 +08:00
|
|
|
auto load = [](const auto &ptr_reader) {
|
|
|
|
auto load_int = [](const auto &int_reader) {
|
|
|
|
return new int(int_reader.getValue());
|
2018-05-04 16:35:31 +08:00
|
|
|
};
|
2018-05-16 19:48:56 +08:00
|
|
|
return utils::LoadUniquePtr<utils::capnp::BoxInt32, int>(ptr_reader,
|
2018-05-04 16:35:31 +08:00
|
|
|
load_int);
|
|
|
|
};
|
|
|
|
element =
|
|
|
|
utils::LoadOptional<utils::capnp::UniquePtr<utils::capnp::BoxInt32>,
|
|
|
|
std::unique_ptr<int>>(reader, load);
|
|
|
|
}
|
|
|
|
EXPECT_EQ(*element.value(), 5);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CheckUniquePtrInt(const std::unique_ptr<int> &x1) {
|
|
|
|
::capnp::MallocMessageBuilder message;
|
|
|
|
std::unique_ptr<int> y1;
|
|
|
|
{
|
|
|
|
auto builder =
|
|
|
|
message.initRoot<utils::capnp::UniquePtr<utils::capnp::BoxInt32>>();
|
|
|
|
auto save = [](utils::capnp::BoxInt32::Builder *builder, int value) {
|
|
|
|
builder->setValue(value);
|
|
|
|
};
|
|
|
|
utils::SaveUniquePtr<utils::capnp::BoxInt32, int>(x1, &builder, save);
|
|
|
|
}
|
|
|
|
{
|
|
|
|
auto reader =
|
|
|
|
message.getRoot<utils::capnp::UniquePtr<utils::capnp::BoxInt32>>();
|
2018-05-16 19:48:56 +08:00
|
|
|
auto load = [](const auto &int_reader) {
|
|
|
|
return new int(int_reader.getValue());
|
2018-05-04 16:35:31 +08:00
|
|
|
};
|
|
|
|
y1 = utils::LoadUniquePtr<utils::capnp::BoxInt32, int>(reader, load);
|
|
|
|
}
|
|
|
|
if (!x1)
|
|
|
|
EXPECT_EQ(y1, nullptr);
|
|
|
|
else
|
|
|
|
EXPECT_EQ(*x1, *y1);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(Serialization, CapnpUniquePtr) {
|
|
|
|
auto x1 = std::make_unique<int>(42);
|
|
|
|
std::unique_ptr<int> x2;
|
|
|
|
|
|
|
|
CheckUniquePtrInt(x1);
|
|
|
|
CheckUniquePtrInt(x2);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(Serialization, CapnpUniquePtrNonCopyable) {
|
|
|
|
std::unique_ptr<std::unique_ptr<int>> data =
|
|
|
|
std::make_unique<std::unique_ptr<int>>(std::make_unique<int>(5));
|
|
|
|
::capnp::MallocMessageBuilder message;
|
|
|
|
{
|
|
|
|
auto builder = message.initRoot<utils::capnp::UniquePtr<
|
|
|
|
utils::capnp::UniquePtr<utils::capnp::BoxInt32>>>();
|
2018-05-16 19:48:56 +08:00
|
|
|
auto save = [](auto *ptr_builder, const auto &data) {
|
|
|
|
auto save_int = [](auto *int_builder, int value) {
|
|
|
|
int_builder->setValue(value);
|
2018-05-04 16:35:31 +08:00
|
|
|
};
|
2018-05-16 19:48:56 +08:00
|
|
|
utils::SaveUniquePtr<utils::capnp::BoxInt32, int>(data, ptr_builder,
|
2018-05-04 16:35:31 +08:00
|
|
|
save_int);
|
|
|
|
};
|
|
|
|
utils::SaveUniquePtr<utils::capnp::UniquePtr<utils::capnp::BoxInt32>,
|
|
|
|
std::unique_ptr<int>>(data, &builder, save);
|
|
|
|
}
|
|
|
|
std::unique_ptr<std::unique_ptr<int>> element;
|
|
|
|
{
|
|
|
|
auto reader = message.getRoot<utils::capnp::UniquePtr<
|
|
|
|
utils::capnp::UniquePtr<utils::capnp::BoxInt32>>>();
|
2018-05-16 19:48:56 +08:00
|
|
|
auto load = [](const auto &ptr_reader) {
|
|
|
|
auto load_int = [](const auto &int_reader) {
|
|
|
|
return new int(int_reader.getValue());
|
2018-05-04 16:35:31 +08:00
|
|
|
};
|
2018-05-16 19:48:56 +08:00
|
|
|
return new std::unique_ptr<int>(
|
|
|
|
utils::LoadUniquePtr<utils::capnp::BoxInt32, int>(ptr_reader,
|
|
|
|
load_int));
|
2018-05-04 16:35:31 +08:00
|
|
|
};
|
|
|
|
element =
|
|
|
|
utils::LoadUniquePtr<utils::capnp::UniquePtr<utils::capnp::BoxInt32>,
|
|
|
|
std::unique_ptr<int>>(reader, load);
|
|
|
|
}
|
|
|
|
EXPECT_EQ(**element, 5);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(Serialization, CapnpSharedPtr) {
|
|
|
|
std::vector<int *> saved_pointers;
|
|
|
|
auto p1 = std::make_shared<int>(5);
|
|
|
|
std::shared_ptr<int> p2;
|
|
|
|
std::vector<std::shared_ptr<int>> pointers{p1, p1, p2};
|
|
|
|
::capnp::MallocMessageBuilder message;
|
|
|
|
{
|
|
|
|
auto builders = message.initRoot<
|
|
|
|
::capnp::List<utils::capnp::SharedPtr<utils::capnp::BoxInt32>>>(
|
|
|
|
pointers.size());
|
|
|
|
auto save = [](utils::capnp::BoxInt32::Builder *builder, int value) {
|
|
|
|
builder->setValue(value);
|
|
|
|
};
|
|
|
|
for (size_t i = 0; i < pointers.size(); ++i) {
|
|
|
|
auto ptr_builder = builders[i];
|
|
|
|
utils::SaveSharedPtr<utils::capnp::BoxInt32, int>(
|
|
|
|
pointers[i], &ptr_builder, save, &saved_pointers);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
EXPECT_EQ(saved_pointers.size(), 1);
|
|
|
|
std::vector<std::pair<uint64_t, std::shared_ptr<int>>> loaded_pointers;
|
|
|
|
std::vector<std::shared_ptr<int>> elements;
|
|
|
|
{
|
|
|
|
auto reader = message.getRoot<
|
|
|
|
::capnp::List<utils::capnp::SharedPtr<utils::capnp::BoxInt32>>>();
|
2018-05-16 19:48:56 +08:00
|
|
|
auto load = [](const auto &int_reader) {
|
|
|
|
return new int(int_reader.getValue());
|
2018-05-04 16:35:31 +08:00
|
|
|
};
|
|
|
|
for (const auto ptr_reader : reader) {
|
|
|
|
elements.emplace_back(utils::LoadSharedPtr<utils::capnp::BoxInt32, int>(
|
|
|
|
ptr_reader, load, &loaded_pointers));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
EXPECT_EQ(loaded_pointers.size(), 1);
|
|
|
|
EXPECT_EQ(elements.size(), 3);
|
|
|
|
EXPECT_EQ(*elements[0], 5);
|
|
|
|
EXPECT_EQ(*elements[0], *elements[1]);
|
|
|
|
EXPECT_EQ(elements[2].get(), nullptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(Serialization, CapnpSharedPtrNonCopyable) {
|
|
|
|
std::shared_ptr<std::unique_ptr<int>> data =
|
|
|
|
std::make_shared<std::unique_ptr<int>>(std::make_unique<int>(5));
|
|
|
|
std::vector<std::unique_ptr<int> *> saved_pointers;
|
|
|
|
::capnp::MallocMessageBuilder message;
|
|
|
|
{
|
|
|
|
auto builder = message.initRoot<utils::capnp::SharedPtr<
|
|
|
|
utils::capnp::UniquePtr<utils::capnp::BoxInt32>>>();
|
2018-05-16 19:48:56 +08:00
|
|
|
auto save = [](auto *ptr_builder, const auto &data) {
|
|
|
|
auto save_int = [](auto *int_builder, int value) {
|
|
|
|
int_builder->setValue(value);
|
2018-05-04 16:35:31 +08:00
|
|
|
};
|
2018-05-16 19:48:56 +08:00
|
|
|
utils::SaveUniquePtr<utils::capnp::BoxInt32, int>(data, ptr_builder,
|
2018-05-04 16:35:31 +08:00
|
|
|
save_int);
|
|
|
|
};
|
|
|
|
utils::SaveSharedPtr<utils::capnp::UniquePtr<utils::capnp::BoxInt32>,
|
|
|
|
std::unique_ptr<int>>(data, &builder, save,
|
|
|
|
&saved_pointers);
|
|
|
|
}
|
|
|
|
std::shared_ptr<std::unique_ptr<int>> element;
|
|
|
|
std::vector<std::pair<uint64_t, std::shared_ptr<std::unique_ptr<int>>>>
|
|
|
|
loaded_pointers;
|
|
|
|
{
|
|
|
|
auto reader = message.getRoot<utils::capnp::SharedPtr<
|
|
|
|
utils::capnp::UniquePtr<utils::capnp::BoxInt32>>>();
|
2018-05-16 19:48:56 +08:00
|
|
|
auto load = [](const auto &ptr_reader) {
|
|
|
|
auto load_int = [](const auto &int_reader) {
|
|
|
|
return new int(int_reader.getValue());
|
2018-05-04 16:35:31 +08:00
|
|
|
};
|
2018-05-16 19:48:56 +08:00
|
|
|
return new std::unique_ptr<int>(
|
|
|
|
utils::LoadUniquePtr<utils::capnp::BoxInt32, int>(ptr_reader,
|
|
|
|
load_int));
|
2018-05-04 16:35:31 +08:00
|
|
|
};
|
|
|
|
element =
|
|
|
|
utils::LoadSharedPtr<utils::capnp::UniquePtr<utils::capnp::BoxInt32>,
|
|
|
|
std::unique_ptr<int>>(reader, load,
|
|
|
|
&loaded_pointers);
|
|
|
|
}
|
|
|
|
EXPECT_EQ(**element, 5);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(Serialization, CapnpVectorPrimitive) {
|
|
|
|
std::vector<int> data{1, 2, 3};
|
|
|
|
::capnp::MallocMessageBuilder message;
|
|
|
|
{
|
|
|
|
auto list_builder = message.initRoot<::capnp::List<int>>(data.size());
|
|
|
|
utils::SaveVector<int>(data, &list_builder);
|
|
|
|
}
|
|
|
|
std::vector<int> elements;
|
|
|
|
{
|
|
|
|
auto reader = message.getRoot<::capnp::List<int>>();
|
|
|
|
utils::LoadVector<int>(&elements, reader);
|
|
|
|
}
|
|
|
|
EXPECT_EQ(elements.size(), 3);
|
|
|
|
EXPECT_EQ(elements[0], 1);
|
|
|
|
EXPECT_EQ(elements[1], 2);
|
|
|
|
EXPECT_EQ(elements[2], 3);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(Serialization, CapnpVector) {
|
|
|
|
std::vector<int> data{1, 2, 3};
|
|
|
|
::capnp::MallocMessageBuilder message;
|
|
|
|
{
|
|
|
|
auto list_builder =
|
|
|
|
message.initRoot<::capnp::List<utils::capnp::BoxInt32>>(data.size());
|
|
|
|
auto save = [](utils::capnp::BoxInt32::Builder *builder, int value) {
|
|
|
|
builder->setValue(value);
|
|
|
|
};
|
|
|
|
utils::SaveVector<utils::capnp::BoxInt32, int>(data, &list_builder, save);
|
|
|
|
}
|
|
|
|
std::vector<int> elements;
|
|
|
|
{
|
|
|
|
auto reader = message.getRoot<::capnp::List<utils::capnp::BoxInt32>>();
|
|
|
|
auto load = [](const utils::capnp::BoxInt32::Reader &reader) -> int {
|
|
|
|
return reader.getValue();
|
|
|
|
};
|
|
|
|
utils::LoadVector<utils::capnp::BoxInt32, int>(&elements, reader, load);
|
|
|
|
}
|
|
|
|
EXPECT_EQ(elements.size(), 3);
|
|
|
|
EXPECT_EQ(elements[0], 1);
|
|
|
|
EXPECT_EQ(elements[1], 2);
|
|
|
|
EXPECT_EQ(elements[2], 3);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(Serialization, CapnpVectorNonCopyable) {
|
|
|
|
std::vector<std::unique_ptr<int>> data;
|
|
|
|
data.emplace_back(std::make_unique<int>(5));
|
|
|
|
data.emplace_back(std::make_unique<int>(10));
|
|
|
|
::capnp::MallocMessageBuilder message;
|
|
|
|
{
|
|
|
|
auto list_builder = message.initRoot<
|
|
|
|
::capnp::List<utils::capnp::UniquePtr<utils::capnp::BoxInt32>>>(
|
|
|
|
data.size());
|
2018-05-16 19:48:56 +08:00
|
|
|
auto save = [](auto *ptr_builder, const auto &data) {
|
|
|
|
auto save_int = [](auto *int_builder, int value) {
|
|
|
|
int_builder->setValue(value);
|
2018-05-04 16:35:31 +08:00
|
|
|
};
|
2018-05-16 19:48:56 +08:00
|
|
|
utils::SaveUniquePtr<utils::capnp::BoxInt32, int>(data, ptr_builder,
|
2018-05-04 16:35:31 +08:00
|
|
|
save_int);
|
|
|
|
};
|
|
|
|
utils::SaveVector<utils::capnp::UniquePtr<utils::capnp::BoxInt32>,
|
|
|
|
std::unique_ptr<int>>(data, &list_builder, save);
|
|
|
|
}
|
|
|
|
std::vector<std::unique_ptr<int>> elements;
|
|
|
|
{
|
|
|
|
auto reader = message.getRoot<
|
|
|
|
::capnp::List<utils::capnp::UniquePtr<utils::capnp::BoxInt32>>>();
|
2018-05-16 19:48:56 +08:00
|
|
|
auto load = [](const auto &ptr_reader) {
|
|
|
|
auto load_int = [](const auto &int_reader) {
|
|
|
|
return new int(int_reader.getValue());
|
2018-05-04 16:35:31 +08:00
|
|
|
};
|
2018-05-16 19:48:56 +08:00
|
|
|
return utils::LoadUniquePtr<utils::capnp::BoxInt32, int>(ptr_reader,
|
2018-05-04 16:35:31 +08:00
|
|
|
load_int);
|
|
|
|
};
|
|
|
|
utils::LoadVector<utils::capnp::UniquePtr<utils::capnp::BoxInt32>,
|
|
|
|
std::unique_ptr<int>>(&elements, reader, load);
|
|
|
|
}
|
|
|
|
EXPECT_EQ(elements.size(), 2);
|
|
|
|
EXPECT_EQ(*elements[0], 5);
|
|
|
|
EXPECT_EQ(*elements[1], 10);
|
|
|
|
}
|
Replace boost with capnp in RPC
Summary:
Converts the RPC stack to use Cap'n Proto for serialization instead of
boost. There are still some traces of boost in other places in the code,
but most of it is removed. A future diff should cleanup boost for good.
The RPC API is now changed to be more flexible with regards to how
serialize data. This makes the simplest cases a bit more verbose, but
allows complex serialization code to be correctly written instead of
relying on hacks. (For reference, look for the old serialization of
`PullRpc` which had a nasty pointer hacks to inject accessors in
`TypedValue`.)
Since RPC messages were uselessly modeled via inheritance of Message
base class, that class is now removed. Furthermore, that approach
doesn't really work with Cap'n Proto. Instead, each message type is
required to have some type information. This can be automated, so
`define-rpc` has been added to LCP, which hopefully simplifies defining
new RPC request and response messages.
Specify Cap'n Proto schema ID in cmake
This preserves Cap'n Proto generated typeIds across multiple generations
of capnp schemas through LCP. It is imperative that typeId stays the
same to ensure that different compilations of Memgraph may communicate
via RPC in a distributed cluster.
Use CLOS for meta information on C++ types in LCP
Since some structure slots and functions have started to repeat
themselves, it makes sense to model C++ meta information via Common Lisp
Object System.
Depends on D1391
Reviewers: buda, dgleich, mferencevic, mtomic, mculinovic, msantl
Reviewed By: msantl
Subscribers: pullbot
Differential Revision: https://phabricator.memgraph.io/D1407
2018-06-04 15:48:48 +08:00
|
|
|
|
|
|
|
TEST(Serialization, CapnpMap) {
|
|
|
|
std::map<std::string, std::string> map{{"my_key", "my_value"},
|
|
|
|
{"other_key", "other_value"}};
|
|
|
|
::capnp::MallocMessageBuilder message;
|
|
|
|
{
|
|
|
|
auto map_builder =
|
|
|
|
message.initRoot<utils::capnp::Map<capnp::Text, capnp::Text>>();
|
|
|
|
utils::SaveMap<capnp::Text, capnp::Text>(
|
|
|
|
map, &map_builder, [](auto *entry_builder, const auto &entry) {
|
|
|
|
entry_builder->setKey(entry.first);
|
|
|
|
entry_builder->setValue(entry.second);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
std::map<std::string, std::string> new_map;
|
|
|
|
{
|
|
|
|
auto map_reader =
|
|
|
|
message.getRoot<utils::capnp::Map<capnp::Text, capnp::Text>>();
|
|
|
|
utils::LoadMap<capnp::Text, capnp::Text>(
|
|
|
|
&new_map, map_reader, [](const auto &entry_reader) {
|
|
|
|
std::string key = entry_reader.getKey();
|
|
|
|
std::string value = entry_reader.getValue();
|
|
|
|
return std::make_pair(key, value);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
EXPECT_EQ(new_map, map);
|
|
|
|
}
|