1 | // Adapted from https://github.com/PENGUINLIONG/graphi-t |
2 | |
3 | // Copyright (c) 2019 Rendong Liang |
4 | // |
5 | // Permission is hereby granted, free of charge, to any |
6 | // person obtaining a copy of this software and associated |
7 | // documentation files (the "Software"), to deal in the |
8 | // Software without restriction, including without |
9 | // limitation the rights to use, copy, modify, merge, |
10 | // publish, distribute, sublicense, and/or sell copies of |
11 | // the Software, and to permit persons to whom the Software |
12 | // is furnished to do so, subject to the following |
13 | // conditions: |
14 | // |
15 | // The above copyright notice and this permission notice |
16 | // shall be included in all copies or substantial portions |
17 | // of the Software. |
18 | // |
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF |
20 | // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED |
21 | // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A |
22 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT |
23 | // SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY |
24 | // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
25 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR |
26 | // IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
27 | // DEALINGS IN THE SOFTWARE. |
28 | |
29 | // JSON generated ser/de. |
30 | // @PENGUINLIONG |
31 | #pragma once |
32 | #include <memory> |
33 | #include <array> |
34 | #include <vector> |
35 | #include <map> |
36 | #include <unordered_map> |
37 | #include <type_traits> |
38 | #include <optional> |
39 | #include "taichi/common/json.h" |
40 | |
41 | namespace liong { |
42 | namespace json { |
43 | |
44 | namespace detail { |
45 | |
46 | struct FieldNameList { |
47 | const std::vector<std::string> field_names; |
48 | |
49 | static std::vector<std::string> split_field_names(const char *field_names) { |
50 | std::vector<std::string> out{}; |
51 | std::string buf{}; |
52 | |
53 | const char *pos = field_names; |
54 | for (char c = *pos; c != '\0'; c = *(++pos)) { |
55 | bool is_lower = (c >= 'a' && c <= 'z'); |
56 | bool is_upper = (c >= 'A' && c <= 'Z'); |
57 | bool is_digit = (c >= '0' && c <= '9'); |
58 | bool is_underscore = c == '_'; |
59 | |
60 | if (is_lower || is_upper || is_digit || is_underscore) { |
61 | buf.push_back(c); |
62 | } else { |
63 | if (!buf.empty()) { |
64 | out.emplace_back(std::exchange(buf, std::string())); |
65 | } |
66 | } |
67 | } |
68 | if (!buf.empty()) { |
69 | out.emplace_back(std::move(buf)); |
70 | } |
71 | return out; |
72 | } |
73 | |
74 | explicit FieldNameList(const char *field_names) |
75 | : field_names(split_field_names(field_names)) { |
76 | } |
77 | }; |
78 | |
79 | template <typename T> |
80 | struct JsonSerde { |
81 | // Numeric and boolean types (integers and floating-point numbers). |
82 | template <typename U = typename std::remove_cv<T>::type> |
83 | static JsonValue serialize( |
84 | typename std::enable_if_t<std::is_arithmetic<U>::value, T> x) { |
85 | return JsonValue(x); |
86 | } |
87 | template <typename U = typename std::remove_cv<T>::type> |
88 | static void deserialize( |
89 | const JsonValue &j, |
90 | typename std::enable_if_t<std::is_arithmetic<U>::value, T> &x) { |
91 | x = (T)j; |
92 | } |
93 | template <typename U = typename std::remove_cv<T>::type> |
94 | static JsonValue serialize( |
95 | typename std::enable_if_t<std::is_enum<U>::value, T> x) { |
96 | return JsonValue((typename std::underlying_type<T>::type)x); |
97 | } |
98 | template <typename U = typename std::remove_cv<T>::type> |
99 | static void deserialize( |
100 | const JsonValue &j, |
101 | typename std::enable_if_t<std::is_enum<U>::value, T> &x) { |
102 | x = (T)(typename std::underlying_type<T>::type)j; |
103 | } |
104 | |
105 | // String type. |
106 | template <typename U = typename std::remove_cv<T>::type> |
107 | static JsonValue serialize( |
108 | typename std::enable_if_t<std::is_same<U, std::string>::value, T> x) { |
109 | return JsonValue(x); |
110 | } |
111 | template <typename U = typename std::remove_cv<T>::type> |
112 | static void deserialize( |
113 | const JsonValue &j, |
114 | typename std::enable_if_t<std::is_same<U, std::string>::value, T> &x) { |
115 | x = (T)j; |
116 | } |
117 | |
118 | // Structure types (with a `FieldNameList` field provided). |
119 | template <typename U = typename std::remove_cv<T>::type> |
120 | static JsonValue serialize( |
121 | const typename std::enable_if_t< |
122 | std::is_same<decltype(std::declval<U>().json_serialize_fields()), |
123 | JsonValue>::value, |
124 | T> &x) { |
125 | return JsonValue(x.json_serialize_fields()); |
126 | } |
127 | template <typename U = typename std::remove_cv<T>::type> |
128 | static void deserialize( |
129 | const JsonValue &j, |
130 | typename std::enable_if_t< |
131 | std::is_same<decltype(std::declval<U>().json_deserialize_fields( |
132 | std::declval<const JsonObject &>())), |
133 | void>::value, |
134 | T> &x) { |
135 | x.json_deserialize_fields((const JsonObject &)j); |
136 | } |
137 | |
138 | // Key-value pairs. |
139 | template <typename U = typename std::remove_cv<T>::type> |
140 | static JsonValue serialize(const typename std::enable_if_t< |
141 | std::is_same<std::pair<typename U::first_type, |
142 | typename U::second_type>, |
143 | T>::value, |
144 | T> &x) { |
145 | JsonObject obj{}; |
146 | obj.inner.emplace(std::make_pair<const std::string, JsonValue>( |
147 | "key" , JsonSerde<typename T::first_type>::serialize(x.first))); |
148 | obj.inner.emplace(std::make_pair<const std::string, JsonValue>( |
149 | "value" , JsonSerde<typename T::second_type>::serialize(x.second))); |
150 | return JsonValue(std::move(obj)); |
151 | } |
152 | template <typename U = typename std::remove_cv<T>::type> |
153 | static void deserialize( |
154 | const JsonValue &j, |
155 | typename std::enable_if_t<std::is_same<std::pair<typename U::first_type, |
156 | typename U::second_type>, |
157 | T>::value, |
158 | T> &x) { |
159 | JsonSerde<typename T::first_type>::deserialize(j["key" ], x.first); |
160 | JsonSerde<typename T::second_type>::deserialize(j["value" ], x.second); |
161 | } |
162 | |
163 | // Owned pointer (requires default constructable). |
164 | template <typename U = typename std::remove_cv<T>::type> |
165 | static JsonValue serialize( |
166 | const typename std::enable_if_t< |
167 | std::is_same<std::unique_ptr<typename U::element_type>, T>::value, |
168 | T> &x) { |
169 | if (x == nullptr) { |
170 | return JsonValue(nullptr); |
171 | } else { |
172 | return JsonSerde<typename T::element_type>::serialize(*x); |
173 | } |
174 | } |
175 | template <typename U = typename std::remove_cv<T>::type> |
176 | static void deserialize( |
177 | const JsonValue &j, |
178 | typename std::enable_if_t< |
179 | std::is_same<std::unique_ptr<typename U::element_type>, T>::value, |
180 | T> &x) { |
181 | if (j.is_null()) { |
182 | x = nullptr; |
183 | } else { |
184 | x = std::make_unique<typename T::element_type>(); |
185 | JsonSerde<typename T::element_type>::deserialize(j, *x); |
186 | } |
187 | } |
188 | |
189 | // Array types (requires default + move constructable). |
190 | template <typename U = typename std::remove_cv<T>::type> |
191 | static JsonValue serialize( |
192 | const typename std::enable_if_t<std::is_array<U>::value, T> &x) { |
193 | JsonArray arr{}; |
194 | for (const auto &xx : x) { |
195 | arr.inner.emplace_back( |
196 | JsonSerde<typename std::remove_extent_t<T>>::serialize(xx)); |
197 | } |
198 | return JsonValue(std::move(arr)); |
199 | } |
200 | template <typename U = typename std::remove_cv<T>::type> |
201 | static JsonValue serialize(const typename std::enable_if_t< |
202 | std::is_same<std::array<typename U::value_type, |
203 | std::tuple_size<U>::value>, |
204 | T>::value, |
205 | T> &x) { |
206 | JsonArray arr{}; |
207 | for (const auto &xx : x) { |
208 | arr.inner.emplace_back(JsonSerde<typename T::value_type>::serialize(xx)); |
209 | } |
210 | return JsonValue(std::move(arr)); |
211 | } |
212 | template <typename U = typename std::remove_cv<T>::type> |
213 | static JsonValue serialize( |
214 | const typename std::enable_if_t< |
215 | std::is_same<std::vector<typename U::value_type>, T>::value, |
216 | T> &x) { |
217 | JsonArray arr{}; |
218 | for (const auto &xx : x) { |
219 | arr.inner.emplace_back(JsonSerde<typename T::value_type>::serialize(xx)); |
220 | } |
221 | return JsonValue(std::move(arr)); |
222 | } |
223 | template <typename U = typename std::remove_cv<T>::type> |
224 | static void deserialize( |
225 | const JsonValue &j, |
226 | typename std::enable_if_t<std::is_array<U>::value, T> &x) { |
227 | for (size_t i = 0; i < std::extent<T>::value; ++i) { |
228 | JsonSerde<typename std::remove_extent_t<T>>::deserialize(j[i], x[i]); |
229 | } |
230 | } |
231 | template <typename U = typename std::remove_cv<T>::type> |
232 | static void deserialize( |
233 | const JsonValue &j, |
234 | typename std::enable_if_t< |
235 | std::is_same< |
236 | std::array<typename U::value_type, std::tuple_size<U>::value>, |
237 | T>::value, |
238 | T> &x) { |
239 | for (size_t i = 0; i < x.size(); ++i) { |
240 | JsonSerde<typename T::value_type>::deserialize(j[i], x.at(i)); |
241 | } |
242 | } |
243 | template <typename U = typename std::remove_cv<T>::type> |
244 | static void deserialize( |
245 | const JsonValue &j, |
246 | typename std::enable_if_t< |
247 | std::is_same<std::vector<typename U::value_type>, T>::value, |
248 | T> &x) { |
249 | x.clear(); |
250 | for (const auto &elem : j.elems()) { |
251 | typename T::value_type xx{}; |
252 | JsonSerde<decltype(xx)>::deserialize(elem, xx); |
253 | x.emplace_back(std::move(xx)); |
254 | } |
255 | } |
256 | |
257 | // Dictionary types (requires default + move constructable). |
258 | template <typename U = typename std::remove_cv<T>::type> |
259 | static JsonValue serialize( |
260 | const typename std::enable_if_t< |
261 | std::is_same<std::map<typename U::key_type, typename U::mapped_type>, |
262 | T>::value, |
263 | T> &x) { |
264 | JsonArray arr{}; |
265 | for (const auto &xx : x) { |
266 | arr.inner.emplace_back(JsonSerde<typename T::value_type>::serialize(xx)); |
267 | } |
268 | return JsonValue(std::move(arr)); |
269 | } |
270 | template <typename U = typename std::remove_cv<T>::type> |
271 | static JsonValue serialize( |
272 | const typename std::enable_if_t< |
273 | std::is_same< |
274 | std::unordered_map<typename U::key_type, typename U::mapped_type>, |
275 | T>::value, |
276 | T> &x) { |
277 | JsonArray arr{}; |
278 | for (const auto &xx : x) { |
279 | arr.inner.emplace_back(JsonSerde<typename T::value_type>::serialize(xx)); |
280 | } |
281 | return JsonValue(std::move(arr)); |
282 | } |
283 | template <typename U = typename std::remove_cv<T>::type> |
284 | static void deserialize( |
285 | const JsonValue &j, |
286 | typename std::enable_if_t< |
287 | std::is_same<std::map<typename U::key_type, typename U::mapped_type>, |
288 | T>::value, |
289 | T> &x) { |
290 | x.clear(); |
291 | for (const auto &elem : j.elems()) { |
292 | std::pair<typename T::key_type, typename T::mapped_type> xx{}; |
293 | JsonSerde<decltype(xx)>::deserialize(elem, xx); |
294 | x.emplace(std::move(*(std::pair<const typename T::key_type, |
295 | typename T::mapped_type> *)&xx)); |
296 | } |
297 | } |
298 | template <typename U = typename std::remove_cv<T>::type> |
299 | static void deserialize( |
300 | const JsonValue &j, |
301 | typename std::enable_if_t< |
302 | std::is_same< |
303 | std::unordered_map<typename U::key_type, typename U::mapped_type>, |
304 | T>::value, |
305 | T> &x) { |
306 | x.clear(); |
307 | for (const auto &elem : j.elems()) { |
308 | std::pair<typename T::key_type, typename T::mapped_type> xx{}; |
309 | JsonSerde<decltype(xx)>::deserialize(elem, xx); |
310 | x.emplace(std::move(*(std::pair<const typename T::key_type, |
311 | typename T::mapped_type> *)&xx)); |
312 | } |
313 | } |
314 | |
315 | // Optional types (requires default + move constructable). |
316 | template <typename U = typename std::remove_cv<T>::type> |
317 | static JsonValue serialize( |
318 | const typename std::enable_if_t< |
319 | std::is_same<std::optional<typename U::value_type>, T>::value, |
320 | T> &x) { |
321 | if (x.has_value()) { |
322 | return JsonSerde<typename T::value_type>::serialize(x.value()); |
323 | } else { |
324 | return JsonValue(nullptr); |
325 | } |
326 | } |
327 | template <typename U = typename std::remove_cv<T>::type> |
328 | static void deserialize( |
329 | const JsonValue &j, |
330 | typename std::enable_if_t< |
331 | std::is_same<std::optional<typename U::value_type>, T>::value, |
332 | T> &x) { |
333 | if (j.is_null()) { |
334 | x = std::nullopt; |
335 | } else { |
336 | typename T::value_type xx; |
337 | JsonSerde<typename T::value_type>::deserialize(j, xx); |
338 | x = std::move(xx); |
339 | } |
340 | } |
341 | }; |
342 | |
343 | template <typename... TArgs> |
344 | struct JsonSerdeFieldImpl {}; |
345 | template <typename TFirst, typename... TOthers> |
346 | struct JsonSerdeFieldImpl<TFirst, TOthers...> { |
347 | inline static void serialize(JsonObject &obj, |
348 | std::vector<std::string>::const_iterator name, |
349 | const TFirst &first, |
350 | const TOthers &...others) { |
351 | obj.inner.emplace(std::make_pair<std::string, JsonValue>( |
352 | std::string(*name), JsonSerde<TFirst>::serialize(first))); |
353 | JsonSerdeFieldImpl<TOthers...>::serialize(obj, ++name, others...); |
354 | } |
355 | inline static void deserialize(const JsonObject &obj, |
356 | std::vector<std::string>::const_iterator name, |
357 | TFirst &first, |
358 | TOthers &...others) { |
359 | auto it = obj.inner.find(*name); |
360 | if (it != obj.inner.end()) { |
361 | JsonSerde<TFirst>::deserialize(it->second, first); |
362 | } |
363 | JsonSerdeFieldImpl<TOthers...>::deserialize(obj, ++name, others...); |
364 | } |
365 | }; |
366 | template <> |
367 | struct JsonSerdeFieldImpl<> { |
368 | inline static void serialize(JsonObject &obj, |
369 | std::vector<std::string>::const_iterator name) { |
370 | } |
371 | inline static void deserialize( |
372 | const JsonObject &obj, |
373 | std::vector<std::string>::const_iterator name) { |
374 | } |
375 | }; |
376 | template <typename... TArgs> |
377 | inline void json_serialize_field_impl( |
378 | JsonObject &obj, |
379 | std::vector<std::string>::const_iterator name, |
380 | const TArgs &...args) { |
381 | JsonSerdeFieldImpl<TArgs...>::serialize(obj, name, args...); |
382 | } |
383 | template <typename... TArgs> |
384 | inline void json_deserialize_field_impl( |
385 | const JsonObject &obj, |
386 | std::vector<std::string>::const_iterator name, |
387 | TArgs &...args) { |
388 | JsonSerdeFieldImpl<TArgs...>::deserialize(obj, name, args...); |
389 | } |
390 | |
391 | } // namespace detail |
392 | |
393 | // Serialize a JSON serde object, turning in-memory representations into JSON |
394 | // text. |
395 | template <typename T> |
396 | JsonValue serialize(const T &x) { |
397 | return detail::JsonSerde<T>::serialize(x); |
398 | } |
399 | |
400 | // Deserialize a JSON serde object, turning JSON text into in-memory |
401 | // representations. |
402 | template <typename T> |
403 | void deserialize(const JsonValue &j, T &out) { |
404 | detail::JsonSerde<T>::deserialize(j, out); |
405 | } |
406 | |
407 | // If you need to control the serialization process on your own, you might want |
408 | // to inherit from this. |
409 | struct CustomJsonSerdeBase { |
410 | public: |
411 | // Serialize the field values into a JSON object. |
412 | virtual JsonObject json_serialize_fields() const = 0; |
413 | // Deserialize the current object with JSON fields. |
414 | virtual void json_deserialize_fields(const JsonObject &j) = 0; |
415 | }; |
416 | |
417 | } // namespace json |
418 | } // namespace liong |
419 | |
420 | #define L_JSON_SERDE_FIELDS(...) \ |
421 | const std::vector<std::string> &json_serde_field_names() const { \ |
422 | static ::liong::json::detail::FieldNameList JSON_SERDE_FIELD_NAMES{ \ |
423 | #__VA_ARGS__}; \ |
424 | return JSON_SERDE_FIELD_NAMES.field_names; \ |
425 | } \ |
426 | ::liong::json::JsonValue json_serialize_fields() const { \ |
427 | ::liong::json::JsonObject out{}; \ |
428 | ::liong::json::detail::json_serialize_field_impl( \ |
429 | out, json_serde_field_names().begin(), __VA_ARGS__); \ |
430 | return ::liong::json::JsonValue(std::move(out)); \ |
431 | } \ |
432 | void json_deserialize_fields(const ::liong::json::JsonObject &j) { \ |
433 | ::liong::json::detail::json_deserialize_field_impl( \ |
434 | j, json_serde_field_names().begin(), __VA_ARGS__); \ |
435 | } |
436 | |