From fdff209744ac4c422f63fe2549aa0132df7e6292 Mon Sep 17 00:00:00 2001
From: Alexey Rusakov <Kitsune-Ral@users.sf.net>
Date: Fri, 21 Jan 2022 02:04:10 +0100
Subject: Redo EventRelation; deprecate RelatesTo

RelatesTo and EventRelation have been two means to the same end in two
different contexts. (Modernised) EventRelation is the one used now both
for ReactionEvent and EventContent::TextContent. The modernisation
mostly boils down to using inline variables instead of functions to
return relation types and switching to QLatin1String from const char*
(because we know exactly that those constants are Latin-1 and
QLatin1String is more efficient than const char* to compare/convert to
QString).
---
 lib/events/eventrelation.cpp    | 38 ++++++++++++++++++++++++++++++
 lib/events/eventrelation.h      | 52 +++++++++++++++++++++++++++++++++++++++++
 lib/events/reactionevent.cpp    | 29 -----------------------
 lib/events/reactionevent.h      | 32 ++-----------------------
 lib/events/roommessageevent.cpp | 38 ++++++++----------------------
 lib/events/roommessageevent.h   | 27 +++++++++++----------
 6 files changed, 117 insertions(+), 99 deletions(-)
 create mode 100644 lib/events/eventrelation.cpp
 create mode 100644 lib/events/eventrelation.h
 delete mode 100644 lib/events/reactionevent.cpp

(limited to 'lib/events')

