Commit be1d3de4 by Niels Lohmann Committed by Théo DELRIEU

💄 moved changes to re2c file and ran `make pretty`

parent aa2679a8
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -39,66 +39,66 @@ TEST_CASE("lexer class") ...@@ -39,66 +39,66 @@ TEST_CASE("lexer class")
SECTION("structural characters") SECTION("structural characters")
{ {
CHECK((json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("["), CHECK((json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("["),
1).scan() == json::lexer::token_type::begin_array)); 1).scan() == json::lexer::token_type::begin_array));
CHECK((json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("]"), CHECK((json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("]"),
1).scan() == json::lexer::token_type::end_array)); 1).scan() == json::lexer::token_type::end_array));
CHECK((json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("{"), CHECK((json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("{"),
1).scan() == json::lexer::token_type::begin_object)); 1).scan() == json::lexer::token_type::begin_object));
CHECK((json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("}"), CHECK((json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("}"),
1).scan() == json::lexer::token_type::end_object)); 1).scan() == json::lexer::token_type::end_object));
CHECK((json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>(","), CHECK((json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>(","),
1).scan() == json::lexer::token_type::value_separator)); 1).scan() == json::lexer::token_type::value_separator));
CHECK((json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>(":"), CHECK((json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>(":"),
1).scan() == json::lexer::token_type::name_separator)); 1).scan() == json::lexer::token_type::name_separator));
} }
SECTION("literal names") SECTION("literal names")
{ {
CHECK((json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("null"), CHECK((json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("null"),
4).scan() == json::lexer::token_type::literal_null)); 4).scan() == json::lexer::token_type::literal_null));
CHECK((json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("true"), CHECK((json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("true"),
4).scan() == json::lexer::token_type::literal_true)); 4).scan() == json::lexer::token_type::literal_true));
CHECK((json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("false"), CHECK((json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("false"),
5).scan() == json::lexer::token_type::literal_false)); 5).scan() == json::lexer::token_type::literal_false));
} }
SECTION("numbers") SECTION("numbers")
{ {
CHECK((json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("0"), CHECK((json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("0"),
1).scan() == json::lexer::token_type::value_number)); 1).scan() == json::lexer::token_type::value_number));
CHECK((json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("1"), CHECK((json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("1"),
1).scan() == json::lexer::token_type::value_number)); 1).scan() == json::lexer::token_type::value_number));
CHECK((json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("2"), CHECK((json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("2"),
1).scan() == json::lexer::token_type::value_number)); 1).scan() == json::lexer::token_type::value_number));
CHECK((json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("3"), CHECK((json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("3"),
1).scan() == json::lexer::token_type::value_number)); 1).scan() == json::lexer::token_type::value_number));
CHECK((json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("4"), CHECK((json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("4"),
1).scan() == json::lexer::token_type::value_number)); 1).scan() == json::lexer::token_type::value_number));
CHECK((json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("5"), CHECK((json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("5"),
1).scan() == json::lexer::token_type::value_number)); 1).scan() == json::lexer::token_type::value_number));
CHECK((json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("6"), CHECK((json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("6"),
1).scan() == json::lexer::token_type::value_number)); 1).scan() == json::lexer::token_type::value_number));
CHECK((json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("7"), CHECK((json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("7"),
1).scan() == json::lexer::token_type::value_number)); 1).scan() == json::lexer::token_type::value_number));
CHECK((json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("8"), CHECK((json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("8"),
1).scan() == json::lexer::token_type::value_number)); 1).scan() == json::lexer::token_type::value_number));
CHECK((json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("9"), CHECK((json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("9"),
1).scan() == json::lexer::token_type::value_number)); 1).scan() == json::lexer::token_type::value_number));
} }
SECTION("whitespace") SECTION("whitespace")
{ {
// result is end_of_input, because not token is following // result is end_of_input, because not token is following
CHECK((json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>(" "), CHECK((json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>(" "),
1).scan() == json::lexer::token_type::end_of_input)); 1).scan() == json::lexer::token_type::end_of_input));
CHECK((json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("\t"), CHECK((json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("\t"),
1).scan() == json::lexer::token_type::end_of_input)); 1).scan() == json::lexer::token_type::end_of_input));
CHECK((json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("\n"), CHECK((json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("\n"),
1).scan() == json::lexer::token_type::end_of_input)); 1).scan() == json::lexer::token_type::end_of_input));
CHECK((json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("\r"), CHECK((json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>("\r"),
1).scan() == json::lexer::token_type::end_of_input)); 1).scan() == json::lexer::token_type::end_of_input));
CHECK((json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>(" \t\n\r\n\t "), CHECK((json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>(" \t\n\r\n\t "),
7).scan() == json::lexer::token_type::end_of_input)); 7).scan() == json::lexer::token_type::end_of_input));
} }
} }
......
...@@ -38,252 +38,257 @@ using nlohmann::json; ...@@ -38,252 +38,257 @@ using nlohmann::json;
namespace udt namespace udt
{ {
enum class country enum class country
{ {
china, china,
france, france,
russia russia
}; };
struct age struct age
{ {
int m_val; int m_val;
}; };
struct name struct name
{ {
std::string m_val; std::string m_val;
}; };
struct address struct address
{ {
std::string m_val; std::string m_val;
}; };
struct person struct person
{ {
age m_age; age m_age;
name m_name; name m_name;
country m_country; country m_country;
}; };
struct contact struct contact
{ {
person m_person; person m_person;
address m_address; address m_address;
}; };
struct contact_book struct contact_book
{ {
name m_book_name; name m_book_name;
std::vector<contact> m_contacts; std::vector<contact> m_contacts;
}; };
} }
// to_json methods // to_json methods
namespace udt namespace udt
{ {
// templates because of the custom_json tests (see below) // templates because of the custom_json tests (see below)
template <typename Json> template <typename Json>
void to_json(Json& j, age a) void to_json(Json& j, age a)
{ {
j = a.m_val; j = a.m_val;
} }
template <typename Json> template <typename Json>
void to_json(Json& j, name const& n) void to_json(Json& j, name const& n)
{ {
j = n.m_val; j = n.m_val;
} }
template <typename Json> template <typename Json>
void to_json(Json& j, country c) void to_json(Json& j, country c)
{ {
switch (c) switch (c)
{ {
case country::china: case country::china:
j = u8"中华人民共和国"; j = u8"中华人民共和国";
return; return;
case country::france: case country::france:
j = "France"; j = "France";
return; return;
case country::russia: case country::russia:
j = u8"Российская Федерация"; j = u8"Российская Федерация";
return; return;
} }
} }
template <typename Json> template <typename Json>
void to_json(Json& j, person const& p) void to_json(Json& j, person const& p)
{ {
j = Json{{"age", p.m_age}, {"name", p.m_name}, {"country", p.m_country}}; j = Json{{"age", p.m_age}, {"name", p.m_name}, {"country", p.m_country}};
} }
void to_json(nlohmann::json& j, address const& a) void to_json(nlohmann::json& j, address const& a)
{ {
j = a.m_val; j = a.m_val;
} }
void to_json(nlohmann::json& j, contact const& c) void to_json(nlohmann::json& j, contact const& c)
{ {
j = json{{"person", c.m_person}, {"address", c.m_address}}; j = json{{"person", c.m_person}, {"address", c.m_address}};
} }
void to_json(nlohmann::json& j, contact_book const& cb) void to_json(nlohmann::json& j, contact_book const& cb)
{ {
j = json{{"name", cb.m_book_name}, {"contacts", cb.m_contacts}}; j = json{{"name", cb.m_book_name}, {"contacts", cb.m_contacts}};
} }
// operators // operators
bool operator==(age lhs, age rhs) bool operator==(age lhs, age rhs)
{ {
return lhs.m_val == rhs.m_val; return lhs.m_val == rhs.m_val;
} }
bool operator==(address const &lhs, address const &rhs) bool operator==(address const& lhs, address const& rhs)
{ {
return lhs.m_val == rhs.m_val; return lhs.m_val == rhs.m_val;
} }
bool operator==(name const &lhs, name const &rhs) bool operator==(name const& lhs, name const& rhs)
{ {
return lhs.m_val == rhs.m_val; return lhs.m_val == rhs.m_val;
} }
bool operator==(person const &lhs, person const &rhs) bool operator==(person const& lhs, person const& rhs)
{ {
return std::tie(lhs.m_name, lhs.m_age) == std::tie(rhs.m_name, rhs.m_age); return std::tie(lhs.m_name, lhs.m_age) == std::tie(rhs.m_name, rhs.m_age);
} }
bool operator==(contact const &lhs, contact const &rhs) bool operator==(contact const& lhs, contact const& rhs)
{ {
return std::tie(lhs.m_person, lhs.m_address) == return std::tie(lhs.m_person, lhs.m_address) ==
std::tie(rhs.m_person, rhs.m_address); std::tie(rhs.m_person, rhs.m_address);
} }
bool operator==(contact_book const &lhs, contact_book const &rhs) bool operator==(contact_book const& lhs, contact_book const& rhs)
{ {
return std::tie(lhs.m_book_name, lhs.m_contacts) == return std::tie(lhs.m_book_name, lhs.m_contacts) ==
std::tie(rhs.m_book_name, rhs.m_contacts); std::tie(rhs.m_book_name, rhs.m_contacts);
} }
} }
// from_json methods // from_json methods
namespace udt namespace udt
{ {
template <typename Json> template <typename Json>
void from_json(Json const& j, age &a) void from_json(Json const& j, age& a)
{ {
a.m_val = j.template get<int>(); a.m_val = j.template get<int>();
} }
template <typename Json> template <typename Json>
void from_json(Json const& j, name &n) void from_json(Json const& j, name& n)
{ {
n.m_val = j.template get<std::string>(); n.m_val = j.template get<std::string>();
} }
template <typename Json> template <typename Json>
void from_json(Json const &j, country &c) void from_json(Json const& j, country& c)
{ {
const auto str = j.template get<std::string>(); const auto str = j.template get<std::string>();
static const std::map<std::string, country> m = { static const std::map<std::string, country> m =
{
{u8"中华人民共和国", country::china}, {u8"中华人民共和国", country::china},
{"France", country::france}, {"France", country::france},
{"Российская Федерация", country::russia}}; {"Российская Федерация", country::russia}
};
const auto it = m.find(str); const auto it = m.find(str);
// TODO test exceptions // TODO test exceptions
c = it->second; c = it->second;
} }
template <typename Json> template <typename Json>
void from_json(Json const& j, person &p) void from_json(Json const& j, person& p)
{ {
p.m_age = j["age"].template get<age>(); p.m_age = j["age"].template get<age>();
p.m_name = j["name"].template get<name>(); p.m_name = j["name"].template get<name>();
p.m_country = j["country"].template get<country>(); p.m_country = j["country"].template get<country>();
} }
void from_json(nlohmann::json const &j, address &a) void from_json(nlohmann::json const& j, address& a)
{ {
a.m_val = j.get<std::string>(); a.m_val = j.get<std::string>();
} }
void from_json(nlohmann::json const& j, contact &c) void from_json(nlohmann::json const& j, contact& c)
{ {
c.m_person = j["person"].get<person>(); c.m_person = j["person"].get<person>();
c.m_address = j["address"].get<address>(); c.m_address = j["address"].get<address>();
} }
void from_json(nlohmann::json const&j, contact_book &cb) void from_json(nlohmann::json const& j, contact_book& cb)
{ {
cb.m_book_name = j["name"].get<name>(); cb.m_book_name = j["name"].get<name>();
cb.m_contacts = j["contacts"].get<std::vector<contact>>(); cb.m_contacts = j["contacts"].get<std::vector<contact>>();
} }
} }
TEST_CASE("basic usage", "[udt]") TEST_CASE("basic usage", "[udt]")
{ {
// a bit narcissic maybe :) ? // a bit narcissic maybe :) ?
const udt::age a{23}; const udt::age a
const udt::name n{"theo"}; {
const udt::country c{udt::country::france}; 23
const udt::person sfinae_addict{a, n, c}; };
const udt::person senior_programmer{{42}, {u8"王芳"}, udt::country::china}; const udt::name n{"theo"};
const udt::address addr{"Paris"}; const udt::country c{udt::country::france};
const udt::contact cpp_programmer{sfinae_addict, addr}; const udt::person sfinae_addict{a, n, c};
const udt::contact_book book{{"C++"}, {cpp_programmer, {senior_programmer, addr}}}; const udt::person senior_programmer{{42}, {u8"王芳"}, udt::country::china};
const udt::address addr{"Paris"};
SECTION("conversion to json via free-functions") const udt::contact cpp_programmer{sfinae_addict, addr};
{ const udt::contact_book book{{"C++"}, {cpp_programmer, {senior_programmer, addr}}};
CHECK(json(a) == json(23));
CHECK(json(n) == json("theo")); SECTION("conversion to json via free-functions")
CHECK(json(c) == json("France")); {
CHECK(json(sfinae_addict) == R"({"name":"theo", "age":23, "country":"France"})"_json); CHECK(json(a) == json(23));
CHECK(json("Paris") == json(addr)); CHECK(json(n) == json("theo"));
CHECK(json(cpp_programmer) == CHECK(json(c) == json("France"));
R"({"person" : {"age":23, "name":"theo", "country":"France"}, "address":"Paris"})"_json); CHECK(json(sfinae_addict) == R"({"name":"theo", "age":23, "country":"France"})"_json);
CHECK(json("Paris") == json(addr));
CHECK( CHECK(json(cpp_programmer) ==
json(book) == R"({"person" : {"age":23, "name":"theo", "country":"France"}, "address":"Paris"})"_json);
u8R"({"name":"C++", "contacts" : [{"person" : {"age":23, "name":"theo", "country":"France"}, "address":"Paris"}, {"person" : {"age":42, "country":"中华人民共和国", "name":"王芳"}, "address":"Paris"}]})"_json);
CHECK(
} json(book) ==
u8R"({"name":"C++", "contacts" : [{"person" : {"age":23, "name":"theo", "country":"France"}, "address":"Paris"}, {"person" : {"age":42, "country":"中华人民共和国", "name":"王芳"}, "address":"Paris"}]})"_json);
SECTION("conversion from json via free-functions")
{ }
const auto big_json =
u8R"({"name":"C++", "contacts" : [{"person" : {"age":23, "name":"theo", "country":"France"}, "address":"Paris"}, {"person" : {"age":42, "country":"中华人民共和国", "name":"王芳"}, "address":"Paris"}]})"_json; SECTION("conversion from json via free-functions")
const auto parsed_book = big_json.get<udt::contact_book>(); {
const auto book_name = big_json["name"].get<udt::name>(); const auto big_json =
const auto contacts = big_json["contacts"].get<std::vector<udt::contact>>(); u8R"({"name":"C++", "contacts" : [{"person" : {"age":23, "name":"theo", "country":"France"}, "address":"Paris"}, {"person" : {"age":42, "country":"中华人民共和国", "name":"王芳"}, "address":"Paris"}]})"_json;
const auto contact_json = big_json["contacts"].at(0); const auto parsed_book = big_json.get<udt::contact_book>();
const auto contact = contact_json.get<udt::contact>(); const auto book_name = big_json["name"].get<udt::name>();
const auto person = contact_json["person"].get<udt::person>(); const auto contacts = big_json["contacts"].get<std::vector<udt::contact>>();
const auto address = contact_json["address"].get<udt::address>(); const auto contact_json = big_json["contacts"].at(0);
const auto age = contact_json["person"]["age"].get<udt::age>(); const auto contact = contact_json.get<udt::contact>();
const auto country = contact_json["person"]["country"].get<udt::country>(); const auto person = contact_json["person"].get<udt::person>();
const auto name = contact_json["person"]["name"].get<udt::name>(); const auto address = contact_json["address"].get<udt::address>();
const auto age = contact_json["person"]["age"].get<udt::age>();
CHECK(age == a); const auto country = contact_json["person"]["country"].get<udt::country>();
CHECK(name == n); const auto name = contact_json["person"]["name"].get<udt::name>();
CHECK(country == c);
CHECK(address == addr); CHECK(age == a);
CHECK(person == sfinae_addict); CHECK(name == n);
CHECK(contact == cpp_programmer); CHECK(country == c);
CHECK(contacts == book.m_contacts); CHECK(address == addr);
CHECK(book_name == udt::name{"C++"}); CHECK(person == sfinae_addict);
CHECK(book == parsed_book); CHECK(contact == cpp_programmer);
} CHECK(contacts == book.m_contacts);
CHECK(book_name == udt::name{"C++"});
CHECK(book == parsed_book);
}
} }
namespace udt namespace udt
{ {
struct legacy_type struct legacy_type
{ {
std::string number; std::string number;
}; };
} }
...@@ -292,88 +297,96 @@ namespace nlohmann ...@@ -292,88 +297,96 @@ namespace nlohmann
template <typename T> template <typename T>
struct adl_serializer<std::shared_ptr<T>> struct adl_serializer<std::shared_ptr<T>>
{ {
static void to_json(json& j, std::shared_ptr<T> const& opt) static void to_json(json& j, std::shared_ptr<T> const& opt)
{ {
if (opt) if (opt)
j = *opt; {
else j = *opt;
j = nullptr; }
} else
{
static void from_json(json const &j, std::shared_ptr<T> &opt) j = nullptr;
{ }
if (j.is_null()) }
opt = nullptr;
else static void from_json(json const& j, std::shared_ptr<T>& opt)
opt.reset(new T(j.get<T>())); {
} if (j.is_null())
{
opt = nullptr;
}
else
{
opt.reset(new T(j.get<T>()));
}
}
}; };
template <> template <>
struct adl_serializer<udt::legacy_type> struct adl_serializer<udt::legacy_type>
{ {
static void to_json(json& j, udt::legacy_type const& l) static void to_json(json& j, udt::legacy_type const& l)
{ {
j = std::stoi(l.number); j = std::stoi(l.number);
} }
static void from_json(json const& j, udt::legacy_type& l) static void from_json(json const& j, udt::legacy_type& l)
{ {
l.number = std::to_string(j.get<int>()); l.number = std::to_string(j.get<int>());
} }
}; };
} }
TEST_CASE("adl_serializer specialization", "[udt]") TEST_CASE("adl_serializer specialization", "[udt]")
{ {
SECTION("partial specialization") SECTION("partial specialization")
{
SECTION("to_json")
{ {
std::shared_ptr<udt::person> optPerson; SECTION("to_json")
{
std::shared_ptr<udt::person> optPerson;
json j = optPerson; json j = optPerson;
CHECK(j.is_null()); CHECK(j.is_null());
optPerson.reset(new udt::person{{42}, {"John Doe"}}); optPerson.reset(new udt::person{{42}, {"John Doe"}});
j = optPerson; j = optPerson;
CHECK_FALSE(j.is_null()); CHECK_FALSE(j.is_null());
CHECK(j.get<udt::person>() == *optPerson); CHECK(j.get<udt::person>() == *optPerson);
} }
SECTION("from_json") SECTION("from_json")
{ {
auto person = udt::person{{42}, {"John Doe"}}; auto person = udt::person{{42}, {"John Doe"}};
json j = person; json j = person;
auto optPerson = j.get<std::shared_ptr<udt::person>>(); auto optPerson = j.get<std::shared_ptr<udt::person>>();
REQUIRE(optPerson); REQUIRE(optPerson);
CHECK(*optPerson == person); CHECK(*optPerson == person);
j = nullptr; j = nullptr;
optPerson = j.get<std::shared_ptr<udt::person>>(); optPerson = j.get<std::shared_ptr<udt::person>>();
CHECK(!optPerson); CHECK(!optPerson);
}
} }
}
SECTION("total specialization") SECTION("total specialization")
{
SECTION("to_json")
{ {
udt::legacy_type lt{"4242"}; SECTION("to_json")
{
json j = lt; udt::legacy_type lt{"4242"};
CHECK(j.get<int>() == 4242);
json j = lt;
CHECK(j.get<int>() == 4242);
}
SECTION("from_json")
{
json j = 4242;
auto lt = j.get<udt::legacy_type>();
CHECK(lt.number == "4242");
}
} }
SECTION("from_json")
{
json j = 4242;
auto lt = j.get<udt::legacy_type>();
CHECK(lt.number == "4242");
}
}
} }
namespace nlohmann namespace nlohmann
...@@ -383,22 +396,22 @@ namespace nlohmann ...@@ -383,22 +396,22 @@ namespace nlohmann
template <typename T> template <typename T>
struct adl_serializer<std::vector<T>> struct adl_serializer<std::vector<T>>
{ {
static void to_json(json& j, std::vector<T> const& opt) static void to_json(json& j, std::vector<T> const& opt)
{ {
} }
static void from_json(json const &j, std::vector<T> &opt) static void from_json(json const& j, std::vector<T>& opt)
{ {
} }
}; };
} }
TEST_CASE("current supported types are preferred over specializations", "[udt]") TEST_CASE("current supported types are preferred over specializations", "[udt]")
{ {
json j = std::vector<int>{1, 2, 3}; json j = std::vector<int> {1, 2, 3};
auto f = j.get<std::vector<int>>(); auto f = j.get<std::vector<int>>();
CHECK((f == std::vector<int>{1, 2, 3})); CHECK((f == std::vector<int> {1, 2, 3}));
} }
namespace nlohmann namespace nlohmann
...@@ -406,55 +419,63 @@ namespace nlohmann ...@@ -406,55 +419,63 @@ namespace nlohmann
template <typename T> template <typename T>
struct adl_serializer<std::unique_ptr<T>> struct adl_serializer<std::unique_ptr<T>>
{ {
static void to_json(json& j, std::unique_ptr<T> const& opt) static void to_json(json& j, std::unique_ptr<T> const& opt)
{ {
if (opt) if (opt)
j = *opt; {
else j = *opt;
j = nullptr; }
} else
{
// this is the overload needed for non-copyable types, j = nullptr;
// should we add a priority tag in the implementation to prefer this overload if it exists? }
static std::unique_ptr<T> from_json(json const &j) }
{
if (j.is_null()) // this is the overload needed for non-copyable types,
return nullptr; // should we add a priority tag in the implementation to prefer this overload if it exists?
else static std::unique_ptr<T> from_json(json const& j)
return std::unique_ptr<T>(new T(j.get<T>())); {
} if (j.is_null())
{
return nullptr;
}
else
{
return std::unique_ptr<T>(new T(j.get<T>()));
}
}
}; };
} }
TEST_CASE("Non-copyable types", "[udt]") TEST_CASE("Non-copyable types", "[udt]")
{ {
SECTION("to_json") SECTION("to_json")
{ {
std::unique_ptr<udt::person> optPerson; std::unique_ptr<udt::person> optPerson;
json j = optPerson; json j = optPerson;
CHECK(j.is_null()); CHECK(j.is_null());
optPerson.reset(new udt::person{{42}, {"John Doe"}}); optPerson.reset(new udt::person{{42}, {"John Doe"}});
j = optPerson; j = optPerson;
CHECK_FALSE(j.is_null()); CHECK_FALSE(j.is_null());
CHECK(j.get<udt::person>() == *optPerson); CHECK(j.get<udt::person>() == *optPerson);
} }
SECTION("from_json") SECTION("from_json")
{ {
auto person = udt::person{{42}, {"John Doe"}}; auto person = udt::person{{42}, {"John Doe"}};
json j = person; json j = person;
auto optPerson = j.get<std::unique_ptr<udt::person>>(); auto optPerson = j.get<std::unique_ptr<udt::person>>();
REQUIRE(optPerson); REQUIRE(optPerson);
CHECK(*optPerson == person); CHECK(*optPerson == person);
j = nullptr; j = nullptr;
optPerson = j.get<std::unique_ptr<udt::person>>(); optPerson = j.get<std::unique_ptr<udt::person>>();
CHECK(!optPerson); CHECK(!optPerson);
} }
} }
// custom serializer // custom serializer
...@@ -462,87 +483,89 @@ TEST_CASE("Non-copyable types", "[udt]") ...@@ -462,87 +483,89 @@ TEST_CASE("Non-copyable types", "[udt]")
template <typename T, typename = typename std::enable_if<std::is_pod<T>::value>::type> template <typename T, typename = typename std::enable_if<std::is_pod<T>::value>::type>
struct pod_serializer struct pod_serializer
{ {
// I could forward-declare this struct, and add a basic_json alias // I could forward-declare this struct, and add a basic_json alias
template <typename Json> template <typename Json>
static void from_json(Json const& j , T& t) static void from_json(Json const& j , T& t)
{ {
auto value = j.template get<std::uint64_t>(); auto value = j.template get<std::uint64_t>();
auto bytes = static_cast<char*>(static_cast<void*>(&value)); auto bytes = static_cast<char*>(static_cast<void*>(&value));
std::memcpy(&t, bytes, sizeof(value)); std::memcpy(&t, bytes, sizeof(value));
} }
template <typename Json> template <typename Json>
static void to_json(Json& j, T const& t) static void to_json(Json& j, T const& t)
{ {
auto bytes = static_cast<char const*>(static_cast<void const*>(&t)); auto bytes = static_cast<char const*>(static_cast<void const*>(&t));
std::uint64_t value = bytes[0]; std::uint64_t value = bytes[0];
for (auto i = 1; i < 8; ++i) for (auto i = 1; i < 8; ++i)
value |= bytes[i] << 8 * i; {
value |= bytes[i] << 8 * i;
j = value; }
}
j = value;
}
}; };
namespace udt namespace udt
{ {
struct small_pod struct small_pod
{ {
int begin; int begin;
char middle; char middle;
short end; short end;
}; };
bool operator==(small_pod lhs, small_pod rhs) bool operator==(small_pod lhs, small_pod rhs)
{ {
return std::tie(lhs.begin, lhs.middle, lhs.end) == return std::tie(lhs.begin, lhs.middle, lhs.end) ==
std::tie(lhs.begin, lhs.middle, lhs.end); std::tie(lhs.begin, lhs.middle, lhs.end);
} }
} }
TEST_CASE("custom serializer for pods", "[udt]") TEST_CASE("custom serializer for pods", "[udt]")
{ {
using custom_json = nlohmann::basic_json<std::map, std::vector, std::string, bool, std::int64_t, std::uint64_t, double, std::allocator, pod_serializer>; using custom_json = nlohmann::basic_json<std::map, std::vector, std::string, bool, std::int64_t, std::uint64_t, double, std::allocator, pod_serializer>;
auto p = udt::small_pod{42, '/', 42}; auto p = udt::small_pod{42, '/', 42};
custom_json j = p; custom_json j = p;
auto p2 = j.get<udt::small_pod>(); auto p2 = j.get<udt::small_pod>();
CHECK(p == p2); CHECK(p == p2);
} }
template <typename T, typename> template <typename T, typename>
struct another_adl_serializer; struct another_adl_serializer;
using custom_json = nlohmann::basic_json<std::map, std::vector, std::string, bool, std::int64_t, std::uint64_t, double, std::allocator, another_adl_serializer>; using custom_json = nlohmann::basic_json<std::map, std::vector, std::string, bool, std::int64_t, std::uint64_t, double, std::allocator, another_adl_serializer>;
template <typename T, typename> template <typename T, typename>
struct another_adl_serializer struct another_adl_serializer
{ {
static void from_json(custom_json const& j , T& t) static void from_json(custom_json const& j , T& t)
{ {
using nlohmann::from_json; using nlohmann::from_json;
from_json(j, t); from_json(j, t);
} }
static void to_json(custom_json& j , T const& t) static void to_json(custom_json& j , T const& t)
{ {
using nlohmann::to_json; using nlohmann::to_json;
to_json(j, t); to_json(j, t);
} }
}; };
TEST_CASE("custom serializer that does adl by default", "[udt]") TEST_CASE("custom serializer that does adl by default", "[udt]")
{ {
using json = nlohmann::json; using json = nlohmann::json;
auto me = udt::person{23, "theo", udt::country::france}; auto me = udt::person{23, "theo", udt::country::france};
json j = me; json j = me;
custom_json cj = me; custom_json cj = me;
CHECK(j.dump() == cj.dump()); CHECK(j.dump() == cj.dump());
CHECK(me == j.get<udt::person>()); CHECK(me == j.get<udt::person>());
CHECK(me == cj.get<udt::person>()); CHECK(me == cj.get<udt::person>());
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment