jsonizer.tpp 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. //
  2. // jsonizer.tpp
  3. // serializer
  4. //
  5. // Created by Sam Jaffe on 3/15/23.
  6. //
  7. #pragma once
  8. #include <stdexcept>
  9. #include <expect/expect.hpp>
  10. #include <json/json.h>
  11. #include <magic_enum/magic_enum.hpp>
  12. #include <string_utils/cast.h>
  13. #include <serializer/jsonizer.h>
  14. #include <serializer/jsonizer_ios.tpp>
  15. #include <serializer/shared_cache.h>
  16. #include <serializer/strconv.h>
  17. #include <serializer/traits.h>
  18. namespace serializer {
  19. inline Jsonizer::Jsonizer() : p_cache(std::make_shared<SharedCache>()) {}
  20. /**
  21. * @brief Construct a jsonizer with an externally owned cache
  22. * @param cache A shared_ptr to a data cache. Cannot be null
  23. * @throws std::logic_error if cache == nullptr
  24. */
  25. inline Jsonizer::Jsonizer(std::shared_ptr<SharedCache> cache) : p_cache(cache) {
  26. expects(p_cache != nullptr);
  27. }
  28. template <typename T, size_t... Is>
  29. Json::Value Jsonizer::to_json(T & value, std::index_sequence<Is...>) const {
  30. Json::Value json;
  31. [[maybe_unused]] auto l = {
  32. ((json[int(Is)] = to_json(std::get<Is>(value))), 0)...};
  33. return json;
  34. }
  35. template <typename T>
  36. Json::Value Jsonizer::to_json(std::optional<T> const & opt) const {
  37. return opt.has_value() ? to_json(*opt) : Json::Value();
  38. }
  39. template <typename T> Json::Value Jsonizer::to_json(T const & value) const {
  40. if constexpr (detail::has_serial_type_v<T>) {
  41. return to_json(static_cast<typename T::serial_type>(value));
  42. } else if constexpr (std::is_enum_v<T>) {
  43. return to_string(value);
  44. } else if constexpr (detail::is_tuple_v<T>) {
  45. return to_json(value, std::make_index_sequence<std::tuple_size_v<T>>());
  46. } else if constexpr (std::is_constructible_v<std::string, T>) {
  47. return std::string(value);
  48. } else if constexpr (std::is_floating_point_v<T>) {
  49. return static_cast<double>(value);
  50. } else if constexpr (std::is_same_v<bool, T>) {
  51. return value;
  52. } else if constexpr (std::is_arithmetic_v<T> && std::is_unsigned_v<T>) {
  53. return static_cast<uint64_t>(value);
  54. } else if constexpr (std::is_arithmetic_v<T>) {
  55. return static_cast<int64_t>(value);
  56. } else if constexpr (detail::is_associative_container_v<T>) {
  57. Json::Value rval;
  58. using K = std::decay_t<typename T::key_type>;
  59. if constexpr (std::is_same_v<std::string, K> || std::is_arithmetic_v<K>) {
  60. for (auto const & [k, v] : value) {
  61. rval[to_string(k)] = to_json(v);
  62. }
  63. } else {
  64. for (auto const & pair : value) {
  65. rval.append(to_json(pair));
  66. }
  67. }
  68. return rval;
  69. } else if constexpr (detail::is_container_v<T>) {
  70. Json::Value rval;
  71. for (auto const & elem : value) {
  72. rval.append(to_json(elem));
  73. }
  74. return rval;
  75. } else if constexpr (detail::is_wrapper_v<T>) {
  76. using V = std::decay_t<typename T::value_type>;
  77. return to_json(static_cast<V const &>(value));
  78. } else {
  79. return to_json_impl(value);
  80. }
  81. }
  82. template <typename T, size_t... Is>
  83. void Jsonizer::from_json(T & value, Json::Value const & json,
  84. std::index_sequence<Is...>) const {
  85. [[maybe_unused]] auto l = {
  86. ((std::get<Is>(value) =
  87. from_json<std::tuple_element_t<Is, T>>(json[int(Is)])),
  88. 0)...};
  89. }
  90. template <typename T>
  91. void Jsonizer::from_json(std::optional<T> & opt,
  92. Json::Value const & json) const {
  93. opt = json.isNull() ? std::nullopt : std::optional{from_json<T>(json)};
  94. }
  95. template <typename T>
  96. void Jsonizer::from_json(T & value, Json::Value const & json) const {
  97. if (json.isNull()) return;
  98. if constexpr (detail::has_serial_type_v<T>) {
  99. value = T(from_json<typename T::serial_type>(json));
  100. } else if constexpr (std::is_enum_v<T>) {
  101. if (json.isInt()) {
  102. value = *magic_enum::enum_cast<T>(json.asInt());
  103. } else if (!string_utils::cast(value, json.asString())) {
  104. throw std::invalid_argument("Cannot cast to enum: " + json.asString());
  105. }
  106. } else if constexpr (std::is_same_v<std::string, T>) {
  107. value = json.asString();
  108. } else if constexpr (detail::is_tuple_v<T>) {
  109. from_json(value, json, std::make_index_sequence<std::tuple_size_v<T>>());
  110. } else if constexpr (detail::is_associative_container_v<T>) {
  111. using K = std::decay_t<typename T::key_type>;
  112. using V = std::decay_t<typename T::mapped_type>;
  113. if (json.isArray()) {
  114. std::vector<std::pair<K, V>> tmp;
  115. from_json(tmp, json);
  116. value.insert(tmp.begin(), tmp.end());
  117. } else if (json.isObject()) {
  118. if constexpr (std::is_constructible_v<K, std::string>) {
  119. for (auto it = json.begin(), end = json.end(); it != end; ++it) {
  120. value.emplace(it.key().asString(), from_json<V>(*it));
  121. }
  122. } else {
  123. for (auto it = json.begin(), end = json.end(); it != end; ++it) {
  124. value.emplace(from_string<K>(it.key().asString()), from_json<V>(*it));
  125. }
  126. }
  127. } else {
  128. throw std::invalid_argument(
  129. "cannot construct container from non-container");
  130. }
  131. } else if constexpr (detail::is_container_v<T>) {
  132. using V = std::decay_t<typename T::value_type>;
  133. if (!json.isArray()) {
  134. throw std::invalid_argument("cannot construct container from non-array");
  135. }
  136. for (auto const & elem : json) {
  137. value.insert(value.end(), from_json<V>(elem));
  138. }
  139. } else if constexpr (detail::is_wrapper_v<T>) {
  140. using V = std::decay_t<typename T::value_type>;
  141. value = from_json<V>(json);
  142. } else if constexpr (std::is_floating_point_v<T>) {
  143. value = static_cast<T>(json.asDouble());
  144. } else if constexpr (std::is_same_v<bool, T>) {
  145. value = json.asBool();
  146. } else if constexpr (std::is_arithmetic_v<T> && std::is_unsigned_v<T>) {
  147. value = static_cast<T>(json.asUInt64());
  148. } else if constexpr (std::is_arithmetic_v<T>) {
  149. value = static_cast<T>(json.asInt64());
  150. } else {
  151. from_json_impl(value, json);
  152. }
  153. }
  154. template <typename T, typename F>
  155. T Jsonizer::from_cached_json(std::string const & key, Json::Value const & json,
  156. F && fetch) const {
  157. std::shared_ptr<T const> ptr = p_cache->fetch<T>(json[key].asString());
  158. if (!ptr) {
  159. T value{};
  160. std::forward<F>(fetch)(value, json);
  161. ptr = p_cache->store(value.name, std::move(value));
  162. }
  163. return *ptr;
  164. }
  165. template <typename T>
  166. void Jsonizer::from_json(std::shared_ptr<T const> & ptr,
  167. Json::Value const & json) const {
  168. if (json.isString()) {
  169. ptr = p_cache->fetch<T>(json.asString());
  170. } else {
  171. T local{};
  172. from_json(local, json);
  173. ptr = p_cache->store(local.name, local);
  174. }
  175. }
  176. }