Loading...
Searching...
No Matches
QXmppTask.h
// SPDX-FileCopyrightText: 2022 Linus Jahn <lnj@kaidan.im>
// SPDX-FileCopyrightText: 2022 Jonah Brüchert <jbb@kaidan.im>
//
// SPDX-License-Identifier: LGPL-2.1-or-later
#ifndef QXMPPTASK_H
#define QXMPPTASK_H
#include "qxmpp_export.h"
#include <functional>
#include <memory>
#include <optional>
#include <QFuture>
#include <QPointer>
template<typename T>
class QXmppPromise;
namespace QXmpp::Private {
template<typename T>
struct TaskData {
std::function<void(TaskData &)> continuation;
std::conditional_t<std::is_void_v<T>, std::monostate, std::optional<T>> result;
bool finished = false;
};
} // namespace QXmpp::Private
template<typename T>
class QXmppTask
{
public:
~QXmppTask() = default;
#ifndef QXMPP_DOC
template<typename Continuation>
#endif
void then(const QObject *context, Continuation continuation)
{
using namespace QXmpp::Private;
if constexpr (std::is_void_v<T>) {
static_assert(std::is_invocable_v<Continuation>, "Function needs to be invocable without arguments.");
} else {
static_assert(std::is_invocable_v<Continuation, T &&>, "Function needs to be invocable with T &&.");
}
if (d->finished) {
if constexpr (std::is_void_v<T>) {
continuation();
} else {
if (hasResult()) {
auto value = std::move(*d->result);
d->result.reset();
continuation(std::move(value));
}
}
} else {
d->continuation = [context = QPointer(context),
continuation = std::forward<Continuation>(continuation)](TaskData<T> &d) mutable {
if (context) {
if constexpr (std::is_void_v<T>) {
continuation();
} else {
// move out value (only one continuation allowed)
auto value = std::move(*d.result);
d.result.reset();
continuation(std::move(value));
}
}
};
}
}
[[nodiscard]]
bool isFinished() const
{
return d->finished;
}
#ifndef QXMPP_DOC
template<typename U = T, std::enable_if_t<(!std::is_void_v<U>)> * = nullptr>
#endif
[[nodiscard]]
bool hasResult() const
{
return d->result.has_value();
}
#ifdef QXMPP_DOC
[[nodiscard]]
const T &result() const
#else
template<typename U = T, std::enable_if_t<(!std::is_void_v<U>)> * = nullptr>
[[nodiscard]]
const U &result() const
#endif
{
Q_ASSERT(isFinished());
Q_ASSERT(hasResult());
return d->result.value();
}
#ifdef QXMPP_DOC
[[nodiscard]]
T takeResult()
#else
template<typename U = T, std::enable_if_t<(!std::is_void_v<U>)> * = nullptr>
[[nodiscard]]
U takeResult()
#endif
{
Q_ASSERT(isFinished());
Q_ASSERT(hasResult());
auto value = std::move(*d->result);
d->result.reset();
return std::move(value);
}
QFuture<T> toFuture(const QObject *context)
{
QFutureInterface<T> interface;
if constexpr (std::is_same_v<T, void>) {
then(context, [interface]() mutable {
interface.reportFinished();
});
} else {
then(context, [interface](T &&val) mutable {
interface.reportResult(val);
interface.reportFinished();
});
}
return interface.future();
}
private:
friend class QXmppPromise<T>;
explicit QXmppTask(std::shared_ptr<QXmpp::Private::TaskData<T>> data)
: d(std::move(data))
{
}
std::shared_ptr<QXmpp::Private::TaskData<T>> d;
};
namespace QXmpp {
namespace Private {
template<typename T>
struct IsTaskHelper {
constexpr static bool Value = false;
};
template<typename T>
struct IsTaskHelper<QXmppTask<T>> {
using Type = T;
constexpr static bool Value = true;
};
} // namespace Private
template<typename T>
concept IsTask = Private::IsTaskHelper<T>::Value;
template<IsTask T>
using TaskValueType = typename Private::IsTaskHelper<T>::Type;
} // namespace QXmpp
#endif // QXMPPTASK_H
QXmppPromise
Create and update QXmppTask objects to communicate results of asynchronous operations.
Definition QXmppPromise.h:23
QXmppTask
Definition QXmppTask.h:46
QXmppTask::hasResult
bool hasResult() const
Definition QXmppTask.h:144
QXmppTask::result
const T & result() const
Definition QXmppTask.h:156
QXmppTask::toFuture
QFuture< T > toFuture(const QObject *context)
Definition QXmppTask.h:192
QXmppTask::isFinished
bool isFinished() const
Definition QXmppTask.h:132
QXmppTask::takeResult
T takeResult()
Definition QXmppTask.h:175
QXmppTask::then
void then(const QObject *context, Continuation continuation)
Definition QXmppTask.h:89
QXmpp::IsTask
Definition QXmppTask.h:243
QXmpp
Definition Algorithms.h:14
QXmpp::TaskValueType
typename Private::IsTaskHelper< T >::Type TaskValueType
Definition QXmppTask.h:251