diff --git a/CMakeLists.txt b/CMakeLists.txt index 8ddac2d..aa85211 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,9 +11,12 @@ option(BUILD_TESTING "Build testing" ON) set(CMAKE_CXX_STANDARD 17) if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" OR CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC") - add_compile_options("/utf-8" "/W4" "/WX") + add_compile_options("/utf-8" "/W4" "/WX" "/Zc:preprocessor") else() add_compile_options("-Wall;-Wextra;-Wpedantic;-Werror;-mtune=native") + if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") + add_compile_options("-Wno-gnu-zero-variadic-macro-arguments") + endif() if(CMAKE_SYSTEM_PROCESSOR MATCHES "AMD64|EM64T|x86_64") add_compile_options("-msse4.1") endif() diff --git a/README.md b/README.md index 0554bf8..ad9bbb5 100644 --- a/README.md +++ b/README.md @@ -256,3 +256,48 @@ void serializing() ofs.close(); } ``` + +### 序列化 + +```c++ +// 如果使用 MSVC, 请添加 "/Zc:preprocessor" 到项目配置中 +// 如果使用 AppleClang, 请添加 "-Wno-gnu-zero-variadic-macro-arguments" 到项目配置中 +void test_jsonization() +{ + struct MyStruct + { + std::vector vec; + std::map map; + int i = 0; + double d = 0; + + + // MEO_OPT 表示该变量是一个可选项 + // 即使输入中不存在该字段依然可以读取 + MEO_JSONIZATION(vec, map, MEO_OPT i, d); + }; + + MyStruct a; + a.vec = { 1, 2, 3 }; + a.map = { { "key", 5 } }; + a.i = 100; + a.d = 0.5; + + json::value dumps = a; + + // output: { "d" : 0.500000, "i" : 100, "map" : { "key" : 5 }, "vec" : [ 1, 2, 3 ] } + std::cout << dumps << std::endl; + + dumps.erase("i") + // output: { "d" : 0.500000, "map" : { "key" : 5 }, "vec" : [ 1, 2, 3 ] } + std::cout << dumps << std::endl; + + // MEO_OPT 表示该变量是一个可选项 + // 即使输入中不存在该字段依然可以读取 + MyStruct b(dumps); + + // output: { "d" : 0.500000, "i" : 0, "map" : { "key" : 5 }, "vec" : [ 1, 2, 3 ] } + // 我们从 dumps 中删除了 "i", 所以 "i" 是 0 + std::cout << json::value(b) << std::endl; +} +``` diff --git a/README_en.md b/README_en.md index 9abab83..18f9e3f 100644 --- a/README_en.md +++ b/README_en.md @@ -256,3 +256,47 @@ void serializing() ofs.close(); } ``` + +### JSONization + +```c++ +// if you are using MSVC, please add "/Zc:preprocessor" to your project +// if you are using AppleClang, please add "-Wno-gnu-zero-variadic-macro-arguments" to your project +void test_jsonization() +{ + struct MyStruct + { + std::vector vec; + std::map map; + int i = 0; + double d = 0; + + // MEO_OPT means the var is optional + // and can still be read even if the field doesn't exist in the input. + MEO_JSONIZATION(vec, map, MEO_OPT i, d); + }; + + MyStruct a; + a.vec = { 1, 2, 3 }; + a.map = { { "key", 5 } }; + a.i = 100; + a.d = 0.5; + + json::value dumps = a; + + // output: { "d" : 0.500000, "i" : 100, "map" : { "key" : 5 }, "vec" : [ 1, 2, 3 ] } + std::cout << dumps << std::endl; + + dumps.erase("i") + // output: { "d" : 0.500000, "map" : { "key" : 5 }, "vec" : [ 1, 2, 3 ] } + std::cout << dumps << std::endl; + + // MEO_OPT means the var is optional + // and can still be read even if the field doesn't exist in the input. + MyStruct b(dumps); + + // output: { "d" : 0.500000, "i" : 0, "map" : { "key" : 5 }, "vec" : [ 1, 2, 3 ] } + // "i" is 0 because we erase "i" from the dumps + std::cout << json::value(b) << std::endl; +} +``` diff --git a/include/json.hpp b/include/json.hpp index fa3b06d..9cbee67 100644 --- a/include/json.hpp +++ b/include/json.hpp @@ -59,7 +59,85 @@ namespace utils constexpr bool is_collection = false; template constexpr bool is_collection = is_container && !is_map; -} + + template + class has_to_json_in_member + { + template + static auto test(int) -> decltype(std::declval().to_json(), std::true_type()); + + template + static std::false_type test(...); + + public: + static constexpr bool value = decltype(test(0))::value; + }; + + template + class has_to_json_in_global + { + template + static auto test(int) -> decltype(to_json(std::declval()), std::true_type()); + + template + static std::false_type test(...); + + public: + static constexpr bool value = decltype(test(0))::value; + }; + + template + class has_check_json_in_member + { + template + static auto test(int) -> decltype(std::declval().check_json(std::declval()), std::true_type()); + + template + static std::false_type test(...); + + public: + static constexpr bool value = decltype(test(0))::value; + }; + + template + class has_check_json_in_global + { + template + static auto test(int) -> decltype(check_json(std::declval(), std::declval()), std::true_type()); + + template + static std::false_type test(...); + + public: + static constexpr bool value = decltype(test(0))::value; + }; + + template + class has_from_json_in_member + { + template + static auto test(int) -> decltype(std::declval().from_json(std::declval()), std::true_type()); + + template + static std::false_type test(...); + + public: + static constexpr bool value = decltype(test(0))::value; + }; + + template + class has_from_json_in_global + { + template + static auto test(int) -> decltype(from_json(std::declval(), std::declval()), std::true_type()); + + template + static std::false_type test(...); + + public: + static constexpr bool value = decltype(test(0))::value; + }; +} // namespace utils // ********************************* // * basic_value declare * @@ -126,6 +204,13 @@ class basic_value basic_value(map_t&& map) : basic_value(basic_object(std::forward(map))) {} + template ::value, bool> = true> + basic_value(const jsonization_t& jsonization) : basic_value(jsonization.to_json()) + {} + template ::value, bool> = true> + basic_value(const jsonization_t& jsonization) : basic_value(to_json(jsonization)) + {} + template >, bool> = true> basic_value(value_t) = delete; @@ -271,6 +356,9 @@ class basic_value explicit operator long double() const { return as_long_double(); } explicit operator string_t() const { return as_string(); } + explicit operator basic_array() const { return as_array(); } + explicit operator basic_object() const { return as_object(); } + template typename collection_t = std::vector, typename _ = std::enable_if_t>>> explicit operator collection_t() const @@ -334,14 +422,20 @@ class basic_array basic_array(std::initializer_list init_list); basic_array(typename raw_array::size_type size); - explicit basic_array(const basic_value& val); - explicit basic_array(basic_value&& val); + // explicit basic_array(const basic_value& val); + // explicit basic_array(basic_value&& val); template >>> basic_array(collection_t arr) : _array_data(std::make_move_iterator(arr.begin()), std::make_move_iterator(arr.end())) {} + template ::value, bool> = true> + basic_array(const jsonization_t& jsonization) : basic_array(jsonization.to_json()) + {} + template ::value, bool> = true> + basic_array(const jsonization_t& jsonization) : basic_array(to_json(jsonization)) + {} ~basic_array() noexcept = default; @@ -450,12 +544,20 @@ class basic_object basic_object(const basic_object& rhs) = default; basic_object(basic_object&& rhs) noexcept = default; basic_object(std::initializer_list init_list); - explicit basic_object(const basic_value& val); - explicit basic_object(basic_value&& val); + + // explicit basic_object(const basic_value& val); + // explicit basic_object(basic_value&& val); + template >>> basic_object(map_t map) : _object_data(std::make_move_iterator(map.begin()), std::make_move_iterator(map.end())) {} + template ::value, bool> = true> + basic_object(const jsonization_t& jsonization) : basic_object(jsonization.to_json()) + {} + template ::value, bool> = true> + basic_object(const jsonization_t& jsonization) : basic_object(to_json(jsonization)) + {} ~basic_object() = default; @@ -798,6 +900,12 @@ inline bool basic_value::is() const noexcept else if constexpr (std::is_constructible_v) { return is_string(); } + else if constexpr (utils::has_check_json_in_member::value) { + return value_t().check_json(*this); + } + else if constexpr (utils::has_check_json_in_global::value) { + return check_json(*this, value_t()); + } else { static_assert(!sizeof(value_t), "Unsupported type"); } @@ -1119,7 +1227,26 @@ template template inline value_t basic_value::as() const { - return static_cast(*this); + if constexpr (std::is_same_v, value_t>) { + return *this; + } + else if constexpr (utils::has_from_json_in_member::value) { + value_t val; + if (!val.from_json(*this)) { + throw exception("Wrong JSON"); + } + return val; + } + else if constexpr (utils::has_from_json_in_global::value) { + value_t val; + if (!from_json(*this, val)) { + throw exception("Wrong JSON"); + } + return val; + } + else { + return static_cast(*this); + } } template @@ -1423,14 +1550,14 @@ template inline basic_array::basic_array(typename raw_array::size_type size) : _array_data(size) {} -template -inline basic_array::basic_array(const basic_value& val) : basic_array(val.as_array()) -{} - -template -inline basic_array::basic_array(basic_value&& val) - : basic_array(std::move(val.as_array())) -{} +// template +// inline basic_array::basic_array(const basic_value& val) : basic_array(val.as_array()) +//{} +// +// template +// inline basic_array::basic_array(basic_value&& val) +// : basic_array(std::move(val.as_array())) +//{} template inline void basic_array::clear() noexcept @@ -1536,7 +1663,6 @@ template template typename collection_t> inline collection_t basic_array::as_collection() const { - collection_t result; if constexpr (_as_collection_helper::has_emplace_back>::value) { for (const auto& elem : _array_data) { @@ -1764,14 +1890,15 @@ inline basic_object::basic_object(std::initializer_list in : _object_data(std::make_move_iterator(init_list.begin()), std::make_move_iterator(init_list.end())) {} -template -inline basic_object::basic_object(const basic_value& val) : basic_object(val.as_object()) -{} - -template -inline basic_object::basic_object(basic_value&& val) - : basic_object(std::move(val.as_object())) -{} +// template +// inline basic_object::basic_object(const basic_value& val) : +// basic_object(val.as_object()) +//{} +// +// template +// inline basic_object::basic_object(basic_value&& val) +// : basic_object(std::move(val.as_object())) +//{} template inline bool basic_object::contains(const string_t& key) const @@ -2770,3 +2897,224 @@ static constexpr string_t unescape_string(const string_t& str) return result; } } // namespace json + +namespace json::_jsonization_helper +{ +struct next_is_optional_t +{}; +struct va_arg_end +{}; + +struct dumper +{ + template + json::value _to_json(const char* key, const var_t& var, rest_t&&... rest) const + { + json::value result = _to_json(std::forward(rest)...); + result.emplace(key, var); + return result; + } + template + json::value _to_json(const char*, next_is_optional_t, rest_t&&... rest) const + { + return _to_json(std::forward(rest)...); + } + json::value _to_json(va_arg_end) const { return {}; } +}; + +struct checker +{ + template + bool _check_json(const json::value& in, std::string& error_key, const char* key, const var_t&, + rest_t&&... rest) const + { + auto opt = in.find(key); + if (!opt || !opt->is()) { + error_key = key; + return false; + } + return _check_json(in, error_key, std::forward(rest)...); + } + template + bool _check_json(const json::value& in, std::string& error_key, const char*, next_is_optional_t, const char* key, + const var_t&, rest_t&&... rest) const + { + auto opt = in.find(key); + if (opt) { + if (!opt->is()) { + error_key = key; + return false; + } + } // next_is_optional_t, ignore key not found + + return _check_json(in, error_key, std::forward(rest)...); + } + bool _check_json(const json::value&, std::string&, va_arg_end) const { return true; } +}; + +struct loader +{ + template + bool _from_json(const json::value& in, std::string& error_key, const char* key, var_t& var, rest_t&&... rest) const + { + auto opt = in.find(key); + if (!opt || !opt->is()) { + error_key = key; + return false; + } + var = std::move(opt)->as(); + + return _from_json(in, error_key, std::forward(rest)...); + } + template + bool _from_json(const json::value& in, std::string& error_key, const char*, next_is_optional_t, const char* key, + var_t& var, rest_t&&... rest) const + { + auto opt = in.find(key); + if (opt) { + if (!opt->is()) { + error_key = key; + return false; + } + var = std::move(opt)->as(); + } // next_is_optional_t, ignore key not found + + return _from_json(in, error_key, std::forward(rest)...); + } + bool _from_json(const json::value&, std::string&, va_arg_end) const { return true; } +}; +} // namespace json::_jsonization_helper + +namespace json::_private_macro +{ +#define _MEOJSON_STRINGIZE(arg) _MEOJSON_STRINGIZE1(arg) +#define _MEOJSON_STRINGIZE1(arg) _MEOJSON_STRINGIZE2(arg) +#define _MEOJSON_STRINGIZE2(arg) #arg + +#define _MEOJSON_CONCATENATE(arg1, arg2) _MEOJSON_CONCATENATE1(arg1, arg2) +#define _MEOJSON_CONCATENATE1(arg1, arg2) _MEOJSON_CONCATENATE2(arg1, arg2) +#define _MEOJSON_CONCATENATE2(arg1, arg2) arg1##arg2 + +#define _MEOJSON_FOR_EACH_0(pred, ...) +#define _MEOJSON_FOR_EACH_1(pred, x, ...) pred(x) +#define _MEOJSON_FOR_EACH_2(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_1(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_3(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_2(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_4(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_3(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_5(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_4(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_6(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_5(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_7(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_6(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_8(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_7(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_9(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_8(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_10(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_9(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_11(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_10(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_12(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_11(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_13(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_12(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_14(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_13(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_15(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_14(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_16(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_15(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_17(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_16(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_18(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_17(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_19(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_18(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_20(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_19(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_21(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_20(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_22(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_21(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_23(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_22(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_24(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_23(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_25(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_24(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_26(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_25(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_27(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_26(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_28(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_27(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_29(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_28(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_30(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_29(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_31(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_30(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_32(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_31(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_33(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_32(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_34(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_33(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_35(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_34(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_36(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_35(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_37(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_36(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_38(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_37(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_39(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_38(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_40(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_39(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_41(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_40(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_42(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_41(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_43(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_42(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_44(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_43(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_45(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_44(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_46(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_45(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_47(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_46(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_48(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_47(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_49(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_48(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_50(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_49(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_51(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_50(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_52(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_51(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_53(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_52(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_54(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_53(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_55(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_54(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_56(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_55(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_57(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_56(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_58(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_57(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_59(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_58(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_60(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_59(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_61(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_60(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_62(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_61(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_63(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_62(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH_64(pred, x, ...) pred(x) _MEOJSON_FOR_EACH_63(pred, __VA_ARGS__) + +#define _MEOJSON_ARG_COUNT(...) \ + _MEOJSON_ARG_COUNT1(0, ##__VA_ARGS__, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, \ + 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 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, 0) +#define _MEOJSON_ARG_COUNT1(_0, _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, _31, _32, _33, _34, _35, _36, _37, \ + _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, \ + _56, _57, _58, _59, _60, _61, _62, _63, _64, N, ...) \ + N + +#define _MEOJSON_FOR_EACH_(N, pred, ...) _MEOJSON_CONCATENATE(_MEOJSON_FOR_EACH_, N)(pred, __VA_ARGS__) +#define _MEOJSON_FOR_EACH(pred, ...) _MEOJSON_FOR_EACH_(_MEOJSON_ARG_COUNT(__VA_ARGS__), pred, __VA_ARGS__) + +#define _MEOJSON_VARNAME(x) _MEOJSON_CONCATENATE(_meojson_jsonization_, x) +#define _MEOJSON_KEY_VALUE(x) _MEOJSON_STRINGIZE(x), x, +} // namespace json::_private_macro + +// if you are using MSVC, please add "/Zc:preprocessor" to your project +#define MEO_TOJSON(...) \ + json::value to_json() const \ + { \ + return json::_jsonization_helper::dumper()._to_json(_MEOJSON_FOR_EACH(_MEOJSON_KEY_VALUE, __VA_ARGS__) \ + json::_jsonization_helper::va_arg_end {}); \ + } + +// if you are using MSVC, please add "/Zc:preprocessor" to your project +#define MEO_CHECKJSON(...) \ + bool check_json(const json::value& _MEOJSON_VARNAME(in)) const \ + { \ + std::string _MEOJSON_VARNAME(error_key); \ + return check_json(_MEOJSON_VARNAME(in), _MEOJSON_VARNAME(error_key)); \ + } \ + bool check_json(const json::value& _MEOJSON_VARNAME(in), std::string& _MEOJSON_VARNAME(error_key)) const \ + { \ + return json::_jsonization_helper::checker()._check_json(_MEOJSON_VARNAME(in), _MEOJSON_VARNAME(error_key), \ + _MEOJSON_FOR_EACH(_MEOJSON_KEY_VALUE, __VA_ARGS__) \ + json::_jsonization_helper::va_arg_end {}); \ + } + +// if you are using MSVC, please add "/Zc:preprocessor" to your project +#define MEO_FROMJSON(...) \ + bool from_json(const json::value& _MEOJSON_VARNAME(in)) \ + { \ + std::string _MEOJSON_VARNAME(error_key); \ + return from_json(_MEOJSON_VARNAME(in), _MEOJSON_VARNAME(error_key)); \ + } \ + bool from_json(const json::value& _MEOJSON_VARNAME(in), std::string& _MEOJSON_VARNAME(error_key)) \ + { \ + return json::_jsonization_helper::loader()._from_json(_MEOJSON_VARNAME(in), _MEOJSON_VARNAME(error_key), \ + _MEOJSON_FOR_EACH(_MEOJSON_KEY_VALUE, __VA_ARGS__) \ + json::_jsonization_helper::va_arg_end {}); \ + } + +// if you are using MSVC, please add "/Zc:preprocessor" to your project +#define MEO_JSONIZATION(...) MEO_TOJSON(__VA_ARGS__) MEO_CHECKJSON(__VA_ARGS__) MEO_FROMJSON(__VA_ARGS__) + +#define MEO_OPT json::_jsonization_helper::next_is_optional_t {}, diff --git a/sample/sample.cpp b/sample/sample.cpp index e00c3be..0e73600 100644 --- a/sample/sample.cpp +++ b/sample/sample.cpp @@ -11,20 +11,23 @@ bool parsing(); bool parsing_width(); bool serializing(); +void test_jsonization(); int main() { - std::cout << "\n****** Parsing ******\n" << std::endl; + // std::cout << "\n****** Parsing ******\n" << std::endl; - if (!parsing()) { - return -1; - } + // if (!parsing()) { + // return -1; + // } - std::cout << "\n****** Serializing ******\n" << std::endl; + // std::cout << "\n****** Serializing ******\n" << std::endl; - if (!serializing()) { - return -1; - } + // if (!serializing()) { + // return -1; + // } + + test_jsonization(); return 0; } @@ -293,3 +296,70 @@ bool serializing() return true; } + +struct TypeFromOtherLibrary +{ + int a_i = 100; +}; + +json::value to_json(const TypeFromOtherLibrary& t) +{ + return t.a_i; +} +bool check_json(const json::value& j, const TypeFromOtherLibrary&) +{ + return j.is_number(); +} +bool from_json(const json::value& j, TypeFromOtherLibrary& out) +{ + out.a_i = j.as_integer(); + return true; +} + +void test_jsonization() +{ + struct AAA + { + int a_i = 100; + + TypeFromOtherLibrary other; + + MEO_JSONIZATION(a_i, other); + }; + + struct BBB + { + int b_i = 10; + double b_d = 0.5; + + std::vector b_aaa; + + MEO_JSONIZATION(b_i, MEO_OPT b_d, b_aaa); + }; + + std::vector my_vec(3); + json::value j = my_vec; + std::cout << j << std::endl; + + std::vector result(j); + std::cout << json::value(result) << std::endl; + + // MyStruct a; + + // a.vec = { 1, 2, 3 }; + // a.map = { { "key", 5 } }; + // a.i = 100; + // a.d = 0.5; + + // json::object j = a.to_json(); + // std::cout << j << std::endl; + + //// for test MEO_OPT + // j.erase("i"); + + // MyStruct b; + // bool loaded = b.from_json(j); + + // std::cout << "loaded: " << loaded << std::endl; + // std::cout << b.myCustomStructure.b_i << std::endl; +}