libQuotient
A Qt library for building matrix clients
Loading...
Searching...
No Matches
stateevent.h
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2018 Kitsune Ral <kitsune-ral@users.sf.net>
2// SPDX-License-Identifier: LGPL-2.1-or-later
3
4#pragma once
5
6#include "roomevent.h"
7
8namespace Quotient {
9
10constexpr inline auto PrevContentKey = "prev_content"_L1;
11
12class QUOTIENT_API StateEvent : public RoomEvent {
13public:
14 QUO_BASE_EVENT(StateEvent, RoomEvent, "json.contains('state_key')")
15
16 static bool isValid(const QJsonObject& fullJson)
17 {
18 return fullJson.contains(StateKeyKey);
19 }
20
21 //! \brief Static setting of whether a given even type uses state keys
22 //!
23 //! Most event types don't use a state key; overriding this to `true`
24 //! for a given type changes the calls across Quotient to include state key
25 //! in their signatures; otherwise, state key is still accessible but
26 //! constructors and calls in, e.g., RoomStateView don't include it.
27 static constexpr auto needsStateKey = false;
28
29 explicit StateEvent(event_type_t type, const QString& stateKey = {},
30 const QJsonObject& contentJson = {});
31
32 //! Make a minimal correct Matrix state event JSON
33 static QJsonObject basicJson(const QString& matrixTypeId,
34 const QString& stateKey = {},
35 const QJsonObject& contentJson = {})
36 {
37 return { { TypeKey, matrixTypeId },
38 { StateKeyKey, stateKey },
39 { ContentKey, contentJson } };
40 }
41
42 QString replacedState() const;
43 virtual bool repeatsState() const;
44
45protected:
46 explicit StateEvent(const QJsonObject& json);
47 void dumpTo(QDebug dbg) const override;
48};
49using StateEventPtr = event_ptr_tt<StateEvent>;
50using StateEvents = EventsArray<StateEvent>;
51
52/**
53 * A combination of event type and state key uniquely identifies a piece
54 * of state in Matrix.
55 * \sa
56 * https://matrix.org/docs/spec/client_server/unstable.html#types-of-room-events
57 */
58using StateEventKey = std::pair<QString, QString>;
59
60template <typename EventT, typename ContentT>
61class EventTemplate<EventT, StateEvent, ContentT>
62 : public StateEvent {
63public:
64 using content_type = ContentT;
65
66 struct Prev {
67 explicit Prev() = default;
68 explicit Prev(const QJsonObject& unsignedJson)
69 : senderId(fromJson<QString>(unsignedJson["prev_sender"_L1]))
70 , content(fromJson<std::optional<ContentT>>(unsignedJson[PrevContentKey]))
71 {}
72
73 QString senderId;
74 std::optional<ContentT> content;
75 };
76
77 explicit EventTemplate(const QJsonObject& fullJson)
78 : StateEvent(fullJson)
79 , _content(fromJson<ContentT>(Event::contentJson()))
80 , _prev(unsignedJson())
81 {}
82 template <typename... ContentParamTs>
83 explicit EventTemplate(const QString& stateKey,
84 ContentParamTs&&... contentParams)
85 : StateEvent(EventT::TypeId, stateKey)
86 , _content { std::forward<ContentParamTs>(contentParams)... }
87 {
88 editJson().insert(ContentKey, toJson(_content));
89 }
90
91 const ContentT& content() const { return _content; }
92
93 template <typename VisitorT>
94 void editContent(VisitorT&& visitor)
95 {
96 visitor(_content);
97 editJson()[ContentKey] = toJson(_content);
98 }
99 const std::optional<ContentT>& prevContent() const { return _prev.content; }
100 QString prevSenderId() const { return _prev.senderId; }
101
102private:
103 ContentT _content;
104 Prev _prev;
105};
106
107template <typename EventT, typename ContentT>
108class KeyedStateEventBase
109 : public EventTemplate<EventT, StateEvent, ContentT> {
110public:
111 static constexpr auto needsStateKey = true;
112
113 using EventTemplate<EventT, StateEvent, ContentT>::EventTemplate;
114};
115
116template <typename EvT>
117concept Keyed_State_Event = EvT::needsStateKey;
118
119template <typename EventT, typename ContentT>
120class KeylessStateEventBase
121 : public EventTemplate<EventT, StateEvent, ContentT> {
122private:
123 using base_type = EventTemplate<EventT, StateEvent, ContentT>;
124
125public:
126 template <typename... ContentParamTs>
127 // Ideally, we want to check std::constructible_from<ContentT, ContentParamTs...> -
128 // unfortunately, Xcode 15.4 still thinks that, e.g., AliasEventContent is not constructible
129 // from QString and QStringList, so we have to make the check slightly indirect
130 requires std::constructible_from<base_type, QString, ContentParamTs...>
131 explicit KeylessStateEventBase(ContentParamTs&&... contentParams)
132 : base_type(QString(), std::forward<ContentParamTs>(contentParams)...)
133 {}
134
135protected:
136 explicit KeylessStateEventBase(const QJsonObject& fullJson)
137 : base_type(fullJson)
138 {}
139};
140
141template <typename EvT>
142concept Keyless_State_Event = !EvT::needsStateKey;
143
144} // namespace Quotient
145Q_DECLARE_METATYPE(Quotient::StateEvent*)
146Q_DECLARE_METATYPE(const Quotient::StateEvent*)
147
148// https://stackoverflow.com/questions/68320024/why-did-the-c-standards-committee-not-include-stdhash-for-pair-and-tuple
149template <>
150struct std::hash<Quotient::StateEventKey> {
151 size_t operator()(const Quotient::StateEventKey& k) const
152 {
153 return qHash(k, QHashSeed::globalSeed());
154 }
155};
#define QUO_BASE_EVENT(CppType_, BaseCppType_,...)
Supply event metatype information in base event types.
Definition event.h:408
#define QUOTIENT_API