aboutsummaryrefslogtreecommitdiff
path: root/lib/converters.h
diff options
context:
space:
mode:
Diffstat (limited to 'lib/converters.h')
-rw-r--r--lib/converters.h51
1 files changed, 39 insertions, 12 deletions
diff --git a/lib/converters.h b/lib/converters.h
index 8ddf6e45..515c96fd 100644
--- a/lib/converters.h
+++ b/lib/converters.h
@@ -14,6 +14,7 @@
#include <QtCore/QUrlQuery>
#include <QtCore/QVector>
+#include <type_traits>
#include <vector>
class QVariant;
@@ -21,10 +22,29 @@ 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
@@ -41,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()); }