diff --git a/lib/events/eventrelation.cpp b/lib/events/eventrelation.cpp
new file mode 100644
index 00000000..04972f45
--- /dev/null
+++ b/lib/events/eventrelation.cpp
@@ -0,0 +1,38 @@
+// SPDX-FileCopyrightText: 2022 Kitsune Ral <kitsune-ral@users.sf.net>
+// SPDX-License-Identifier: LGPL-2.1-or-later
+
+#include "eventrelation.h"
+
+#include "../logging.h"
+#include "event.h"
+
+using namespace Quotient;
+
+void JsonObjectConverter<EventRelation>::dumpTo(QJsonObject& jo,
+                                                const EventRelation& pod)
+{
+    if (pod.type.isEmpty()) {
+        qCWarning(MAIN) << "Empty relation type; won't dump to JSON";
+        return;
+    }
+    jo.insert(RelTypeKey, pod.type);
+    jo.insert(EventIdKey, pod.eventId);
+    if (pod.type == EventRelation::AnnotationType)
+        jo.insert(QStringLiteral("key"), pod.key);
+}
+
+void JsonObjectConverter<EventRelation>::fillFrom(const QJsonObject& jo,
+                                                  EventRelation& pod)
+{
+    if (const auto replyJson = jo.value(EventRelation::ReplyType).toObject();
+        !replyJson.isEmpty()) {
+        pod.type = EventRelation::ReplyType;
+        fromJson(replyJson[EventIdKeyL], pod.eventId);
+    } else {
+        // The experimental logic for generic relationships (MSC1849)
+        fromJson(jo[RelTypeKey], pod.type);
+        fromJson(jo[EventIdKeyL], pod.eventId);
+        if (pod.type == EventRelation::AnnotationType)
+            fromJson(jo["key"_ls], pod.key);
+    }
+}
diff --git a/lib/events/eventrelation.h b/lib/events/eventrelation.h
new file mode 100644
index 00000000..e445ee42
--- /dev/null
+++ b/lib/events/eventrelation.h
@@ -0,0 +1,52 @@
+// SPDX-FileCopyrightText: 2022 Kitsune Ral <kitsune-ral@users.sf.net>
+// SPDX-License-Identifier: LGPL-2.1-or-later
+
+#pragma once
+
+#include "converters.h"
+
+namespace Quotient {
+
+[[maybe_unused]] constexpr auto RelatesToKey = "m.relates_to"_ls;
+constexpr auto RelTypeKey = "rel_type"_ls;
+
+struct QUOTIENT_API EventRelation {
+    using reltypeid_t = QLatin1String;
+
+    QString type;
+    QString eventId;
+    QString key = {}; // Only used for m.annotation for now
+
+    static constexpr auto ReplyType = "m.in_reply_to"_ls;
+    static constexpr auto AnnotationType = "m.annotation"_ls;
+    static constexpr auto ReplacementType = "m.replace"_ls;
+
+    static EventRelation replyTo(QString eventId)
+    {
+        return { ReplyType, std::move(eventId) };
+    }
+    static EventRelation annotate(QString eventId, QString key)
+    {
+        return { AnnotationType, std::move(eventId), std::move(key) };
+    }
+    static EventRelation replace(QString eventId)
+    {
+        return { ReplacementType, std::move(eventId) };
+    }
+
+    [[deprecated("Use ReplyRelation variable instead")]]
+    static constexpr auto Reply() { return ReplyType; }
+    [[deprecated("Use AnnotationRelation variable instead")]] //
+    static constexpr auto Annotation() { return AnnotationType; }
+    [[deprecated("Use ReplacementRelation variable instead")]] //
+    static constexpr auto Replacement() { return ReplacementType; }
+};
+
+template <>
+struct QUOTIENT_API JsonObjectConverter<EventRelation> {
+    static void dumpTo(QJsonObject& jo, const EventRelation& pod);
+    static void fillFrom(const QJsonObject& jo, EventRelation& pod);
+};
+
+}
+
diff --git a/lib/events/reactionevent.cpp b/lib/events/reactionevent.cpp
deleted file mode 100644
index b53fffd6..00000000
--- a/lib/events/reactionevent.cpp
+++ /dev/null
@@ -1,29 +0,0 @@
-// SPDX-FileCopyrightText: 2019 Kitsune Ral <kitsune-ral@users.sf.net>
-// SPDX-License-Identifier: LGPL-2.1-or-later
-
-#include "reactionevent.h"
-
-using namespace Quotient;
-
-void JsonObjectConverter<EventRelation>::dumpTo(
-    QJsonObject& jo, const EventRelation& pod)
-{
-    if (pod.type.isEmpty()) {
-        qCWarning(MAIN) << "Empty relation type; won't dump to JSON";
-        return;
-    }
-    jo.insert(QStringLiteral("rel_type"), pod.type);
-    jo.insert(EventIdKey, pod.eventId);
-    if (pod.type == EventRelation::Annotation())
-        jo.insert(QStringLiteral("key"), pod.key);
-}
-
-void JsonObjectConverter<EventRelation>::fillFrom(
-    const QJsonObject& jo, EventRelation& pod)
-{
-    // The experimental logic for generic relationships (MSC1849)
-    fromJson(jo["rel_type"_ls], pod.type);
-    fromJson(jo[EventIdKeyL], pod.eventId);
-    if (pod.type == EventRelation::Annotation())
-        fromJson(jo["key"_ls], pod.key);
-}
diff --git a/lib/events/reactionevent.h b/lib/events/reactionevent.h
index ce11eaed..b3cb3ca7 100644
--- a/lib/events/reactionevent.h
+++ b/lib/events/reactionevent.h
@@ -4,38 +4,10 @@
 #pragma once
 
 #include "roomevent.h"
