|
5 | 5 |
|
6 | 6 | #include <iris/config.hpp> // IWYU pragma: keep |
7 | 7 |
|
8 | | -#include <iris/marshal/serialize_traits.hpp> |
| 8 | +#include <iris/marshal/serialize.hpp> |
9 | 9 | #include <iris/marshal/detail/field.hpp> |
10 | 10 |
|
11 | 11 | #include <iris/alloy/utility.hpp> |
|
16 | 16 |
|
17 | 17 | #include <nlohmann/json.hpp> |
18 | 18 |
|
| 19 | +#include <vector> |
19 | 20 | #include <string> |
20 | 21 | #include <utility> |
21 | 22 | #include <type_traits> |
22 | 23 |
|
23 | 24 | namespace iris::marshal::json { |
24 | 25 |
|
25 | | -namespace detail { |
26 | | - |
27 | | -template<class T> |
28 | | -struct native_t_impl |
29 | | -{ |
30 | | - using type = T; |
31 | | -}; |
32 | | - |
33 | | -template<StringLike T> |
34 | | -struct native_t_impl<T> |
35 | | -{ |
36 | | - using type = std::string; |
37 | | -}; |
38 | | - |
39 | | -} // detail |
40 | | - |
41 | 26 | struct format : generic_format |
42 | 27 | { |
43 | 28 | template<class K> |
@@ -100,104 +85,70 @@ template<class T> concept deserializable_array = marshal::deserializable_arra |
100 | 85 | template<class T> concept deserializable_tuple = marshal::deserializable_tuple<T, format>; |
101 | 86 | template<class T> concept deserializable = marshal::deserializable<T, format>; |
102 | 87 |
|
103 | | -namespace detail { |
104 | | - |
105 | | -struct save_fn |
| 88 | +class dom_writer |
106 | 89 | { |
107 | | - template<serializable_scalar T> |
108 | | - static void operator()(nlohmann::json& out, T const& value) |
109 | | - { |
110 | | - if constexpr (std::is_enum_v<T>) { |
111 | | - out = std::to_underlying(value); |
112 | | - } else { |
113 | | - out = value; |
114 | | - } |
115 | | - } |
| 90 | + nlohmann::json& root_; |
| 91 | + std::vector<nlohmann::json*> stack_; |
| 92 | + std::string pending_key_; |
116 | 93 |
|
117 | | - template<serializable_array R> |
118 | | - static void operator()(nlohmann::json& out, R const& arr) |
| 94 | + [[nodiscard]] nlohmann::json& slot() |
119 | 95 | { |
120 | | - auto json_arr = nlohmann::json::array(); |
| 96 | + if (stack_.empty()) return root_; |
| 97 | + auto& parent = *stack_.back(); |
| 98 | + return parent.is_object() ? parent[pending_key_] : parent.emplace_back(); |
| 99 | + } |
121 | 100 |
|
122 | | - for (auto const& elem : arr) { |
123 | | - nlohmann::json elem_json; |
124 | | - save_fn{}(elem_json, elem); |
125 | | - json_arr.emplace_back(std::move(elem_json)); |
126 | | - } |
| 101 | +public: |
| 102 | + using format = json::format; |
| 103 | + using result_type = nlohmann::json; |
127 | 104 |
|
128 | | - out = std::move(json_arr); |
129 | | - } |
| 105 | + explicit dom_writer(nlohmann::json& root) |
| 106 | + : root_(root) |
| 107 | + {} |
130 | 108 |
|
131 | | - template<serializable_map MapT> |
132 | | - static void operator()(nlohmann::json& out, MapT const& map) |
| 109 | + template<class T> |
| 110 | + requires format::loadable_scalar<T> |
| 111 | + void scalar(T const& value) |
133 | 112 | { |
134 | | - auto json_map = nlohmann::json::object(); |
135 | | - |
136 | | - for (auto const& [key, value] : map) { |
137 | | - if constexpr (adapted_proxy<ranges::range_key_t<MapT>, format>) { |
138 | | - auto&& json_key = adapted_proxy_traits<ranges::range_key_t<MapT>, format>::to_native_type(key); |
139 | | - save_fn{}(json_map[json_key], value); |
140 | | - } else { |
141 | | - save_fn{}(json_map[std::basic_string_view{key}], value); |
142 | | - } |
| 113 | + if constexpr (std::is_enum_v<T>) { |
| 114 | + slot() = std::to_underlying(value); |
| 115 | + } else { |
| 116 | + slot() = value; |
143 | 117 | } |
144 | | - |
145 | | - out = std::move(json_map); |
146 | 118 | } |
147 | 119 |
|
148 | | - template<serializable_tuple TupleT> |
149 | | - static void operator()(nlohmann::json& out, TupleT const& tup) |
| 120 | + void null() |
150 | 121 | { |
151 | | - auto json_arr = nlohmann::json::array(); |
152 | | - |
153 | | - alloy::for_each(tup, [&](auto const& elem) { |
154 | | - nlohmann::json elem_json; |
155 | | - save_fn{}(elem_json, elem); |
156 | | - json_arr.emplace_back(std::move(elem_json)); |
157 | | - }); |
158 | | - |
159 | | - out = std::move(json_arr); |
| 122 | + slot() = nullptr; |
160 | 123 | } |
161 | 124 |
|
162 | | - template<serializable_class ClassT> |
163 | | - static void operator()(nlohmann::json& out, ClassT const& klass) |
| 125 | + void begin_array() |
164 | 126 | { |
165 | | - auto json_map = nlohmann::json::object(); |
166 | | - |
167 | | - constexpr auto const& fields = adapted_class_traits<ClassT>::fields; |
168 | | - alloy::for_each(fields, [&]<class T, auto GetMem, auto SetMem>(marshal::detail::field_definition<T, GetMem, SetMem> const& def) { |
169 | | - save_fn{}(json_map[def.name], (klass.*GetMem)()); |
170 | | - }); |
171 | | - |
172 | | - out = std::move(json_map); |
| 127 | + stack_.push_back(&(slot() = nlohmann::json::array())); |
173 | 128 | } |
174 | | - |
175 | | - template<serializable_optional OptionalT> |
176 | | - static void operator()(nlohmann::json& out, OptionalT const& opt) |
| 129 | + void end_array() |
177 | 130 | { |
178 | | - if (opt) { |
179 | | - save_fn{}(out, *opt); |
180 | | - } else { |
181 | | - out = nullptr; |
182 | | - } |
| 131 | + stack_.pop_back(); |
183 | 132 | } |
184 | 133 |
|
185 | | - template<serializable_proxy ProxyT> |
186 | | - static void operator()(nlohmann::json& out, ProxyT const& proxy) |
| 134 | + void begin_object() |
187 | 135 | { |
188 | | - save_fn{}(out, adapted_proxy_traits<ProxyT, format>::to_native_type(proxy)); |
| 136 | + stack_.push_back(&(slot() = nlohmann::json::object())); |
189 | 137 | } |
190 | | - |
191 | | - template<serializable T> |
192 | | - [[nodiscard]] static nlohmann::json operator()(T const& value) |
| 138 | + void map_key(std::string_view k) |
| 139 | + { |
| 140 | + pending_key_.assign(k); |
| 141 | + } |
| 142 | + void end_object() |
193 | 143 | { |
194 | | - nlohmann::json out; |
195 | | - save_fn{}(out, value); |
196 | | - return out; |
| 144 | + stack_.pop_back(); |
197 | 145 | } |
198 | 146 | }; |
199 | 147 |
|
200 | | -// ---------------------------------------------------- |
| 148 | +[[maybe_unused]] inline constexpr basic_save_fn<dom_writer> save{}; |
| 149 | + |
| 150 | + |
| 151 | +namespace detail { |
201 | 152 |
|
202 | 153 | struct load_fn |
203 | 154 | { |
@@ -296,9 +247,6 @@ struct load_fn |
296 | 247 |
|
297 | 248 | } // detail |
298 | 249 |
|
299 | | -[[maybe_unused]] inline constexpr detail::save_fn save{}; |
300 | | - |
301 | | - |
302 | 250 | template<deserializable T> |
303 | 251 | requires requires(nlohmann::json const& j) { |
304 | 252 | detail::load_fn{}(j, std::declval<T&>()); |
|
0 commit comments