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
41namespace liong {
42namespace json {
43
44namespace detail {
45
46struct 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
79template <typename T>
80struct 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
343template <typename... TArgs>
344struct JsonSerdeFieldImpl {};
345template <typename TFirst, typename... TOthers>
346struct 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};
366template <>
367struct 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};
376template <typename... TArgs>
377inline 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}
383template <typename... TArgs>
384inline 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.
395template <typename T>
396JsonValue 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.
402template <typename T>
403void 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.
409struct 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