libQuotient
A Qt library for building matrix clients
Loading...
Searching...
No Matches
roomstateview.h
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2021 Kitsune Ral <kitsune-ral@users.sf.net>
2// SPDX-License-Identifier: LGPL-2.1-or-later
3
4#pragma once
5
6#include "events/stateevent.h"
8
9#include <QtCore/QHash>
10
11namespace Quotient {
12
13class Room;
14
15// NB: Both concepts below expect EvT::needsStateKey to exist so you can't
16// express one via negation of the other (there's still an invalid case of
17// a non-state event where needsStateKey is not even defined).
18
19template <typename FnT, class EvT = std::decay_t<fn_arg_t<FnT>>>
20concept Keyed_State_Fn = EvT::needsStateKey;
21
22template <typename FnT, class EvT = std::decay_t<fn_arg_t<FnT>>>
23concept Keyless_State_Fn = !EvT::needsStateKey;
24
26 : private QHash<StateEventKey, const StateEvent*> {
28public:
29 const QHash<StateEventKey, const StateEvent*>& events() const
30 {
31 return *this;
32 }
33
34 //! \brief Get a state event with the given event type and state key
35 //! \return A state event corresponding to the pair of event type
36 //! \p evtType and state key \p stateKey, or `nullptr` if there's
37 //! no such \p evtType / \p stateKey combination in the current
38 //! state.
39 //! \warning The returned value is not guaranteed to be non-`nullptr`; you
40 //! MUST check it before using or use other methods of this class
41 //! such as query() and content() to access state safely.
42 //! \sa content, contentJson, query
44 const QString& stateKey = {}) const;
45
46 //! \brief Get a state event with the given event type and state key
47 //!
48 //! This is a typesafe overload that accepts a C++ event type instead of
49 //! its Matrix name. It is only defined for events with state key (i.e.,
50 //! derived from KeyedStateEvent).
51 template <Keyed_State_Event EvT>
52 const EvT* get(const QString& stateKey = {}) const
53 {
54 if (const auto* evt = get(EvT::TypeId, stateKey)) {
56 && evt->stateKey() == stateKey);
57 return eventCast<const EvT>(evt);
58 }
59 return nullptr;
60 }
61
62 //! \brief Get a state event with the given event type
63 //!
64 //! This is a typesafe overload that accepts a C++ event type instead of
65 //! its Matrix name. This overload only defined for events that do not use
66 //! state key (i.e., derived from KeylessStateEvent).
67 template <Keyless_State_Event EvT>
68 const EvT* get() const
69 {
70 if (const auto* evt = get(EvT::TypeId)) {
72 return eventCast<const EvT>(evt);
73 }
74 return nullptr;
75 }
76
77 using QHash::contains;
78
79 bool contains(const QString& evtType, const QString& stateKey = {}) const;
80
81 template <Keyed_State_Event EvT>
82 bool contains(const QString& stateKey = {}) const
83 {
84 return contains(EvT::TypeId, stateKey);
85 }
86
87 template <Keyless_State_Event EvT>
88 bool contains() const
89 {
90 return contains(EvT::TypeId);
91 }
92
93 template <Keyed_State_Event EvT>
95 typename EvT::content_type defaultValue = {}) const
96 {
97 // EventBase<>::content is special in that it returns a const-ref,
98 // and lift() inside queryOr() can't wrap that in a temporary optional.
99 if (const auto evt = get<EvT>(stateKey))
100 return evt->content();
101 return std::move(defaultValue);
102 }
103
104 template <Keyless_State_Event EvT>
105 auto content(typename EvT::content_type defaultValue = {}) const
106 {
107 // Same as above
108 if (const auto evt = get<EvT>())
109 return evt->content();
110 return defaultValue;
111 }
112
113 //! \brief Get the content of the current state event with the given
114 //! event type and state key
115 //! \return An empty object if there's no event in the current state with
116 //! this event type and state key; the contents of the event
117 //! <tt>'content'</tt> object otherwise
119 const QString& stateKey = {}) const;
120
121 //! \brief Get all state events in the room of a certain type
122 //!
123 //! This function allows to retrieve all events of one type regardless of their state key.
124 //! \note To do its job, the function has to look through the entire list of state events
125 //! currently in the room; this may have implications in performance-sensitive code.
126 //! \return all known state events of \p evtType that have occurred in the room
128
129 //! \brief Get all state events in the room of a certain type
130 //!
131 //! This is a type-safe overload for the case when the event type is known at compile time.
132 //! \note This overload is only defined for event types that expect a state key.
133 //! \note Same as the other overload, this one has to look through the entire list of state
134 //! events, although it is slightly faster thanks to the event type known at compile time.
135 //! \return all known state events of type \p EvT that have occurred in the room
136 template <Keyed_State_Event EvT>
137 QVector<const EvT*> eventsOfType() const
138 {
139 using namespace std::ranges::views;
140 return rangeTo<QVector>(filter(*this, &Event::is<EvT>) | transform([](const StateEvent* e) {
141 return static_cast<const EvT*>(e); }));
142 }
143
144 //! \brief Run a function on a state event with the given type and key
145 //!
146 //! Use this overload when there's no predefined event type or the event
147 //! type is unknown at compile time.
148 //! \return an optional with the result of the function call, or std::nullopt if the event
149 //! is not found or \p fn fails
150 template <typename FnT>
151 auto query(const QString& evtType, const QString& stateKey, FnT&& fn) const
152 {
153 return lift(std::forward<FnT>(fn), get(evtType, stateKey));
154 }
155
156 //! \brief Run a function on a state event with the given type and key
157 //!
158 //! This is an overload for keyed state events (those that have
159 //! `needsStateKey == true`) with type defined at compile time.
160 //! \return an optional with the result of the function call, or std::nullopt if the event
161 //! is not found or \p fn fails
162 template <Keyed_State_Fn FnT>
163 auto query(const QString& stateKey, FnT&& fn) const
164 {
165 using EventT = std::decay_t<fn_arg_t<FnT>>;
166 return lift(std::forward<FnT>(fn), get<EventT>(stateKey));
167 }
168
169 //! \brief Run a function on a keyless state event with the given type
170 //!
171 //! This is an overload for keyless state events (those having
172 //! `needsStateKey == false`) with type defined at compile time.
173 //! \return an optional with the result of the function call, or std::nullopt if the event
174 //! is not found or \p fn fails
175 template <Keyless_State_Fn FnT>
176 auto query(FnT&& fn) const
177 {
178 using EventT = std::decay_t<fn_arg_t<FnT>>;
179 return lift(std::forward<FnT>(fn), get<EventT>());
180 }
181
182 //! \brief Run a function on each event of the given type
183 //!
184 //! This is effectively a combination of query and eventsOfType() except that it doesn't create
185 //! a new container. The return value of \p FnT is ignored.
186 template <Keyed_State_Fn FnT>
187 void queryAll(FnT&& fn) const
188 {
189 using EventT = std::decay_t<fn_arg_t<FnT>>;
190 for (const auto* e : std::ranges::filter_view(events(), &Event::is<EventT>))
191 fn(static_cast<const EventT&>(*e));
192 }
193
194 //! \brief Same as query() but with a fallback value
195 //!
196 //! This is a shortcut for `query().value_or()`, passing respective
197 //! arguments to the respective functions. This is an overload for the case
198 //! when the event type cannot be fixed at compile time.
199 //! \return the result of \p fn execution, or \p fallback if the requested
200 //! event doesn't exist or the function fails
201 template <typename FnT, typename FallbackT>
202 auto queryOr(const QString& evtType, const QString& stateKey, FnT&& fn,
203 FallbackT&& fallback) const
204 {
205 return query(evtType, stateKey, std::forward<FnT>(fn))
207 }
208
209 //! \brief Same as query() but with a fallback value
210 //!
211 //! This is a shortcut for `query().value_or()`, passing respective
212 //! arguments to the respective functions. This is an overload for the case
213 //! when the event type cannot be fixed at compile time.
214 //! \return the result of \p fn execution, or \p fallback if the requested
215 //! event doesn't exist or the function fails
216 template <typename FnT, typename FallbackT>
217 auto queryOr(const QString& stateKey, FnT&& fn, FallbackT&& fallback) const
218 {
219 return query(stateKey, std::forward<FnT>(fn))
221 }
222
223 //! \brief Same as query() but with a fallback value
224 //!
225 //! This is a shortcut for `query().value_or()`, passing respective
226 //! arguments to the respective functions. This is an overload for the case
227 //! when the event type cannot be fixed at compile time.
228 //! \return the result of \p fn execution, or \p fallback if the requested
229 //! event doesn't exist or the function fails
230 template <typename FnT, typename FallbackT>
231 auto queryOr(FnT&& fn, FallbackT&& fallback) const
232 {
233 return query(std::forward<FnT>(fn))
235 }
236
237private:
238 friend class Room; // Factory class for RoomStateView
239 using QHash<StateEventKey, const StateEvent*>::QHash;
240};
241} // namespace Quotient
#define QUOTIENT_API