8 #include <Quotient/converters.h>
9 #include <Quotient/function_traits.h>
16 template <
typename EventT>
17 using event_ptr_tt = std::unique_ptr<EventT>;
21 constexpr inline auto TypeKey =
"type"_L1;
22 constexpr inline auto ContentKey =
"content"_L1;
23 constexpr inline auto SenderKey =
"sender"_L1;
24 constexpr inline auto UnsignedKey =
"unsigned"_L1;
26 using event_type_t = QLatin1String;
32 template <
typename EventT,
typename BaseEventT = Event>
33 concept EventClass = std::derived_from<EventT, BaseEventT>;
35 template <EventClass EventT>
36 bool is(
const Event& e);
46 const char*
const className;
47 const AbstractEventMetaType*
const baseType;
48 const event_type_t matrixId;
51 explicit AbstractEventMetaType(
const char* className,
52 AbstractEventMetaType* nearestBase =
nullptr,
53 const char* matrixId =
nullptr)
54 : className(className), baseType(nearestBase), matrixId(matrixId)
57 nearestBase->addDerived(
this);
60 void addDerived(
const AbstractEventMetaType* newType);
61 auto derivedTypes()
const {
return std::span(_derivedTypes); }
63 virtual ~AbstractEventMetaType() =
default;
67 template <
class EventT>
68 friend class EventMetaType;
72 virtual bool doLoadFrom(
const QJsonObject& fullJson,
const QString& type,
73 Event*& event)
const = 0;
76 std::vector<
const AbstractEventMetaType*> _derivedTypes{};
77 Q_DISABLE_COPY_MOVE(AbstractEventMetaType)
82 inline bool operator==(
const AbstractEventMetaType& lhs,
83 const AbstractEventMetaType& rhs)
98 template <
class EventT>
103 using AbstractEventMetaType::AbstractEventMetaType;
135 event_ptr_tt<EventT> loadFrom(
const QJsonObject& fullJson,
136 const QString& type)
const
138 Event* event =
nullptr;
139 const bool goodEnough = doLoadFrom(fullJson, type, event);
140 if (!event && goodEnough)
141 return event_ptr_tt<EventT>{
new EventT(fullJson) };
142 return event_ptr_tt<EventT>{
static_cast<EventT*>(event) };
146 bool doLoadFrom(
const QJsonObject& fullJson,
const QString& type,
147 Event*& event)
const override
149 if constexpr (requires { EventT::TypeId; }) {
150 if (EventT::TypeId != type)
153 for (
const auto& p : _derivedTypes) {
154 p->doLoadFrom(fullJson, type, event);
156 Q_ASSERT(is<EventT>(*event));
161 if constexpr (requires { EventT::isValid; }) {
162 if (!EventT::isValid(fullJson))
164 }
else if constexpr (!requires { EventT::TypeId; })
166 event =
new EventT(fullJson);
177 template <EventClass EventT,
typename... ArgTs>
178 inline event_ptr_tt<EventT> makeEvent(ArgTs&&... args)
180 return std::make_unique<EventT>(std::forward<ArgTs>(args)...);
183 template <EventClass EventT>
184 constexpr const auto& mostSpecificMetaType()
186 if constexpr (requires { EventT::MetaType; })
187 return EventT::MetaType;
189 return EventT::BaseMetaType;
197 template <EventClass EventT>
198 inline event_ptr_tt<EventT> loadEvent(
const QJsonObject& fullJson)
200 return mostSpecificMetaType<EventT>().loadFrom(
201 fullJson, fullJson[TypeKey].toString());
209 template <EventClass EventT>
210 inline event_ptr_tt<EventT> loadEvent(
const QString& matrixType,
211 const auto&... otherBasicJsonParams)
213 return mostSpecificMetaType<EventT>().loadFrom(
214 EventT::basicJson(matrixType, otherBasicJsonParams...), matrixType);
217 template <EventClass EventT>
218 struct JsonConverter<event_ptr_tt<EventT>>
219 : JsonObjectUnpacker<event_ptr_tt<EventT>> {
222 using JsonObjectUnpacker<event_ptr_tt<EventT>>::load;
223 static auto load(
const QJsonObject& jo)
225 return loadEvent<EventT>(jo);
233 static inline EventMetaType<Event> BaseMetaType {
"Event" };
234 virtual const AbstractEventMetaType& metaType()
const
239 Q_DISABLE_COPY(Event)
240 Event(Event&&)
noexcept =
default;
241 Event& operator=(Event&&) =
delete;
245 static QJsonObject basicJson(
const QString& matrixType,
246 const QJsonObject& content)
248 return { { TypeKey, matrixType }, { ContentKey, content } };
252 QString matrixType()
const;
254 template <EventClass EventT>
257 return Quotient::is<EventT>(*
this);
288 template <
typename... VisitorTs>
289 auto switchOnType(VisitorTs&&... visitors)
const;
291 const QJsonObject& fullJson()
const {
return _json; }
300 const QJsonObject contentJson()
const;
307 template <
typename T,
typename KeyT>
308 const T contentPart(KeyT&& key)
const
310 return fromJson<T>(contentJson()[std::forward<KeyT>(key)]);
313 const QJsonObject unsignedJson()
const;
320 template <
typename T,
typename KeyT>
321 const T unsignedPart(KeyT&& key)
const
323 return fromJson<T>(unsignedJson()[std::forward<KeyT>(key)]);
328 const QDebugStateSaver _dss { dbg };
329 dbg.noquote().nospace()
330 << e.matrixType() <<
'(' << e.metaType().className <<
"): ";
335 #if Quotient_VERSION_MAJOR == 0
&& Quotient_VERSION_MINOR <= 9
336 [[deprecated(
"isStateEvent() has moved to RoomEvent")]]
bool isStateEvent()
const;
340 friend class EventMetaType<Event>;
342 explicit Event(
const QJsonObject& json);
344 QJsonObject& editJson() {
return _json; }
345 virtual void dumpTo(QDebug dbg)
const;
350 using EventPtr = event_ptr_tt<Event>;
352 template <EventClass EventT>
353 using EventsArray = std::vector<event_ptr_tt<EventT>>;
354 using Events = EventsArray<Event>;
375 template <
typename EventT, EventClass BaseEventT,
typename ContentT =
void>
376 class EventTemplate :
public BaseEventT {
381 !std::is_same_v<ContentT,
void>,
382 "If you see this, you tried to use EventTemplate with the default"
383 " ContentT type, which is void. This default is only used with explicit"
384 " specialisations (see CallEvent, e.g.). Otherwise, if you don't intend"
385 " to use the content part of EventTemplate then you don't need"
386 " EventTemplate; just use the base event class directly");
387 using content_type = ContentT;
389 explicit EventTemplate(
const QJsonObject& json)
392 explicit EventTemplate(
const ContentT& c)
393 : BaseEventT(EventT::basicJson(EventT::TypeId, toJson(c)))
396 ContentT content()
const {
return fromJson<ContentT>(
this->contentJson()); }
408 #define QUO_BASE_EVENT(CppType_, BaseCppType_, ...)
409 friend class EventMetaType<CppType_>;
410 static inline EventMetaType<CppType_> BaseMetaType{
411 #CppType_, &BaseCppType_::BaseMetaType __VA_OPT__(, ) __VA_ARGS__
413 static_assert(&CppType_::BaseMetaType == &BaseMetaType,
414 #CppType_ " is wrong here - check for copy-pasta");
415 const AbstractEventMetaType& metaType() const override
436 #define QUO_EVENT(CppType_, MatrixType_)
437 friend class EventMetaType<CppType_>;
438 static inline const EventMetaType<CppType_> MetaType{ #CppType_,
441 static_assert(&CppType_::MetaType == &MetaType,
442 #CppType_ " is wrong here - check for copy-pasta");
443 static inline const auto& TypeId = MetaType.matrixId;
444 const AbstractEventMetaType& metaType() const override
450 #define QUO_CONTENT_GETTER_X(PartType_, PartName_, JsonKey_)
451 PartType_ PartName_() const
453 static const auto PartName_##JsonKey = JsonKey_;
454 return contentPart<PartType_>(PartName_##JsonKey);
465 #define QUO_CONTENT_GETTER(PartType_, PartName_)
476 #define DEFINE_SIMPLE_EVENT(Name_, Base_, TypeId_, ValueType_, GetterName_, JsonKey_)
477 constexpr inline auto Name_##ContentKey = JsonKey_##_L1;
479 : public ::Quotient::EventTemplate<
480 Name_, Base_, EventContent::SingleKeyValue<ValueType_, Name_##ContentKey>> {
483 using value_type = ValueType_;
484 using EventTemplate::EventTemplate;
491 template <EventClass EventT>
492 inline bool is(
const Event& e)
495 static_assert(requires { &EventT::metaType; },
496 "Event class doesn't have a public metaType() override - "
497 "did you misplace the QUO_*EVENT macro?");
498 if constexpr (requires { EventT::MetaType; }) {
499 return &e.metaType() == &EventT::MetaType;
501 const auto* p = &e.metaType();
503 if (p == &EventT::BaseMetaType)
505 }
while ((p = p->baseType) !=
nullptr);
517 template <EventClass EventT,
typename BasePtrT>
518 inline auto eventCast(
const BasePtrT& eptr)
519 ->
decltype(
static_cast<EventT*>(std::to_address(eptr)))
521 return eptr && is<std::decay_t<EventT>>(*eptr)
522 ?
static_cast<EventT*>(std::to_address(eptr))
540 template <EventClass EventT,
typename BaseEventT>
541 inline auto eventCast(event_ptr_tt<BaseEventT>&& eptr)
543 return eptr && is<std::decay_t<EventT>>(*eptr)
544 ? event_ptr_tt<EventT>(
static_cast<EventT*>(eptr.release()))
549 template <
typename FnT,
typename BaseT>
550 concept Invocable_With_Downcast =
551 EventClass<BaseT> && std::derived_from<std::remove_cvref_t<fn_arg_t<FnT>>, BaseT>;
554 template <EventClass BaseT,
typename TailT>
555 inline auto switchOnType(
const BaseT& event, TailT&& tail)
557 if constexpr (std::is_invocable_v<TailT, BaseT>) {
559 }
else if constexpr (_impl::Invocable_With_Downcast<TailT, BaseT>) {
560 using event_type = fn_arg_t<TailT>;
561 if (is<std::decay_t<event_type>>(event))
562 return tail(
static_cast<event_type>(event));
563 return std::invoke_result_t<TailT, event_type>();
565 return std::forward<TailT>(tail);
569 template <
typename FnT1,
typename... FnTs>
570 inline auto switchOnType(
const EventClass
auto& event, FnT1&& fn1, FnTs&&... fns)
572 using event_type1 = fn_arg_t<FnT1>;
573 if (is<std::decay_t<event_type1>>(event))
574 return fn1(
static_cast<event_type1>(event));
575 return switchOnType(event, std::forward<FnTs>(fns)...);
578 template <
typename... VisitorTs>
579 inline auto Event::switchOnType(VisitorTs&&... visitors)
const
581 return Quotient::switchOnType(*
this,
582 std::forward<VisitorTs>(visitors)...);
586 Q_DECLARE_METATYPE(Quotient::Event*)
587 Q_DECLARE_METATYPE(
const Quotient::Event*)