diff options
author | Alexey Rusakov <Kitsune-Ral@users.sf.net> | 2022-02-13 19:25:24 +0100 |
---|---|---|
committer | Alexey Rusakov <Kitsune-Ral@users.sf.net> | 2022-02-13 19:25:24 +0100 |
commit | 044ae4a029b710571420f830a497647f7a54698a (patch) | |
tree | 14d50ba0eb1a5cfac995f13cd6059aed74e506b2 /lib/converters.h | |
parent | b0aef4af9cbf00755c7b70c71d77f0bf7ce0d200 (diff) | |
parent | 10ac7c13cdcd62b62af6e89cb726376cfbc53302 (diff) | |
download | libquotient-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.h | 72 |
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 |