+#include "eventrelation.h"
 
 namespace Quotient {
 
-struct QUOTIENT_API EventRelation {
-    using reltypeid_t = const char*;
-    static constexpr reltypeid_t Reply() { return "m.in_reply_to"; }
-    static constexpr reltypeid_t Annotation() { return "m.annotation"; }
-    static constexpr reltypeid_t Replacement() { return "m.replace"; }
-
-    QString type;
-    QString eventId;
-    QString key = {}; // Only used for m.annotation for now
-
-    static EventRelation replyTo(QString eventId)
-    {
-        return { Reply(), std::move(eventId) };
-    }
-    static EventRelation annotate(QString eventId, QString key)
-    {
-        return { Annotation(), std::move(eventId), std::move(key) };
-    }
-    static EventRelation replace(QString eventId)
-    {
-        return { Replacement(), std::move(eventId) };
-    }
-};
-template <>
-struct QUOTIENT_API JsonObjectConverter<EventRelation> {
-    static void dumpTo(QJsonObject& jo, const EventRelation& pod);
-    static void fillFrom(const QJsonObject& jo, EventRelation& pod);
-};
-
 class QUOTIENT_API ReactionEvent : public RoomEvent {
 public:
     DEFINE_EVENT_TYPEID("m.reaction", ReactionEvent)
@@ -47,7 +19,7 @@ public:
     explicit ReactionEvent(const QJsonObject& obj) : RoomEvent(typeId(), obj) {}
     EventRelation relation() const
     {
-        return contentPart<EventRelation>("m.relates_to"_ls);
+        return contentPart<EventRelation>(RelatesToKey);
     }
 };
 REGISTER_EVENT_TYPE(ReactionEvent)
diff --git a/lib/events/roommessageevent.cpp b/lib/events/roommessageevent.cpp
index 5ab0f845..c07a4f3c 100644
--- a/lib/events/roommessageevent.cpp
+++ b/lib/events/roommessageevent.cpp
@@ -6,6 +6,7 @@
 #include "roommessageevent.h"
 
 #include "logging.h"
+#include "events/eventrelation.h"
 
 #include <QtCore/QFileInfo>
 #include <QtCore/QMimeDatabase>
@@ -20,7 +21,6 @@ using namespace EventContent;
 using MsgType = RoomMessageEvent::MsgType;
 
 namespace { // Supporting internal definitions
-
 constexpr auto RelatesToKey = "m.relates_to"_ls;
 constexpr auto MsgTypeKey = "msgtype"_ls;
 constexpr auto FormattedBodyKey = "formatted_body"_ls;
@@ -84,9 +84,9 @@ MsgType jsonToMsgType(const QString& matrixType)
     return MsgType::Unknown;
 }
 
-inline bool isReplacement(const Omittable<RelatesTo>& rel)
+inline bool isReplacement(const Omittable<EventRelation>& rel)
 {
-    return rel && rel->type == RelatesTo::ReplacementTypeId();
+    return rel && rel->type == EventRelation::ReplacementType;
 }
 
 } // anonymous namespace
@@ -105,10 +105,10 @@ QJsonObject RoomMessageEvent::assembleContentJson(const QString& plainBody,
                 << "messages; the relation has been stripped off";
         } else {
             // After the above, we know for sure that the content is TextContent
-            // and that its RelatesTo structure is not omitted
+            // and that its EventRelation structure is not omitted
             auto* textContent = static_cast<const TextContent*>(content);
             Q_ASSERT(textContent && textContent->relatesTo.has_value());
-            if (textContent->relatesTo->type == RelatesTo::ReplacementTypeId()) {
+            if (textContent->relatesTo->type == EventRelation::ReplacementType) {
                 auto newContentJson = json.take("m.new_content"_ls).toObject();
                 newContentJson.insert(BodyKey, plainBody);
                 newContentJson.insert(MsgTypeKey, jsonMsgType);
@@ -269,7 +269,7 @@ QString RoomMessageEvent::rawMsgTypeForFile(const QFileInfo& fi)
 }
 
 TextContent::TextContent(QString text, const QString& contentType,
-                         Omittable<RelatesTo> relatesTo)
+                         Omittable<EventRelation> relatesTo)
     : mimeType(QMimeDatabase().mimeTypeForName(contentType))
     , body(std::move(text))
     , relatesTo(std::move(relatesTo))
@@ -278,26 +278,8 @@ TextContent::TextContent(QString text, const QString& contentType,
         mimeType = QMimeDatabase().mimeTypeForName("text/html");
 }
 
-namespace Quotient {
-// Overload the default fromJson<> logic that defined in converters.h
-// as we want
-template <>
-Omittable<RelatesTo> fromJson(const QJsonValue& jv)
-{
-    const auto jo = jv.toObject();
-    if (jo.isEmpty())
-        return none;
-    const auto replyJson = jo.value(RelatesTo::ReplyTypeId()).toObject();
-    if (!replyJson.isEmpty())
-        return replyTo(fromJson<QString>(replyJson[EventIdKeyL]));
-
-    return RelatesTo { jo.value("rel_type"_ls).toString(),
-                       jo.value(EventIdKeyL).toString() };
-}
-} // namespace Quotient
-
 TextContent::TextContent(const QJsonObject& json)
-    : relatesTo(fromJson<Omittable<RelatesTo>>(json[RelatesToKey]))
+    : relatesTo(fromJson<Omittable<EventRelation>>(json[RelatesToKey]))
 {
     QMimeDatabase db;
     static const auto PlainTextMimeType = db.mimeTypeForName("text/plain");
@@ -331,13 +313,13 @@ void TextContent::fillJson(QJsonObject* json) const
     if (relatesTo) {
         json->insert(
             QStringLiteral("m.relates_to"),
-            relatesTo->type == RelatesTo::ReplyTypeId()
+            relatesTo->type == EventRelation::ReplyType
                 ? QJsonObject { { relatesTo->type,
                                   QJsonObject {
                                       { EventIdKey, relatesTo->eventId } } } }
-                : QJsonObject { { "rel_type", relatesTo->type },
+                : QJsonObject { { RelTypeKey, relatesTo->type },
                                 { EventIdKey, relatesTo->eventId } });
-        if (relatesTo->type == RelatesTo::ReplacementTypeId()) {
+        if (relatesTo->type == EventRelation::ReplacementType) {
             QJsonObject newContentJson;
             if (mimeType.inherits("text/html")) {
                 newContentJson.insert(FormatKey, HtmlContentTypeId);
diff --git a/lib/events/roommessageevent.h b/lib/events/roommessageevent.h
index 0c901b7a..44ef05fb 100644
--- a/lib/events/roommessageevent.h
+++ b/lib/events/roommessageevent.h
@@ -6,6 +6,7 @@
 #pragma once
 
 #include "eventcontent.h"
+#include "eventrelation.h"
 #include "roomevent.h"
 
 class QFileInfo;
@@ -97,23 +98,25 @@ REGISTER_EVENT_TYPE(RoomMessageEvent)
 using MessageEventType = RoomMessageEvent::MsgType;
 
 namespace EventContent {
-    // Additional event content types
 
-    struct RelatesTo {
-        static constexpr const char* ReplyTypeId() { return "m.in_reply_to"; }
-        static constexpr const char* ReplacementTypeId() { return "m.replace"; }
-        QString type; // The only supported relation so far
-        QString eventId;
+    struct [[deprecated("Use Quotient::EventRelation instead")]] RelatesTo
+        : EventRelation {
+        static constexpr auto ReplyTypeId() { return Reply(); }
+        static constexpr auto ReplacementTypeId() { return Replacement(); }
     };
-    inline RelatesTo replyTo(QString eventId)
+    [[deprecated("Use EventRelation::replyTo() instead")]]
+    inline auto replyTo(QString eventId)
     {
-        return { RelatesTo::ReplyTypeId(), std::move(eventId) };
+        return EventRelation::replyTo(std::move(eventId));
     }
-    inline RelatesTo replacementOf(QString eventId)
+    [[deprecated("Use EventRelation::replace() instead")]]
+    inline auto replacementOf(QString eventId)
     {
-        return { RelatesTo::ReplacementTypeId(), std::move(eventId) };
+        return EventRelation::replace(std::move(eventId));
     }
 
+    // Additional event content types
+
     /**
      * Rich text content for m.text, m.emote, m.notice
      *
@@ -123,14 +126,14 @@ namespace EventContent {
     class QUOTIENT_API TextContent : public TypedBase {
     public:
         TextContent(QString text, const QString& contentType,
-                    Omittable<RelatesTo> relatesTo = none);
+                    Omittable<EventRelation> relatesTo = none);
         explicit TextContent(const QJsonObject& json);
 
         QMimeType type() const override { return mimeType; }
 
         QMimeType mimeType;
         QString body;
-        Omittable<RelatesTo> relatesTo;
+        Omittable<EventRelation> relatesTo;
 
     protected:
         void fillJson(QJsonObject* json) const override;
-- 
cgit v1.2.3