Files
qt5-legatus-legacy/Lts/Common/LtsUtils/LtsUtilsCore/promise.h
T
2026-08-13 18:33:10 +02:00

133 lines
5.9 KiB
C++
Executable File

#pragma once
/*
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org/>
*/
#include <LtsUtilsCore/ltsutilscore_export.h>
#include <QObject>
#include <QVariant>
#include <functional>
class QTimer;
namespace LtsUtils
{
typedef std::function<void(const QVariant &value)> RawResultFunction;
typedef const RawResultFunction &ResultFunction;
/**
* @brief The Promise class is the (sort of) non-retarded brother of QFuture and a clone of Javascript's
* famous Promise. Its purpose is to have a function be executed asynchronously after Qt's event loop was
* entered, and having a positive (resolve) or negative (reject) result after execution.
* Otherwise a new class for every promise-like situation has to be created, maintained, and tested.
* See examples on how to use a Promise here: LtsUtilsCore/promise_examples.h
* Note that C(++) is a static typed language, this makes this C++ version of Promises need a little more
* boilerplate code than the original Javascript implementation. Excuse: But TypeScript causes this, too.
*/
class LTSUTILSCORE_EXPORT Promise : public QObject
{
Q_OBJECT
public:
/**
* @brief Promise creates a promise with the given function - the function is called after Qt entered the event loop
* so that a task can execute asyncronous. The code inside function has to call either resolve(..) or reject(..) (but never both)
* if its execution is done. Calling resolve(..) or reject(..) will call the function given beforehand with resolved(..)
* and / or with reject(..). Failing to call either resolve(..) or reject(..) will result in a promise that
* will never return and will never remove itself from heap. Don't forget to call either one!
* This class can be created without setting a function. But then a function has to be set with with setFunction. Otherwise
* the promise is not executed. The promise is queued for execution if either a function was set in the constructor or
* it was set with setFunction.
* @param function
*/
Promise(const std::function<void(ResultFunction resolve, ResultFunction reject)> &function, QObject *parent = nullptr);
/**
* @brief setFunction sets the function and queues it for execution into the Qt event loop. Do not use if a
* function was alread specified in the constructor, because the constructor already calls setFunction if a
* function was given to the constructor.
* Calling this method more than once, or a function was already specified in the constructor, does nothing.
* @param function
*/
void setFunction(const std::function<void(ResultFunction resolve, ResultFunction reject)> &function);
/**
* @brief resolve must only be called from the function given to the promise's constructor
* @param value the value to give as a parameter to resolveFn (resolveFn is set by calling resolved(..) after the promise was created)
*/
void resolve(const QVariant &value = QVariant());
/**
* @brief reject must only be called from the function given to the promise's constructor
* @param value the value to give as a parameter to rejectFn (rejectFn is set by calling rejected(..) after the promise was created)
*/
void reject(const QVariant &value = QVariant());
/**
* @brief setTimeout starts a timer that when interval is reached, the reject function is called with the value "timeout".
* Useful if you depend on the promise to always deliver, even though the asynchronous functionality behind the function
* is not returning. The timer behind the timeout is started right before the function is executed and is stopped right
* before the function resolves or rejects. Timeout is default off.
* @param interval milliseconds after the function was executed. Or 0 if timeout should be deactivated again.
*/
void setTimeout(int interval);
/**
* @brief resolved sets resolveFn - resolveFn is called if the function given to the promise's constructor calls resolve(..)
* @param resolveFn the function that is called if resolve(..) was called
* @return this promise, so that another ResultFunctin can be set directly, without having to call the promise again
*/
Promise &resolved(ResultFunction resolveFn);
/**
* @brief rejected sets rejectFn - rejectFn is called if the function given to the promise's constructor calls reject(..)
* @param rejectFn the function that is called if reject(..) was called
* @return this promise, so that another ResultFunctin can be set directly, without having to call the promise again
*/
Promise &rejected(ResultFunction rejectFn);
private:
RawResultFunction m_resolveFn;
RawResultFunction m_rejectFn;
bool m_functionAlreadySet;
QTimer *m_timeout;
bool m_resultSet;
bool m_timeoutSet;
private slots:
void slotTimeout();
};
} // namespace LtsUtils