8 #include <QtCore/QDate>
9 #include <QtCore/QJsonArray>
10 #include <QtCore/QJsonDocument>
11 #include <QtCore/QJsonObject>
12 #include <QtCore/QSet>
13 #include <QtCore/QUrlQuery>
14 #include <QtCore/QVector>
16 #include <type_traits>
26 struct JsonObjectConverter {
28 static void dumpTo(QJsonObject&,
const T&) =
delete;
29 static void fillFrom(
const QJsonObject&, T&) =
delete;
32 template <
typename PodT,
typename JsonT>
33 PodT fromJson(
const JsonT&);
36 struct JsonObjectUnpacker {
41 static T load(
const QJsonValue& jv) {
return fromJson<T>(jv.toObject()); }
42 static T load(
const QJsonDocument& jd) {
return fromJson<T>(jd.object()); }
61 struct JsonConverter : JsonObjectUnpacker<T> {
62 static auto dump(
const T& data)
64 if constexpr (requires() { data.toJson(); })
68 JsonObjectConverter<T>::dumpTo(jo, data);
73 using JsonObjectUnpacker<T>::load;
74 static T load(
const QJsonObject& jo)
78 if constexpr (std::is_same_v<T, QJsonObject>)
80 else if constexpr (std::is_constructible_v<T, QJsonObject>)
84 JsonObjectConverter<T>::fillFrom(jo, pod);
91 inline auto toJson(
const T& pod)
95 if constexpr (std::is_constructible_v<QJsonValue, T>)
98 return JsonConverter<T>::dump(pod);
101 template <
typename T>
102 inline void fillJson(QJsonObject& json,
const T& data)
104 JsonObjectConverter<T>::dumpTo(json, data);
107 template <
typename PodT,
typename JsonT>
108 inline PodT fromJson(
const JsonT& json)
112 return JsonConverter<PodT>::load(json);
119 template <
typename JsonT,
typename PodT>
120 inline void fromJson(
const JsonT& json, PodT& pod)
122 pod = fromJson<PodT>(json);
125 template <
typename T>
126 inline void fillFromJson(
const QJsonValue& jv, T& pod)
128 if constexpr (requires() { JsonObjectConverter<T>::fillFrom({}, pod); }) {
129 JsonObjectConverter<T>::fillFrom(jv.toObject(), pod);
131 }
else if (!jv.isUndefined())
132 pod = fromJson<T>(jv);
136 void warnUnknownEnumValue(
const QString& stringValue,
137 const char* enumTypeName);
138 void reportEnumOutOfBounds(uint32_t v,
const char* enumTypeName);
149 template <
typename EnumT,
typename EnumStringValuesT>
150 EnumT enumFromJsonString(
const QString& s,
const EnumStringValuesT& enumValues,
153 static_assert(std::is_unsigned_v<std::underlying_type_t<EnumT>>);
154 if (
const auto it = std::find(cbegin(enumValues), cend(enumValues), s);
155 it != cend(enumValues))
156 return static_cast<EnumT>(it - cbegin(enumValues));
159 _impl::warnUnknownEnumValue(s, qt_getEnumName(EnumT()));
172 template <
typename EnumT,
typename EnumStringValuesT>
173 QString enumToJsonString(EnumT v,
const EnumStringValuesT& enumValues)
175 static_assert(std::is_unsigned_v<std::underlying_type_t<EnumT>>);
176 if (v < size(enumValues))
177 return enumValues[v];
179 _impl::reportEnumOutOfBounds(
static_cast<uint32_t>(v),
180 qt_getEnumName(EnumT()));
195 template <
typename FlagT,
typename FlagStringValuesT>
196 FlagT flagFromJsonString(
const QString& s,
const FlagStringValuesT& flagValues,
197 FlagT defaultValue = FlagT(0U))
200 static_assert(std::is_unsigned_v<std::underlying_type_t<FlagT>>);
201 if (
const auto it = std::ranges::find(flagValues, s); it != cend(flagValues))
202 return static_cast<FlagT>(1U << (it - cbegin(flagValues)));
205 _impl::warnUnknownEnumValue(s, qt_getEnumName(FlagT()));
209 template <
typename FlagT,
typename FlagStringValuesT>
210 QString flagToJsonString(FlagT v,
const FlagStringValuesT& flagValues)
212 static_assert(std::is_unsigned_v<std::underlying_type_t<FlagT>>);
213 if (
const auto offset = std::countr_zero(std::to_underlying(v)); offset < ssize(flagValues))
214 return flagValues[offset];
216 _impl::reportEnumOutOfBounds(
static_cast<uint32_t>(v), qt_getEnumName(FlagT()));
224 inline bool fromJson(
const QJsonValue& jv) {
return jv.toBool(); }
227 inline int fromJson(
const QJsonValue& jv) {
return jv.toInt(); }
230 inline double fromJson(
const QJsonValue& jv) {
return jv.toDouble(); }
233 inline float fromJson(
const QJsonValue& jv) {
return float(jv.toDouble()); }
236 inline qint64 fromJson(
const QJsonValue& jv) {
return qint64(jv.toDouble()); }
239 inline QString fromJson(
const QJsonValue& jv) {
return jv.toString(); }
247 inline QByteArray fromJson(
const QJsonValue& jv) =
delete;
250 inline QJsonArray fromJson(
const QJsonValue& jv) {
return jv.toArray(); }
253 inline QJsonArray fromJson(
const QJsonDocument& jd) {
return jd.array(); }
255 inline QJsonValue toJson(
const QDateTime& val)
257 return val.isValid() ? val.toMSecsSinceEpoch() : QJsonValue();
260 inline QDateTime fromJson(
const QJsonValue& jv)
262 return QDateTime::fromMSecsSinceEpoch(fromJson<qint64>(jv), Qt::UTC);
265 inline QJsonValue toJson(
const QDate& val) {
return toJson(val.startOfDay()); }
267 inline QDate fromJson(
const QJsonValue& jv)
269 return fromJson<QDateTime>(jv).date();
277 struct JsonConverter<QUrl> {
278 static auto load(
const QJsonValue& jv)
280 return QUrl(jv.toString());
282 static auto dump(
const QUrl& url)
284 return url.toString(QUrl::FullyEncoded);
290 static QJsonValue dump(
const QVariant& v);
291 static QVariant load(
const QJsonValue& jv);
294 template <
typename... Ts>
295 inline QJsonValue toJson(
const std::variant<Ts...>& v)
301 [](
const auto& value) {
return QJsonValue { toJson(value) }; }, v);
304 template <
typename T>
305 struct JsonConverter<std::variant<QString, T>> {
306 static std::variant<QString, T> load(
const QJsonValue& jv)
309 return fromJson<QString>(jv);
310 return fromJson<T>(jv);
314 template <
typename T>
315 struct JsonConverter<std::optional<T>> {
316 static QJsonValue dump(
const std::optional<T>& from)
318 return from.has_value() ? toJson(*from) : QJsonValue();
320 static std::optional<T> load(
const QJsonValue& jv)
322 if (jv.isUndefined() || jv.isNull())
324 return fromJson<T>(jv);
328 template <
typename ContT>
329 struct JsonArrayConverter {
330 static auto dump(
const ContT& vals)
333 for (
const auto& v : vals)
334 ja.push_back(toJson(v));
337 static auto load(
const QJsonArray& ja)
340 vals.reserve(
static_cast<
typename ContT::size_type>(ja.size()));
345 for (
const auto& v : ja)
346 vals.push_back(fromJson<
typename ContT::value_type, QJsonValue>(v));
349 static auto load(
const QJsonValue& jv) {
return load(jv.toArray()); }
350 static auto load(
const QJsonDocument& jd) {
return load(jd.array()); }
353 template <
typename T>
354 struct JsonConverter<std::vector<T>>
355 :
public JsonArrayConverter<std::vector<T>> {};
357 template <
typename T, size_t N>
358 struct JsonConverter<std::array<T, N>> {
366 static constexpr std::make_index_sequence<N> Indices{};
367 template <
typename TargetT, size_t... I>
368 static auto staticTransform(
const auto& source, std::index_sequence<I...>,
371 return TargetT { unaryFn(source[I])... };
373 static auto dump(
const std::array<T, N> a)
375 return staticTransform<QJsonArray>(a, Indices, [](
const T& v) {
379 static auto load(
const QJsonArray& ja)
381 return staticTransform<std::array<T, N>>(ja, Indices,
382 fromJson<T, QJsonValue>);
386 template <
typename T>
387 struct JsonConverter<QList<T>> :
public JsonArrayConverter<QList<T>> {};
390 struct JsonConverter<QStringList> :
public JsonArrayConverter<QStringList> {
391 static auto dump(
const QStringList& sl)
393 return QJsonArray::fromStringList(sl);
398 struct JsonObjectConverter<QSet<QString>> {
399 static void dumpTo(QJsonObject& json,
const QSet<QString>& s)
401 for (
const auto& e : s)
402 json.insert(e, QJsonObject {});
404 static void fillFrom(
const QJsonObject& json, QSet<QString>& s)
406 s.reserve(s.size() + json.size());
407 for (
auto it = json.begin(); it != json.end(); ++it)
412 template <
typename HashMapT>
413 struct HashMapFromJson {
414 static void dumpTo(QJsonObject& json,
const HashMapT& hashMap)
416 for (
auto it = hashMap.begin(); it != hashMap.end(); ++it)
417 json.insert(it.key(), toJson(it.value()));
419 static void fillFrom(
const QJsonObject& jo, HashMapT& h)
421 h.reserve(h.size() + jo.size());
424 for (
auto it = jo.begin(); it != jo.end(); ++it)
425 h[it.key()] = fromJson<
typename HashMapT::mapped_type, QJsonValue>(
430 template <
typename T,
typename HashT>
431 struct JsonObjectConverter<std::unordered_map<QString, T, HashT>>
432 :
public HashMapFromJson<std::unordered_map<QString, T, HashT>> {};
434 template <
typename T>
435 struct JsonObjectConverter<QHash<QString, T>>
436 :
public HashMapFromJson<QHash<QString, T>> {};
440 QVariantHash
QUOTIENT_API fromJson(
const QJsonValue& jv);
444 constexpr bool IfNotEmpty =
false;
447 template <
typename ValT>
448 inline void addTo(QJsonObject& o,
const QString& k, ValT&& v)
450 o.insert(k, toJson(std::forward<ValT>(v)));
453 inline void addTo(QUrlQuery& q,
const QString& k,
auto v)
454 requires requires { QStringLiteral(
"%1").arg(v); }
456 q.addQueryItem(k, QStringLiteral(
"%1").arg(v));
461 inline void addTo(QUrlQuery& q,
const QString& k,
bool v)
463 q.addQueryItem(k, v ? QStringLiteral(
"true") : QStringLiteral(
"false"));
466 inline void addTo(QUrlQuery& q,
const QString& k,
const QUrl& v)
468 q.addQueryItem(k, QString::fromLatin1(v.toEncoded()));
471 inline void addTo(QUrlQuery& q,
const QString& k,
const QStringList& vals)
473 for (
const auto& v : vals)
474 q.addQueryItem(k, v);
477 template <
typename ValT>
478 inline void addTo(QUrlQuery& q,
const QString&,
const QHash<QString, ValT>& fields)
480 for (
const auto& [k, v] : fields.asKeyValueRange())
486 template <
typename ValT,
bool Force =
true>
488 template <
typename ForwardedT>
489 static void impl(
auto& container,
const QString& key, ForwardedT&& value)
491 addTo(container, key, std::forward<ForwardedT>(value));
496 template <
typename ValT>
497 requires requires(ValT v) { v.isEmpty(); }
498 struct AddNode<ValT, IfNotEmpty> {
499 template <
typename ForwardedT>
500 static void impl(
auto& container,
const QString& key, ForwardedT&& value)
502 if (!value.isEmpty())
503 addTo(container, key, std::forward<ForwardedT>(value));
508 template <
typename ValT>
509 struct AddNode<std::optional<ValT>, IfNotEmpty> {
510 static void impl(
auto& container,
const QString& key,
const auto& optValue)
513 addTo(container, key, *optValue);
541 template <
bool Force =
true,
typename ContT,
typename ValT>
542 inline void addParam(ContT& container,
const QString& key, ValT&& value)
544 _impl::AddNode<std::decay_t<ValT>, Force>::impl(container, key,
545 std::forward<ValT>(value));
551 inline auto toSnakeCase(QLatin1String s)
553 QString result { s };
554 for (
auto it = result.begin(); it != result.end(); ++it)
556 const auto offset =
static_cast<
int>(it - result.begin());
557 result.insert(offset, u'_');
558 it = result.begin() + offset + 1;