Skip to content

Commit 244c92a

Browse files
authored
[struct_json] support user-defined serialize/deserialize (#619)
1 parent 14d1323 commit 244c92a

File tree

8 files changed

+174
-103
lines changed

8 files changed

+174
-103
lines changed

include/ylt/thirdparty/iguana/json_reader.hpp

+66-54
Large diffs are not rendered by default.

include/ylt/thirdparty/iguana/json_writer.hpp

+39-37
Original file line numberDiff line numberDiff line change
@@ -11,33 +11,33 @@ namespace iguana {
1111
template <bool Is_writing_escape = true, typename Stream, typename T,
1212
std::enable_if_t<refletable_v<T>, int> = 0>
1313
IGUANA_INLINE void to_json(T &&t, Stream &s);
14-
14+
namespace detail {
1515
template <bool Is_writing_escape = true, typename Stream, typename T>
16-
IGUANA_INLINE void render_json_value(Stream &ss, std::optional<T> &val);
16+
IGUANA_INLINE void to_json_impl(Stream &ss, std::optional<T> &val);
1717

1818
template <bool Is_writing_escape = true, typename Stream, typename T,
1919
std::enable_if_t<fixed_array_v<T>, int> = 0>
20-
IGUANA_INLINE void render_json_value(Stream &ss, const T &t);
20+
IGUANA_INLINE void to_json_impl(Stream &ss, const T &t);
2121

2222
template <bool Is_writing_escape = true, typename Stream, typename T,
2323
std::enable_if_t<sequence_container_v<T>, int> = 0>
24-
IGUANA_INLINE void render_json_value(Stream &ss, const T &v);
24+
IGUANA_INLINE void to_json_impl(Stream &ss, const T &v);
2525

2626
template <bool Is_writing_escape = true, typename Stream, typename T,
2727
std::enable_if_t<smart_ptr_v<T>, int> = 0>
28-
IGUANA_INLINE void render_json_value(Stream &ss, const T &v);
28+
IGUANA_INLINE void to_json_impl(Stream &ss, const T &v);
2929

3030
template <bool Is_writing_escape = true, typename Stream, typename T,
3131
std::enable_if_t<map_container_v<T>, int> = 0>
32-
IGUANA_INLINE void render_json_value(Stream &ss, const T &o);
32+
IGUANA_INLINE void to_json_impl(Stream &ss, const T &o);
3333

3434
template <bool Is_writing_escape = true, typename Stream, typename T,
3535
std::enable_if_t<tuple_v<T>, int> = 0>
36-
IGUANA_INLINE void render_json_value(Stream &s, T &&t);
36+
IGUANA_INLINE void to_json_impl(Stream &s, T &&t);
3737

3838
template <bool Is_writing_escape = true, typename Stream, typename T,
3939
std::enable_if_t<variant_v<T>, int> = 0>
40-
IGUANA_INLINE void render_json_value(Stream &s, T &&t);
40+
IGUANA_INLINE void to_json_impl(Stream &s, T &&t);
4141

4242
template <typename Stream, typename InputIt, typename T, typename F>
4343
IGUANA_INLINE void join(Stream &ss, InputIt first, InputIt last, const T &delim,
@@ -52,39 +52,39 @@ IGUANA_INLINE void join(Stream &ss, InputIt first, InputIt last, const T &delim,
5252
}
5353

5454
template <bool Is_writing_escape, typename Stream>
55-
IGUANA_INLINE void render_json_value(Stream &ss, std::nullptr_t) {
55+
IGUANA_INLINE void to_json_impl(Stream &ss, std::nullptr_t) {
5656
ss.append("null");
5757
}
5858

5959
template <bool Is_writing_escape, typename Stream>
60-
IGUANA_INLINE void render_json_value(Stream &ss, bool b) {
60+
IGUANA_INLINE void to_json_impl(Stream &ss, bool b) {
6161
ss.append(b ? "true" : "false");
6262
};
6363

6464
template <bool Is_writing_escape, typename Stream>
65-
IGUANA_INLINE void render_json_value(Stream &ss, char value) {
65+
IGUANA_INLINE void to_json_impl(Stream &ss, char value) {
6666
ss.append("\"");
6767
ss.push_back(value);
6868
ss.append("\"");
6969
}
7070

7171
template <bool Is_writing_escape, typename Stream, typename T,
7272
std::enable_if_t<num_v<T>, int> = 0>
73-
IGUANA_INLINE void render_json_value(Stream &ss, T value) {
73+
IGUANA_INLINE void to_json_impl(Stream &ss, T value) {
7474
char temp[65];
7575
auto p = detail::to_chars(temp, value);
7676
ss.append(temp, p - temp);
7777
}
7878

7979
template <bool Is_writing_escape, typename Stream, typename T,
8080
std::enable_if_t<numeric_str_v<T>, int> = 0>
81-
IGUANA_INLINE void render_json_value(Stream &ss, T v) {
81+
IGUANA_INLINE void to_json_impl(Stream &ss, T v) {
8282
ss.append(v.value().data(), v.value().size());
8383
}
8484

8585
template <bool Is_writing_escape, typename Stream, typename T,
8686
std::enable_if_t<string_container_v<T>, int> = 0>
87-
IGUANA_INLINE void render_json_value(Stream &ss, T &&t) {
87+
IGUANA_INLINE void to_json_impl(Stream &ss, T &&t) {
8888
ss.push_back('"');
8989
if constexpr (Is_writing_escape) {
9090
write_string_with_escape(t.data(), t.size(), ss);
@@ -99,36 +99,36 @@ template <bool Is_writing_escape, typename Stream, typename T,
9999
std::enable_if_t<num_v<T>, int> = 0>
100100
IGUANA_INLINE void render_key(Stream &ss, T &t) {
101101
ss.push_back('"');
102-
render_json_value<Is_writing_escape>(ss, t);
102+
to_json_impl<Is_writing_escape>(ss, t);
103103
ss.push_back('"');
104104
}
105105

106106
template <bool Is_writing_escape, typename Stream, typename T,
107107
std::enable_if_t<string_container_v<T>, int> = 0>
108108
IGUANA_INLINE void render_key(Stream &ss, T &&t) {
109-
render_json_value<Is_writing_escape>(ss, std::forward<T>(t));
109+
to_json_impl<Is_writing_escape>(ss, std::forward<T>(t));
110110
}
111111

112112
template <bool Is_writing_escape, typename Stream, typename T,
113113
std::enable_if_t<refletable_v<T>, int> = 0>
114-
IGUANA_INLINE void render_json_value(Stream &ss, T &&t) {
114+
IGUANA_INLINE void to_json_impl(Stream &ss, T &&t) {
115115
to_json(std::forward<T>(t), ss);
116116
}
117117

118118
template <bool Is_writing_escape, typename Stream, typename T,
119119
std::enable_if_t<enum_v<T>, int> = 0>
120-
IGUANA_INLINE void render_json_value(Stream &ss, T val) {
120+
IGUANA_INLINE void to_json_impl(Stream &ss, T val) {
121121
static constexpr auto enum_to_str = get_enum_map<false, std::decay_t<T>>();
122122
if constexpr (bool_v<decltype(enum_to_str)>) {
123-
render_json_value<Is_writing_escape>(
123+
to_json_impl<Is_writing_escape>(
124124
ss, static_cast<std::underlying_type_t<T>>(val));
125125
}
126126
else {
127127
auto it = enum_to_str.find(val);
128128
if (it != enum_to_str.end())
129129
IGUANA_LIKELY {
130130
auto str = it->second;
131-
render_json_value<Is_writing_escape>(
131+
to_json_impl<Is_writing_escape>(
132132
ss, std::string_view(str.data(), str.size()));
133133
}
134134
else {
@@ -140,12 +140,12 @@ IGUANA_INLINE void render_json_value(Stream &ss, T val) {
140140
}
141141

142142
template <bool Is_writing_escape, typename Stream, typename T>
143-
IGUANA_INLINE void render_json_value(Stream &ss, std::optional<T> &val) {
143+
IGUANA_INLINE void to_json_impl(Stream &ss, std::optional<T> &val) {
144144
if (!val) {
145145
ss.append("null");
146146
}
147147
else {
148-
render_json_value<Is_writing_escape>(ss, *val);
148+
to_json_impl<Is_writing_escape>(ss, *val);
149149
}
150150
}
151151

@@ -154,14 +154,14 @@ IGUANA_INLINE void render_array(Stream &ss, const T &v) {
154154
ss.push_back('[');
155155
join(ss, std::begin(v), std::end(v), ',',
156156
[&ss](const auto &jsv) IGUANA__INLINE_LAMBDA {
157-
render_json_value<Is_writing_escape>(ss, jsv);
157+
to_json_impl<Is_writing_escape>(ss, jsv);
158158
});
159159
ss.push_back(']');
160160
}
161161

162162
template <bool Is_writing_escape, typename Stream, typename T,
163163
std::enable_if_t<fixed_array_v<T>, int>>
164-
IGUANA_INLINE void render_json_value(Stream &ss, const T &t) {
164+
IGUANA_INLINE void to_json_impl(Stream &ss, const T &t) {
165165
if constexpr (std::is_same_v<char, std::remove_reference_t<
166166
decltype(std::declval<T>()[0])>>) {
167167
constexpr size_t n = sizeof(T) / sizeof(decltype(std::declval<T>()[0]));
@@ -184,24 +184,24 @@ IGUANA_INLINE void render_json_value(Stream &ss, const T &t) {
184184

185185
template <bool Is_writing_escape, typename Stream, typename T,
186186
std::enable_if_t<map_container_v<T>, int>>
187-
IGUANA_INLINE void render_json_value(Stream &ss, const T &o) {
187+
IGUANA_INLINE void to_json_impl(Stream &ss, const T &o) {
188188
ss.push_back('{');
189189
join(ss, o.cbegin(), o.cend(), ',',
190190
[&ss](const auto &jsv) IGUANA__INLINE_LAMBDA {
191191
render_key<Is_writing_escape>(ss, jsv.first);
192192
ss.push_back(':');
193-
render_json_value<Is_writing_escape>(ss, jsv.second);
193+
to_json_impl<Is_writing_escape>(ss, jsv.second);
194194
});
195195
ss.push_back('}');
196196
}
197197

198198
template <bool Is_writing_escape, typename Stream, typename T,
199199
std::enable_if_t<sequence_container_v<T>, int>>
200-
IGUANA_INLINE void render_json_value(Stream &ss, const T &v) {
200+
IGUANA_INLINE void to_json_impl(Stream &ss, const T &v) {
201201
ss.push_back('[');
202202
join(ss, v.cbegin(), v.cend(), ',',
203203
[&ss](const auto &jsv) IGUANA__INLINE_LAMBDA {
204-
render_json_value<Is_writing_escape>(ss, jsv);
204+
to_json_impl<Is_writing_escape>(ss, jsv);
205205
});
206206
ss.push_back(']');
207207
}
@@ -217,9 +217,9 @@ constexpr auto write_json_key = [](auto &s, auto i,
217217

218218
template <bool Is_writing_escape, typename Stream, typename T,
219219
std::enable_if_t<smart_ptr_v<T>, int>>
220-
IGUANA_INLINE void render_json_value(Stream &ss, const T &v) {
220+
IGUANA_INLINE void to_json_impl(Stream &ss, const T &v) {
221221
if (v) {
222-
render_json_value<Is_writing_escape>(ss, *v);
222+
to_json_impl<Is_writing_escape>(ss, *v);
223223
}
224224
else {
225225
ss.append("null");
@@ -228,13 +228,13 @@ IGUANA_INLINE void render_json_value(Stream &ss, const T &v) {
228228

229229
template <bool Is_writing_escape, typename Stream, typename T,
230230
std::enable_if_t<tuple_v<T>, int>>
231-
IGUANA_INLINE void render_json_value(Stream &s, T &&t) {
231+
IGUANA_INLINE void to_json_impl(Stream &s, T &&t) {
232232
using U = typename std::decay_t<T>;
233233
s.push_back('[');
234234
constexpr size_t size = std::tuple_size_v<U>;
235235
for_each(std::forward<T>(t),
236236
[&s, size](auto &v, auto i) IGUANA__INLINE_LAMBDA {
237-
render_json_value<Is_writing_escape>(s, v);
237+
to_json_impl<Is_writing_escape>(s, v);
238238

239239
if (i != size - 1)
240240
IGUANA_LIKELY { s.push_back(','); }
@@ -244,17 +244,18 @@ IGUANA_INLINE void render_json_value(Stream &s, T &&t) {
244244

245245
template <bool Is_writing_escape, typename Stream, typename T,
246246
std::enable_if_t<variant_v<T>, int>>
247-
IGUANA_INLINE void render_json_value(Stream &s, T &&t) {
247+
IGUANA_INLINE void to_json_impl(Stream &s, T &&t) {
248248
std::visit(
249249
[&s](auto value) {
250-
render_json_value<Is_writing_escape>(s, value);
250+
to_json_impl<Is_writing_escape>(s, value);
251251
},
252252
t);
253253
}
254-
254+
} // namespace detail
255255
template <bool Is_writing_escape, typename Stream, typename T,
256256
std::enable_if_t<refletable_v<T>, int>>
257257
IGUANA_INLINE void to_json(T &&t, Stream &s) {
258+
using namespace detail;
258259
s.push_back('{');
259260
for_each(std::forward<T>(t),
260261
[&t, &s](const auto &v, auto i) IGUANA__INLINE_LAMBDA {
@@ -265,7 +266,7 @@ IGUANA_INLINE void to_json(T &&t, Stream &s) {
265266

266267
write_json_key(s, i, t);
267268
s.push_back(':');
268-
render_json_value<Is_writing_escape>(s, t.*v);
269+
to_json_impl<Is_writing_escape>(s, t.*v);
269270
if (Idx < Count - 1)
270271
IGUANA_LIKELY { s.push_back(','); }
271272
});
@@ -275,7 +276,8 @@ IGUANA_INLINE void to_json(T &&t, Stream &s) {
275276
template <bool Is_writing_escape = true, typename Stream, typename T,
276277
std::enable_if_t<non_refletable_v<T>, int> = 0>
277278
IGUANA_INLINE void to_json(T &&t, Stream &s) {
278-
render_json_value<Is_writing_escape>(s, t);
279+
using namespace detail;
280+
to_json_impl<Is_writing_escape>(s, t);
279281
}
280282

281283
} // namespace iguana

include/ylt/thirdparty/iguana/reflection.hpp

-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
#include <variant>
1818
#include <vector>
1919

20-
#include "detail/itoa.hpp"
2120
#include "detail/string_stream.hpp"
2221
#include "detail/traits.hpp"
2322
#include "frozen/string.h"

include/ylt/thirdparty/iguana/util.hpp

+3-6
Original file line numberDiff line numberDiff line change
@@ -139,15 +139,12 @@ struct is_variant<std::variant<T...>> : std::true_type {};
139139
template <typename T>
140140
constexpr inline bool variant_v = is_variant<std::remove_cvref_t<T>>::value;
141141

142-
template <class T>
143-
constexpr inline bool non_refletable_v =
144-
container_v<T> || c_array_v<T> || tuple_v<T> || optional_v<T> ||
145-
smart_ptr_v<T> || std::is_fundamental_v<std::remove_cvref_t<T>> ||
146-
variant_v<T>;
147-
148142
template <typename T>
149143
constexpr inline bool refletable_v = is_reflection_v<std::remove_cvref_t<T>>;
150144

145+
template <class T>
146+
constexpr inline bool non_refletable_v = !refletable_v<T>;
147+
151148
template <typename T>
152149
constexpr inline bool plain_v =
153150
string_container_v<T> || num_v<T> || char_v<T> || bool_v<T> || enum_v<T>;

src/struct_json/examples/BUILD.bazel

+1-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
cc_binary(
22
name = "struct_json_example",
3-
srcs =
4-
[
5-
"main.cpp",
6-
],
3+
srcs = glob(["*.cpp"]),
74
copts = [
85
"-std=c++20",
96
],

src/struct_json/examples/CMakeLists.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,4 @@ else()
1818
# include_directories(include)
1919
# include_directories(include/ylt/thirdparty)
2020
endif()
21-
add_executable(struct_json_example main.cpp)
21+
add_executable(struct_json_example main.cpp user_defined_struct.cpp)

src/struct_json/examples/main.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
#include <cassert>
2+
#include <iguana/json_reader.hpp>
3+
#include <iguana/json_writer.hpp>
24
#include <iostream>
35

46
#include "ylt/struct_json/json_reader.h"
57
#include "ylt/struct_json/json_writer.h"
68

9+
void test_user_defined_struct();
10+
711
struct person {
812
std::string name;
913
int age;
@@ -90,4 +94,5 @@ int main() {
9094
test_inner_object();
9195
use_smart_pointer();
9296
test_escape_serialize();
97+
test_user_defined_struct();
9398
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#include <ylt/struct_json/json_reader.h>
2+
#include <ylt/struct_json/json_writer.h>
3+
4+
#include <string>
5+
6+
#include "iguana/json_writer.hpp"
7+
8+
namespace my_space {
9+
struct my_struct {
10+
int x, y, z;
11+
bool operator==(const my_struct& o) const {
12+
return x == o.x && y == o.y && z == o.z;
13+
}
14+
};
15+
16+
template <bool Is_writing_escape, typename Stream>
17+
inline void to_json_impl(Stream& s, const my_struct& t) {
18+
struct_json::to_json<Is_writing_escape>(*(int(*)[3]) & t, s);
19+
}
20+
21+
template <typename It>
22+
IGUANA_INLINE void from_json_impl(my_struct& value, It&& it, It&& end) {
23+
struct_json::from_json(*(int(*)[3]) & value, it, end);
24+
}
25+
26+
} // namespace my_space
27+
28+
struct nest {
29+
std::string name;
30+
my_space::my_struct value;
31+
bool operator==(const nest& o) const {
32+
return name == o.name && value == o.value;
33+
}
34+
};
35+
36+
REFLECTION(nest, name, value);
37+
38+
void example1() {
39+
my_space::my_struct v{1, 2, 3}, v2;
40+
std::string s;
41+
struct_json::to_json(v, s);
42+
std::cout << s << std::endl;
43+
struct_json::from_json(v2, s);
44+
assert(v == v2);
45+
};
46+
47+
void example2() {
48+
nest v{"Hi", {1, 2, 3}}, v2;
49+
std::string s;
50+
struct_json::to_json(v, s);
51+
std::cout << s << std::endl;
52+
struct_json::from_json(v2, s);
53+
assert(v == v2);
54+
};
55+
56+
void test_user_defined_struct() {
57+
example1();
58+
example2();
59+
}

0 commit comments

Comments
 (0)