From b8a78fe7a2370697eea4517ab000130fe1180715 Mon Sep 17 00:00:00 2001 From: Alexey Rusakov Date: Sun, 13 Jun 2021 14:10:47 +0200 Subject: Exclude code no more needed with Qt6 --- lib/converters.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'lib/converters.h') diff --git a/lib/converters.h b/lib/converters.h index e07b6ee4..af6c0192 100644 --- a/lib/converters.h +++ b/lib/converters.h @@ -221,14 +221,16 @@ template struct JsonConverter> : public JsonArrayConverter> {}; +#if QT_VERSION_MAJOR < 6 // QVector is an alias of QList in Qt6 but not in Qt 5 template struct JsonConverter> : public JsonArrayConverter> {}; +#endif template struct JsonConverter> : public JsonArrayConverter> {}; template <> -struct JsonConverter : public JsonConverter> { +struct JsonConverter : public JsonArrayConverter { static auto dump(const QStringList& sl) { return QJsonArray::fromStringList(sl); -- cgit v1.2.3 From 35ce036407e1865402d01070e9680a9cda4f361c Mon Sep 17 00:00:00 2001 From: Alexey Rusakov Date: Sat, 7 Aug 2021 22:06:42 +0200 Subject: converters.h: (actually) enable QUrl; drop unused types QUrl can now be converted even with QT_NO_URL_CAST_FROM_STRING; and it can also be put to queries. QByteArray did not really need conversion in JSON context; and QJsonObject is/was never used in queries. --- lib/converters.h | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) (limited to 'lib/converters.h') diff --git a/lib/converters.h b/lib/converters.h index af6c0192..cc6378e4 100644 --- a/lib/converters.h +++ b/lib/converters.h @@ -151,10 +151,17 @@ struct JsonConverter { }; template <> -struct JsonConverter : JsonConverter { - static auto dump(const QUrl& url) // Override on top of that for QString +struct JsonConverter { + static auto load(const QJsonValue& jv) + { + // QT_NO_URL_CAST_FROM_STRING makes this a bit more verbose + QUrl url; + url.setUrl(jv.toString()); + return url; + } + static auto dump(const QUrl& url) { - return JsonConverter::dump(url.toString(QUrl::FullyEncoded)); + return url.toString(QUrl::FullyEncoded); } }; @@ -163,15 +170,6 @@ struct JsonConverter : public TrivialJsonDumper { static auto load(const QJsonValue& jv) { return jv.toArray(); } }; -template <> -struct JsonConverter { - static QString dump(const QByteArray& ba) { return ba.constData(); } - static auto load(const QJsonValue& jv) - { - return fromJson(jv).toLatin1(); - } -}; - template <> struct JsonConverter { static QJsonValue dump(const QVariant& v); @@ -304,16 +302,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 -- cgit v1.2.3 From 05e71a72fdc6da3fb319edc67b723999285c9657 Mon Sep 17 00:00:00 2001 From: Alexey Rusakov Date: Thu, 11 Nov 2021 14:35:54 +0100 Subject: Fix a few quirks in converters.h --- lib/converters.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'lib/converters.h') diff --git a/lib/converters.h b/lib/converters.h index cc6378e4..2df18b03 100644 --- a/lib/converters.h +++ b/lib/converters.h @@ -242,12 +242,11 @@ struct JsonObjectConverter> { for (const auto& e : s) json.insert(toJson(e), QJsonObject {}); } - static auto fillFrom(const QJsonObject& json, QSet& s) + static void fillFrom(const QJsonObject& json, QSet& s) { s.reserve(s.size() + json.size()); for (auto it = json.begin(); it != json.end(); ++it) s.insert(it.key()); - return s; } }; @@ -260,7 +259,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(it.value()); } -- cgit v1.2.3 From f2bf3f203965c51824e8681427798f7a09784ce3 Mon Sep 17 00:00:00 2001 From: Alexey Rusakov Date: Thu, 11 Nov 2021 22:18:18 +0100 Subject: Make ReceiptEvent constructible from content Makes the Room::P::toJson() code more readable. --- lib/converters.h | 7 +++++-- lib/events/receiptevent.cpp | 29 +++++++++++++++++++++++++---- lib/events/receiptevent.h | 5 +++-- lib/room.cpp | 27 +++++++-------------------- 4 files changed, 40 insertions(+), 28 deletions(-) (limited to 'lib/converters.h') diff --git a/lib/converters.h b/lib/converters.h index 2df18b03..d9a68bfb 100644 --- a/lib/converters.h +++ b/lib/converters.h @@ -134,7 +134,10 @@ struct JsonConverter : public TrivialJsonDumper { template <> struct JsonConverter { - static auto dump(const QDateTime& val) = delete; // not provided yet + static auto dump(const QDateTime& val) + { + return val.isValid() ? val.toMSecsSinceEpoch() : QJsonValue(); + } static auto load(const QJsonValue& jv) { return QDateTime::fromMSecsSinceEpoch(fromJson(jv), Qt::UTC); @@ -143,7 +146,7 @@ struct JsonConverter { template <> struct JsonConverter { - static auto dump(const QDate& val) = delete; // not provided yet + static auto dump(const QDate& val) { return toJson(QDateTime(val)); } static auto load(const QJsonValue& jv) { return fromJson(jv).date(); diff --git a/lib/events/receiptevent.cpp b/lib/events/receiptevent.cpp index 4185d92d..72dbf2e3 100644 --- a/lib/events/receiptevent.cpp +++ b/lib/events/receiptevent.cpp @@ -25,6 +25,27 @@ Example of a Receipt Event: using namespace Quotient; +// The library loads the event-ids-to-receipts JSON map into a vector because +// map lookups are not used and vectors are massively faster. Same goes for +// de-/serialization of ReceiptsForEvent::receipts. +// (XXX: would this be generally preferred across CS API JSON maps?..) +QJsonObject toJson(const EventsWithReceipts& ewrs) +{ + QJsonObject json; + for (const auto& e : ewrs) { + QJsonObject receiptsJson; + for (const auto& r : e.receipts) + receiptsJson.insert(r.userId, + QJsonObject { { "ts"_ls, toJson(r.timestamp) } }); + json.insert(e.evtId, QJsonObject { { "m.read"_ls, receiptsJson } }); + } + return json; +} + +ReceiptEvent::ReceiptEvent(const EventsWithReceipts &ewrs) + : Event(typeId(), matrixTypeId(), toJson(ewrs)) +{} + EventsWithReceipts ReceiptEvent::eventsWithReceipts() const { EventsWithReceipts result; @@ -39,14 +60,14 @@ EventsWithReceipts ReceiptEvent::eventsWithReceipts() const } const auto reads = eventIt.value().toObject().value("m.read"_ls).toObject(); - QVector receipts; - receipts.reserve(reads.size()); + QVector usersAtEvent; + usersAtEvent.reserve(reads.size()); for (auto userIt = reads.begin(); userIt != reads.end(); ++userIt) { const auto user = userIt.value().toObject(); - receipts.push_back( + usersAtEvent.push_back( { userIt.key(), fromJson(user["ts"_ls]) }); } - result.push_back({ eventIt.key(), std::move(receipts) }); + result.push_back({ eventIt.key(), std::move(usersAtEvent) }); } return result; } diff --git a/lib/events/receiptevent.h b/lib/events/receiptevent.h index 4feec9ea..9683deef 100644 --- a/lib/events/receiptevent.h +++ b/lib/events/receiptevent.h @@ -9,19 +9,20 @@ #include namespace Quotient { -struct Receipt { +struct UserTimestamp { QString userId; QDateTime timestamp; }; struct ReceiptsForEvent { QString evtId; - QVector receipts; + QVector receipts; }; using EventsWithReceipts = QVector; class ReceiptEvent : public Event { public: DEFINE_EVENT_TYPEID("m.receipt", ReceiptEvent) + explicit ReceiptEvent(const EventsWithReceipts& ewrs); explicit ReceiptEvent(const QJsonObject& obj) : Event(typeId(), obj) {} EventsWithReceipts eventsWithReceipts() const; diff --git a/lib/room.cpp b/lib/room.cpp index 4d11878f..58950aac 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -2813,7 +2813,7 @@ Room::Changes Room::processEphemeralEvent(EventPtr&& event) // are not supposed to move backwards. Otherwise, blindly store // the event id for this user and update the read marker when/if // the event is fetched later on. - for (const Receipt& r : p.receipts) + for (const auto& r : p.receipts) if (isMember(r.userId)) { d->setLastReadReceipt(user(r.userId), newMarker, { p.evtId, r.timestamp }); @@ -3021,30 +3021,17 @@ QJsonObject Room::Private::toJson() const { QStringLiteral("events"), accountDataEvents } }); } - if (const auto& readReceiptEventId = - lastReadReceipts.value(q->localUser()).eventId; - !readReceiptEventId.isEmpty()) // + if (const auto& readReceipt = q->lastReadReceipt(connection->userId()); + !readReceipt.eventId.isEmpty()) // { - // Okay, that's a mouthful; but basically, it's simply placing an m.read - // event in the 'ephemeral' section of the cached sync payload. - // See also receiptevent.* and m.read example in the spec. - // Only the local user's read receipt is saved - others' are really - // considered ephemeral but this one is useful in understanding where - // the user is in the timeline before any history is loaded. result.insert( QStringLiteral("ephemeral"), QJsonObject { { QStringLiteral("events"), - QJsonArray { QJsonObject { - { TypeKey, ReceiptEvent::matrixTypeId() }, - { ContentKey, - QJsonObject { - { readReceiptEventId, - QJsonObject { - { QStringLiteral("m.read"), - QJsonObject { - { connection->userId(), - QJsonObject {} } } } } } } } } } } }); + QJsonArray { ReceiptEvent({ { readReceipt.eventId, + { { connection->userId(), + readReceipt.timestamp } } } }) + .fullJson() } } }); } QJsonObject unreadNotifObj { { SyncRoomData::UnreadCountKey, -- cgit v1.2.3 From bcf7f7e6408872d8315e5c69829d7ce790e4820a Mon Sep 17 00:00:00 2001 From: Alexey Rusakov Date: Wed, 17 Nov 2021 20:27:10 +0100 Subject: Fix QDateTime(QDate) deprecation warnings --- lib/converters.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'lib/converters.h') diff --git a/lib/converters.h b/lib/converters.h index d9a68bfb..8ec0fa81 100644 --- a/lib/converters.h +++ b/lib/converters.h @@ -146,7 +146,15 @@ struct JsonConverter { template <> struct JsonConverter { - static auto dump(const QDate& val) { return toJson(QDateTime(val)); } + static auto dump(const QDate& val) { + return toJson( +#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) + QDateTime(val) +#else + val.startOfDay() +#endif + ); + } static auto load(const QJsonValue& jv) { return fromJson(jv).date(); -- cgit v1.2.3 From e12a7aac030aaf53122da4b1bd55f3a97325f624 Mon Sep 17 00:00:00 2001 From: Alexey Rusakov Date: Sun, 28 Nov 2021 15:44:41 +0100 Subject: Fix CI breakage caused by the previous commit --- lib/converters.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib/converters.h') diff --git a/lib/converters.h b/lib/converters.h index 8ec0fa81..f6d56527 100644 --- a/lib/converters.h +++ b/lib/converters.h @@ -62,6 +62,8 @@ inline T fromJson(const QJsonValue& jv) return JsonConverter::load(jv); } +inline QJsonValue fromJson(const QJsonValue& jv) { return jv; } + template inline T fromJson(const QJsonDocument& jd) { -- cgit v1.2.3 From 080af15c8aa7cc51f97c924ba4678083b7f8da8f Mon Sep 17 00:00:00 2001 From: Alexey Rusakov Date: Sun, 28 Nov 2021 16:04:42 +0100 Subject: One more small thing to actually fix CI breakage It's might look weird; but without making fromJson() a specialisation it becomes an overload next to an implicit specialisation of the template function defined just above, and then loses to that specialisation because it (also) has the perfect match. (would be great if the compiler shaded the implicit specialisation in such cases - alas it's not how the standard works.) --- lib/converters.h | 1 + 1 file changed, 1 insertion(+) (limited to 'lib/converters.h') diff --git a/lib/converters.h b/lib/converters.h index f6d56527..84fab798 100644 --- a/lib/converters.h +++ b/lib/converters.h @@ -62,6 +62,7 @@ inline T fromJson(const QJsonValue& jv) return JsonConverter::load(jv); } +template<> inline QJsonValue fromJson(const QJsonValue& jv) { return jv; } template -- cgit v1.2.3 From 121c2a08b25d79bcfd09c050d72c6ea7cc7720f9 Mon Sep 17 00:00:00 2001 From: Alexey Rusakov Date: Sun, 28 Nov 2021 17:21:01 +0100 Subject: Simplify converters.* There was a lot of excess redirection in fromJson() and toJson() with most of JsonConverter<> specialisations being unnecessary boilerplate. These have been replaced by overloads for toJson() and explicit specialisations for fromJson() wherever possible without breaking the conversion logic. --- lib/converters.cpp | 11 +++-- lib/converters.h | 126 +++++++++++++++++++++++++---------------------------- 2 files changed, 64 insertions(+), 73 deletions(-) (limited to 'lib/converters.h') diff --git a/lib/converters.cpp b/lib/converters.cpp index 4338e8ed..444ca4f6 100644 --- a/lib/converters.cpp +++ b/lib/converters.cpp @@ -5,24 +5,23 @@ #include -using namespace Quotient; - -QJsonValue JsonConverter::dump(const QVariant& v) +QJsonValue Quotient::JsonConverter::dump(const QVariant& v) { return QJsonValue::fromVariant(v); } -QVariant JsonConverter::load(const QJsonValue& jv) +QVariant Quotient::JsonConverter::load(const QJsonValue& jv) { return jv.toVariant(); } -QJsonObject JsonConverter::dump(const QVariantHash& vh) +QJsonObject Quotient::toJson(const QVariantHash& vh) { return QJsonObject::fromVariantHash(vh); } -QVariantHash JsonConverter::load(const QJsonValue& jv) +template<> +QVariantHash Quotient::fromJson(const QJsonValue& jv) { return jv.toObject().toVariantHash(); } diff --git a/lib/converters.h b/lib/converters.h index 84fab798..90349019 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 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 +template >> inline auto toJson(const T& pod) +// -> can return anything from which QJsonValue or, in some cases, QJsonDocument +// is constructible { return JsonConverter::dump(pod); } inline auto toJson(const QJsonObject& jo) { return jo; } +inline auto toJson(const QJsonValue& jv) { return jv; } template inline void fillJson(QJsonObject& json, const T& data) @@ -98,80 +117,64 @@ inline void fillFromJson(const QJsonValue& jv, T& pod) // JsonConverter<> specialisations -template -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 : public TrivialJsonDumper { - static auto load(const QJsonValue& jv) { return jv.toBool(); } -}; +inline int fromJson(const QJsonValue& jv) { return jv.toInt(); } template <> -struct JsonConverter : public TrivialJsonDumper { - static auto load(const QJsonValue& jv) { return jv.toInt(); } -}; +inline double fromJson(const QJsonValue& jv) { return jv.toDouble(); } template <> -struct JsonConverter : public TrivialJsonDumper { - static auto load(const QJsonValue& jv) { return jv.toDouble(); } -}; +inline float fromJson(const QJsonValue& jv) { return float(jv.toDouble()); } template <> -struct JsonConverter : public TrivialJsonDumper { - static auto load(const QJsonValue& jv) { return float(jv.toDouble()); } -}; +inline qint64 fromJson(const QJsonValue& jv) { return qint64(jv.toDouble()); } template <> -struct JsonConverter : public TrivialJsonDumper { - static auto load(const QJsonValue& jv) { return qint64(jv.toDouble()); } -}; +inline QString fromJson(const QJsonValue& jv) { return jv.toString(); } template <> -struct JsonConverter : public TrivialJsonDumper { - static auto load(const QJsonValue& jv) { return jv.toString(); } -}; +inline QJsonArray fromJson(const QJsonValue& jv) { return jv.toArray(); } template <> -struct JsonConverter { - static auto dump(const QDateTime& val) - { - return val.isValid() ? val.toMSecsSinceEpoch() : QJsonValue(); - } - static auto load(const QJsonValue& jv) - { - return QDateTime::fromMSecsSinceEpoch(fromJson(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 { - static auto dump(const QDate& val) { - return toJson( +inline QDateTime fromJson(const QJsonValue& jv) +{ + return QDateTime::fromMSecsSinceEpoch(fromJson(jv), Qt::UTC); +} + +inline QJsonValue toJson(const QDate& val) { + return toJson( #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) - QDateTime(val) + QDateTime(val) #else - val.startOfDay() + val.startOfDay() #endif - ); - } - static auto load(const QJsonValue& jv) - { - return fromJson(jv).date(); - } -}; + ); +} +template <> +inline QDate fromJson(const QJsonValue& jv) +{ + return fromJson(jv).date(); +} + +// 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 { static auto load(const QJsonValue& jv) { - // QT_NO_URL_CAST_FROM_STRING makes this a bit more verbose - QUrl url; - url.setUrl(jv.toString()); - return url; + return QUrl(jv.toString()); } static auto dump(const QUrl& url) { @@ -179,11 +182,6 @@ struct JsonConverter { } }; -template <> -struct JsonConverter : public TrivialJsonDumper { - static auto load(const QJsonValue& jv) { return jv.toArray(); } -}; - template <> struct JsonConverter { static QJsonValue dump(const QVariant& v); @@ -206,15 +204,11 @@ struct JsonConverter> { template 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) @@ -254,7 +248,7 @@ struct JsonObjectConverter> { static void dumpTo(QJsonObject& json, const QSet& s) { for (const auto& e : s) - json.insert(toJson(e), QJsonObject {}); + json.insert(e, QJsonObject {}); } static void fillFrom(const QJsonObject& json, QSet& s) { @@ -287,11 +281,9 @@ template struct JsonObjectConverter> : public HashMapFromJson> {}; +QJsonObject toJson(const QVariantHash& vh); template <> -struct JsonConverter { - static QJsonObject dump(const QVariantHash& vh); - static QVariantHash load(const QJsonValue& jv); -}; +QVariantHash fromJson(const QJsonValue& jv); // Conditional insertion into a QJsonObject -- cgit v1.2.3 From c3a0515ac2ead7b2d0653be3517836cd31be480e Mon Sep 17 00:00:00 2001 From: Alexey Rusakov Date: Thu, 2 Dec 2021 21:18:30 +0100 Subject: Cleanup on Sonar issues --- lib/converters.h | 4 ++-- lib/function_traits.cpp | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'lib/converters.h') diff --git a/lib/converters.h b/lib/converters.h index 90349019..9c3d5749 100644 --- a/lib/converters.h +++ b/lib/converters.h @@ -27,8 +27,8 @@ struct JsonObjectConverter { //! \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 diff --git a/lib/function_traits.cpp b/lib/function_traits.cpp index 4ff427e4..20bcf30e 100644 --- a/lib/function_traits.cpp +++ b/lib/function_traits.cpp @@ -8,11 +8,11 @@ using namespace Quotient; int f_(); -static_assert(std::is_same, int>::value, +static_assert(std::is_same_v, int>, "Test fn_return_t<>"); void f1_(int, float); -static_assert(std::is_same, float>::value, +static_assert(std::is_same_v, float>, "Test fn_arg_t<>"); struct Fo { @@ -43,7 +43,7 @@ static_assert(std::is_same_v, const double&>, struct Fo1 { void operator()(int); }; -static_assert(std::is_same, int>(), +static_assert(std::is_same_v, int>, "Test fn_arg_t defaulting to first argument"); template -- cgit v1.2.3