QXmpp Version: 1.12.0
Loading...
Searching...
No Matches
QXmppTask.h
1// SPDX-FileCopyrightText: 2022 Linus Jahn <lnj@kaidan.im>
2// SPDX-FileCopyrightText: 2022 Jonah BrĂ¼chert <jbb@kaidan.im>
3//
4// SPDX-License-Identifier: LGPL-2.1-or-later
5
6#ifndef QXMPPTASK_H
7#define QXMPPTASK_H
8
9#include "qxmpp_export.h"
10
11#include <functional>
12#include <memory>
13#include <optional>
14
15#include <QFuture>
16#include <QPointer>
17
18template<typename T>
19class QXmppPromise;
20
21namespace QXmpp::Private {
22
23template<typename T>
24struct TaskData {
25 std::function<void(TaskData &)> continuation;
26 std::conditional_t<std::is_void_v<T>, std::monostate, std::optional<T>> result;
27 bool finished = false;
28};
29
30} // namespace QXmpp::Private
31
44template<typename T>
46{
47public:
48 ~QXmppTask() = default;
49
86#ifndef QXMPP_DOC
87 template<typename Continuation>
88#endif
89 void then(const QObject *context, Continuation continuation)
90 {
91 using namespace QXmpp::Private;
92 if constexpr (std::is_void_v<T>) {
93 static_assert(std::is_invocable_v<Continuation>, "Function needs to be invocable without arguments.");
94 } else {
95 static_assert(std::is_invocable_v<Continuation, T &&>, "Function needs to be invocable with T &&.");
96 }
97
98 if (d->finished) {
99 if constexpr (std::is_void_v<T>) {
100 continuation();
101 } else {
102 if (hasResult()) {
103 auto value = std::move(*d->result);
104 d->result.reset();
105 continuation(std::move(value));
106 }
107 }
108 } else {
109 d->continuation = [context = QPointer(context),
110 continuation = std::forward<Continuation>(continuation)](TaskData<T> &d) mutable {
111 if (context) {
112 if constexpr (std::is_void_v<T>) {
113 continuation();
114 } else {
115 // move out value (only one continuation allowed)
116 auto value = std::move(*d.result);
117 d.result.reset();
118 continuation(std::move(value));
119 }
120 }
121 };
122 }
123 }
124
131 [[nodiscard]]
132 bool isFinished() const
133 {
134 return d->finished;
135 }
136
140#ifndef QXMPP_DOC
141 template<typename U = T, std::enable_if_t<(!std::is_void_v<U>)> * = nullptr>
142#endif
143 [[nodiscard]]
144 bool hasResult() const
145 {
146 return d->result.has_value();
147 }
148
154#ifdef QXMPP_DOC
155 [[nodiscard]]
156 const T &result() const
157#else
158 template<typename U = T, std::enable_if_t<(!std::is_void_v<U>)> * = nullptr>
159 [[nodiscard]]
160 const U &result() const
161#endif
162 {
163 Q_ASSERT(isFinished());
164 Q_ASSERT(hasResult());
165 return d->result.value();
166 }
167
173#ifdef QXMPP_DOC
174 [[nodiscard]]
176#else
177 template<typename U = T, std::enable_if_t<(!std::is_void_v<U>)> * = nullptr>
178 [[nodiscard]]
179 U takeResult()
180#endif
181 {
182 Q_ASSERT(isFinished());
183 Q_ASSERT(hasResult());
184 auto value = std::move(*d->result);
185 d->result.reset();
186 return std::move(value);
187 }
188
192 QFuture<T> toFuture(const QObject *context)
193 {
194 QFutureInterface<T> interface;
195
196 if constexpr (std::is_same_v<T, void>) {
197 then(context, [interface]() mutable {
198 interface.reportFinished();
199 });
200 } else {
201 then(context, [interface](T &&val) mutable {
202 interface.reportResult(val);
203 interface.reportFinished();
204 });
205 }
206
207 return interface.future();
208 }
209
210private:
211 friend class QXmppPromise<T>;
212
213 explicit QXmppTask(std::shared_ptr<QXmpp::Private::TaskData<T>> data)
214 : d(std::move(data))
215 {
216 }
217
218 std::shared_ptr<QXmpp::Private::TaskData<T>> d;
219};
220
221#endif // QXMPPTASK_H
Create and update QXmppTask objects to communicate results of asynchronous operations.
Definition QXmppPromise.h:23
Definition QXmppTask.h:46
bool hasResult() const
Definition QXmppTask.h:144
const T & result() const
Definition QXmppTask.h:156
QFuture< T > toFuture(const QObject *context)
Definition QXmppTask.h:192
bool isFinished() const
Definition QXmppTask.h:132
T takeResult()
Definition QXmppTask.h:175
void then(const QObject *context, Continuation continuation)
Definition QXmppTask.h:89