AUI Framework  master
Cross-platform module-based framework for developing C++20 desktop applications
Conversion.h
1/*
2 * AUI Framework - Declarative UI toolkit for modern C++20
3 * Copyright (C) 2020-2024 Alex2772 and Contributors
4 *
5 * SPDX-License-Identifier: MPL-2.0
6 *
7 * This Source Code Form is subject to the terms of the Mozilla Public
8 * License, v. 2.0. If a copy of the MPL was not distributed with this
9 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 */
11
12#pragma once
13
14#include <AUI/Json/AJson.h>
15#include <AUI/IO/APath.h>
16#include "AUI/Traits/parameter_pack.h"
17#include "AUI/Traits/members.h"
18#include <AUI/Reflect/AEnumerate.h>
19#include <AUI/Traits/strings.h>
20
41template<typename T, typename Specialization = void>
42struct AJsonConv;
43
44namespace aui {
45 template<typename T>
46 constexpr bool has_json_converter = aui::is_complete<AJsonConv<T>>;
47
48 template<typename T>
49 inline AJson to_json(const T& t) {
50 static_assert(aui::has_json_converter<T>, "this type does not implement AJsonConv<T> trait");
51 return AJsonConv<T>::toJson(t);
52 }
53 template<typename T>
54 inline T from_json(const AJson& v) {
55 static_assert(aui::has_json_converter<T>, "this type does not implement AJsonConv<T> trait");
56 T dst;
58 return dst;
59 }
60
61 template<typename T>
62 inline void from_json(const AJson& v, T& dst) {
63 static_assert(aui::has_json_converter<T>, "this type does not implement AJsonConv<T> trait");
65 }
66}
67
68// win fix
69#ifdef OPTIONAL
70#undef OPTIONAL
71#endif
72
73
74AUI_ENUM_FLAG(AJsonFieldFlags) {
75 DEFAULT = 0b0,
76
80 OPTIONAL = 0b1,
81};
82
83namespace aui::impl::json {
84
85 template<typename T>
86 struct Field {
87 T& value;
88 const char* name;
89 AJsonFieldFlags flags;
90
91 Field(T& value, const char* name, AJsonFieldFlags flags) : value(value), name(name), flags(flags) {}
92
93 void operator()(const AJson::Object& object) {
94 if (auto c = object.contains(name)) {
95 aui::from_json<T>(c->second, value);
96 } else {
97 if (!(flags & AJsonFieldFlags::OPTIONAL)) {
98 throw AJsonException(R"(field "{}" is not present)"_format(name));
99 }
100 }
101 }
102 void operator()(AJson::Object& object) {
103 object[name] = aui::to_json<T>(value);
104 }
105 };
106
107 template<typename... Items>
108 struct my_tuple: std::tuple<Items...> {
109 my_tuple(Items... items): std::tuple<Items...>(std::move(items)...) {}
110
111 template<typename T>
112 auto operator()(T& v, const char* n, AJsonFieldFlags flags = AJsonFieldFlags::DEFAULT) {
113 return (std::apply)([&](auto&&... args) {
115 }, stdTuple());
116 }
117
118 std::tuple<Items...>& stdTuple() {
119 return (std::tuple<Items...>&)*this;
120 }
121 };
122
123 struct empty_tuple {
124 template<typename T>
125 auto operator()(T& v, const char* n, AJsonFieldFlags flags = AJsonFieldFlags::DEFAULT) {
126 return my_tuple(aui::impl::json::Field(v, n, flags));
127 }
128 };
129}
130
131
132template<typename T>
134
183#define AJSON_FIELDS(N, ...) \
184template<> struct AJsonConvFieldDescriptor<N>: N { \
185 auto operator()() { \
186 return aui::impl::json::empty_tuple() \
187 __VA_ARGS__ \
188 ; \
189 } \
190};
191
196#define AJSON_FIELDS_ENTRY(name) (name, AUI_PP_STRINGIZE(name))
197
203template<typename T>
204struct AJsonConv<T, std::enable_if_t<aui::is_complete<AJsonConvFieldDescriptor<T>>>> {
205
206 static AJson toJson(const T& t) {
207 AJson::Object json;
208 std::apply([&](auto&&... fields) {
209 aui::parameter_pack::for_each([&](auto&& field) {
210 field(json);
211 }, fields...);
212 }, ((AJsonConvFieldDescriptor<T>&)t)().stdTuple());
213 return std::move(json);
214 }
215
216 static void fromJson(const AJson& json, T& dst) {
217 const auto& jsonObject = json.asObject();
218 std::apply([&](auto&&... fields) {
219 aui::parameter_pack::for_each([&](auto&& field) {
220 field(jsonObject);
221 }, fields...);
222 }, ((AJsonConvFieldDescriptor<T>&)dst)().stdTuple());
223 }
224};
225
226
227template<>
228struct AJsonConv<int> {
229 static AJson toJson(int v) {
230 return v;
231 }
232 static void fromJson(const AJson& json, int& dst) {
233 dst = json.asInt();
234 }
235};
236
237template<>
238struct AJsonConv<int64_t> {
239 static AJson toJson(int64_t v) {
240 return v;
241 }
242 static void fromJson(const AJson& json, int64_t& dst) {
243 dst = json.asLongInt();
244 }
245};
246template<>
247struct AJsonConv<short> {
248 static AJson toJson(int v) {
249 return v;
250 }
251 static int fromJson(const AJson& json) {
252 return json.asInt();
253 }
254};
255
256template<>
257struct AJsonConv<float> {
258 static AJson toJson(float v) {
259 return v;
260 }
261 static void fromJson(const AJson& json, float& dst) {
262 dst = json.asNumber();
263 }
264};
265
266template<>
267struct AJsonConv<double> {
268 static AJson toJson(double v) {
269 return v;
270 }
271 static void fromJson(const AJson& json, double& dst) {
272 dst = json.asNumber();
273 }
274};
275
276template<aui::arithmetic UnderlyingType, auto min, auto max>
277 requires aui::convertible_to<decltype(min), UnderlyingType> && aui::convertible_to<decltype(max), UnderlyingType>
278struct AJsonConv<aui::ranged_number<UnderlyingType, min, max>> {
280 return (UnderlyingType) v;
281 }
282 static void fromJson(const AJson& json, aui::ranged_number<UnderlyingType, min, max>& dst) {
283 if constexpr (aui::same_as<UnderlyingType, float> || aui::same_as<UnderlyingType, double>) {
284 dst = (UnderlyingType) json.asNumber();
285 } else {
286 dst = (UnderlyingType) json.asLongInt();
287 }
288 }
289};
290
291template<>
292struct AJsonConv<bool> {
293 static AJson toJson(bool v) {
294 return v;
295 }
296 static void fromJson(const AJson& json, bool& dst) {
297 dst = json.asBool();
298 }
299};
300
301template<>
303 static AJson toJson(AString v) {
304 return v;
305 }
306 static void fromJson(const AJson& json, AString& dst) {
307 dst = json.asString();
308 }
309};
310template<>
312 static AJson toJson(APath v) {
313 return v;
314 }
315 static void fromJson(const AJson& json, APath& dst) {
316 dst = json.asString();
317 }
318};
319
320template<typename T1, typename T2>
321struct AJsonConv<std::pair<T1, T2>> {
322 static AJson toJson(std::pair<T1, T2> v) {
323 return AJson::Array({aui::to_json(v.first), aui::to_json(v.second)});
324 }
325 static void fromJson(const AJson& json, std::pair<T1, T2>& dst) {
326 const auto& array = json.asArray();
327 dst = { aui::from_json<T1>(array.at(0)), aui::from_json<T2>(array.at(1)) };
328 }
329};
330
331template<>
332struct AJsonConv<AJson::Array> {
333 static AJson toJson(AJson::Array v) {
334 return std::move(v);
335 }
336 static void fromJson(const AJson& json, AJson::Array& dst) {
337 dst = json.asArray();
338 }
339};
340
341template<>
342struct AJsonConv<AJson::Object> {
343 static AJson toJson(AJson::Object v) {
344 return std::move(v);
345 }
346 static void fromJson(const AJson& json, AJson::Object& dst) {
347 dst = json.asObject();
348 }
349};
350
351template<typename T>
352struct AJsonConv<AVector<T>, typename std::enable_if_t<aui::has_json_converter<T>>> {
353 static AJson toJson(const AVector<T>& v) {
354 AJson::Array array;
355 array.reserve(v.size());
356 for (const auto& elem : v) {
357 array << aui::to_json(elem);
358 }
359 return std::move(array);
360 }
361 static void fromJson(const AJson& json, AVector<T>& dst) {
362 auto& array = json.asArray();
363 dst.clear();
364 dst.reserve(array.size());
365 for (const auto& elem : array) {
366 dst << aui::from_json<T>(elem);
367 }
368 }
369};
370
371
372template<typename T>
373struct AJsonConv<T, typename std::enable_if_t<std::is_enum_v<T>>> {
374 static AJson toJson(const T& v) {
376 }
377 static void fromJson(const AJson& json, T& dst) {
378 dst = AEnumerate<T>::byName(json.asString());
379 }
380};
381
static enum_t byName(const AString &name)
Map runtime name to enum value. Transforms name to uppercase as a fallback. Throws an exception if no...
Definition: AEnumerate.h:121
static const AMap< enum_t, AString, enum_less > & valueToNameMap()
Map runtime enum value to name.
Definition: AEnumerate.h:183
Definition: Exception.h:17
Json atom.
Definition: AJson.h:79
An add-on to AString with functions for working with the path.
Definition: APath.h:106
Represents a Unicode character string.
Definition: AString.h:37
A std::vector with AUI extensions.
Definition: AVector.h:38
API_AUI_CORE const ACommandLineArgs & args() noexcept
Definition: OSAndroid.cpp:29
bool contains(const Container &c, const typename Container::const_reference value) noexcept
Definition: containers.h:153
AUI_ENUM_FLAG(ASide)
Describes sides of a 2D rectangle.
Definition: ASide.h:24
@ DEFAULT
There's no concrete input action. Let the OS decide which action is the most appropriate.
Definition: Conversion.h:133
Definition: Conversion.h:42
Definition: AJson.h:31
Definition: Conversion.h:86
Definition: Conversion.h:123
Definition: Conversion.h:108
Clamps the possible values for a number to the specified range: [min;max].
Definition: values.h:452