jsonizer.tpp 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. //
  2. // jsonizer.tpp
  3. // serializer
  4. //
  5. // Created by Sam Jaffe on 3/15/23.
  6. //
  7. #pragma once
  8. #include <fstream>
  9. #include <iostream>
  10. #include <stdexcept>
  11. #include <json/json.h>
  12. #include <magic_enum.hpp>
  13. #include <serializer/jsonizer.h>
  14. #include <serializer/strconv.h>
  15. #include <serializer/traits.h>
  16. #include <string_utils/cast.h>
  17. namespace serializer {
  18. template <typename T, size_t... Is>
  19. Json::Value Jsonizer::to_json(T & value, std::index_sequence<Is...>) const {
  20. Json::Value json;
  21. [[maybe_unused]] auto l = {
  22. ((json[int(Is)] = to_json(std::get<Is>(value))), 0)...};
  23. return json;
  24. }
  25. template <typename T> Json::Value Jsonizer::to_json(T const & value) const {
  26. if constexpr (detail::has_serial_type_v<T>) {
  27. return to_json(static_cast<typename T::serial_type>(value));
  28. } else if constexpr (std::is_enum_v<T>) {
  29. constexpr auto type = magic_enum::as_flags<magic_enum::detail::is_flags_v<T>>;
  30. return std::string(magic_enum::enum_name<type>(value));
  31. } else if constexpr (detail::is_tuple_v<T>) {
  32. return to_json(value, std::make_index_sequence<std::tuple_size_v<T>>());
  33. } else if constexpr (std::is_constructible_v<std::string, T>) {
  34. return std::string(value);
  35. } else if constexpr (std::is_floating_point_v<T>) {
  36. return static_cast<double>(value);
  37. } else if constexpr (std::is_same_v<bool, T>) {
  38. return value;
  39. } else if constexpr (std::is_arithmetic_v<T>) {
  40. return static_cast<int>(value);
  41. } else if constexpr (detail::is_associative_container_v<T>) {
  42. Json::Value rval;
  43. using K = std::decay_t<typename T::key_type>;
  44. if constexpr (std::is_same_v<std::string, K> || std::is_arithmetic_v<K>) {
  45. for (auto const & [k, v] : value) {
  46. rval[to_string(k)] = to_json(v);
  47. }
  48. } else {
  49. for (auto const & pair : value) {
  50. rval.append(to_json(pair));
  51. }
  52. }
  53. return rval;
  54. } else if constexpr (detail::is_container_v<T>) {
  55. Json::Value rval;
  56. for (auto const & elem : value) {
  57. rval.append(to_json(elem));
  58. }
  59. return rval;
  60. } else {
  61. return to_json_impl(value);
  62. }
  63. }
  64. template <typename T, size_t... Is>
  65. void Jsonizer::from_json(T & value, Json::Value const & json,
  66. std::index_sequence<Is...>) const {
  67. [[maybe_unused]] auto l = {
  68. ((std::get<Is>(value) =
  69. from_json<std::tuple_element_t<Is, T>>(json[int(Is)])),
  70. 0)...};
  71. }
  72. template <typename T>
  73. void Jsonizer::from_json(T & value, Json::Value const & json) const {
  74. if (json.isNull()) return;
  75. if constexpr (detail::has_serial_type_v<T>) {
  76. value = T(from_json<typename T::serial_type>(json));
  77. } else if constexpr (std::is_enum_v<T>) {
  78. if (!string_utils::cast(value, json.asString())) {
  79. throw std::invalid_argument("Cannot cast to enum: " + json.asString());
  80. }
  81. } else if constexpr (std::is_same_v<std::string, T>) {
  82. value = json.asString();
  83. } else if constexpr (detail::is_tuple_v<T>) {
  84. from_json(value, json, std::make_index_sequence<std::tuple_size_v<T>>());
  85. } else if constexpr (detail::is_associative_container_v<T>) {
  86. using K = std::decay_t<typename T::key_type>;
  87. using V = std::decay_t<typename T::mapped_type>;
  88. if (json.isArray()) {
  89. std::vector<std::pair<K, V>> tmp;
  90. from_json(tmp, json);
  91. value.insert(tmp.begin(), tmp.end());
  92. } else if (json.isObject()) {
  93. if constexpr (std::is_constructible_v<K, std::string>) {
  94. for (auto it = json.begin(), end = json.end(); it != end; ++it) {
  95. value.emplace(it.key().asString(), from_json<V>(*it));
  96. }
  97. } else {
  98. for (auto it = json.begin(), end = json.end(); it != end; ++it) {
  99. value.emplace(from_string<K>(it.key().asString()), from_json<V>(*it));
  100. }
  101. }
  102. } else {
  103. throw std::invalid_argument(
  104. "cannot construct container from non-container");
  105. }
  106. } else if constexpr (detail::is_container_v<T>) {
  107. using V = std::decay_t<typename T::value_type>;
  108. if (!json.isArray()) {
  109. throw std::invalid_argument("cannot construct container from non-array");
  110. }
  111. for (auto const & elem : json) {
  112. value.insert(value.end(), from_json<V>(elem));
  113. }
  114. } else if constexpr (std::is_floating_point_v<T>) {
  115. value = static_cast<T>(json.asDouble());
  116. } else if constexpr (std::is_same_v<bool, T>) {
  117. value = json.asBool();
  118. } else if constexpr (std::is_arithmetic_v<T>) {
  119. value = static_cast<T>(json.asInt());
  120. } else {
  121. from_json_impl(value, json);
  122. }
  123. }
  124. template <typename T> T Jsonizer::from_json(Json::Value const & json) const {
  125. std::decay_t<T> tmp;
  126. from_json(tmp, json);
  127. return tmp;
  128. }
  129. template <typename T> T Jsonizer::from_stream(std::istream & in) const {
  130. Json::Value root;
  131. in >> root;
  132. return from_json<T>(root);
  133. }
  134. template <typename T> T Jsonizer::from_string(std::string const & in) const {
  135. std::stringstream ss;
  136. ss << in;
  137. return from_stream<T>(ss);
  138. }
  139. template <typename T>
  140. void Jsonizer::to_stream(T const & value, std::ostream & out) const {
  141. Json::Value root = to_json(value);
  142. out << root;
  143. }
  144. template <typename T> T Jsonizer::from_file(std::string const & file) const {
  145. std::ifstream in(file);
  146. return from_stream<T>(in);
  147. }
  148. }