aboutsummaryrefslogtreecommitdiff
path: root/lib/converters.h
diff options
context:
space:
mode:
authorarawaaa <77910862+arawaaa@users.noreply.github.com>2021-12-27 17:35:28 -0600
committerGitHub <noreply@github.com>2021-12-27 17:35:28 -0600
commit7ec3ba834dd313c4408622da30e04cdc6f4cf7c7 (patch)
tree679d7dc5939a229ad46676cd1d7aeaea7a25abce /lib/converters.h
parent17bf4d180297c7e87363e179b8afa79ddb15dca7 (diff)
parent674e984e459375974f619d0e778d43a2cc928dc3 (diff)
downloadlibquotient-7ec3ba834dd313c4408622da30e04cdc6f4cf7c7.tar.gz
libquotient-7ec3ba834dd313c4408622da30e04cdc6f4cf7c7.zip
Merge branch 'dev' into pinned
Diffstat (limited to 'lib/converters.h')
-rw-r--r--lib/converters.h150
1 files changed, 77 insertions, 73 deletions
diff --git a/lib/converters.h b/lib/converters.h
index e07b6ee4..9c3d5749 100644
--- a/lib/converters.h
+++ b/lib/converters.h
@@ -24,6 +24,21 @@ struct JsonObjectConverter {
static void fillFrom(const QJsonObject& jo, T& pod) { pod = T(jo); }
};
+//! \brief The switchboard for extra conversion algorithms behind from/toJson
+//!
+//! This template is mainly intended for partial conversion specialisations
+//! since from/toJson are functions and cannot be partially specialised.
+//! Another case for JsonConverter is to insulate types that can be constructed
+//! from basic types - namely, QVariant and QUrl can be directly constructed
+//! from QString and having an overload or specialisation for those leads to
+//! ambiguity between these and QJsonValue. For trivial (converting
+//! QJsonObject/QJsonValue) and most simple cases such as primitive types or
+//! QString this class is not needed.
+//!
+//! Do NOT call the functions of this class directly unless you know what you're
+//! doing; and do not try to specialise basic things unless you're really sure
+//! that they are not supported and it's not feasible to support those by means
+//! of overloading toJson() and specialising fromJson().
template <typename T>
struct JsonConverter {
static QJsonObject dump(const T& pod)
@@ -42,13 +57,17 @@ struct JsonConverter {
static T load(const QJsonDocument& jd) { return doLoad(jd.object()); }
};
-template <typename T>
+template <typename T,
+ typename = std::enable_if_t<!std::is_constructible_v<QJsonValue, T>>>
inline auto toJson(const T& pod)
+// -> can return anything from which QJsonValue or, in some cases, QJsonDocument
+// is constructible
{
return JsonConverter<T>::dump(pod);
}
inline auto toJson(const QJsonObject& jo) { return jo; }
+inline auto toJson(const QJsonValue& jv) { return jv; }
template <typename T>
inline void fillJson(QJsonObject& json, const T& data)
@@ -62,6 +81,9 @@ inline T fromJson(const QJsonValue& jv)
return JsonConverter<T>::load(jv);
}
+template<>
+inline QJsonValue fromJson(const QJsonValue& jv) { return jv; }
+
template <typename T>
inline T fromJson(const QJsonDocument& jd)
{
@@ -95,80 +117,68 @@ inline void fillFromJson(const QJsonValue& jv, T& pod)
// JsonConverter<> specialisations
-template <typename T>
-struct TrivialJsonDumper {
- // Works for: QJsonValue (and all things it can consume),
- // QJsonObject, QJsonArray
- static auto dump(const T& val) { return val; }
-};
+template<>
+inline bool fromJson(const QJsonValue& jv) { return jv.toBool(); }
template <>
-struct JsonConverter<bool> : public TrivialJsonDumper<bool> {
- static auto load(const QJsonValue& jv) { return jv.toBool(); }
-};
+inline int fromJson(const QJsonValue& jv) { return jv.toInt(); }
template <>
-struct JsonConverter<int> : public TrivialJsonDumper<int> {
- static auto load(const QJsonValue& jv) { return jv.toInt(); }
-};
+inline double fromJson(const QJsonValue& jv) { return jv.toDouble(); }
template <>
-struct JsonConverter<double> : public TrivialJsonDumper<double> {
- static auto load(const QJsonValue& jv) { return jv.toDouble(); }
-};
+inline float fromJson(const QJsonValue& jv) { return float(jv.toDouble()); }
template <>
-struct JsonConverter<float> : public TrivialJsonDumper<float> {
- static auto load(const QJsonValue& jv) { return float(jv.toDouble()); }
-};
+inline qint64 fromJson(const QJsonValue& jv) { return qint64(jv.toDouble()); }
template <>
-struct JsonConverter<qint64> : public TrivialJsonDumper<qint64> {
- static auto load(const QJsonValue& jv) { return qint64(jv.toDouble()); }
-};
+inline QString fromJson(const QJsonValue& jv) { return jv.toString(); }
template <>
-struct JsonConverter<QString> : public TrivialJsonDumper<QString> {
- static auto load(const QJsonValue& jv) { return jv.toString(); }
-};
+inline QJsonArray fromJson(const QJsonValue& jv) { return jv.toArray(); }
template <>
-struct JsonConverter<QDateTime> {
- static auto dump(const QDateTime& val) = delete; // not provided yet
- static auto load(const QJsonValue& jv)
- {
- return QDateTime::fromMSecsSinceEpoch(fromJson<qint64>(jv), Qt::UTC);
- }
-};
+inline QJsonArray fromJson(const QJsonDocument& jd) { return jd.array(); }
+inline QJsonValue toJson(const QDateTime& val)
+{
+ return val.isValid() ? val.toMSecsSinceEpoch() : QJsonValue();
+}
template <>
-struct JsonConverter<QDate> {
- static auto dump(const QDate& val) = delete; // not provided yet
- static auto load(const QJsonValue& jv)
- {
- return fromJson<QDateTime>(jv).date();
- }
-};
+inline QDateTime fromJson(const QJsonValue& jv)
+{
+ return QDateTime::fromMSecsSinceEpoch(fromJson<qint64>(jv), Qt::UTC);
+}
+inline QJsonValue toJson(const QDate& val) {
+ return toJson(
+#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
+ QDateTime(val)
+#else
+ val.startOfDay()
+#endif
+ );
+}
template <>
-struct JsonConverter<QUrl> : JsonConverter<QString> {
- static auto dump(const QUrl& url) // Override on top of that for QString
- {
- return JsonConverter<QString>::dump(url.toString(QUrl::FullyEncoded));
- }
-};
+inline QDate fromJson(const QJsonValue& jv)
+{
+ return fromJson<QDateTime>(jv).date();
+}
-template <>
-struct JsonConverter<QJsonArray> : public TrivialJsonDumper<QJsonArray> {
- static auto load(const QJsonValue& jv) { return jv.toArray(); }
-};
+// Insulate QVariant and QUrl conversions into JsonConverter so that they don't
+// interfere with toJson(const QJsonValue&) over QString, since both types are
+// constructible from QString (even if QUrl requires explicit construction).
template <>
-struct JsonConverter<QByteArray> {
- static QString dump(const QByteArray& ba) { return ba.constData(); }
+struct JsonConverter<QUrl> {
static auto load(const QJsonValue& jv)
{
- return fromJson<QString>(jv).toLatin1();
+ return QUrl(jv.toString());
+ }
+ static auto dump(const QUrl& url)
+ {
+ return url.toString(QUrl::FullyEncoded);
}
};
@@ -194,15 +204,11 @@ struct JsonConverter<Omittable<T>> {
template <typename VectorT, typename T = typename VectorT::value_type>
struct JsonArrayConverter {
- static void dumpTo(QJsonArray& ar, const VectorT& vals)
- {
- for (const auto& v : vals)
- ar.push_back(toJson(v));
- }
static auto dump(const VectorT& vals)
{
QJsonArray ja;
- dumpTo(ja, vals);
+ for (const auto& v : vals)
+ ja.push_back(toJson(v));
return ja;
}
static auto load(const QJsonArray& ja)
@@ -221,14 +227,16 @@ template <typename T>
struct JsonConverter<std::vector<T>>
: public JsonArrayConverter<std::vector<T>> {};
+#if QT_VERSION_MAJOR < 6 // QVector is an alias of QList in Qt6 but not in Qt 5
template <typename T>
struct JsonConverter<QVector<T>> : public JsonArrayConverter<QVector<T>> {};
+#endif
template <typename T>
struct JsonConverter<QList<T>> : public JsonArrayConverter<QList<T>> {};
template <>
-struct JsonConverter<QStringList> : public JsonConverter<QList<QString>> {
+struct JsonConverter<QStringList> : public JsonArrayConverter<QStringList> {
static auto dump(const QStringList& sl)
{
return QJsonArray::fromStringList(sl);
@@ -240,14 +248,13 @@ struct JsonObjectConverter<QSet<QString>> {
static void dumpTo(QJsonObject& json, const QSet<QString>& s)
{
for (const auto& e : s)
- json.insert(toJson(e), QJsonObject {});
+ json.insert(e, QJsonObject {});
}
- static auto fillFrom(const QJsonObject& json, QSet<QString>& s)
+ static void fillFrom(const QJsonObject& json, QSet<QString>& s)
{
s.reserve(s.size() + json.size());
for (auto it = json.begin(); it != json.end(); ++it)
s.insert(it.key());
- return s;
}
};
@@ -260,7 +267,7 @@ struct HashMapFromJson {
}
static void fillFrom(const QJsonObject& jo, HashMapT& h)
{
- h.reserve(jo.size());
+ h.reserve(h.size() + jo.size());
for (auto it = jo.begin(); it != jo.end(); ++it)
h[it.key()] = fromJson<typename HashMapT::mapped_type>(it.value());
}
@@ -274,11 +281,9 @@ template <typename T>
struct JsonObjectConverter<QHash<QString, T>>
: public HashMapFromJson<QHash<QString, T>> {};
+QJsonObject toJson(const QVariantHash& vh);
template <>
-struct JsonConverter<QVariantHash> {
- static QJsonObject dump(const QVariantHash& vh);
- static QVariantHash load(const QJsonValue& jv);
-};
+QVariantHash fromJson(const QJsonValue& jv);
// Conditional insertion into a QJsonObject
@@ -302,16 +307,15 @@ namespace _impl {
q.addQueryItem(k, v ? QStringLiteral("true") : QStringLiteral("false"));
}
- inline void addTo(QUrlQuery& q, const QString& k, const QStringList& vals)
+ inline void addTo(QUrlQuery& q, const QString& k, const QUrl& v)
{
- for (const auto& v : vals)
- q.addQueryItem(k, v);
+ q.addQueryItem(k, v.toEncoded());
}
- inline void addTo(QUrlQuery& q, const QString&, const QJsonObject& vals)
+ inline void addTo(QUrlQuery& q, const QString& k, const QStringList& vals)
{
- for (auto it = vals.begin(); it != vals.end(); ++it)
- q.addQueryItem(it.key(), it.value().toString());
+ for (const auto& v : vals)
+ q.addQueryItem(k, v);
}
// This one is for types that don't have isEmpty() and for all types