9#include "QXmppAsync_p.h"
10#include "QXmppGlobal.h"
15#include <QFutureWatcher>
17namespace QXmpp::Private {
19template<
typename Function>
20auto later(QObject *context, Function function)
22 QMetaObject::invokeMethod(context, std::forward<Function>(function), Qt::QueuedConnection);
25#if QT_VERSION >= QT_VERSION_CHECK(6, 6, 0)
27QFuture<T> makeReadyFuture(T &&value) {
return QtFuture::makeReadyValueFuture(std::move(value)); }
28#elif QT_VERSION >= QT_VERSION_CHECK(6, 1, 0)
29using QtFuture::makeReadyFuture;
32QFuture<T> makeReadyFuture(T &&value)
34 QFutureInterface<T> interface(QFutureInterfaceBase::Started);
35 interface.reportResult(std::move(value));
36 interface.reportFinished();
37 return interface.future();
40inline QFuture<void> makeReadyFuture()
42 using State = QFutureInterfaceBase::State;
43 return QFutureInterface<void>(State(State::Started | State::Finished)).future();
47template<
typename T,
typename Handler>
48void await(
const QFuture<T> &future, QObject *context, Handler handler)
50 auto *watcher =
new QFutureWatcher<T>(context);
51 QObject::connect(watcher, &QFutureWatcherBase::finished,
52 context, [watcher, handler = std::move(handler)]()
mutable {
53 handler(watcher->result());
54 watcher->deleteLater();
56 watcher->setFuture(future);
59template<
typename Handler>
60void await(
const QFuture<void> &future, QObject *context, Handler handler)
62 auto *watcher =
new QFutureWatcher<void>(context);
63 QObject::connect(watcher, &QFutureWatcherBase::finished,
64 context, [watcher, handler = std::move(handler)]()
mutable {
66 watcher->deleteLater();
68 watcher->setFuture(future);
71template<
typename T,
typename Err,
typename Function>
72auto mapSuccess(std::variant<T, Err> var, Function lambda)
74 using MapResult = std::decay_t<
decltype(lambda({}))>;
75 using MappedVariant = std::variant<MapResult, Err>;
76 return std::visit(overloaded {
77 [lambda = std::move(lambda)](T val) -> MappedVariant {
78 return lambda(std::move(val));
80 [](Err err) -> MappedVariant {
86template<
typename T,
typename Err>
87auto mapToSuccess(std::variant<T, Err> var)
89 return mapSuccess(std::move(var), [](T) {
94template<
typename T,
typename Err>
95auto chainSuccess(QXmppTask<std::variant<T, Err>> &&source, QObject *context) -> QXmppTask<std::variant<QXmpp::Success, QXmppError>>
97 return chain<std::variant<QXmpp::Success, QXmppError>>(std::move(source), context, mapToSuccess<T, Err>);
100template<
typename Input,
typename Converter>
101auto chainMapSuccess(QXmppTask<Input> &&source, QObject *context, Converter convert)
103 return chain<std::variant<
decltype(convert({})), QXmppError>>(std::move(source), context, [convert](Input &&input) {
104 return mapSuccess(std::move(input), convert);
110QXmppTask<void> joinVoidTasks(QObject *context, QList<QXmppTask<T>> &&tasks)
112 int taskCount = tasks.size();
113 auto finishedTaskCount = std::make_shared<int>();
115 QXmppPromise<void> promise;
117 for (
auto &task : tasks) {
118 task.then(context, [=]()
mutable {
119 if (++(*finishedTaskCount) == taskCount) {
125 return promise.
task();
128template<
typename Params,
typename Response>
129struct AttachableRequests {
132 std::vector<QXmppPromise<Response>> promises;
135 std::vector<Request> requests;
138 std::optional<QXmppTask<Response>> attach(
const Params &key)
140 auto itr = std::ranges::find(requests, key, &Request::params);
141 if (itr != requests.end()) {
142 QXmppPromise<Response> p;
143 auto task = p.
task();
144 itr->promises.push_back(std::move(p));
151 QXmppTask<Response> makeNew(Params key)
153 Q_ASSERT(!contains(requests, key, &Request::params));
155 QXmppPromise<Response> p;
156 auto task = p.
task();
157 requests.push_back(Request { key, { std::move(p) } });
161 void finish(
const Params &key, Response &&response)
163 auto itr = std::ranges::find(requests, key, &Request::params);
164 Q_ASSERT(itr != requests.end());
165 if (itr == requests.end()) {
169 auto promises = std::move(itr->promises);
172 for (
auto it = promises.begin(); it != promises.end(); ++it) {
174 it->finish(std::next(it) == promises.end() ? std::move(response) : response);
178 QXmppTask<Response> produce(Params key, std::function<QXmppTask<Response>(Params)> requestFunction, QObject *context)
180 if (
auto task = attach(key)) {
181 return std::move(*task);
183 auto task = makeNew(key);
184 requestFunction(key).then(context, [
this, key](
auto &&response) {
185 finish(key, std::move(response));
193 std::vector<QXmppPromise<T>> promises;
195 void finish(T &&response)
197 for (
auto it = promises.begin(); it != promises.end(); ++it) {
199 it->finish(std::next(it) == promises.end() ? std::move(response) : response);
202 QXmppTask<T> generateTask()
204 promises.push_back(QXmppPromise<T>());
205 return promises.back().task();
210struct MultiPromise<void> {
211 std::vector<QXmppPromise<void>> promises;
215 for (
auto &p : promises) {
219 QXmppTask<void> generateTask()
221 promises.push_back(QXmppPromise<void>());
222 return promises.back().task();
QXmppTask< T > task()
Definition QXmppPromise.h:86