aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt2
-rw-r--r--lib/events/callanswerevent.h3
-rw-r--r--lib/events/callcandidatesevent.h4
-rw-r--r--lib/events/callhangupevent.h4
-rw-r--r--lib/events/callinviteevent.h4
-rw-r--r--lib/events/directchatevent.h3
-rw-r--r--lib/events/encryptedevent.h4
-rw-r--r--lib/events/encryptionevent.h3
-rw-r--r--lib/events/event.cpp41
-rw-r--r--lib/events/event.h355
-rw-r--r--lib/events/keyverificationevent.h26
-rw-r--r--lib/events/receiptevent.h3
-rw-r--r--lib/events/redactionevent.h3
-rw-r--r--lib/events/roomavatarevent.h3
-rw-r--r--lib/events/roomcanonicalaliasevent.h3
-rw-r--r--lib/events/roomcreateevent.h3
-rw-r--r--lib/events/roomevent.h16
-rw-r--r--lib/events/roomkeyevent.h3
-rw-r--r--lib/events/roommemberevent.h12
-rw-r--r--lib/events/roommessageevent.h4
-rw-r--r--lib/events/roompowerlevelsevent.h3
-rw-r--r--lib/events/roomtombstoneevent.h3
-rw-r--r--lib/events/simplestateevents.h5
-rw-r--r--lib/events/stateevent.h30
-rw-r--r--lib/events/stickerevent.h3
25 files changed, 326 insertions, 217 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 06e754aa..9983f860 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -32,7 +32,7 @@ endif(CMAKE_BUILD_TYPE)
message(STATUS "Using compiler: ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION}" )
include(CheckCXXCompilerFlag)
if (MSVC)
- add_compile_options(/EHsc /W4
+ add_compile_options(/Zc:preprocessor /EHsc /W4
/wd4100 /wd4127 /wd4242 /wd4244 /wd4245 /wd4267 /wd4365 /wd4456 /wd4459
/wd4464 /wd4505 /wd4514 /wd4571 /wd4619 /wd4623 /wd4625 /wd4626 /wd4706
/wd4710 /wd4774 /wd4820 /wd4946 /wd5026 /wd5027)
diff --git a/lib/events/callanswerevent.h b/lib/events/callanswerevent.h
index 4d539b85..70ca1c7e 100644
--- a/lib/events/callanswerevent.h
+++ b/lib/events/callanswerevent.h
@@ -9,7 +9,7 @@
namespace Quotient {
class QUOTIENT_API CallAnswerEvent : public CallEventBase {
public:
- DEFINE_EVENT_TYPEID("m.call.answer", CallAnswerEvent)
+ QUO_EVENT(CallAnswerEvent, "m.call.answer")
explicit CallAnswerEvent(const QJsonObject& obj);
@@ -20,5 +20,4 @@ public:
return contentPart<QJsonObject>("answer"_ls).value("sdp"_ls).toString();
}
};
-REGISTER_EVENT_TYPE(CallAnswerEvent)
} // namespace Quotient
diff --git a/lib/events/callcandidatesevent.h b/lib/events/callcandidatesevent.h
index e949f722..cb96f358 100644
--- a/lib/events/callcandidatesevent.h
+++ b/lib/events/callcandidatesevent.h
@@ -11,7 +11,7 @@
namespace Quotient {
class CallCandidatesEvent : public CallEventBase {
public:
- DEFINE_EVENT_TYPEID("m.call.candidates", CallCandidatesEvent)
+ QUO_EVENT(CallCandidatesEvent, "m.call.candidates")
explicit CallCandidatesEvent(const QJsonObject& obj)
: CallEventBase(typeId(), obj)
@@ -27,6 +27,4 @@ public:
QUO_CONTENT_GETTER(QString, callId)
QUO_CONTENT_GETTER(int, version)
};
-
-REGISTER_EVENT_TYPE(CallCandidatesEvent)
} // namespace Quotient
diff --git a/lib/events/callhangupevent.h b/lib/events/callhangupevent.h
index b0017c59..e4d9bb78 100644
--- a/lib/events/callhangupevent.h
+++ b/lib/events/callhangupevent.h
@@ -9,7 +9,7 @@
namespace Quotient {
class QUOTIENT_API CallHangupEvent : public CallEventBase {
public:
- DEFINE_EVENT_TYPEID("m.call.hangup", CallHangupEvent)
+ QUO_EVENT(CallHangupEvent, "m.call.hangup")
explicit CallHangupEvent(const QJsonObject& obj)
: CallEventBase(typeId(), obj)
@@ -18,6 +18,4 @@ public:
: CallEventBase(typeId(), matrixTypeId(), callId, 0)
{}
};
-
-REGISTER_EVENT_TYPE(CallHangupEvent)
} // namespace Quotient
diff --git a/lib/events/callinviteevent.h b/lib/events/callinviteevent.h
index 5b4ca0df..f96f416d 100644
--- a/lib/events/callinviteevent.h
+++ b/lib/events/callinviteevent.h
@@ -9,7 +9,7 @@
namespace Quotient {
class QUOTIENT_API CallInviteEvent : public CallEventBase {
public:
- DEFINE_EVENT_TYPEID("m.call.invite", CallInviteEvent)
+ QUO_EVENT(CallInviteEvent, "m.call.invite")
explicit CallInviteEvent(const QJsonObject& obj);
@@ -22,6 +22,4 @@ public:
return contentPart<QJsonObject>("offer"_ls).value("sdp"_ls).toString();
}
};
-
-REGISTER_EVENT_TYPE(CallInviteEvent)
} // namespace Quotient
diff --git a/lib/events/directchatevent.h b/lib/events/directchatevent.h
index 2018d3d6..942edba4 100644
--- a/lib/events/directchatevent.h
+++ b/lib/events/directchatevent.h
@@ -8,11 +8,10 @@
namespace Quotient {
class QUOTIENT_API DirectChatEvent : public Event {
public:
- DEFINE_EVENT_TYPEID("m.direct", DirectChatEvent)
+ QUO_EVENT(DirectChatEvent, "m.direct")
explicit DirectChatEvent(const QJsonObject& obj) : Event(typeId(), obj) {}
QMultiHash<QString, QString> usersToDirectChats() const;
};
-REGISTER_EVENT_TYPE(DirectChatEvent)
} // namespace Quotient
diff --git a/lib/events/encryptedevent.h b/lib/events/encryptedevent.h
index ddd5e415..22e51cb8 100644
--- a/lib/events/encryptedevent.h
+++ b/lib/events/encryptedevent.h
@@ -27,7 +27,7 @@ namespace Quotient {
*/
class QUOTIENT_API EncryptedEvent : public RoomEvent {
public:
- DEFINE_EVENT_TYPEID("m.room.encrypted", EncryptedEvent)
+ QUO_EVENT(EncryptedEvent, "m.room.encrypted")
/* In case with Olm, the encrypted content of the event is
* a map from the recipient Curve25519 identity key to ciphertext
@@ -59,6 +59,4 @@ public:
void setRelation(const QJsonObject& relation);
};
-REGISTER_EVENT_TYPE(EncryptedEvent)
-
} // namespace Quotient
diff --git a/lib/events/encryptionevent.h b/lib/events/encryptionevent.h
index 91452c3f..60e77451 100644
--- a/lib/events/encryptionevent.h
+++ b/lib/events/encryptionevent.h
@@ -28,7 +28,7 @@ public:
class QUOTIENT_API EncryptionEvent : public StateEvent<EncryptionEventContent> {
public:
- DEFINE_EVENT_TYPEID("m.room.encryption", EncryptionEvent)
+ QUO_EVENT(EncryptionEvent, "m.room.encryption")
using EncryptionType
[[deprecated("Use Quotient::EncryptionType instead")]] =
@@ -48,5 +48,4 @@ public:
bool useEncryption() const { return !algorithm().isEmpty(); }
};
-REGISTER_EVENT_TYPE(EncryptionEvent)
} // namespace Quotient
diff --git a/lib/events/event.cpp b/lib/events/event.cpp
index 1f1eebaa..595e20a5 100644
--- a/lib/events/event.cpp
+++ b/lib/events/event.cpp
@@ -4,6 +4,7 @@
#include "event.h"
#include "logging.h"
+#include "stateevent.h"
#include <QtCore/QJsonDocument>
@@ -11,12 +12,38 @@ using namespace Quotient;
QString EventTypeRegistry::getMatrixType(event_type_t typeId) { return typeId; }
-void _impl::EventFactoryBase::logAddingMethod(event_type_t TypeId,
- size_t newSize)
+void AbstractEventMetaType::addDerived(AbstractEventMetaType* newType)
{
- qDebug(EVENTS) << "Adding factory method for" << TypeId << "events;"
- << newSize << "methods will be in the" << name
- << "chain";
+ if (const auto existing =
+ std::find_if(derivedTypes.cbegin(), derivedTypes.cend(),
+ [&newType](const AbstractEventMetaType* t) {
+ return t->matrixId == newType->matrixId;
+ });
+ existing != derivedTypes.cend())
+ {
+ if (*existing == newType)
+ return;
+ // Two different metatype objects claim the same Matrix type id; this
+ // is not normal, so give as much information as possible to diagnose
+ if ((*existing)->className == newType->className) {
+ qCritical(EVENTS)
+ << newType->className << "claims" << newType->matrixId
+ << "repeatedly; check that it's exported across translation "
+ "units or shared objects";
+ Q_ASSERT(false); // That situation is plain wrong
+ return; // So maybe std::terminate() even?
+ }
+ qWarning(EVENTS).nospace()
+ << newType->matrixId << " is already mapped to "
+ << (*existing)->className << " before " << newType->className
+ << "; unless the two have different isValid() conditions, the "
+ "latter class will never be used";
+ }
+ derivedTypes.emplace_back(newType);
+ qDebug(EVENTS).nospace()
+ << newType->matrixId << " -> " << newType->className << "; "
+ << derivedTypes.size() << " derived type(s) registered for "
+ << className;
}
Event::Event(Type type, const QJsonObject& json) : _type(type), _json(json)
@@ -48,6 +75,10 @@ const QJsonObject Event::unsignedJson() const
return fullJson()[UnsignedKeyL].toObject();
}
+bool Event::isStateEvent() const { return is<StateEventBase>(); }
+
+bool Event::isCallEvent() const { return is<CallEventBase>(); }
+
void Event::dumpTo(QDebug dbg) const
{
dbg << QJsonDocument(contentJson()).toJson(QJsonDocument::Compact);
diff --git a/lib/events/event.h b/lib/events/event.h
index 711f8fd4..ea827244 100644
--- a/lib/events/event.h
+++ b/lib/events/event.h
@@ -85,91 +85,167 @@ inline event_ptr_tt<EventT> makeEvent(ArgTs&&... args)
return std::make_unique<EventT>(std::forward<ArgTs>(args)...);
}
-namespace _impl {
- class QUOTIENT_API EventFactoryBase {
- public:
- EventFactoryBase(const EventFactoryBase&) = delete;
-
- protected: // This class is only to inherit from
- explicit EventFactoryBase(const char* name)
- : name(name)
- {}
- void logAddingMethod(event_type_t TypeId, size_t newSize);
-
- private:
- const char* const name;
- };
-} // namespace _impl
-
-//! \brief A family of event factories to create events from CS API responses
-//!
-//! Each of these factories, as instantiated by event base types (Event,
-//! RoomEvent etc.) is capable of producing an event object derived from
-//! \p BaseEventT, using the JSON payload and the event type passed to its
-//! make() method. Don't use these directly to make events; use loadEvent()
-//! overloads as the frontend for these. Never instantiate new factories
-//! outside of base event classes.
-//! \sa loadEvent, setupFactory, Event::factory, RoomEvent::factory,
-//! StateEventBase::factory
-template <typename BaseEventT>
-class EventFactory : public _impl::EventFactoryBase {
-private:
- using method_t = event_ptr_tt<BaseEventT> (*)(const QJsonObject&,
- const QString&);
- std::vector<method_t> methods {};
+// === EventMetaType ===
- template <class EventT>
- static event_ptr_tt<BaseEventT> makeIfMatches(const QJsonObject& json,
- const QString& matrixType)
+class Event;
+
+template <class EventT>
+bool is(const Event& e);
+
+//! \brief The base class for event metatypes
+//!
+//! You should not normally have to use this directly, unless you need to devise
+//! a whole new kind of event metatypes.
+class QUOTIENT_API AbstractEventMetaType {
+public:
+ // The public fields here are const and are not to be changeable anyway.
+ // NOLINTBEGIN(misc-non-private-member-variables-in-classes)
+ const char* const className;
+ const event_type_t matrixId;
+ const AbstractEventMetaType* const baseType = nullptr;
+ // NOLINTEND(misc-non-private-member-variables-in-classes)
+
+ explicit AbstractEventMetaType(const char* className)
+ : className(className)
+ {}
+ explicit AbstractEventMetaType(const char* className, event_type_t matrixId,
+ AbstractEventMetaType& nearestBase)
+ : className(className), matrixId(matrixId), baseType(&nearestBase)
{
- // If your matrix event type is not all ASCII, it's your problem
- // (see https://github.com/matrix-org/matrix-doc/pull/2758)
- return EventT::TypeId == matrixType ? makeEvent<EventT>(json) : nullptr;
+ nearestBase.addDerived(this);
}
+ void addDerived(AbstractEventMetaType *newType);
+
+ virtual ~AbstractEventMetaType() = default;
+
+protected:
+ // Allow template specialisations to call into one another
+ template <class EventT>
+ friend class EventMetaType;
+
+ // The returned value indicates whether a generic object has to be created
+ // on the top level when `event` is empty, instead of returning nullptr
+ virtual bool doLoadFrom(const QJsonObject& fullJson, const QString& type,
+ Event*& event) const = 0;
+
+private:
+ std::vector<const AbstractEventMetaType*> derivedTypes{};
+ Q_DISABLE_COPY_MOVE(AbstractEventMetaType)
+};
+
+// Any event metatype is unique (note Q_DISABLE_COPY_MOVE above) so can be
+// identified by its address
+inline bool operator==(const AbstractEventMetaType& lhs,
+ const AbstractEventMetaType& rhs)
+{
+ return &lhs == &rhs;
+}
+
+//! \brief A family of event meta-types to load and match events
+//!
+//! TL;DR for the loadFrom() story:
+//! - for base event types, use QUO_BASE_EVENT and, if you have additional
+//! validation (e.g., JSON has to contain a certain key - see StateEventBase
+//! for a real example), define it in the static EventT::isValid() member
+//! function accepting QJsonObject and returning bool.
+//! - for leaf (specific) event types - simply use QUO_EVENT and it will do
+//! everything necessary, including the TypeId definition.
+//! \sa QUO_EVENT, QUO_BASE_EVENT
+template <class EventT>
+class QUOTIENT_API EventMetaType : public AbstractEventMetaType {
+ // Above: can't constrain EventT to be EventClass because it's incomplete
+ // at the point of EventMetaType<EventT> instantiation.
public:
- explicit EventFactory(const char* fName)
- : EventFactoryBase { fName }
- {}
+ using AbstractEventMetaType::AbstractEventMetaType;
- //! \brief Add a method to create events of a given type
+ //! \brief Try to load an event from JSON, with dynamic type resolution
//!
- //! Adds a standard factory method (makeIfMatches) for \p EventT so that
- //! event objects of this type can be created dynamically by loadEvent.
- //! The caller is responsible for ensuring this method is called only
- //! once per type.
- //! \sa loadEvent, Quotient::loadEvent
- template <class EventT>
- const auto& addMethod()
+ //! The generic logic defined in this class template and invoked applies to
+ //! all event types defined in the library and boils down to the following:
+ //! 1.
+ //! a. If EventT has TypeId defined (which normally is a case of
+ //! all leaf - specific - event types, via QUO_EVENT macro) and
+ //! \p type doesn't exactly match it, nullptr is immediately returned.
+ //! b. In absence of TypeId, an event type is assumed to be a base;
+ //! its derivedTypes are examined, and this algorithm is applied
+ //! recursively on each.
+ //! 2. Optional validation: if EventT (or, due to the way inheritance works,
+ //! any of its base event types) has a static isValid() predicate and
+ //! the event JSON does not satisfy it, nullptr is immediately returned
+ //! to the upper level or to the loadFrom() caller. This is how existence
+ //! of `state_key` is checked in any type derived from StateEventBase.
+ //! 3. If step 1b above returned non-nullptr, immediately return it.
+ //! 4.
+ //! a. If EventT::isValid() or EventT::TypeId (either, or both) exist and
+ //! are satisfied (see steps 1a and 2 above), an object of this type
+ //! is created from the passed JSON and returned. In case of a base
+ //! event type, this will be a generic (aka "unknown") event.
+ //! b. If neither exists, a generic event is only created and returned
+ //! when on the top level (i.e., outside of recursion into
+ //! derivedTypes); lower levels return nullptr instead and the type
+ //! lookup continues. The latter is a case of a derived base event
+ //! metatype (e.g. RoomEvent) called from its base event metatype
+ //! (i.e., Event). If no matching type derived from RoomEvent is found,
+ //! the nested lookup returns nullptr rather than a generic RoomEvent,
+ //! so that other types derived from Event could be examined.
+ event_ptr_tt<EventT> loadFrom(const QJsonObject& fullJson,
+ const QString& type) const
{
- const auto m = &makeIfMatches<EventT>;
- const auto it = std::find(methods.cbegin(), methods.cend(), m);
- if (it != methods.cend())
- return *it;
- logAddingMethod(EventT::TypeId, methods.size() + 1);
- return methods.emplace_back(m);
+ Event* event = nullptr;
+ const bool goodEnough = doLoadFrom(fullJson, type, event);
+ if (!event && goodEnough)
+ return event_ptr_tt<EventT>{ makeEvent(fullJson) };
+ return event_ptr_tt<EventT>{ static_cast<EventT*>(event) };
}
- auto loadEvent(const QJsonObject& json, const QString& matrixType)
+private:
+ bool doLoadFrom(const QJsonObject& fullJson, const QString& type,
+ Event*& event) const override
+ {
+ if constexpr (requires { EventT::TypeId; }) {
+ if (EventT::TypeId != type)
+ return false;
+ } else {
+ for (const auto& p : derivedTypes) {
+ p->doLoadFrom(fullJson, type, event);
+ if (event) {
+ Q_ASSERT(is<EventT>(*event));
+ return false;
+ }
+ }
+ }
+ if constexpr (requires { EventT::isValid; }) {
+ if (!EventT::isValid(fullJson))
+ return false;
+ } else if constexpr (!requires { EventT::TypeId; })
+ return true; // Create a generic event object if on the top level
+ event = makeEvent(fullJson);
+ return false;
+ }
+ static auto makeEvent(const QJsonObject& fullJson)
{
- for (const auto& f : methods)
- if (auto e = f(json, matrixType))
- return e;
- return makeEvent<BaseEventT>(UnknownEventTypeId, json);
+ if constexpr (requires { EventT::TypeId; })
+ return new EventT(fullJson);
+ else
+ return new EventT(UnknownEventTypeId, fullJson);
}
};
-//! \brief Point of customisation to dynamically load events
-//!
-//! The default specialisation of this calls BaseEventT::factory.loadEvent()
-//! and if that fails (i.e. returns nullptr) creates an unknown event of
-//! BaseEventT. Other specialisations may reuse other factories, add validations
-//! common to BaseEventT events, and so on.
-template <class BaseEventT>
-event_ptr_tt<BaseEventT> doLoadEvent(const QJsonObject& json,
- const QString& matrixType)
+template <class EventT>
+constexpr const auto& mostSpecificMetaType()
{
- return BaseEventT::factory.loadEvent(json, matrixType);
+ if constexpr (requires { EventT::MetaType; })
+ return EventT::MetaType;
+ else
+ return EventT::BaseMetaType;
+}
+
+template <class EventT>
+inline event_ptr_tt<EventT> doLoadEvent(const QJsonObject& json,
+ const QString& matrixType)
+{
+ return mostSpecificMetaType<EventT>().loadFrom(json, matrixType);
}
// === Event ===
@@ -177,7 +253,12 @@ event_ptr_tt<BaseEventT> doLoadEvent(const QJsonObject& json,
class QUOTIENT_API Event {
public:
using Type = event_type_t;
- static inline EventFactory<Event> factory { "Event" };
+ static inline EventMetaType<Event> BaseMetaType { "Event" };
+ virtual const AbstractEventMetaType& metaType() const
+ {
+ return BaseMetaType;
+ }
+
explicit Event(Type type, const QJsonObject& json);
explicit Event(Type type, event_mtype_t matrixType,
@@ -194,8 +275,26 @@ public:
return { { TypeKey, matrixType }, { ContentKey, content } };
}
- Type type() const { return _type; }
+ //! \brief Event Matrix type, as identified by its metatype object
+ //!
+ //! For generic/unknown events it will contain a descriptive/generic string
+ //! defined by the respective base event type (that can be empty).
+ //! \sa matrixType
+ Type type() const { return metaType().matrixId; }
+
+ //! \brief Exact Matrix type stored in JSON
+ //!
+ //! Coincides with the result of type() (but is slower) for events defined
+ //! in C++ (not necessarily in the library); for generic/unknown events
+ //! the returned value will be different.
QString matrixType() const;
+
+ template <class EventT>
+ bool is() const
+ {
+ return Quotient::is<EventT>(*this);
+ }
+
[[deprecated("Use fullJson() and stringify it with QJsonDocument::toJson() "
"or by other means")]]
QByteArray originalJson() const;
@@ -237,13 +336,17 @@ public:
friend QUOTIENT_API QDebug operator<<(QDebug dbg, const Event& e)
{
QDebugStateSaver _dss { dbg };
- dbg.noquote().nospace() << e.matrixType() << '(' << e.type() << "): ";
+ dbg.noquote().nospace()
+ << e.matrixType() << '(' << e.metaType().className << "): ";
e.dumpTo(dbg);
return dbg;
}
- virtual bool isStateEvent() const { return false; }
- virtual bool isCallEvent() const { return false; }
+ // State events are quite special in Matrix; so isStateEvent() is here,
+ // as an exception. For other base events, Event::is<>() and
+ // Quotient::is<>() should be used; don't add is* methods here
+ bool isStateEvent() const;
+ [[deprecated("Use is<CallEventBase>() instead")]] bool isCallEvent() const;
protected:
QJsonObject& editJson() { return _json; }
@@ -259,11 +362,64 @@ template <typename EventT>
using EventsArray = std::vector<event_ptr_tt<EventT>>;
using Events = EventsArray<Event>;
+// === Facilities for event class definitions ===
+
+//! \brief Supply event metatype information in base event types
+//!
+//! Use this macro in a public section of your base event class to provide
+//! type identity and enable dynamic loading of generic events of that type.
+//! Do _not_ add this macro if your class is an intermediate wrapper and is not
+//! supposed to be instantiated on its own. Provides BaseMetaType static field
+//! initialised by parameters passed to the macro, and a metaType() override
+//! pointing to that BaseMetaType.
+//! \sa EventMetaType, EventMetaType::SuppressLoadDerived
+#define QUO_BASE_EVENT(CppType_, ...) \
+ static inline EventMetaType<CppType_> BaseMetaType{ \
+ #CppType_ __VA_OPT__(,) __VA_ARGS__ }; \
+ const AbstractEventMetaType& metaType() const override \
+ { \
+ return BaseMetaType; \
+ } \
+ // End of macro
+
+//! Supply event metatype information in (specific) event types
+//!
+//! Use this macro in a public section of your event class to provide type
+//! identity and enable dynamic loading of generic events of that type.
+//! Do _not_ use this macro if your class is an intermediate wrapper and is not
+//! supposed to be instantiated on its own. Provides MetaType static field
+//! initialised as described below; a metaType() override pointing to it; and
+//! the TypeId static field that is equal to MetaType.matrixId.
+//!
+//! The first two macro parameters are used as the first two EventMetaType
+//! constructor parameters; the third EventMetaType parameter is always
+//! BaseMetaType; and additional base types can be passed in extra macro
+//! parameters if you need to include the same event type in more than one
+//! event factory hierarchy (e.g., EncryptedEvent).
+//! \sa EventMetaType
+#define QUO_EVENT(CppType_, MatrixType_, ...) \
+ static inline const auto& TypeId = MatrixType_##_ls; \
+ static inline const EventMetaType<CppType_> MetaType{ \
+ #CppType_, TypeId, BaseMetaType __VA_OPT__(,) __VA_ARGS__ \
+ }; \
+ const AbstractEventMetaType& metaType() const override \
+ { \
+ return MetaType; \
+ } \
+ [[deprecated("Use " #CppType_ "::TypeId directly instead")]] \
+ static constexpr const char* matrixTypeId() { return MatrixType_; } \
+ [[deprecated("Use " #CppType_ "::TypeId directly instead")]] \
+ static event_type_t typeId() { return TypeId; } \
+ // End of macro
+
+//! \deprecated This is the old name for what is now known as QUO_EVENT
+#define DEFINE_EVENT_TYPEID(Type_, Id_) QUO_EVENT(Type_, Id_)
+
#define QUO_CONTENT_GETTER_X(PartType_, PartName_, JsonKey_) \
- PartType_ PartName_() const \
- { \
- static const auto PartName_##JsonKey = JsonKey_; \
- return contentPart<PartType_>(PartName_##JsonKey); \
+ PartType_ PartName_() const \
+ { \
+ static const auto PartName_##JsonKey = JsonKey_; \
+ return contentPart<PartType_>(PartName_##JsonKey); \
}
//! \brief Define an inline method obtaining a content part
@@ -277,25 +433,9 @@ using Events = EventsArray<Event>;
#define QUO_CONTENT_GETTER(PartType_, PartName_) \
QUO_CONTENT_GETTER_X(PartType_, PartName_, toSnakeCase(#PartName_##_ls))
-// === Facilities for event class definitions ===
-
-// This macro should be used in a public section of an event class to
-// provide matrixTypeId() and typeId().
-#define DEFINE_EVENT_TYPEID(Id_, Type_) \
- static constexpr event_type_t TypeId = Id_##_ls; \
- [[deprecated("Use " #Type_ "::TypeId directly instead")]] \
- static constexpr event_mtype_t matrixTypeId() { return Id_; } \
- [[deprecated("Use " #Type_ "::TypeId directly instead")]] \
- static event_type_t typeId() { return TypeId; } \
- // End of macro
-
-// This macro should be put after an event class definition (in .h or .cpp)
-// to enable its deserialisation from a /sync and other
-// polymorphic event arrays
-#define REGISTER_EVENT_TYPE(Type_) \
- [[maybe_unused]] inline const auto& factoryMethodFor##Type_ = \
- Type_::factory.addMethod<Type_>(); \
- // End of macro
+//! \deprecated This macro was used after an event class definition
+//! to enable its dynamic loading; it is completely superseded by QUO_EVENT
+#define REGISTER_EVENT_TYPE(Type_)
/// \brief Define a new event class with a single key-value pair in the content
///
@@ -309,7 +449,7 @@ using Events = EventsArray<Event>;
JsonKey_) \
class QUOTIENT_API Name_ : public Base_ { \
public: \
- DEFINE_EVENT_TYPEID(TypeId_, Name_) \
+ QUO_EVENT(Name_, TypeId_) \
using value_type = ValueType_; \
explicit Name_(const QJsonObject& obj) : Base_(TypeId, obj) {} \
explicit Name_(const value_type& v) \
@@ -318,7 +458,6 @@ using Events = EventsArray<Event>;
QUO_CONTENT_GETTER_X(ValueType_, GetterName_, JsonKey) \
static inline const auto JsonKey = toSnakeCase(#GetterName_##_ls); \
}; \
- REGISTER_EVENT_TYPE(Name_) \
// End of macro
// === is<>(), eventCast<>() and switchOnType<>() ===
@@ -326,12 +465,16 @@ using Events = EventsArray<Event>;
template <class EventT>
inline bool is(const Event& e)
{
- return e.type() == typeId<EventT>();
-}
-
-inline bool isUnknown(const Event& e)
-{
- return e.type() == UnknownEventTypeId;
+ if constexpr (requires { EventT::MetaType; }) {
+ return &e.metaType() == &EventT::MetaType;
+ } else {
+ const auto* p = &e.metaType();
+ do {
+ if (p == &EventT::BaseMetaType)
+ return true;
+ } while ((p = p->baseType) != nullptr);
+ return false;
+ }
}
//! \brief Cast the event pointer down in a type-safe way
diff --git a/lib/events/keyverificationevent.h b/lib/events/keyverificationevent.h
index 5b587522..5b5a518f 100644
--- a/lib/events/keyverificationevent.h
+++ b/lib/events/keyverificationevent.h
@@ -13,7 +13,7 @@ static constexpr auto SasV1Method = "m.sas.v1"_ls;
/// Typically sent as a to-device event.
class QUOTIENT_API KeyVerificationRequestEvent : public Event {
public:
- DEFINE_EVENT_TYPEID("m.key.verification.request", KeyVerificationRequestEvent)
+ QUO_EVENT(KeyVerificationRequestEvent, "m.key.verification.request")
explicit KeyVerificationRequestEvent(const QJsonObject& obj)
: Event(TypeId, obj)
@@ -45,11 +45,10 @@ public:
/// by the receiver.
QUO_CONTENT_GETTER(QDateTime, timestamp)
};
-REGISTER_EVENT_TYPE(KeyVerificationRequestEvent)
class QUOTIENT_API KeyVerificationReadyEvent : public Event {
public:
- DEFINE_EVENT_TYPEID("m.key.verification.ready", KeyVerificationReadyEvent)
+ QUO_EVENT(KeyVerificationReadyEvent, "m.key.verification.ready")
explicit KeyVerificationReadyEvent(const QJsonObject& obj)
: Event(TypeId, obj)
@@ -72,13 +71,11 @@ public:
/// The verification methods supported by the sender.
QUO_CONTENT_GETTER(QStringList, methods)
};
-REGISTER_EVENT_TYPE(KeyVerificationReadyEvent)
-
/// Begins a key verification process.
class QUOTIENT_API KeyVerificationStartEvent : public Event {
public:
- DEFINE_EVENT_TYPEID("m.key.verification.start", KeyVerificationStartEvent)
+ QUO_EVENT(KeyVerificationStartEvent, "m.key.verification.start")
explicit KeyVerificationStartEvent(const QJsonObject& obj)
: Event(TypeId, obj)
@@ -146,13 +143,12 @@ public:
return contentPart<QString>("short_authentification_string"_ls);
}
};
-REGISTER_EVENT_TYPE(KeyVerificationStartEvent)
/// Accepts a previously sent m.key.verification.start message.
/// Typically sent as a to-device event.
class QUOTIENT_API KeyVerificationAcceptEvent : public Event {
public:
- DEFINE_EVENT_TYPEID("m.key.verification.accept", KeyVerificationAcceptEvent)
+ QUO_EVENT(KeyVerificationAcceptEvent, "m.key.verification.accept")
explicit KeyVerificationAcceptEvent(const QJsonObject& obj)
: Event(TypeId, obj)
@@ -199,11 +195,10 @@ public:
/// canonical JSON representation of the m.key.verification.start message.
QUO_CONTENT_GETTER(QString, commitment)
};
-REGISTER_EVENT_TYPE(KeyVerificationAcceptEvent)
class QUOTIENT_API KeyVerificationCancelEvent : public Event {
public:
- DEFINE_EVENT_TYPEID("m.key.verification.cancel", KeyVerificationCancelEvent)
+ QUO_EVENT(KeyVerificationCancelEvent, "m.key.verification.cancel")
explicit KeyVerificationCancelEvent(const QJsonObject& obj)
: Event(TypeId, obj)
@@ -228,13 +223,12 @@ public:
/// The error code for why the process/request was cancelled by the user.
QUO_CONTENT_GETTER(QString, code)
};
-REGISTER_EVENT_TYPE(KeyVerificationCancelEvent)
/// Sends the ephemeral public key for a device to the partner device.
/// Typically sent as a to-device event.
class QUOTIENT_API KeyVerificationKeyEvent : public Event {
public:
- DEFINE_EVENT_TYPEID("m.key.verification.key", KeyVerificationKeyEvent)
+ QUO_EVENT(KeyVerificationKeyEvent, "m.key.verification.key")
explicit KeyVerificationKeyEvent(const QJsonObject& obj)
: Event(TypeId, obj)
@@ -251,12 +245,11 @@ public:
/// The device's ephemeral public key, encoded as unpadded base64.
QUO_CONTENT_GETTER(QString, key)
};
-REGISTER_EVENT_TYPE(KeyVerificationKeyEvent)
/// Sends the MAC of a device's key to the partner device.
class QUOTIENT_API KeyVerificationMacEvent : public Event {
public:
- DEFINE_EVENT_TYPEID("m.key.verification.mac", KeyVerificationMacEvent)
+ QUO_EVENT(KeyVerificationMacEvent, "m.key.verification.mac")
explicit KeyVerificationMacEvent(const QJsonObject& obj)
: Event(TypeId, obj)
@@ -280,11 +273,10 @@ public:
return contentPart<QHash<QString, QString>>("mac"_ls);
}
};
-REGISTER_EVENT_TYPE(KeyVerificationMacEvent)
class QUOTIENT_API KeyVerificationDoneEvent : public Event {
public:
- DEFINE_EVENT_TYPEID("m.key.verification.done", KeyVerificationDoneEvent)
+ QUO_EVENT(KeyVerificationDoneEvent, "m.key.verification.done")
explicit KeyVerificationDoneEvent(const QJsonObject& obj)
: Event(TypeId, obj)
@@ -297,6 +289,4 @@ public:
/// The same transactionId as before
QUO_CONTENT_GETTER(QString, transactionId)
};
-REGISTER_EVENT_TYPE(KeyVerificationDoneEvent)
-
} // namespace Quotient
diff --git a/lib/events/receiptevent.h b/lib/events/receiptevent.h
index 5e077e47..a02f4592 100644
--- a/lib/events/receiptevent.h
+++ b/lib/events/receiptevent.h
@@ -21,11 +21,10 @@ using EventsWithReceipts = QVector<ReceiptsForEvent>;
class QUOTIENT_API ReceiptEvent : public Event {
public:
- DEFINE_EVENT_TYPEID("m.receipt", ReceiptEvent)
+ QUO_EVENT(ReceiptEvent, "m.receipt")
explicit ReceiptEvent(const EventsWithReceipts& ewrs);
explicit ReceiptEvent(const QJsonObject& obj) : Event(typeId(), obj) {}
EventsWithReceipts eventsWithReceipts() const;
};
-REGISTER_EVENT_TYPE(ReceiptEvent)
} // namespace Quotient
diff --git a/lib/events/redactionevent.h b/lib/events/redactionevent.h
index 63617e54..c193054a 100644
--- a/lib/events/redactionevent.h
+++ b/lib/events/redactionevent.h
@@ -8,7 +8,7 @@
namespace Quotient {
class QUOTIENT_API RedactionEvent : public RoomEvent {
public:
- DEFINE_EVENT_TYPEID("m.room.redaction", RedactionEvent)
+ QUO_EVENT(RedactionEvent, "m.room.redaction")
explicit RedactionEvent(const QJsonObject& obj) : RoomEvent(typeId(), obj)
{}
@@ -19,5 +19,4 @@ public:
}
QUO_CONTENT_GETTER(QString, reason)
};
-REGISTER_EVENT_TYPE(RedactionEvent)
} // namespace Quotient
diff --git a/lib/events/roomavatarevent.h b/lib/events/roomavatarevent.h
index af291696..2ebe29bf 100644
--- a/lib/events/roomavatarevent.h
+++ b/lib/events/roomavatarevent.h
@@ -14,7 +14,7 @@ class QUOTIENT_API RoomAvatarEvent
// without a thumbnail. But The Spec says there be thumbnails, and
// we follow The Spec.
public:
- DEFINE_EVENT_TYPEID("m.room.avatar", RoomAvatarEvent)
+ QUO_EVENT(RoomAvatarEvent, "m.room.avatar")
explicit RoomAvatarEvent(const QJsonObject& obj) : StateEvent(typeId(), obj)
{}
explicit RoomAvatarEvent(const EventContent::ImageContent& avatar)
@@ -31,5 +31,4 @@ public:
QUrl url() const { return content().url(); }
};
-REGISTER_EVENT_TYPE(RoomAvatarEvent)
} // namespace Quotient
diff --git a/lib/events/roomcanonicalaliasevent.h b/lib/events/roomcanonicalaliasevent.h
index 60ca68ac..e1c7888e 100644
--- a/lib/events/roomcanonicalaliasevent.h
+++ b/lib/events/roomcanonicalaliasevent.h
@@ -34,7 +34,7 @@ inline auto toJson(const EventContent::AliasesEventContent& c)
class QUOTIENT_API RoomCanonicalAliasEvent
: public StateEvent<EventContent::AliasesEventContent> {
public:
- DEFINE_EVENT_TYPEID("m.room.canonical_alias", RoomCanonicalAliasEvent)
+ QUO_EVENT(RoomCanonicalAliasEvent, "m.room.canonical_alias")
explicit RoomCanonicalAliasEvent(const QJsonObject& obj)
: StateEvent(typeId(), obj)
@@ -55,5 +55,4 @@ public:
QString alias() const { return content().canonicalAlias; }
QStringList altAliases() const { return content().altAliases; }
};
-REGISTER_EVENT_TYPE(RoomCanonicalAliasEvent)
} // namespace Quotient
diff --git a/lib/events/roomcreateevent.h b/lib/events/roomcreateevent.h
index 989030ac..f22752b4 100644
--- a/lib/events/roomcreateevent.h
+++ b/lib/events/roomcreateevent.h
@@ -9,7 +9,7 @@
namespace Quotient {
class QUOTIENT_API RoomCreateEvent : public StateEventBase {
public:
- DEFINE_EVENT_TYPEID("m.room.create", RoomCreateEvent)
+ QUO_EVENT(RoomCreateEvent, "m.room.create")
explicit RoomCreateEvent(const QJsonObject& obj)
: StateEventBase(typeId(), obj)
@@ -26,5 +26,4 @@ public:
bool isUpgrade() const;
RoomType roomType() const;
};
-REGISTER_EVENT_TYPE(RoomCreateEvent)
} // namespace Quotient
diff --git a/lib/events/roomevent.h b/lib/events/roomevent.h
index 9461340b..532e72e2 100644
--- a/lib/events/roomevent.h
+++ b/lib/events/roomevent.h
@@ -10,10 +10,11 @@
namespace Quotient {
class RedactionEvent;
-/** This class corresponds to m.room.* events */
+// That check could look into Event and find most stuff already deleted...
+// NOLINTNEXTLINE(cppcoreguidelines-special-member-functions)
class QUOTIENT_API RoomEvent : public Event {
public:
- static inline EventFactory<RoomEvent> factory { "RoomEvent" };
+ QUO_BASE_EVENT(RoomEvent, {}, Event::BaseMetaType)
// RedactionEvent is an incomplete type here so we cannot inline
// constructors and destructors and we cannot use 'using'.
@@ -80,21 +81,14 @@ using RoomEventPtr = event_ptr_tt<RoomEvent>;
using RoomEvents = EventsArray<RoomEvent>;
using RoomEventsRange = Range<RoomEvents>;
-template <>
-inline EventPtr doLoadEvent(const QJsonObject& json, const QString& matrixType)
-{
- if (matrixType == "m.room.encrypted")
- return RoomEvent::factory.loadEvent(json, matrixType);
- return Event::factory.loadEvent(json, matrixType);
-}
-
class QUOTIENT_API CallEventBase : public RoomEvent {
public:
+ QUO_BASE_EVENT(CallEventBase, "m.call.*"_ls, RoomEvent::BaseMetaType)
+
CallEventBase(Type type, event_mtype_t matrixType, const QString& callId,
int version, const QJsonObject& contentJson = {});
CallEventBase(Type type, const QJsonObject& json);
~CallEventBase() override = default;
- bool isCallEvent() const override { return true; }
QUO_CONTENT_GETTER(QString, callId)
QUO_CONTENT_GETTER(int, version)
diff --git a/lib/events/roomkeyevent.h b/lib/events/roomkeyevent.h
index 0dfdf383..6883a2a5 100644
--- a/lib/events/roomkeyevent.h
+++ b/lib/events/roomkeyevent.h
@@ -9,7 +9,7 @@ namespace Quotient {
class QUOTIENT_API RoomKeyEvent : public Event
{
public:
- DEFINE_EVENT_TYPEID("m.room_key", RoomKeyEvent)
+ QUO_EVENT(RoomKeyEvent, "m.room_key")
explicit RoomKeyEvent(const QJsonObject& obj);
explicit RoomKeyEvent(const QString& algorithm, const QString& roomId,
@@ -23,5 +23,4 @@ public:
return contentPart<QString>("session_key"_ls).toLatin1();
}
};
-REGISTER_EVENT_TYPE(RoomKeyEvent)
} // namespace Quotient
diff --git a/lib/events/roommemberevent.h b/lib/events/roommemberevent.h
index dd33ea6b..c690586e 100644
--- a/lib/events/roommemberevent.h
+++ b/lib/events/roommemberevent.h
@@ -31,7 +31,7 @@ using MembershipType [[deprecated("Use Membership instead")]] = Membership;
class QUOTIENT_API RoomMemberEvent : public StateEvent<MemberEventContent> {
Q_GADGET
public:
- DEFINE_EVENT_TYPEID("m.room.member", RoomMemberEvent)
+ QUO_EVENT(RoomMemberEvent, "m.room.member")
using MembershipType
[[deprecated("Use Quotient::Membership instead")]] = Membership;
@@ -79,14 +79,4 @@ public:
bool isRename() const;
bool isAvatarUpdate() const;
};
-
-template <>
-inline event_ptr_tt<RoomMemberEvent>
-doLoadEvent<RoomMemberEvent>(const QJsonObject& json, const QString& matrixType)
-{
- if (matrixType == QLatin1String(RoomMemberEvent::matrixTypeId()))
- return makeEvent<RoomMemberEvent>(json);
- return makeEvent<RoomMemberEvent>(unknownEventTypeId(), json);
-}
-REGISTER_EVENT_TYPE(RoomMemberEvent)
} // namespace Quotient
diff --git a/lib/events/roommessageevent.h b/lib/events/roommessageevent.h
index 6968ad70..889fc4dc 100644
--- a/lib/events/roommessageevent.h
+++ b/lib/events/roommessageevent.h
@@ -20,7 +20,7 @@ namespace MessageEventContent = EventContent; // Back-compatibility
class QUOTIENT_API RoomMessageEvent : public RoomEvent {
Q_GADGET
public:
- DEFINE_EVENT_TYPEID("m.room.message", RoomMessageEvent)
+ QUO_EVENT(RoomMessageEvent, "m.room.message")
enum class MsgType {
Text,
@@ -94,7 +94,7 @@ private:
Q_ENUM(MsgType)
};
-REGISTER_EVENT_TYPE(RoomMessageEvent)
+
using MessageEventType = RoomMessageEvent::MsgType;
namespace EventContent {
diff --git a/lib/events/roompowerlevelsevent.h b/lib/events/roompowerlevelsevent.h
index a1638a27..7ac12db0 100644
--- a/lib/events/roompowerlevelsevent.h
+++ b/lib/events/roompowerlevelsevent.h
@@ -33,7 +33,7 @@ struct QUOTIENT_API PowerLevelsEventContent {
class QUOTIENT_API RoomPowerLevelsEvent
: public StateEvent<PowerLevelsEventContent> {
public:
- DEFINE_EVENT_TYPEID("m.room.power_levels", RoomPowerLevelsEvent)
+ QUO_EVENT(RoomPowerLevelsEvent, "m.room.power_levels")
explicit RoomPowerLevelsEvent(PowerLevelsEventContent&& content)
: StateEvent(typeId(), matrixTypeId(), QString(), std::move(content))
@@ -61,5 +61,4 @@ public:
int powerLevelForState(const QString& eventId) const;
int powerLevelForUser(const QString& userId) const;
};
-REGISTER_EVENT_TYPE(RoomPowerLevelsEvent)
} // namespace Quotient
diff --git a/lib/events/roomtombstoneevent.h b/lib/events/roomtombstoneevent.h
index 15d26923..97586587 100644
--- a/lib/events/roomtombstoneevent.h
+++ b/lib/events/roomtombstoneevent.h
@@ -8,7 +8,7 @@
namespace Quotient {
class QUOTIENT_API RoomTombstoneEvent : public StateEventBase {
public:
- DEFINE_EVENT_TYPEID("m.room.tombstone", RoomTombstoneEvent)
+ QUO_EVENT(RoomTombstoneEvent, "m.room.tombstone")
explicit RoomTombstoneEvent(const QJsonObject& obj)
: StateEventBase(typeId(), obj)
@@ -17,5 +17,4 @@ public:
QString serverMessage() const;
QString successorRoomId() const;
};
-REGISTER_EVENT_TYPE(RoomTombstoneEvent)
} // namespace Quotient
diff --git a/lib/events/simplestateevents.h b/lib/events/simplestateevents.h
index a8eaab56..c79d03b0 100644
--- a/lib/events/simplestateevents.h
+++ b/lib/events/simplestateevents.h
@@ -14,7 +14,7 @@ namespace Quotient {
EventContent::SingleKeyValue<_ValueType, &_Name##Key>> { \
public: \
using value_type = _ValueType; \
- DEFINE_EVENT_TYPEID(_TypeId, _Name) \
+ QUO_EVENT(_Name, _TypeId) \
template <typename T> \
explicit _Name(T&& value) \
: StateEvent(TypeId, matrixTypeId(), QString(), \
@@ -25,7 +25,6 @@ namespace Quotient {
{} \
auto _ContentKey() const { return content().value; } \
}; \
- REGISTER_EVENT_TYPE(_Name) \
// End of macro
DEFINE_SIMPLE_STATE_EVENT(RoomNameEvent, "m.room.name", QString, name)
@@ -38,7 +37,7 @@ class QUOTIENT_API RoomAliasesEvent
: public StateEvent<
EventContent::SingleKeyValue<QStringList, &RoomAliasesEventKey>> {
public:
- DEFINE_EVENT_TYPEID("m.room.aliases", RoomAliasesEvent)
+ QUO_EVENT(RoomAliasesEvent, "m.room.aliases")
explicit RoomAliasesEvent(const QJsonObject& obj)
: StateEvent(typeId(), obj)
{}
diff --git a/lib/events/stateevent.h b/lib/events/stateevent.h
index 9f1d7118..74876803 100644
--- a/lib/events/stateevent.h
+++ b/lib/events/stateevent.h
@@ -9,7 +9,12 @@ namespace Quotient {
class QUOTIENT_API StateEventBase : public RoomEvent {
public:
- static inline EventFactory<StateEventBase> factory { "StateEvent" };
+ QUO_BASE_EVENT(StateEventBase, "json.contains('state_key')"_ls,
+ RoomEvent::BaseMetaType)
+ static bool isValid(const QJsonObject& fullJson)
+ {
+ return fullJson.contains(StateKeyKeyL);
+ }
StateEventBase(Type type, const QJsonObject& json);
StateEventBase(Type type, event_mtype_t matrixType,
@@ -27,7 +32,6 @@ public:
{ ContentKey, contentJson } };
}
- bool isStateEvent() const override { return true; }
QString replacedState() const;
void dumpTo(QDebug dbg) const override;
@@ -44,28 +48,6 @@ inline QJsonObject basicStateEventJson(const QString& matrixTypeId,
return StateEventBase::basicJson(matrixTypeId, stateKey, content);
}
-//! \brief Override RoomEvent factory with that from StateEventBase if JSON has
-//! stateKey
-//!
-//! This means in particular that an event with a type known to RoomEvent but
-//! having stateKey set (even to an empty value) will be treated as a state
-//! event and most likely end up as unknown (consider, e.g., m.room.message
-//! that has stateKey set).
-template <>
-inline RoomEventPtr doLoadEvent(const QJsonObject& json,
- const QString& matrixType)
-{
- if (json.contains(StateKeyKeyL))
- return StateEventBase::factory.loadEvent(json, matrixType);
- return RoomEvent::factory.loadEvent(json, matrixType);
-}
-
-template <>
-inline bool is<StateEventBase>(const Event& e)
-{
- return e.isStateEvent();
-}
-
/**
* A combination of event type and state key uniquely identifies a piece
* of state in Matrix.
diff --git a/lib/events/stickerevent.h b/lib/events/stickerevent.h
index e378422d..67905481 100644
--- a/lib/events/stickerevent.h
+++ b/lib/events/stickerevent.h
@@ -14,7 +14,7 @@ namespace Quotient {
class QUOTIENT_API StickerEvent : public RoomEvent
{
public:
- DEFINE_EVENT_TYPEID("m.sticker", StickerEvent)
+ QUO_EVENT(StickerEvent, "m.sticker")
explicit StickerEvent(const QJsonObject& obj)
: RoomEvent(TypeId, obj)
@@ -45,5 +45,4 @@ public:
private:
EventContent::ImageContent m_imageContent;
};
-REGISTER_EVENT_TYPE(StickerEvent)
} // namespace Quotient