9#include <QtCore/QJsonArray>
10#include <QtCore/QJsonDocument>
11#include <QtCore/QJsonObject>
13#include <QtCore/QUrlQuery>
14#include <QtCore/QVector>
15#if QT_VERSION >= QT_VERSION_CHECK(6
, 5
, 0
)
16 #include <QtCore/QTimeZone>
29inline void editSubobject(QJsonObject& json,
auto key, std::invocable<QJsonObject&>
auto visitor)
31 auto subObject = json.take(key).toObject();
33 json.insert(key, subObject);
36inline void replaceSubvalue(QJsonObject& json,
auto topLevelKey,
auto subKey, QJsonValue subValue)
38 editSubobject(json, topLevelKey, [subKey, subValue](QJsonObject& innerJson) {
39 innerJson.insert(subKey, subValue);
44struct JsonObjectConverter;
49template <
typename PodT,
typename JsonT>
58 static T
load(
const QJsonValue& jv) {
return fromJson<T>(jv.toObject()); }
59 static T
load(
const QJsonDocument& jd) {
return fromJson<T>(jd.object()); }
79 static auto dump(
const T& data)
81 if constexpr (requires() { data.toJson(); })
85 JsonObjectConverter<T>::dumpTo(jo, data);
91 static T
load(
const QJsonObject& jo)
95 if constexpr (std::is_same_v<T, QJsonObject>)
97 else if constexpr (std::is_constructible_v<T, QJsonObject>)
101 JsonObjectConverter<T>::fillFrom(jo, pod);
112 if constexpr (std::is_constructible_v<QJsonValue, T>)
119inline void fillJson(QJsonObject& json,
const T& data)
121 JsonObjectConverter<T>::dumpTo(json, data);
124template <
typename PodT,
typename JsonT>
136template <
typename JsonT,
typename PodT>
139 pod = fromJson<PodT>(json);
145 if constexpr (requires() { JsonObjectConverter<T>::fillFrom({}, pod); }) {
146 JsonObjectConverter<T>::fillFrom(jv.toObject(), pod);
148 }
else if (!jv.isUndefined())
149 pod = fromJson<T>(jv);
153 QUOTIENT_API void reportEnumOutOfBounds(uint32_t v,
const char* enumTypeName);
164template <
typename EnumT,
typename EnumStringValuesT>
167 static_assert(std::is_unsigned_v<std::underlying_type_t<EnumT>>);
168 if (
const auto it = std::ranges::find(enumValues, s); it != cend(enumValues))
169 return static_cast<EnumT>(it - cbegin(enumValues));
183template <
typename EnumT,
typename EnumStringValuesT>
186 static_assert(std::is_unsigned_v<std::underlying_type_t<EnumT>>);
187 if (v < size(enumValues))
188 return enumValues[v];
190 _impl::reportEnumOutOfBounds(
static_cast<uint32_t>(v),
191 qt_getEnumName(EnumT()));
205template <
typename FlagT,
typename FlagStringValuesT>
209 static_assert(std::is_unsigned_v<std::underlying_type_t<FlagT>>);
210 if (
const auto it = std::ranges::find(flagValues, s); it != cend(flagValues))
211 return static_cast<FlagT>(1U << (it - cbegin(flagValues)));
216template <
typename FlagT,
typename FlagStringValuesT>
219 static_assert(std::is_unsigned_v<std::underlying_type_t<FlagT>>);
220 if (
const auto offset = std::countr_zero(std::to_underlying(v)); offset < ssize(flagValues))
221 return flagValues[offset];
223 _impl::reportEnumOutOfBounds(
static_cast<uint32_t>(v), qt_getEnumName(FlagT()));
231inline bool fromJson(
const QJsonValue& jv) {
return jv.toBool(); }
234inline int fromJson(
const QJsonValue& jv) {
return jv.toInt(); }
237inline double fromJson(
const QJsonValue& jv) {
return jv.toDouble(); }
240inline float fromJson(
const QJsonValue& jv) {
return float(jv.toDouble()); }
264 return val.isValid() ? val.toMSecsSinceEpoch() : QJsonValue();
269 return QDateTime::fromMSecsSinceEpoch(fromJson<qint64>(jv),
270#if QT_VERSION >= QT_VERSION_CHECK(6
, 5
, 0
)
281 return fromJson<QDateTime>(jv).date();
306template <
typename... Ts>
313 [](
const auto& value) {
return QJsonValue { toJson(value) }; }, v);
328 static QJsonValue dump(
const std::optional<T>& from)
330 return from.has_value() ? toJson(*from) : QJsonValue();
332 static std::optional<T> load(
const QJsonValue& jv)
334 if (jv.isUndefined() || jv.isNull())
336 return fromJson<T>(jv);
340template <
typename ContT>
342 static auto dump(
const ContT& vals)
345 for (
const auto& v : vals)
346 ja.push_back(toJson(v));
349 static auto load(
const QJsonArray& ja)
352 vals.reserve(
static_cast<
typename ContT::size_type>(ja.size()));
357 for (
const auto& v : ja)
358 vals.push_back(fromJson<
typename ContT::value_type, QJsonValue>(v));
361 static auto load(
const QJsonValue& jv) {
return load(jv.toArray()); }
362 static auto load(
const QJsonDocument& jd) {
return load(jd.array()); }
369template <
typename T, size_t N>
378 static constexpr std::make_index_sequence<N> Indices{};
379 template <
typename TargetT, size_t... I>
380 static auto staticTransform(
const auto& source, std::index_sequence<I...>,
383 return TargetT { unaryFn(source[I])... };
385 static auto dump(
const std::array<T, N> a)
387 return staticTransform<QJsonArray>(a, Indices, [](
const T& v) {
391 static auto load(
const QJsonArray& ja)
393 return staticTransform<std::array<T, N>>(ja, Indices,
394 fromJson<T, QJsonValue>);
413 for (
const auto&
e :
s)
424template <
typename HashMapT>
426 static void dumpTo(QJsonObject& json,
const HashMapT& hashMap)
428 for (
auto it = hashMap.begin(); it != hashMap.end(); ++it)
429 json.insert(it.key(), toJson(it.value()));
431 static void fillFrom(
const QJsonObject& jo, HashMapT& h)
433 h.reserve(h.size() + jo.size());
436 for (
auto it = jo.begin(); it != jo.end(); ++it)
437 h[it.key()] = fromJson<
typename HashMapT::mapped_type, QJsonValue>(
442template <
typename T,
typename HashT>
459 template <
typename KeyT,
typename ValT>
460 inline void addTo(QJsonObject& o, KeyT&& k, ValT&& v)
462 o.insert(std::forward<KeyT>(k), toJson(std::forward<ValT>(v)));
465 inline void addTo(QUrlQuery& q,
const QString& k,
auto v)
466 requires requires { u"%1"_s.arg(v); }
468 q.addQueryItem(k, u"%1"_s.arg(v));
473 inline void addTo(QUrlQuery& q,
const QString& k,
bool v)
475 q.addQueryItem(k, v ? u"true"_s : u"false"_s);
478 inline void addTo(QUrlQuery& q,
const QString& k,
const QUrl& v)
480 q.addQueryItem(k, QString::fromLatin1(v.toEncoded()));
483 inline void addTo(QUrlQuery& q,
const QString& k,
const QStringList& vals)
485 for (
const auto& v : vals)
486 q.addQueryItem(k, v);
489 template <
typename ValT>
490 inline void addTo(QUrlQuery& q,
const QString&,
const QHash<QString, ValT>& fields)
492 for (
const auto& [k, v] : fields.asKeyValueRange())
498 template <
typename ValT,
bool Force =
true>
500 template <
typename KeyT,
typename ForwardedT>
501 static void impl(
auto& container, KeyT&& key, ForwardedT&& value)
503 addTo(container, std::forward<KeyT>(key), std::forward<ForwardedT>(value));
508 template <
typename ValT>
509 requires requires(ValT v) { v.isEmpty(); }
510 struct AddNode<ValT, IfNotEmpty> {
511 template <
typename KeyT,
typename ForwardedT>
512 static void impl(
auto& container, KeyT&& key, ForwardedT&& value)
514 if (!value.isEmpty())
515 addTo(container, std::forward<KeyT>(key), std::forward<ForwardedT>(value));
520 template <
typename ValT>
521 struct AddNode<std::optional<ValT>, IfNotEmpty> {
522 template <
typename KeyT>
523 static void impl(
auto& container, KeyT&& key,
const auto& optValue)
526 addTo(container, std::forward<KeyT>(key), *optValue);
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554template <
bool Force =
true,
typename ContT,
typename KeyT,
typename ValT>
555inline void addParam(ContT& container, KeyT&& key, ValT&& value)
557 _impl::AddNode<std::decay_t<ValT>, Force>::impl(container, std::forward<KeyT>(key),
558 std::forward<ValT>(value));
566 QString result { s };
567 for (
auto it = result.begin(); it != result.end(); ++it)
569 const auto offset =
static_cast<
int>(it - result.begin());
570 result.insert(offset, u'_');
571 it = result.begin() + offset + 1;
auto toSnakeCase(QLatin1String s)
QString flagToJsonString(FlagT v, const FlagStringValuesT &flagValues)
void fillJson(QJsonObject &json, const T &data)
std::optional< EnumT > enumFromJsonString(const QString &s, const EnumStringValuesT &enumValues)
Facility string-to-enum converter.
QJsonValue toJson(const QDateTime &val)
auto toJson(const T &pod)
void fillFromJson(const QJsonValue &jv, T &pod)
QString enumToJsonString(EnumT v, const EnumStringValuesT &enumValues)
Facility enum-to-string converter.
void fromJson(const JsonT &json, PodT &pod)
QJsonValue toJson(const std::variant< Ts... > &v)
void editSubobject(QJsonObject &json, auto key, std::invocable< QJsonObject & > auto visitor)
void replaceSubvalue(QJsonObject &json, auto topLevelKey, auto subKey, QJsonValue subValue)
bool fromJson(const QJsonValue &jv)
PodT fromJson(const JsonT &)
constexpr bool IfNotEmpty
void addParam(ContT &container, KeyT &&key, ValT &&value)
std::optional< FlagT > flagFromJsonString(const QString &s, const FlagStringValuesT &flagValues)
Facility converter for flags.
static void dumpTo(QJsonObject &json, const HashMapT &hashMap)
static void fillFrom(const QJsonObject &jo, HashMapT &h)
static auto dump(const ContT &vals)
static auto load(const QJsonArray &ja)
The switchboard for extra conversion algorithms behind from/toJson.
static T load(const QJsonObject &jo)
static auto dump(const T &data)
static T load(const QJsonValue &jv)