// SPDX-FileCopyrightText: 2021 Linus Jahn // // SPDX-License-Identifier: LGPL-2.1-or-later #ifndef QXMPPFUTUREUTILS_P_H #define QXMPPFUTUREUTILS_P_H // // W A R N I N G // ------------- // // This file is not part of the QXmpp API. This header file may change from // version to version without notice, or even be removed. // // We mean it. // #include "QXmppIq.h" #include "QXmppSendResult.h" #include #include #include #include namespace QXmpp::Private { // helper for std::visit template struct overloaded : Ts... { using Ts::operator()...; }; // explicit deduction guide (not needed as of C++20) template overloaded(Ts...) -> overloaded; template A lambda_helper(Ret (F::*)(A, Rest...)); template A lambda_helper(Ret (F::*)(A, Rest...) const); template struct first_argument { using type = decltype(lambda_helper(&F::operator())); }; template using first_argument_t = typename first_argument::type; template QFuture makeReadyFuture(T &&value) { QFutureInterface interface(QFutureInterfaceBase::Started); interface.reportResult(std::move(value)); interface.reportFinished(); return interface.future(); } inline QFuture makeReadyFuture() { using State = QFutureInterfaceBase::State; return QFutureInterface(State(State::Started | State::Finished)).future(); } template void awaitLast(const QFuture &future, QObject *context, Handler handler) { auto *watcher = new QFutureWatcher(context); QObject::connect(watcher, &QFutureWatcherBase::finished, context, [watcher, handler = std::move(handler)]() mutable { auto future = watcher->future(); handler(future.resultAt(future.resultCount() - 1)); watcher->deleteLater(); }); watcher->setFuture(future); } template void await(const QFuture &future, QObject *context, Handler handler) { auto *watcher = new QFutureWatcher(context); QObject::connect(watcher, &QFutureWatcherBase::finished, context, [watcher, handler = std::move(handler)]() mutable { handler(watcher->result()); watcher->deleteLater(); }); watcher->setFuture(future); } template void await(const QFuture &future, QObject *context, Handler handler) { auto *watcher = new QFutureWatcher(context); QObject::connect(watcher, &QFutureWatcherBase::finished, context, [watcher, handler = std::move(handler)]() mutable { handler(); watcher->deleteLater(); }); watcher->setFuture(future); } template auto chain(QFuture &&source, QObject *context, Converter task) -> QFuture { QFutureInterface resultInterface(QFutureInterfaceBase::Started); auto *watcher = new QFutureWatcher(context); QObject::connect(watcher, &QFutureWatcherBase::finished, context, [=]() mutable { resultInterface.reportResult(task(watcher->result())); resultInterface.reportFinished(); watcher->deleteLater(); }); watcher->setFuture(source); return resultInterface.future(); } template auto parseIq(Input &&sendResult, Converter convert) -> decltype(convert({})) { using Result = decltype(convert({})); return std::visit(overloaded { [convert = std::move(convert)](const QDomElement &element) -> Result { IqType iq; iq.parse(element); if (iq.type() == QXmppIq::Error) { return iq.error(); } return convert(std::move(iq)); }, [](QXmpp::SendError error) -> Result { using Error = QXmppStanza::Error; return Error(Error::Wait, Error::UndefinedCondition, QStringLiteral("Couldn't send request: ") + error.text); }, }, sendResult); } template auto parseIq(Input &&sendResult) -> Result { return parseIq(std::move(sendResult), [](IqType &&iq) -> Result { // no conversion return iq; }); } template auto chainIq(QFuture &&input, QObject *context, Converter convert) -> QFuture { using Result = decltype(convert({})); using IqType = std::decay_t>; return chain(std::move(input), context, [convert { std::move(convert) }](Input &&input) -> Result { return parseIq(std::move(input), convert); }); } template auto chainIq(QFuture &&input, QObject *context) -> QFuture { // IQ type is first std::variant parameter using IqType = std::decay_t(Result {}))>; return chain(std::move(input), context, [](Input &&sendResult) { return parseIq(sendResult); }); } template void reportFinishedResult(QFutureInterface &interface, const T &result) { interface.reportResult(result); interface.reportFinished(); } } #endif // QXMPPFUTUREUTILS_P_H