diff --git a/include/ylt/thirdparty/iguana/json_reader.hpp b/include/ylt/thirdparty/iguana/json_reader.hpp index dfac6e0949..69b84a3755 100644 --- a/include/ylt/thirdparty/iguana/json_reader.hpp +++ b/include/ylt/thirdparty/iguana/json_reader.hpp @@ -11,13 +11,13 @@ namespace detail { template , int> = 0> -IGUANA_INLINE void parse_item(U &value, It &&it, It &&end); +IGUANA_INLINE void from_json_impl(U &value, It &&it, It &&end); template , int> = 0> -IGUANA_INLINE void parse_item(U &value, It &&it, It &&end); +IGUANA_INLINE void from_json_impl(U &value, It &&it, It &&end); template , int> = 0> -IGUANA_INLINE void parse_item(U &value, It &&it, It &&end) { +IGUANA_INLINE void from_json_impl(U &value, It &&it, It &&end) { from_json(value, it, end); } @@ -61,7 +61,7 @@ IGUANA_INLINE void parse_escape(U &value, It &&it, It &&end) { } template , int> = 0> -IGUANA_INLINE void parse_item(U &value, It &&it, It &&end) { +IGUANA_INLINE void from_json_impl(U &value, It &&it, It &&end) { skip_ws(it, end); if constexpr (contiguous_iterator>) { const auto size = std::distance(it, end); @@ -89,7 +89,7 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end) { } template , int> = 0> -IGUANA_INLINE void parse_item(U &value, It &&it, It &&end) { +IGUANA_INLINE void from_json_impl(U &value, It &&it, It &&end) { skip_ws(it, end); auto start = it; while (it != end && is_numeric(*it)) { @@ -101,7 +101,7 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end) { template , int> = 0> -IGUANA_INLINE void parse_item(U &value, It &&it, It &&end) { +IGUANA_INLINE void from_json_impl(U &value, It &&it, It &&end) { if constexpr (!skip) { skip_ws(it, end); match<'"'>(it, end); @@ -140,7 +140,7 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end) { } template , int> = 0> -IGUANA_INLINE void parse_item(U &&value, It &&it, It &&end) { +IGUANA_INLINE void from_json_impl(U &&value, It &&it, It &&end) { skip_ws(it, end); if (it < end) @@ -166,7 +166,7 @@ IGUANA_INLINE void parse_item(U &&value, It &&it, It &&end) { template , int> = 0> -IGUANA_INLINE void parse_item(U &value, It &&it, It &&end) { +IGUANA_INLINE void from_json_impl(U &value, It &&it, It &&end) { if constexpr (!skip) { skip_ws(it, end); match<'"'>(it, end); @@ -208,7 +208,7 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end) { template , int> = 0> -IGUANA_INLINE void parse_item(U &value, It &&it, It &&end) { +IGUANA_INLINE void from_json_impl(U &value, It &&it, It &&end) { static_assert(contiguous_iterator>, "must be contiguous"); if constexpr (!skip) { skip_ws(it, end); @@ -229,16 +229,16 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end) { } template , int> = 0> -IGUANA_INLINE void parse_item(U &value, It &&it, It &&end) { +IGUANA_INLINE void from_json_impl(U &value, It &&it, It &&end) { static constexpr auto str_to_enum = get_enum_map>(); if constexpr (bool_v) { // not defined a specialization template using T = std::underlying_type_t>; - parse_item(reinterpret_cast(value), it, end); + from_json_impl(reinterpret_cast(value), it, end); } else { std::string_view enum_names; - parse_item(enum_names, it, end); + from_json_impl(enum_names, it, end); auto it = str_to_enum.find(enum_names); if (it != str_to_enum.end()) IGUANA_LIKELY { value = it->second; } @@ -250,7 +250,7 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end) { } template , int> = 0> -IGUANA_INLINE void parse_item(U &value, It &&it, It &&end) { +IGUANA_INLINE void from_json_impl(U &value, It &&it, It &&end) { using T = std::remove_reference_t; constexpr auto n = sizeof(T) / sizeof(decltype(std::declval()[0])); skip_ws(it, end); @@ -262,7 +262,7 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end) { auto value_it = std::begin(value); for (size_t i = 0; i < n; ++i) { if (*it != '"') - IGUANA_LIKELY { parse_item(*value_it++, it, end); } + IGUANA_LIKELY { from_json_impl(*value_it++, it, end); } } match<'"'>(it, end); return; @@ -280,7 +280,7 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end) { } auto value_it = std::begin(value); for (size_t i = 0; i < n; ++i) { - parse_item(*value_it++, it, end); + from_json_impl(*value_it++, it, end); skip_ws(it, end); if (it == end) { throw std::runtime_error("Unexpected end"); @@ -301,7 +301,7 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end) { template , int>> -IGUANA_INLINE void parse_item(U &value, It &&it, It &&end) { +IGUANA_INLINE void from_json_impl(U &value, It &&it, It &&end) { value.clear(); skip_ws(it, end); @@ -316,7 +316,7 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end) { if (i > 0) IGUANA_LIKELY { match<','>(it, end); } - parse_item(value.emplace_back(), it, end); + from_json_impl(value.emplace_back(), it, end); skip_ws(it, end); } throw std::runtime_error("Expected ]"); @@ -337,7 +337,7 @@ IGUANA_INLINE auto get_key(It &&it, It &&end) { // compile time versions of keys it = start; static thread_local std::string static_key{}; - detail::parse_item(static_key, it, end); + detail::from_json_impl(static_key, it, end); return std::string_view(static_key); } else @@ -352,14 +352,14 @@ IGUANA_INLINE auto get_key(It &&it, It &&end) { } else { static thread_local std::string static_key{}; - detail::parse_item(static_key, it, end); + detail::from_json_impl(static_key, it, end); return std::string_view(static_key); } } template , int> = 0> -IGUANA_INLINE void parse_item(U &value, It &&it, It &&end) { +IGUANA_INLINE void from_json_impl(U &value, It &&it, It &&end) { using T = std::remove_reference_t; using key_type = typename T::key_type; skip_ws(it, end); @@ -384,19 +384,19 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end) { match<':'>(it, end); if constexpr (string_v || string_view_v) { - parse_item(value[key_type(key)], it, end); + from_json_impl(value[key_type(key)], it, end); } else { static thread_local key_type key_value{}; - parse_item(key_value, key.begin(), key.end()); - parse_item(value[key_value], it, end); + from_json_impl(key_value, key.begin(), key.end()); + from_json_impl(value[key_value], it, end); } skip_ws(it, end); } } template , int> = 0> -IGUANA_INLINE void parse_item(U &value, It &&it, It &&end) { +IGUANA_INLINE void from_json_impl(U &value, It &&it, It &&end) { skip_ws(it, end); match<'['>(it, end); skip_ws(it, end); @@ -410,7 +410,7 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end) { match<','>(it, end); skip_ws(it, end); } - parse_item(v, it, end); + from_json_impl(v, it, end); skip_ws(it, end); }); @@ -418,7 +418,7 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end) { } template , int> = 0> -IGUANA_INLINE void parse_item(U &value, It &&it, It &&end) { +IGUANA_INLINE void from_json_impl(U &value, It &&it, It &&end) { skip_ws(it, end); if (it < end && *it == '"') IGUANA_LIKELY { ++it; } @@ -439,17 +439,17 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end) { using value_type = typename T::value_type; value_type t; if constexpr (string_v || string_view_v) { - parse_item(t, it, end); + from_json_impl(t, it, end); } else { - parse_item(t, it, end); + from_json_impl(t, it, end); } value = std::move(t); } } template , int>> -IGUANA_INLINE void parse_item(U &value, It &&it, It &&end) { +IGUANA_INLINE void from_json_impl(U &value, It &&it, It &&end) { skip_ws(it, end); if (it == end) IGUANA_UNLIKELY { throw std::runtime_error("Unexexpected eof"); } @@ -465,7 +465,7 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end) { else { value = std::make_shared(); } - parse_item(*value, it, end); + from_json_impl(*value, it, end); } } @@ -522,7 +522,10 @@ IGUANA_INLINE void from_json(T &value, It &&it, It &&end) { IGUANA_UNLIKELY { return; } skip_ws(it, end); match<':'>(it, end); - detail::parse_item(value.*member_ptr, it, end); + { + using namespace detail; + from_json_impl(value.*member_ptr, it, end); + } skip_ws(it, end); if (*it == '}') @@ -551,7 +554,8 @@ IGUANA_INLINE void from_json(T &value, It &&it, It &&end) { [&](auto &&member_ptr) IGUANA__INLINE_LAMBDA { using V = std::decay_t; if constexpr (std::is_member_pointer_v) { - detail::parse_item(value.*member_ptr, it, end); + using namespace detail; + from_json_impl(value.*member_ptr, it, end); } else { static_assert(!sizeof(V), "type not supported"); @@ -583,7 +587,8 @@ IGUANA_INLINE void from_json(T &value, It &&it, It &&end) { template , int> = 0> IGUANA_INLINE void from_json(T &value, It &&it, It &&end) { - detail::parse_item(value, it, end); + using namespace detail; + from_json_impl(value, it, end); } template @@ -681,7 +686,8 @@ inline void parse(jobject &result, It &&it, It &&end) { if (it == end) IGUANA_UNLIKELY { throw std::runtime_error("Expected }"); } std::string key; - detail::parse_item(key, it, end); + using namespace detail; + from_json_impl(key, it, end); auto emplaced = result.try_emplace(key); if (!emplaced.second) @@ -703,6 +709,7 @@ inline void parse(jobject &result, It &&it, It &&end) { template inline void parse(jvalue &result, It &&it, It &&end) { + using namespace detail; skip_ws(it, end); switch (*it) { case 'n': @@ -713,7 +720,7 @@ inline void parse(jvalue &result, It &&it, It &&end) { case 'f': case 't': - detail::parse_item(result.template emplace(), it, end); + from_json_impl(result.template emplace(), it, end); break; case '0': case '1': @@ -727,7 +734,7 @@ inline void parse(jvalue &result, It &&it, It &&end) { case '9': case '-': { double d{}; - detail::parse_item(d, it, end); + from_json_impl(d, it, end); if (static_cast(d) == d) result.emplace(d); else @@ -737,11 +744,11 @@ inline void parse(jvalue &result, It &&it, It &&end) { case '"': if constexpr (Is_view) { result.template emplace(); - detail::parse_item(std::get(result), it, end); + from_json_impl(std::get(result), it, end); } else { result.template emplace(); - detail::parse_item(std::get(result), it, end); + from_json_impl(std::get(result), it, end); } break; case '[': diff --git a/include/ylt/thirdparty/iguana/json_writer.hpp b/include/ylt/thirdparty/iguana/json_writer.hpp index 2df2bfe8df..80e2558dab 100644 --- a/include/ylt/thirdparty/iguana/json_writer.hpp +++ b/include/ylt/thirdparty/iguana/json_writer.hpp @@ -11,33 +11,33 @@ namespace iguana { template , int> = 0> IGUANA_INLINE void to_json(T &&t, Stream &s); - +namespace detail { template -IGUANA_INLINE void render_json_value(Stream &ss, std::optional &val); +IGUANA_INLINE void to_json_impl(Stream &ss, std::optional &val); template , int> = 0> -IGUANA_INLINE void render_json_value(Stream &ss, const T &t); +IGUANA_INLINE void to_json_impl(Stream &ss, const T &t); template , int> = 0> -IGUANA_INLINE void render_json_value(Stream &ss, const T &v); +IGUANA_INLINE void to_json_impl(Stream &ss, const T &v); template , int> = 0> -IGUANA_INLINE void render_json_value(Stream &ss, const T &v); +IGUANA_INLINE void to_json_impl(Stream &ss, const T &v); template , int> = 0> -IGUANA_INLINE void render_json_value(Stream &ss, const T &o); +IGUANA_INLINE void to_json_impl(Stream &ss, const T &o); template , int> = 0> -IGUANA_INLINE void render_json_value(Stream &s, T &&t); +IGUANA_INLINE void to_json_impl(Stream &s, T &&t); template , int> = 0> -IGUANA_INLINE void render_json_value(Stream &s, T &&t); +IGUANA_INLINE void to_json_impl(Stream &s, T &&t); template IGUANA_INLINE void join(Stream &ss, InputIt first, InputIt last, const T &delim, @@ -52,17 +52,17 @@ IGUANA_INLINE void join(Stream &ss, InputIt first, InputIt last, const T &delim, } template -IGUANA_INLINE void render_json_value(Stream &ss, std::nullptr_t) { +IGUANA_INLINE void to_json_impl(Stream &ss, std::nullptr_t) { ss.append("null"); } template -IGUANA_INLINE void render_json_value(Stream &ss, bool b) { +IGUANA_INLINE void to_json_impl(Stream &ss, bool b) { ss.append(b ? "true" : "false"); }; template -IGUANA_INLINE void render_json_value(Stream &ss, char value) { +IGUANA_INLINE void to_json_impl(Stream &ss, char value) { ss.append("\""); ss.push_back(value); ss.append("\""); @@ -70,7 +70,7 @@ IGUANA_INLINE void render_json_value(Stream &ss, char value) { template , int> = 0> -IGUANA_INLINE void render_json_value(Stream &ss, T value) { +IGUANA_INLINE void to_json_impl(Stream &ss, T value) { char temp[65]; auto p = detail::to_chars(temp, value); ss.append(temp, p - temp); @@ -78,13 +78,13 @@ IGUANA_INLINE void render_json_value(Stream &ss, T value) { template , int> = 0> -IGUANA_INLINE void render_json_value(Stream &ss, T v) { +IGUANA_INLINE void to_json_impl(Stream &ss, T v) { ss.append(v.value().data(), v.value().size()); } template , int> = 0> -IGUANA_INLINE void render_json_value(Stream &ss, T &&t) { +IGUANA_INLINE void to_json_impl(Stream &ss, T &&t) { ss.push_back('"'); if constexpr (Is_writing_escape) { write_string_with_escape(t.data(), t.size(), ss); @@ -99,28 +99,28 @@ template , int> = 0> IGUANA_INLINE void render_key(Stream &ss, T &t) { ss.push_back('"'); - render_json_value(ss, t); + to_json_impl(ss, t); ss.push_back('"'); } template , int> = 0> IGUANA_INLINE void render_key(Stream &ss, T &&t) { - render_json_value(ss, std::forward(t)); + to_json_impl(ss, std::forward(t)); } template , int> = 0> -IGUANA_INLINE void render_json_value(Stream &ss, T &&t) { +IGUANA_INLINE void to_json_impl(Stream &ss, T &&t) { to_json(std::forward(t), ss); } template , int> = 0> -IGUANA_INLINE void render_json_value(Stream &ss, T val) { +IGUANA_INLINE void to_json_impl(Stream &ss, T val) { static constexpr auto enum_to_str = get_enum_map>(); if constexpr (bool_v) { - render_json_value( + to_json_impl( ss, static_cast>(val)); } else { @@ -128,7 +128,7 @@ IGUANA_INLINE void render_json_value(Stream &ss, T val) { if (it != enum_to_str.end()) IGUANA_LIKELY { auto str = it->second; - render_json_value( + to_json_impl( ss, std::string_view(str.data(), str.size())); } else { @@ -140,12 +140,12 @@ IGUANA_INLINE void render_json_value(Stream &ss, T val) { } template -IGUANA_INLINE void render_json_value(Stream &ss, std::optional &val) { +IGUANA_INLINE void to_json_impl(Stream &ss, std::optional &val) { if (!val) { ss.append("null"); } else { - render_json_value(ss, *val); + to_json_impl(ss, *val); } } @@ -154,14 +154,14 @@ IGUANA_INLINE void render_array(Stream &ss, const T &v) { ss.push_back('['); join(ss, std::begin(v), std::end(v), ',', [&ss](const auto &jsv) IGUANA__INLINE_LAMBDA { - render_json_value(ss, jsv); + to_json_impl(ss, jsv); }); ss.push_back(']'); } template , int>> -IGUANA_INLINE void render_json_value(Stream &ss, const T &t) { +IGUANA_INLINE void to_json_impl(Stream &ss, const T &t) { if constexpr (std::is_same_v()[0])>>) { constexpr size_t n = sizeof(T) / sizeof(decltype(std::declval()[0])); @@ -184,24 +184,24 @@ IGUANA_INLINE void render_json_value(Stream &ss, const T &t) { template , int>> -IGUANA_INLINE void render_json_value(Stream &ss, const T &o) { +IGUANA_INLINE void to_json_impl(Stream &ss, const T &o) { ss.push_back('{'); join(ss, o.cbegin(), o.cend(), ',', [&ss](const auto &jsv) IGUANA__INLINE_LAMBDA { render_key(ss, jsv.first); ss.push_back(':'); - render_json_value(ss, jsv.second); + to_json_impl(ss, jsv.second); }); ss.push_back('}'); } template , int>> -IGUANA_INLINE void render_json_value(Stream &ss, const T &v) { +IGUANA_INLINE void to_json_impl(Stream &ss, const T &v) { ss.push_back('['); join(ss, v.cbegin(), v.cend(), ',', [&ss](const auto &jsv) IGUANA__INLINE_LAMBDA { - render_json_value(ss, jsv); + to_json_impl(ss, jsv); }); ss.push_back(']'); } @@ -217,9 +217,9 @@ constexpr auto write_json_key = [](auto &s, auto i, template , int>> -IGUANA_INLINE void render_json_value(Stream &ss, const T &v) { +IGUANA_INLINE void to_json_impl(Stream &ss, const T &v) { if (v) { - render_json_value(ss, *v); + to_json_impl(ss, *v); } else { ss.append("null"); @@ -228,13 +228,13 @@ IGUANA_INLINE void render_json_value(Stream &ss, const T &v) { template , int>> -IGUANA_INLINE void render_json_value(Stream &s, T &&t) { +IGUANA_INLINE void to_json_impl(Stream &s, T &&t) { using U = typename std::decay_t; s.push_back('['); constexpr size_t size = std::tuple_size_v; for_each(std::forward(t), [&s, size](auto &v, auto i) IGUANA__INLINE_LAMBDA { - render_json_value(s, v); + to_json_impl(s, v); if (i != size - 1) IGUANA_LIKELY { s.push_back(','); } @@ -244,17 +244,18 @@ IGUANA_INLINE void render_json_value(Stream &s, T &&t) { template , int>> -IGUANA_INLINE void render_json_value(Stream &s, T &&t) { +IGUANA_INLINE void to_json_impl(Stream &s, T &&t) { std::visit( [&s](auto value) { - render_json_value(s, value); + to_json_impl(s, value); }, t); } - +} // namespace detail template , int>> IGUANA_INLINE void to_json(T &&t, Stream &s) { + using namespace detail; s.push_back('{'); for_each(std::forward(t), [&t, &s](const auto &v, auto i) IGUANA__INLINE_LAMBDA { @@ -265,7 +266,7 @@ IGUANA_INLINE void to_json(T &&t, Stream &s) { write_json_key(s, i, t); s.push_back(':'); - render_json_value(s, t.*v); + to_json_impl(s, t.*v); if (Idx < Count - 1) IGUANA_LIKELY { s.push_back(','); } }); @@ -275,7 +276,8 @@ IGUANA_INLINE void to_json(T &&t, Stream &s) { template , int> = 0> IGUANA_INLINE void to_json(T &&t, Stream &s) { - render_json_value(s, t); + using namespace detail; + to_json_impl(s, t); } } // namespace iguana diff --git a/include/ylt/thirdparty/iguana/util.hpp b/include/ylt/thirdparty/iguana/util.hpp index 3d2605cd26..f910db7956 100644 --- a/include/ylt/thirdparty/iguana/util.hpp +++ b/include/ylt/thirdparty/iguana/util.hpp @@ -139,15 +139,12 @@ struct is_variant> : std::true_type {}; template constexpr inline bool variant_v = is_variant>::value; -template -constexpr inline bool non_refletable_v = - container_v || c_array_v || tuple_v || optional_v || - smart_ptr_v || std::is_fundamental_v> || - variant_v; - template constexpr inline bool refletable_v = is_reflection_v>; +template +constexpr inline bool non_refletable_v = !refletable_v; + template constexpr inline bool plain_v = string_container_v || num_v || char_v || bool_v || enum_v; diff --git a/src/struct_json/examples/CMakeLists.txt b/src/struct_json/examples/CMakeLists.txt index ec2f10eecf..4a639a5a57 100644 --- a/src/struct_json/examples/CMakeLists.txt +++ b/src/struct_json/examples/CMakeLists.txt @@ -18,4 +18,4 @@ else() # include_directories(include) # include_directories(include/ylt/thirdparty) endif() -add_executable(struct_json_example main.cpp) \ No newline at end of file +add_executable(struct_json_example main.cpp user_defined_struct.cpp) \ No newline at end of file diff --git a/src/struct_json/examples/main.cpp b/src/struct_json/examples/main.cpp index 9b7c8bae3b..41d175fe0f 100644 --- a/src/struct_json/examples/main.cpp +++ b/src/struct_json/examples/main.cpp @@ -1,9 +1,14 @@ #include #include +#include +#include #include "ylt/struct_json/json_reader.h" #include "ylt/struct_json/json_writer.h" +void test_user_defined_struct(); + + struct person { std::string name; int age; @@ -90,4 +95,5 @@ int main() { test_inner_object(); use_smart_pointer(); test_escape_serialize(); + test_user_defined_struct(); } \ No newline at end of file diff --git a/src/struct_json/examples/user_defined_struct.cpp b/src/struct_json/examples/user_defined_struct.cpp new file mode 100644 index 0000000000..18ebd4b1d3 --- /dev/null +++ b/src/struct_json/examples/user_defined_struct.cpp @@ -0,0 +1,59 @@ +#include +#include + +#include + +#include "iguana/json_writer.hpp" + +namespace my_space { +struct my_struct { + int x, y, z; + bool operator==(const my_struct& o) const { + return x == o.x && y == o.y && z == o.z; + } +}; + +template +inline void to_json_impl(Stream& s, const my_struct& t) { + struct_json::to_json(*(int(*)[3]) & t, s); +} + +template +IGUANA_INLINE void from_json_impl(my_struct& value, It&& it, It&& end) { + struct_json::from_json(*(int(*)[3]) & value, it, end); +} + +} // namespace my_space + +struct nest { + std::string name; + my_space::my_struct value; + bool operator==(const nest& o) const { + return name == o.name && value == o.value; + } +}; + +REFLECTION(nest, name, value); + +void example1() { + my_space::my_struct v{1, 2, 3}, v2; + std::string s; + struct_json::to_json(v, s); + std::cout << s << std::endl; + struct_json::from_json(v2, s); + assert(v == v2); +}; + +void example2() { + nest v{"Hi", {1, 2, 3}}, v2; + std::string s; + struct_json::to_json(v, s); + std::cout << s << std::endl; + struct_json::from_json(v2, s); + assert(v == v2); +}; + +void test_user_defined_struct() { + example1(); + example2(); +} \ No newline at end of file