Nui
Loading...
Searching...
No Matches
val_conversion.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <nui/concepts.hpp>
5
6#pragma clang diagnostic push
7#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
8#pragma clang diagnostic ignored "-Wold-style-cast"
9#include <boost/describe.hpp>
10#include <boost/mp11/algorithm.hpp>
11#pragma clang diagnostic pop
12
13#include <nui/frontend/val.hpp>
14
15#include <optional>
16#include <vector>
17#include <filesystem>
18#include <utility>
19#include <unordered_map>
20#include <memory>
21#include <map>
22#include <variant>
23
24namespace Nui
25{
26 namespace Detail
27 {
28 template <typename T>
29 struct IsOptional : std::false_type
30 {};
31 template <typename T>
32 struct IsOptional<std::optional<T>> : std::true_type
33 {};
34 }
35
36 template <
37 typename T,
38 class Bases = boost::describe::describe_bases<T, boost::describe::mod_any_access>,
39 class Members = boost::describe::describe_members<T, boost::describe::mod_any_access>,
40 class Enable = std::enable_if_t<!std::is_union<T>::value>>
41 void convertToVal(Nui::val& val, T const& obj);
42 template <typename T>
43 Nui::val convertToVal(std::optional<T> const& option);
44 template <typename T>
45 requires Fundamental<T>
46 Nui::val convertToVal(T const& value);
47 Nui::val convertToVal(std::string const& value);
48 Nui::val convertToVal(std::filesystem::path const& value);
50 Nui::val convertToVal(char const* value);
51 template <typename T>
52 Nui::val convertToVal(std::vector<T> const& vector);
53 template <typename T>
54 Nui::val convertToVal(Observed<T> const& observed);
55 template <typename T>
56 Nui::val convertToVal(std::unordered_map<std::string, T> const& map);
57 template <typename T>
58 Nui::val convertToVal(std::map<std::string, T> const& map);
59 template <typename T>
60 Nui::val convertToVal(std::unique_ptr<T> const& ptr);
61 template <typename T>
62 Nui::val convertToVal(std::shared_ptr<T> const& ptr);
63 inline Nui::val convertToVal(long long)
64 {
65 throw std::runtime_error("Cannot convert long long to val");
66 }
67 inline Nui::val convertToVal(std::monostate)
68 {
69 return Nui::val::undefined();
70 }
71 template <typename... Ts>
72 Nui::val convertToVal(std::variant<Ts...> const& variant);
73
74 template <typename T, class Members>
75 requires(!std::is_union_v<T>)
76 void convertFromValObjImpl(Nui::val const& val, T& obj);
77
78 template <typename T, class Bases, class Members>
79 requires(!std::is_union_v<T>)
80 void convertFromVal(Nui::val const& val, T& obj);
81
82 template <typename T, class Members>
83 requires(!std::is_union_v<T> && !boost::describe::has_describe_bases<T>::value)
84 void convertFromVal(Nui::val const& val, T& obj);
85
86 template <typename T>
87 requires Fundamental<T>
88 void convertFromVal(Nui::val const& val, T& value);
89 void convertFromVal(Nui::val const& val, std::string& str);
90 template <typename T>
91 void convertFromVal(Nui::val const& val, std::optional<T>& option);
92 void convertFromVal(Nui::val const& val, std::filesystem::path& value);
93 void convertFromVal(Nui::val const& val, Nui::val& value);
94 template <typename T>
95 void convertFromVal(Nui::val const& val, std::vector<T>& vector);
96 template <typename T>
97 requires Fundamental<T>
98 void convertFromVal(Nui::val const& val, std::vector<T>& vector);
99 template <typename T>
100 void convertFromVal(Nui::val const& val, Observed<T>& observed);
101 template <typename T>
102 void convertFromVal(Nui::val const& val, std::unordered_map<std::string, T>& map);
103 inline void convertFromVal(Nui::val const&, long long)
104 {
105 throw std::invalid_argument("Cannot convert from val to long long");
106 }
107
108 template <typename T, class Bases, class Members, class Enable>
109 void convertToVal(Nui::val& val, T const& obj)
110 {
111 if (val.typeOf().as<std::string>() != "object")
112 val = Nui::val::object();
113
114 boost::mp11::mp_for_each<Bases>([&](auto&& base) {
115 using type = typename std::decay_t<decltype(base)>::type;
116 convertToVal(val, static_cast<type const&>(obj));
117 });
118
119 boost::mp11::mp_for_each<Members>([&](auto&& memAccessor) {
120 val.set(memAccessor.name, convertToVal(obj.*memAccessor.pointer));
121 });
122 }
123 template <
124 typename T,
125 class Bases = boost::describe::describe_bases<T, boost::describe::mod_any_access>,
126 class Members = boost::describe::describe_members<T, boost::describe::mod_any_access>,
127 class Enable = std::enable_if_t<!std::is_union<T>::value>>
128 Nui::val convertToVal(T const& obj)
129 {
130 Nui::val val = Nui::val::object();
131 convertToVal(val, obj);
132 return val;
133 }
134
135 template <typename T>
136 Nui::val convertToVal(std::optional<T> const& option)
137 {
138 return option ? convertToVal(*option) : Nui::val::undefined();
139 }
140 template <typename T>
141 requires Fundamental<T>
142 Nui::val convertToVal(T const& value)
143 {
144 return Nui::val{value};
145 }
146 inline Nui::val convertToVal(std::string const& value)
147 {
148 return Nui::val{value};
149 }
150 inline Nui::val convertToVal(std::filesystem::path const& value)
151 {
152 return Nui::val{value.string()};
153 }
155 {
156 return value;
157 }
158 inline Nui::val convertToVal(char const* value)
159 {
160 return Nui::val{std::string{value}};
161 }
162 template <typename T>
163 Nui::val convertToVal(std::vector<T> const& vector)
164 {
165 Nui::val result = Nui::val::array();
166 for (auto const& element : vector)
167 result.call<void>("push", convertToVal(element));
168 return result;
169 }
170 template <typename T>
172 {
173 return convertToVal(observed.value());
174 }
175 template <typename T>
176 Nui::val convertToVal(std::unordered_map<std::string, T> const& map)
177 {
178 Nui::val result = Nui::val::object();
179 for (auto const& [key, value] : map)
180 result.set(key, convertToVal(value));
181 return result;
182 }
183 template <typename T>
184 Nui::val convertToVal(std::map<std::string, T> const& map)
185 {
186 Nui::val result = Nui::val::object();
187 for (auto const& [key, value] : map)
188 result.set(key, convertToVal(value));
189 return result;
190 }
191 template <typename T>
192 Nui::val convertToVal(std::unique_ptr<T> const& ptr)
193 {
194 if (ptr)
195 return convertToVal(*ptr);
196 else
197 return Nui::val::null();
198 }
199 template <typename T>
200 Nui::val convertToVal(std::shared_ptr<T> const& ptr)
201 {
202 if (ptr)
203 return convertToVal(*ptr);
204 else
205 return Nui::val::null();
206 }
207 template <typename... Ts>
208 Nui::val convertToVal(std::variant<Ts...> const& variant)
209 {
210 return std::visit(
211 [](auto&& value) {
212 return convertToVal(value);
213 },
214 variant);
215 }
216
217 template <typename T, class Members = boost::describe::describe_members<T, boost::describe::mod_any_access>>
218 requires(!std::is_union_v<T> && !boost::describe::has_describe_bases<T>::value)
219 void convertFromVal(Nui::val const& val, T& obj)
220 {
221 convertFromValObjImpl<T, Members>(val, obj);
222 }
223
224 template <
225 typename T,
226 class Bases = boost::describe::describe_bases<T, boost::describe::mod_any_access>,
227 class Members = boost::describe::describe_members<T, boost::describe::mod_any_access>>
228 requires(!std::is_union_v<T> && boost::describe::has_describe_bases<T>::value)
229 void convertFromVal(Nui::val const& val, T& obj)
230 {
231 boost::mp11::mp_for_each<Bases>([&](auto&& base) {
232 using type = typename std::decay_t<decltype(base)>::type;
233 convertFromVal(val, static_cast<type&>(obj));
234 });
235 convertFromValObjImpl<T, Members>(val, obj);
236 }
237
238 template <typename T, class Members = boost::describe::describe_members<T, boost::describe::mod_any_access>>
239 requires(!std::is_union_v<T>)
240 void convertFromValObjImpl(Nui::val const& val, T& obj)
241 {
242 boost::mp11::mp_for_each<Members>([&](auto&& memAccessor) {
243 if (val.hasOwnProperty(memAccessor.name))
244 {
245 if constexpr (!Detail::IsOptional<decltype(obj.*memAccessor.pointer)>::value)
246 {
247 if (val[memAccessor.name].isNull() || val[memAccessor.name].isUndefined())
248 Nui::val::global("console").call<void>(
249 "error",
250 std::string{"Expected member "} + memAccessor.name + " to be defined and non null");
251 else
252 convertFromVal(val[memAccessor.name], obj.*memAccessor.pointer);
253 }
254 else
255 convertFromVal(val[memAccessor.name], obj.*memAccessor.pointer);
256 }
257 });
258 }
259
260 template <typename T>
261 requires Fundamental<T>
262 void convertFromVal(Nui::val const& val, T& value)
263 {
264 value = val.as<T>();
265 }
266 inline void convertFromVal(Nui::val const& val, std::string& str)
267 {
268 str = val.as<std::string>();
269 }
270 template <typename T>
271 void convertFromVal(Nui::val const& val, std::optional<T>& option)
272 {
273 if (val.isNull() || val.isUndefined())
274 option = std::nullopt;
275 else
276 {
277 T value;
278 convertFromVal(val, value);
279 option = value;
280 }
281 }
282 inline void convertFromVal(Nui::val const& val, std::filesystem::path& value)
283 {
284 value = val.as<std::string>();
285 }
286 inline void convertFromVal(Nui::val const& val, Nui::val& value)
287 {
288 value = val;
289 }
290 template <typename T>
291 void convertFromVal(Nui::val const& val, std::vector<T>& vector)
292 {
293 vector.clear();
294 const auto length = val["length"].as<std::size_t>();
295 vector.reserve(length);
296 for (std::size_t i = 0; i < length; ++i)
297 {
298 T value;
299 convertFromVal(val[i], value);
300 vector.push_back(std::move(value));
301 }
302 }
303 template <typename T>
304 requires Fundamental<T>
305 void convertFromVal(Nui::val const& val, std::vector<T>& vector)
306 {
307 vector = emscripten::convertJSArrayToNumberVector<T>(val);
308 }
309 template <typename T>
310 void convertFromVal(Nui::val const& val, Observed<T>& observed)
311 {
312 auto proxy = observed.modify();
313 convertFromVal(val, proxy.value());
314 }
315 template <typename T>
316 void convertFromVal(Nui::val const& val, std::unordered_map<std::string, T>& map)
317 {
318 map.clear();
319 const auto keys = Nui::val::global("Object").call<Nui::val>("keys", val);
320 const auto length = keys["length"].as<std::size_t>();
321 for (std::size_t i = 0; i < length; ++i)
322 {
323 const auto key = keys[i].as<std::string>();
324 T value;
325 convertFromVal(val[key], value);
326 map.emplace(key, std::move(value));
327 }
328 }
329}
ModificationProxy modify()
Can be used to make mutations to the underlying class that get commited when the returned proxy is de...
Definition observed_value.hpp:356
ContainedT & value()
Definition observed_value.hpp:372
Definition observed_value.hpp:1283
Definition concepts.hpp:11
static constexpr auto extractJsonMember(nlohmann::json const &json) -> decltype(auto)
Definition rpc_hub.hpp:29
Definition file_dialog.hpp:6
void convertFromVal(Nui::val const &val, T &obj)
Definition val_conversion.hpp:229
void convertToVal(Nui::val &val, T const &obj)
Definition val_conversion.hpp:109
void convertFromValObjImpl(Nui::val const &val, T &obj)
Definition val_conversion.hpp:240
emscripten::val val
Definition val.hpp:5
Definition val_conversion.hpp:30