diff options
author | Kitsune Ral <Kitsune-Ral@users.sf.net> | 2018-06-09 22:53:29 +0900 |
---|---|---|
committer | Kitsune Ral <Kitsune-Ral@users.sf.net> | 2018-06-09 22:53:29 +0900 |
commit | 46801080846d58ab1528e921bebcb14e651f7956 (patch) | |
tree | 13fadd0e947a184bc7cef77c5c0867bf404bfe0b /lib/converters.h | |
parent | 6767cb8eccea7b74531f59f165a28afa0bec61f4 (diff) | |
download | libquotient-46801080846d58ab1528e921bebcb14e651f7956.tar.gz libquotient-46801080846d58ab1528e921bebcb14e651f7956.zip |
csapi: Now really fix passing query parameters
Also: GetContentThumbnailJob (again) requires width and height.
Diffstat (limited to 'lib/converters.h')
-rw-r--r-- | lib/converters.h | 125 |
1 files changed, 61 insertions, 64 deletions
diff --git a/lib/converters.h b/lib/converters.h index 711d0a7c..7de33c9b 100644 --- a/lib/converters.h +++ b/lib/converters.h @@ -82,22 +82,20 @@ namespace QMatrixClient T& value() { return _value; } T&& release() { _omitted = true; return std::move(_value); } - operator bool() const { return !_omitted; } + operator bool() const { return !omitted(); } private: T _value; bool _omitted; }; - // This catches anything implicitly convertible to QJsonValue/Object/Array inline auto toJson(const QJsonValue& val) { return val; } inline auto toJson(const QJsonObject& o) { return o; } inline auto toJson(const QJsonArray& arr) { return arr; } // Special-case QStrings and bools to avoid ambiguity between QJsonValue - // and QVariant (also, QString.isEmpty() is used in _impl::AddNote<> below) + // and QVariant (also, QString.isEmpty() is used in _impl::AddNode<> below) inline auto toJson(const QString& s) { return s; } - inline QJsonValue toJson(bool b) { return b; } inline QJsonArray toJson(const QStringList& strings) { @@ -109,7 +107,18 @@ namespace QMatrixClient return bytes.constData(); } - QJsonValue toJson(const QVariant& v); + // QVariant is outrageously omnivorous - it consumes whatever is not + // exactly matching the signature of other toJson overloads. The trick + // below disables implicit conversion to QVariant through its numerous + // non-explicit constructors. + QJsonValue variantToJson(const QVariant& v); + template <typename T> + inline auto toJson(T&& var) + -> std::enable_if_t<std::is_same<std::decay_t<T>, QVariant>::value, + QJsonValue> + { + return variantToJson(var); + } QJsonObject toJson(const QMap<QString, QVariant>& map); #if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)) QJsonObject toJson(const QHash<QString, QVariant>& hMap); @@ -151,16 +160,6 @@ namespace QMatrixClient return json; } - template <typename T> - inline auto toJson(const Omittable<T>& omittable) - -> decltype(toJson(omittable.value())) - { - if (omittable) - return toJson(omittable.value()); - - return {}; - } - #if 0 template <typename T> inline auto toJson(const optional<T>& optVal) @@ -333,74 +332,72 @@ namespace QMatrixClient namespace _impl { + template <typename ValT> + inline void addTo(QJsonObject& o, const QString& k, ValT&& v) + { o.insert(k, toJson(v)); } + + template <typename ValT> + inline void addTo(QUrlQuery& q, const QString& k, ValT&& v) + { q.addQueryItem(k, QString("%1").arg(v)); } + + // OpenAPI is entirely JSON-based, which means representing bools as + // textual true/false, rather than 1/0. + template <typename ValT> + inline void addTo(QUrlQuery& q, const QString& k, bool v) + { + q.addQueryItem(k, v ? QStringLiteral("true") + : QStringLiteral("false")); + } + // This one is for types that don't have isEmpty() - template <typename InserterT, typename JsonT, typename = bool> + template <typename ValT, bool Force = true, typename = bool> struct AddNode { - static void impl(InserterT inserter, QString key, JsonT&& value) + template <typename ContT, typename ForwardedT> + static void impl(ContT& container, const QString& key, + ForwardedT&& value) { - inserter(std::move(key), std::forward<JsonT>(value)); + addTo(container, key, std::forward<ForwardedT>(value)); } }; // This one is for types that have isEmpty() - template <typename InserterT, typename JsonT> - struct AddNode<InserterT, JsonT, - decltype(std::declval<JsonT>().isEmpty())> + template <typename ValT> + struct AddNode<ValT, false, + decltype(std::declval<ValT>().isEmpty())> { - static void impl(InserterT inserter, QString key, JsonT&& value) + template <typename ContT, typename ForwardedT> + static void impl(ContT& container, const QString& key, + ForwardedT&& value) { if (!value.isEmpty()) - inserter(std::move(key), std::forward<JsonT>(value)); + AddNode<ValT>::impl(container, + key, std::forward<ForwardedT>(value)); } }; - template <bool Force, typename InserterT, typename ValT> - inline void maybeAdd(InserterT inserter, QString key, ValT&& value) + // This is a special one that unfolds Omittable<> + template <typename ValT, bool Force> + struct AddNode<Omittable<ValT>, Force> { - auto&& json = toJson(std::forward<ValT>(value)); - // QJsonValue doesn't have isEmpty and consumes all other types - // (QString, QJsonObject etc.). - AddNode<InserterT, - std::conditional_t<Force, QJsonValue, decltype(json)>> - ::impl(inserter, std::move(key), std::move(json)); - - } - + template <typename ContT, typename OmittableT> + static void impl(ContT& container, + const QString& key, const OmittableT& value) + { + if (!value.omitted()) + AddNode<ValT>::impl(container, key, value.value()); + else if (Force) // Edge case, no value but must put something + AddNode<ValT>::impl(container, key, QString{}); + } + }; } // namespace _impl static constexpr bool IfNotEmpty = false; - template <bool Force = true, typename ValT> - inline void addToJson(QJsonObject& o, QString key, ValT&& value) - { - using namespace std::placeholders; - _impl::maybeAdd<Force>(bind(&QJsonObject::insert, o, _1, _2), - key, value); - } - - template <bool Force = true, typename ValT> - inline void addToQuery(QUrlQuery& query, QString key, ValT&& value) + template <bool Force = true, typename ContT, typename ValT> + inline void addParam(ContT& container, const QString& key, ValT&& value) { - using namespace std::placeholders; - _impl::maybeAdd<Force>( - [&query] (QString k, auto&& jsonValue) { - query.addQueryItem(k, jsonValue.toString()); - }, key, value); + _impl::AddNode<std::decay_t<ValT>, Force> + ::impl(container, key, std::forward<ValT>(value)); } - - template <bool Force = true> - inline void addToQuery(QUrlQuery& query, QString key, QString value) - { - if (Force || !value.isEmpty()) - query.addQueryItem(key, value); - } - - template <bool Force = true> - inline void addToQuery(QUrlQuery& query, QString key, bool value) - { - query.addQueryItem(key, - value ? QStringLiteral("true") : QStringLiteral("false")); - } - } // namespace QMatrixClient |