diff --git a/include/json.hpp b/include/json.hpp index eb9d43c..bd7ccc6 100644 --- a/include/json.hpp +++ b/include/json.hpp @@ -1119,7 +1119,12 @@ template template inline value_t basic_value::as() const { - return static_cast(*this); + if constexpr (std::is_same_v, value_t>) { + return *this; + } + else { + return static_cast(*this); + } } template @@ -2857,22 +2862,45 @@ static constexpr string_t unescape_string(const string_t& str) #define _MEOJSON_FOR_EACH_(N, what, ...) _MEOJSON_CONCATENATE(_MEOJSON_FOR_EACH_, N)(what, __VA_ARGS__) #define _MEOJSON_FOR_EACH(what, ...) _MEOJSON_FOR_EACH_(_MEOJSON_ARG_COUNT(__VA_ARGS__), what, __VA_ARGS__) -#define _MEOJSON_ARG_TO_PAIR(x) { _MEOJSON_STRINGIZE(x), json::serialize(x) }, +#define _MEOJSON_DUMP_ARG(x) \ + if constexpr (!std::is_same_v, json::_jsonization_helper::next_is_optional>) { \ + result.emplace(_MEOJSON_STRINGIZE(x), json::serialize(x)); \ + } -#define _MEOJSON_ARG_FROM_JSON(x) \ - if (auto _MEOJSON_CONCATENATE(x, _opt) = raw.find(#x)) \ - x = *std::move(_MEOJSON_CONCATENATE(x, _opt)); \ - else \ - return false; +#define _MEOJSON_LOAD_ARG(x) \ + if constexpr (std::is_same_v, json::_jsonization_helper::next_is_optional>) { \ + next_is_optional = true; \ + } \ + else if (auto opt = raw.find(_MEOJSON_STRINGIZE(x))) { \ + if (!opt->is()) { \ + return false; \ + } \ + x = std::move(opt)->as(); \ + next_is_optional = false; \ + } \ + else if (!next_is_optional) { \ + return false; \ + } + +namespace json::_jsonization_helper +{ +struct next_is_optional +{}; +} + +#define MEO_OPTIONAL json::_jsonization_helper::next_is_optional(), // if you are using MSVC, please add "/Zc:preprocessor" to your project -#define MEO_JSONIZATION(...) \ - json::object dump_to_json() const \ - { \ - return { _MEOJSON_FOR_EACH(_MEOJSON_ARG_TO_PAIR, __VA_ARGS__) }; \ - } \ - bool load_from_json(const json::object& raw) \ - { \ - _MEOJSON_FOR_EACH(_MEOJSON_ARG_FROM_JSON, __VA_ARGS__) \ - return true; \ +#define MEO_JSONIZATION(...) \ + json::object dump_to_json() const \ + { \ + json::object result; \ + _MEOJSON_FOR_EACH(_MEOJSON_DUMP_ARG, __VA_ARGS__) \ + return result; \ + } \ + bool load_from_json(const json::object& raw) \ + { \ + [[maybe_unused]] bool next_is_optional = false; \ + _MEOJSON_FOR_EACH(_MEOJSON_LOAD_ARG, __VA_ARGS__) \ + return true; \ } diff --git a/sample/sample.cpp b/sample/sample.cpp index 9082baa..73f48d2 100644 --- a/sample/sample.cpp +++ b/sample/sample.cpp @@ -307,8 +307,7 @@ void test_jsonization() int i = 0; double d = 0; - // if you are using MSVC, please add "/Zc:preprocessor" to your project - MEO_JSONIZATION(vec, map, i, d); + MEO_JSONIZATION(vec, map, MEO_OPTIONAL i, MEO_OPTIONAL d); }; MyStruct a; @@ -320,8 +319,12 @@ void test_jsonization() json::object j = a.dump_to_json(); std::cout << j << std::endl; + // for test MEO_OPTIONAL + j.erase("i"); + MyStruct b; - b.load_from_json(j); + bool loaded = b.load_from_json(j); + std::cout << "loaded: " << loaded << std::endl; std::cout << b.dump_to_json() << std::endl; }