aboutsummaryrefslogtreecommitdiff
path: root/lib/roomstateview.h
diff options
context:
space:
mode:
Diffstat (limited to 'lib/roomstateview.h')
-rw-r--r--lib/roomstateview.h145
1 files changed, 114 insertions, 31 deletions
diff --git a/lib/roomstateview.h b/lib/roomstateview.h
index 29cce00e..c5261a1e 100644
--- a/lib/roomstateview.h
+++ b/lib/roomstateview.h
@@ -11,11 +11,21 @@ namespace Quotient {
class Room;
+// NB: Both concepts below expect EvT::needsStateKey to exist so you can't
+// express one via negation of the other (there's still an invalid case of
+// a non-state event where needsStateKey is not even defined).
+
+template <typename FnT, class EvT = std::decay_t<fn_arg_t<FnT>>>
+concept Keyed_State_Fn = EvT::needsStateKey;
+
+template <typename FnT, class EvT = std::decay_t<fn_arg_t<FnT>>>
+concept Keyless_State_Fn = !EvT::needsStateKey;
+
class QUOTIENT_API RoomStateView
- : private QHash<StateEventKey, const StateEventBase*> {
+ : private QHash<StateEventKey, const StateEvent*> {
Q_GADGET
public:
- const QHash<StateEventKey, const StateEventBase*>& events() const
+ const QHash<StateEventKey, const StateEvent*>& events() const
{
return *this;
}
@@ -30,37 +40,74 @@ public:
//! have to check that it has_value() before using. Alternatively
//! you can now use queryCurrentState() to access state safely.
//! \sa getCurrentStateContentJson
- const StateEventBase* get(const QString& evtType,
- const QString& stateKey = {}) const;
+ const StateEvent* get(const QString& evtType,
+ const QString& stateKey = {}) const;
//! \brief Get a state event with the given event type and state key
//!
//! This is a typesafe overload that accepts a C++ event type instead of
- //! its Matrix name.
- //! \warning In libQuotient 0.7 the return type changed to an Omittable with
- //! a reference wrapper inside - you have to check that it
- //! has_value() before using. Alternatively you can now use
- //! queryCurrentState() to access state safely.
- template <typename EvT>
+ //! its Matrix name. It is only defined for events with state key (i.e.,
+ //! derived from KeyedStateEvent).
+ template <Keyed_State_Event EvT>
const EvT* get(const QString& stateKey = {}) const
{
- static_assert(std::is_base_of_v<StateEventBase, EvT>);
- if (const auto* evt = get(EvT::matrixTypeId(), stateKey)) {
- Q_ASSERT(evt->matrixType() == EvT::matrixTypeId()
+ if (const auto* evt = get(EvT::TypeId, stateKey)) {
+ Q_ASSERT(evt->matrixType() == EvT::TypeId
&& evt->stateKey() == stateKey);
return eventCast<const EvT>(evt);
}
return nullptr;
}
+ //! \brief Get a state event with the given event type
+ //!
+ //! This is a typesafe overload that accepts a C++ event type instead of
+ //! its Matrix name. This overload only defined for events that do not use
+ //! state key (i.e., derived from KeylessStateEvent).
+ template <Keyless_State_Event EvT>
+ const EvT* get() const
+ {
+ if (const auto* evt = get(EvT::TypeId)) {
+ Q_ASSERT(evt->matrixType() == EvT::TypeId);
+ return eventCast<const EvT>(evt);
+ }
+ return nullptr;
+ }
+
using QHash::contains;
bool contains(const QString& evtType, const QString& stateKey = {}) const;
- template <typename EvT>
+ template <Keyed_State_Event EvT>
bool contains(const QString& stateKey = {}) const
{
- return contains(EvT::matrixTypeId(), stateKey);
+ return contains(EvT::TypeId, stateKey);
+ }
+
+ template <Keyless_State_Event EvT>
+ bool contains() const
+ {
+ return contains(EvT::TypeId);
+ }
+
+ template <Keyed_State_Event EvT>
+ auto content(const QString& stateKey,
+ typename EvT::content_type defaultValue = {}) const
+ {
+ // EventBase<>::content is special in that it returns a const-ref,
+ // and lift() inside queryOr() can't wrap that in a temporary Omittable.
+ if (const auto evt = get<EvT>(stateKey))
+ return evt->content();
+ return std::move(defaultValue);
+ }
+
+ template <Keyless_State_Event EvT>
+ auto content(typename EvT::content_type defaultValue = {}) const
+ {
+ // Same as above
+ if (const auto evt = get<EvT>())
+ return evt->content();
+ return defaultValue;
}
//! \brief Get the content of the current state event with the given
@@ -75,51 +122,87 @@ public:
//!
//! This method returns all known state events that have occured in
//! the room of the given type.
- const QVector<const StateEventBase*>
- eventsOfType(const QString& evtType) const;
+ const QVector<const StateEvent*> eventsOfType(const QString& evtType) const;
+ //! \brief Run a function on a state event with the given type and key
+ //!
+ //! Use this overload when there's no predefined event type or the event
+ //! type is unknown at compile time.
+ //! \return an Omittable with either the result of the function call, or
+ //! with `none` if the event is not found or the function fails
template <typename FnT>
auto query(const QString& evtType, const QString& stateKey, FnT&& fn) const
{
return lift(std::forward<FnT>(fn), get(evtType, stateKey));
}
- template <typename FnT>
+ //! \brief Run a function on a state event with the given type and key
+ //!
+ //! This is an overload for keyed state events (those that have
+ //! `needsStateKey == true`) with type defined at compile time.
+ //! \return an Omittable with either the result of the function call, or
+ //! with `none` if the event is not found or the function fails
+ template <Keyed_State_Fn FnT>
auto query(const QString& stateKey, FnT&& fn) const
{
using EventT = std::decay_t<fn_arg_t<FnT>>;
- static_assert(std::is_base_of_v<StateEventBase, EventT>);
return lift(std::forward<FnT>(fn), get<EventT>(stateKey));
}
+ //! \brief Run a function on a keyless state event with the given type
+ //!
+ //! This is an overload for keyless state events (those having
+ //! `needsStateKey == false`) with type defined at compile time.
+ //! \return an Omittable with either the result of the function call, or
+ //! with `none` if the event is not found or the function fails
+ template <Keyless_State_Fn FnT>
+ auto query(FnT&& fn) const
+ {
+ using EventT = std::decay_t<fn_arg_t<FnT>>;
+ return lift(std::forward<FnT>(fn), get<EventT>());
+ }
+
+ //! \brief Same as query() but with a fallback value
+ //!
+ //! This is a shortcut for `query().value_or()`, passing respective
+ //! arguments to the respective functions. This is an overload for the case
+ //! when the event type cannot be fixed at compile time.
+ //! \return the result of \p fn execution, or \p fallback if the requested
+ //! event doesn't exist or the function fails
template <typename FnT, typename FallbackT>
auto queryOr(const QString& evtType, const QString& stateKey, FnT&& fn,
FallbackT&& fallback) const
{
- return lift(std::forward<FnT>(fn), get(evtType, stateKey))
+ return query(evtType, stateKey, std::forward<FnT>(fn))
.value_or(std::forward<FallbackT>(fallback));
}
- template <typename FnT>
- auto query(FnT&& fn) const
- {
- return query({}, std::forward<FnT>(fn));
- }
-
+ //! \brief Same as query() but with a fallback value
+ //!
+ //! This is a shortcut for `query().value_or()`, passing respective
+ //! arguments to the respective functions. This is an overload for the case
+ //! when the event type cannot be fixed at compile time.
+ //! \return the result of \p fn execution, or \p fallback if the requested
+ //! event doesn't exist or the function fails
template <typename FnT, typename FallbackT>
auto queryOr(const QString& stateKey, FnT&& fn, FallbackT&& fallback) const
{
- using EventT = std::decay_t<fn_arg_t<FnT>>;
- static_assert(std::is_base_of_v<StateEventBase, EventT>);
- return lift(std::forward<FnT>(fn), get<EventT>(stateKey))
+ return query(stateKey, std::forward<FnT>(fn))
.value_or(std::forward<FallbackT>(fallback));
}
+ //! \brief Same as query() but with a fallback value
+ //!
+ //! This is a shortcut for `query().value_or()`, passing respective
+ //! arguments to the respective functions. This is an overload for the case
+ //! when the event type cannot be fixed at compile time.
+ //! \return the result of \p fn execution, or \p fallback if the requested
+ //! event doesn't exist or the function fails
template <typename FnT, typename FallbackT>
auto queryOr(FnT&& fn, FallbackT&& fallback) const
{
- return queryOr({}, std::forward<FnT>(fn),
- std::forward<FallbackT>(fallback));
+ return query(std::forward<FnT>(fn))
+ .value_or(std::forward<FallbackT>(fallback));
}
private: