9#include "QXmppAsync_p.h"
10#include "QXmppError.h"
11#include "QXmppGlobal.h"
13#include "Algorithms.h"
19#include <QFutureWatcher>
21namespace QXmpp::Private {
23template<
typename Function>
24auto later(QObject *context, Function function)
26 QMetaObject::invokeMethod(context, std::forward<Function>(function), Qt::QueuedConnection);
32#if QT_VERSION >= QT_VERSION_CHECK(6, 6, 0)
34auto makeReadyFuture(T &&value)
36 return QtFuture::makeReadyValueFuture(std::forward<T>(value));
39using QtFuture::makeReadyFuture;
42template<
typename T,
typename Handler>
43void await(
const QFuture<T> &future, QObject *context, Handler handler)
45 auto *watcher =
new QFutureWatcher<T>(context);
46 QObject::connect(watcher, &QFutureWatcherBase::finished,
47 context, [watcher, handler = std::move(handler)]()
mutable {
48 handler(watcher->result());
49 watcher->deleteLater();
51 watcher->setFuture(future);
54template<
typename Handler>
55void await(
const QFuture<void> &future, QObject *context, Handler handler)
57 auto *watcher =
new QFutureWatcher<void>(context);
58 QObject::connect(watcher, &QFutureWatcherBase::finished,
59 context, [watcher, handler = std::move(handler)]()
mutable {
61 watcher->deleteLater();
63 watcher->setFuture(future);
66template<
typename T,
typename Err,
typename Function>
67auto mapSuccess(
const std::variant<T, Err> &var, Function lambda)
69 using MappedVariant = std::variant<std::invoke_result_t<Function, const T &>, Err>;
70 return map<MappedVariant>(lambda, var);
73template<
typename T,
typename Err,
typename Function>
74auto mapSuccess(std::variant<T, Err> &&var, Function lambda)
76 using MappedVariant = std::variant<std::invoke_result_t<Function, T &&>, Err>;
77 return map<MappedVariant>(lambda, std::move(var));
80template<
typename T,
typename Err>
81auto mapToSuccess(std::variant<T, Err> &&var)
83 return mapSuccess(std::move(var), [](T) {
92 int taskCount = tasks.size();
93 auto finishedTaskCount = std::make_shared<int>();
95 auto promise = std::make_shared<QXmppPromise<void>>();
96 auto result = promise->task();
98 for (
auto &task : tasks) {
99 task.then(context, [=]()
mutable {
100 if (++(*finishedTaskCount) == taskCount) {
109template<
typename Params,
typename Response>
110struct AttachableRequests {
113 std::vector<QXmppPromise<Response>> promises;
116 std::vector<Request> requests;
119 std::optional<QXmppTask<Response>> attach(
const Params &key)
121 auto itr = std::ranges::find(requests, key, &Request::params);
122 if (itr != requests.end()) {
124 auto task = p.
task();
125 itr->promises.push_back(std::move(p));
134 Q_ASSERT(!contains(requests, key, &Request::params));
137 auto task = p.
task();
138 requests.push_back(Request { key, { std::move(p) } });
142 void finish(
const Params &key, Response &&response)
144 auto itr = std::ranges::find(requests, key, &Request::params);
145 Q_ASSERT(itr != requests.end());
146 if (itr == requests.end()) {
150 auto promises = std::move(itr->promises);
153 for (
auto it = promises.begin(); it != promises.end(); ++it) {
155 it->finish(std::next(it) == promises.end() ? std::move(response) : response);
161 if (
auto task = attach(key)) {
162 return std::move(*task);
164 auto task = makeNew(key);
165 requestFunction(key).then(context, [
this, key](
auto &&response) {
166 finish(key, std::move(response));
174 std::deque<QXmppPromise<T>> promises;
176 void finish(T &&response)
178 for (
auto it = promises.begin(); it != promises.end(); ++it) {
180 it->finish(std::next(it) == promises.end() ? std::move(response) : response);
186 return promises.back().task();
191struct MultiPromise<void> {
192 std::vector<QXmppPromise<void>> promises;
196 for (
auto &p : promises) {
203 return promises.back().task();
Create and update QXmppTask objects to communicate results of asynchronous operations.
Definition QXmppTask.h:81
QXmppTask< T > task()
Definition QXmppTask.h:167
void finish()
Definition QXmppTask.h:184
Definition QXmppTask.h:330