QXmpp Version: 1.5.6
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
23struct TaskData;
24
25class QXMPP_EXPORT TaskPrivate
26{
27public:
28 TaskPrivate(void (*freeResult)(void *));
29 ~TaskPrivate();
30
31 bool isFinished() const;
32 void setFinished(bool);
33 bool isContextAlive();
34 void setContext(QObject *);
35 void *result() const;
36 void setResult(void *);
37 void resetResult() { setResult(nullptr); }
38 const std::function<void(TaskPrivate &, void *)> continuation() const;
39 void setContinuation(std::function<void(TaskPrivate &, void *)> &&);
40 void invokeContinuation(void *result);
41
42private:
43 std::shared_ptr<TaskData> d;
44};
45
46} // namespace QXmpp::Private
47
60template<typename T>
62{
63public:
64 ~QXmppTask() = default;
65
98#ifndef QXMPP_DOC
99 template<typename Continuation>
100#endif
101 void then(QObject *context, Continuation continuation)
102 {
103 if constexpr (!std::is_void_v<T>) {
104 static_assert(std::is_invocable_v<Continuation, T &&>, "Function needs to be invocable with T &&.");
105 } else {
106 static_assert(std::is_invocable_v<Continuation>, "Function needs to be invocable without arguments.");
107 }
108 using namespace QXmpp::Private;
109
110 if (d.isFinished()) {
111 if constexpr (std::is_void_v<T>) {
112 continuation();
113 } else {
114 // when calling then() after finished value could be empty
115 if (hasResult()) {
116 continuation(std::move(*reinterpret_cast<T *>(d.result())));
117 d.resetResult();
118 }
119 }
120 } else {
121 d.setContext(context);
122 d.setContinuation([f = std::forward<Continuation>(continuation)](TaskPrivate &d, void *result) mutable {
123 if (d.isContextAlive()) {
124 if constexpr (std::is_void_v<T>) {
125 f();
126 } else {
127 f(std::move(*reinterpret_cast<T *>(result)));
128 }
129 }
130
131 // clear continuation to avoid "deadlocks" in case the user captured this QXmppTask
132 d.setContinuation({});
133 });
134 }
135 }
136
143 [[nodiscard]] bool isFinished() const { return d.isFinished(); }
144
148#ifndef QXMPP_DOC
149 template<typename U = T, std::enable_if_t<(!std::is_void_v<U>)> * = nullptr>
150#endif
151 [[nodiscard]] bool hasResult() const
152 {
153 return d.result() != nullptr;
154 }
155
161#ifdef QXMPP_DOC
162 [[nodiscard]] const T &result() const
163#else
164 template<typename U = T, std::enable_if_t<(!std::is_void_v<U>)> * = nullptr>
165 [[nodiscard]] const U &result() const
166#endif
167 {
168 Q_ASSERT(isFinished());
169 Q_ASSERT(hasResult());
170 return *reinterpret_cast<U *>(d.result());
171 }
172
178#ifdef QXMPP_DOC
179 [[nodiscard]] T takeResult()
180#else
181 template<typename U = T, std::enable_if_t<(!std::is_void_v<U>)> * = nullptr>
182 [[nodiscard]] U takeResult()
183#endif
184 {
185 Q_ASSERT(isFinished());
186 Q_ASSERT(hasResult());
187 U result = std::move(*reinterpret_cast<U *>(d.result()));
188 d.resetResult();
189 return result;
190 }
191
195 QFuture<T> toFuture(QObject *context)
196 {
197 QFutureInterface<T> interface;
198
199 if constexpr (std::is_same_v<T, void>) {
200 then(context, [interface]() mutable {
201 interface.reportFinished();
202 });
203 } else {
204 then(context, [interface](T &&val) mutable {
205 interface.reportResult(val);
206 interface.reportFinished();
207 });
208 }
209
210 return interface.future();
211 }
212
213private:
214 friend class QXmppPromise<T>;
215
216 explicit QXmppTask(QXmpp::Private::TaskPrivate data)
217 : d(std::move(data))
218 {
219 }
220
221 QXmpp::Private::TaskPrivate d;
222};
223
224#endif // QXMPPTASK_H
Create and update QXmppTask objects to communicate results of asynchronous operations.
Definition QXmppPromise.h:23
Definition QXmppTask.h:62
void then(QObject *context, Continuation continuation)
Definition QXmppTask.h:101
QFuture< T > toFuture(QObject *context)
Definition QXmppTask.h:195
bool hasResult() const
Definition QXmppTask.h:151
const T & result() const
Definition QXmppTask.h:162
bool isFinished() const
Definition QXmppTask.h:143
T takeResult()
Definition QXmppTask.h:179