aboutsummaryrefslogtreecommitdiff
path: root/lib/converters.h
diff options
context:
space:
mode:
authorAlexey Rusakov <Kitsune-Ral@users.sf.net>2022-02-13 19:25:24 +0100
committerAlexey Rusakov <Kitsune-Ral@users.sf.net>2022-02-13 19:25:24 +0100
commit044ae4a029b710571420f830a497647f7a54698a (patch)
tree14d50ba0eb1a5cfac995f13cd6059aed74e506b2 /lib/converters.h
parentb0aef4af9cbf00755c7b70c71d77f0bf7ce0d200 (diff)
parent10ac7c13cdcd62b62af6e89cb726376cfbc53302 (diff)
downloadlibquotient-044ae4a029b710571420f830a497647f7a54698a.tar.gz
libquotient-044ae4a029b710571420f830a497647f7a54698a.zip
Merge branch 'dev'
The result is FTBFS as yet; next commits will fix that, along with a few other things.
Diffstat (limited to 'lib/converters.h')
-rw-r--r--lib/converters.h72
1 files changed, 50 insertions, 22 deletions
diff --git a/lib/converters.h b/lib/converters.h
index 90349019..515c96fd 100644
--- a/lib/converters.h
+++ b/lib/converters.h
@@ -3,6 +3,7 @@
#pragma once
+#include "omittable.h"
#include "util.h"
#include <QtCore/QDate>
@@ -13,6 +14,7 @@
#include <QtCore/QUrlQuery>
#include <QtCore/QVector>
+#include <type_traits>
#include <vector>
class QVariant;
@@ -20,15 +22,34 @@ class QVariant;
namespace Quotient {
template <typename T>
struct JsonObjectConverter {
- static void dumpTo(QJsonObject& jo, const T& pod) { jo = pod.toJson(); }
- static void fillFrom(const QJsonObject& jo, T& pod) { pod = T(jo); }
+ // To be implemented in specialisations
+ static void dumpTo(QJsonObject&, const T&) = delete;
+ static void fillFrom(const QJsonObject&, T&) = delete;
};
+namespace _impl {
+ template <typename T, typename = void>
+ struct JsonExporter {
+ static QJsonObject dump(const T& data)
+ {
+ QJsonObject jo;
+ JsonObjectConverter<T>::dumpTo(jo, data);
+ return jo;
+ }
+ };
+
+ template <typename T>
+ struct JsonExporter<
+ T, std::enable_if_t<std::is_invocable_v<decltype(&T::toJson), T>>> {
+ static auto dump(const T& data) { return data.toJson(); }
+ };
+}
+
//! \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
+//! 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
@@ -40,18 +61,25 @@ struct JsonObjectConverter {
//! 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)
- {
- QJsonObject jo;
- JsonObjectConverter<T>::dumpTo(jo, pod);
- return jo;
- }
+struct JsonConverter : _impl::JsonExporter<T> {
+ // Unfortunately, if constexpr doesn't work with dump() and T::toJson
+ // because trying to check invocability of T::toJson hits a hard
+ // (non-SFINAE) compilation error if the member is not there. Hence a bit
+ // more verbose SFINAE construct in _impl::JsonExporter.
+
static T doLoad(const QJsonObject& jo)
{
- T pod;
- JsonObjectConverter<T>::fillFrom(jo, pod);
- return pod;
+ // 'else' below are required to suppress code generation for unused
+ // branches - 'return' is not enough
+ if constexpr (std::is_same_v<T, QJsonObject>)
+ return jo;
+ else if constexpr (std::is_constructible_v<T, QJsonObject>)
+ return T(jo);
+ else {
+ T pod;
+ JsonObjectConverter<T>::fillFrom(jo, pod);
+ return pod;
+ }
}
static T load(const QJsonValue& jv) { return doLoad(jv.toObject()); }
static T load(const QJsonDocument& jd) { return doLoad(jd.object()); }
@@ -183,7 +211,7 @@ struct JsonConverter<QUrl> {
};
template <>
-struct JsonConverter<QVariant> {
+struct QUOTIENT_API JsonConverter<QVariant> {
static QJsonValue dump(const QVariant& v);
static QVariant load(const QJsonValue& jv);
};
@@ -281,12 +309,14 @@ template <typename T>
struct JsonObjectConverter<QHash<QString, T>>
: public HashMapFromJson<QHash<QString, T>> {};
-QJsonObject toJson(const QVariantHash& vh);
+QJsonObject QUOTIENT_API toJson(const QVariantHash& vh);
template <>
-QVariantHash fromJson(const QJsonValue& jv);
+QVariantHash QUOTIENT_API fromJson(const QJsonValue& jv);
// Conditional insertion into a QJsonObject
+constexpr bool IfNotEmpty = false;
+
namespace _impl {
template <typename ValT>
inline void addTo(QJsonObject& o, const QString& k, ValT&& v)
@@ -332,7 +362,7 @@ namespace _impl {
// This one is for types that have isEmpty() when Force is false
template <typename ValT>
- struct AddNode<ValT, false, decltype(std::declval<ValT>().isEmpty())> {
+ struct AddNode<ValT, IfNotEmpty, decltype(std::declval<ValT>().isEmpty())> {
template <typename ContT, typename ForwardedT>
static void impl(ContT& container, const QString& key,
ForwardedT&& value)
@@ -342,9 +372,9 @@ namespace _impl {
}
};
- // This one unfolds Omittable<> (also only when Force is false)
+ // This one unfolds Omittable<> (also only when IfNotEmpty is requested)
template <typename ValT>
- struct AddNode<Omittable<ValT>, false> {
+ struct AddNode<Omittable<ValT>, IfNotEmpty> {
template <typename ContT, typename OmittableT>
static void impl(ContT& container, const QString& key,
const OmittableT& value)
@@ -355,8 +385,6 @@ namespace _impl {
};
} // namespace _impl
-static constexpr bool IfNotEmpty = false;
-
/*! Add a key-value pair to QJsonObject or QUrlQuery
*
* Adds a key-value pair(s) specified by \p key and \p value to