QXmpp Version: 1.13.0
Loading...
Searching...
No Matches
Async.h
1// SPDX-FileCopyrightText: 2021 Linus Jahn <lnj@kaidan.im>
2// SPDX-FileCopyrightText: 2025 Filipe Azevedo <pasnox@gmail.com>
3//
4// SPDX-License-Identifier: LGPL-2.1-or-later
5
6#ifndef ASYNC_H
7#define ASYNC_H
8
9#include "QXmppAsync_p.h"
10#include "QXmppGlobal.h"
11
12#include <memory>
13#include <variant>
14
15#include <QFutureWatcher>
16
17namespace QXmpp::Private {
18
19template<typename Function>
20auto later(QObject *context, Function function)
21{
22 QMetaObject::invokeMethod(context, std::forward<Function>(function), Qt::QueuedConnection);
23}
24
25#if QT_VERSION >= QT_VERSION_CHECK(6, 6, 0)
26template<typename T>
27QFuture<T> makeReadyFuture(T &&value) { return QtFuture::makeReadyValueFuture(std::move(value)); }
28#elif QT_VERSION >= QT_VERSION_CHECK(6, 1, 0)
29using QtFuture::makeReadyFuture;
30#else
31template<typename T>
32QFuture<T> makeReadyFuture(T &&value)
33{
34 QFutureInterface<T> interface(QFutureInterfaceBase::Started);
35 interface.reportResult(std::move(value));
36 interface.reportFinished();
37 return interface.future();
38}
39
40inline QFuture<void> makeReadyFuture()
41{
42 using State = QFutureInterfaceBase::State;
43 return QFutureInterface<void>(State(State::Started | State::Finished)).future();
44}
45#endif
46
47template<typename T, typename Handler>
48void await(const QFuture<T> &future, QObject *context, Handler handler)
49{
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();
55 });
56 watcher->setFuture(future);
57}
58
59template<typename Handler>
60void await(const QFuture<void> &future, QObject *context, Handler handler)
61{
62 auto *watcher = new QFutureWatcher<void>(context);
63 QObject::connect(watcher, &QFutureWatcherBase::finished,
64 context, [watcher, handler = std::move(handler)]() mutable {
65 handler();
66 watcher->deleteLater();
67 });
68 watcher->setFuture(future);
69}
70
71template<typename T, typename Err, typename Function>
72auto mapSuccess(std::variant<T, Err> var, Function lambda)
73{
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));
79 },
80 [](Err err) -> MappedVariant {
81 return err;
82 } },
83 std::move(var));
84}
85
86template<typename T, typename Err>
87auto mapToSuccess(std::variant<T, Err> var)
88{
89 return mapSuccess(std::move(var), [](T) {
90 return Success();
91 });
92}
93
94template<typename T, typename Err>
95auto chainSuccess(QXmppTask<std::variant<T, Err>> &&source, QObject *context) -> QXmppTask<std::variant<QXmpp::Success, QXmppError>>
96{
97 return chain<std::variant<QXmpp::Success, QXmppError>>(std::move(source), context, mapToSuccess<T, Err>);
98}
99
100template<typename Input, typename Converter>
101auto chainMapSuccess(QXmppTask<Input> &&source, QObject *context, Converter convert)
102{
103 return chain<std::variant<decltype(convert({})), QXmppError>>(std::move(source), context, [convert](Input &&input) {
104 return mapSuccess(std::move(input), convert);
105 });
106}
107
108// Creates a task for multiple tasks without a return value.
109template<typename T>
110QXmppTask<void> joinVoidTasks(QObject *context, QList<QXmppTask<T>> &&tasks)
111{
112 int taskCount = tasks.size();
113 auto finishedTaskCount = std::make_shared<int>();
114
115 QXmppPromise<void> promise;
116
117 for (auto task : tasks) {
118 task.then(context, [=]() mutable {
119 if (++(*finishedTaskCount) == taskCount) {
120 promise.finish();
121 }
122 });
123 }
124
125 return promise.task();
126}
127
128} // namespace QXmpp::Private
129
130#endif // ASYNC_H
QXmppTask< T > task()
Definition QXmppPromise.h:86