23#include <QFutureWatcher>
26#include <quentier/exception/RuntimeError.h>
27#include <quentier/threading/Post.h>
28#include <quentier/threading/QtFutureHelpers.h>
30#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
31#include <quentier/threading/Qt5Promise.h>
34#include <quentier/threading/Runnable.h>
36#include <boost/core/demangle.hpp>
42namespace quentier::threading {
101template <
class T,
class Function>
102void processParentFuture(
104 QPromise<
typename ResultTypeHelper<Function, T>::ResultType>>
106 QFuture<T> && future, Function && function)
110 using ResultType =
typename ResultTypeHelper<Function, T>::ResultType;
117 future.waitForFinished();
119 catch (
const QException & e) {
120 promise->setException(e);
131 if constexpr (std::is_void_v<ResultType>) {
132 if constexpr (std::is_void_v<T>) {
136 if (future.resultCount() == 0) {
137 promise->setException(RuntimeError{ErrorString{
139 "Invalid future continuation: detected future "
140 "without result for type %1")
141 .arg(QString::fromStdString(std::string{
142 boost::core::demangle(
typeid(T).name())}))}});
147 function(future.result());
151 if constexpr (std::is_void_v<T>) {
152 promise->addResult(function());
155 promise->addResult(function(future.result()));
159 catch (
const QException & e) {
160 promise->setException(e);
162 catch (
const std::exception & e) {
163 ErrorString error{QT_TRANSLATE_NOOP(
164 "utility",
"Unknown std::exception in then future handler")};
165 error.details() = QString::fromStdString(std::string{e.what()});
166 promise->setException(RuntimeError{std::move(error)});
169 ErrorString error{QT_TRANSLATE_NOOP(
170 "utility",
"Unknown exception in then future handler")};
171 promise->setException(RuntimeError{std::move(error)});
179template <
class T,
class Function>
180QFuture<typename detail::ResultTypeHelper<Function, T>::ResultType> then(
181 QFuture<T> && future, Function && function)
184 typename detail::ResultTypeHelper<Function, T>::ResultType;
186 auto promise = std::make_shared<QPromise<ResultType>>();
187 auto result = promise->future();
189 if (future.isFinished()) {
190 detail::processParentFuture(
191 std::move(promise), std::move(future),
192 std::forward<
decltype(function)>(function));
196 auto watcher = std::make_unique<QFutureWatcher<T>>();
197 auto * rawWatcher = watcher.get();
199 rawWatcher, &QFutureWatcher<T>::finished, rawWatcher,
200 [rawWatcher, function = std::forward<
decltype(function)>(function),
201 promise = std::move(promise)]()
mutable {
202 detail::processParentFuture(
203 std::move(promise), rawWatcher->future(),
204 std::forward<
decltype(function)>(function));
205 rawWatcher->deleteLater();
209 rawWatcher, &QFutureWatcher<T>::canceled, rawWatcher,
210 [rawWatcher] { rawWatcher->deleteLater(); });
212 watcher->setFuture(std::move(future));
213 Q_UNUSED(watcher.release())
218template <class T, class Function>
219QFuture<typename detail::ResultTypeHelper<Function, T>::ResultType> then(
220 QFuture<T> && future, QtFuture::Launch policy, Function && function)
222 if (policy == QtFuture::Launch::Sync) {
224 std::move(future), std::forward<
decltype(function)>(function));
228 std::move(future), QThreadPool::globalInstance(),
229 std::forward<
decltype(function)>(function));
232template <
class T,
class Function>
233QFuture<typename detail::ResultTypeHelper<Function, T>::ResultType> then(
234 QFuture<T> && future, QThreadPool * pool, Function && function)
237 typename detail::ResultTypeHelper<Function, T>::ResultType;
239 auto promise = std::make_shared<QPromise<ResultType>>();
240 auto result = promise->future();
242 if (future.isFinished()) {
243 auto * runnable = createFunctionRunnable(
244 [future = std::move(future), promise = std::move(promise),
245 function = std::forward<
decltype(function)>(function)]()
mutable {
246 detail::processParentFuture(
247 std::move(promise), std::move(future),
248 std::forward<
decltype(function)>(function));
250 runnable->setAutoDelete(
true);
251 pool->start(runnable);
255 auto watcher = std::make_unique<QFutureWatcher<T>>();
256 auto * rawWatcher = watcher.get();
258 rawWatcher, &QFutureWatcher<T>::finished, rawWatcher,
259 [rawWatcher, function = std::forward<
decltype(function)>(function),
260 promise = std::move(promise), pool]()
mutable {
261 auto * runnable = createFunctionRunnable(
262 [function = std::forward<
decltype(function)>(function),
263 promise = std::move(promise),
264 future = rawWatcher->future()]()
mutable {
265 detail::processParentFuture(
266 std::move(promise), std::move(future),
267 std::forward<decltype(function)>(function));
269 runnable->setAutoDelete(
true);
270 pool->start(runnable);
271 rawWatcher->deleteLater();
275 rawWatcher, &QFutureWatcher<T>::canceled, rawWatcher,
276 [rawWatcher] { rawWatcher->deleteLater(); });
278 watcher->setFuture(std::move(future));
279 Q_UNUSED(watcher.release())
284template <class T, class Function>
285QFuture<typename detail::ResultTypeHelper<Function, T>::ResultType> then(
286 QFuture<T> && future, QObject * context, Function && function)
289 typename detail::ResultTypeHelper<Function, T>::ResultType;
291 auto promise = std::make_shared<QPromise<ResultType>>();
292 auto result = promise->future();
294 if (future.isFinished()) {
297 [future = std::move(future), promise = std::move(promise),
298 function = std::forward<
decltype(function)>(function)]()
mutable {
299 detail::processParentFuture(
300 std::move(promise), std::move(future),
301 std::forward<
decltype(function)>(function));
306 auto watcher = std::make_unique<QFutureWatcher<T>>();
307 auto * rawWatcher = watcher.get();
310 rawWatcher, &QFutureWatcher<T>::finished, context,
311 [context, rawWatcher,
312 function = std::forward<
decltype(function)>(function),
313 promise = std::move(promise)]()
mutable {
316 [function = std::forward<
decltype(function)>(function),
317 promise = std::move(promise),
318 future = rawWatcher->future()]()
mutable {
319 detail::processParentFuture(
320 std::move(promise), std::move(future),
321 std::forward<decltype(function)>(function));
323 rawWatcher->deleteLater();
327 rawWatcher, &QFutureWatcher<T>::canceled, rawWatcher,
328 [rawWatcher] { rawWatcher->deleteLater(); });
330 watcher->setFuture(std::move(future));
331 Q_UNUSED(watcher.release())
338template <
class T,
class Function>
339std::enable_if_t<!QtPrivate::ArgResolver<Function>::HasExtraArgs,
void>
340 processPossibleFutureException(
341 std::shared_ptr<
QPromise<T>> promise, QFuture<T> && future,
346 using ArgType =
typename QtPrivate::ArgResolver<Function>::First;
348 typename ResultTypeHelper<Function, std::decay_t<ArgType>>::ResultType;
349 static_assert(std::is_convertible_v<ResultType, T>);
355 future.waitForFinished();
357 catch (
const ArgType & e) {
359 if constexpr (std::is_void_v<ResultType>) {
363 promise->addResult(handler(e));
366 catch (
const QException & e) {
367 promise->setException(e);
369 catch (
const std::exception & e) {
370 ErrorString error{QT_TRANSLATE_NOOP(
372 "Unknown std::exception in onFailed future handler")};
373 error.details() = QString::fromStdString(std::string{e.what()});
374 promise->setException(RuntimeError{std::move(error)});
377 ErrorString error{QT_TRANSLATE_NOOP(
378 "utility",
"Unknown exception in onFailed future handler")};
379 promise->setException(RuntimeError{std::move(error)});
385 catch (
const QException & e) {
386 promise->setException(e);
388 catch (
const std::exception & e) {
389 ErrorString error{QT_TRANSLATE_NOOP(
391 "Unknown std::exception which did not match with onFailed "
393 error.details() = QString::fromStdString(std::string{e.what()});
394 promise->setException(RuntimeError{std::move(error)});
397 ErrorString error{QT_TRANSLATE_NOOP(
399 "Unknown which did not match with onFailed "
401 promise->setException(RuntimeError{std::move(error)});
414template <
class T,
class Function>
415std::enable_if_t<!QtPrivate::ArgResolver<Function>::HasExtraArgs, QFuture<T>>
416 onFailed(QFuture<T> && future, Function && handler)
418 auto promise = std::make_shared<QPromise<T>>();
419 auto result = promise->future();
421 if (future.isFinished()) {
422 detail::processPossibleFutureException(
423 std::move(promise), std::move(future),
424 std::forward<
decltype(handler)>(handler));
428 auto watcher = std::make_unique<QFutureWatcher<T>>();
429 auto * rawWatcher = watcher.get();
431 rawWatcher, &QFutureWatcher<T>::finished, rawWatcher,
432 [rawWatcher, promise = std::move(promise),
433 handler = std::forward<
decltype(handler)>(handler)]()
mutable {
434 auto future = rawWatcher->future();
435 rawWatcher->deleteLater();
436 detail::processPossibleFutureException(
437 std::move(promise), std::move(future),
438 std::forward<
decltype(handler)>(handler));
442 rawWatcher, &QFutureWatcher<T>::canceled, rawWatcher,
443 [rawWatcher] { rawWatcher->deleteLater(); });
445 watcher->setFuture(std::move(future));
446 Q_UNUSED(watcher.release())
451template <class T, class Function>
452std::enable_if_t<!QtPrivate::ArgResolver<Function>::HasExtraArgs, QFuture<T>>
453 onFailed(QFuture<T> && future, QObject * context, Function && handler)
455 auto promise = std::make_shared<QPromise<T>>();
456 auto result = promise->future();
458 if (future.isFinished()) {
461 [promise = std::move(promise), future = std::move(future),
462 handler = std::forward<
decltype(handler)>(handler)]()
mutable {
463 detail::processPossibleFutureException(
464 std::move(promise), std::move(future),
465 std::forward<
decltype(handler)>(handler));
470 auto watcher = std::make_unique<QFutureWatcher<T>>();
471 auto * rawWatcher = watcher.get();
473 rawWatcher, &QFutureWatcher<T>::finished, context,
474 [context, rawWatcher, promise = std::move(promise),
475 handler = std::forward<
decltype(handler)>(handler)]()
mutable {
478 [promise = std::move(promise), future = rawWatcher->future(),
479 handler = std::forward<
decltype(handler)>(handler)]()
mutable {
480 detail::processPossibleFutureException(
481 std::move(promise), std::move(future),
482 std::forward<decltype(handler)>(handler));
484 rawWatcher->deleteLater();
488 rawWatcher, &QFutureWatcher<T>::canceled, rawWatcher,
489 [rawWatcher] { rawWatcher->deleteLater(); });
491 watcher->setFuture(std::move(future));
492 Q_UNUSED(watcher.release())
501template <class T, class U, class Function>
503 QFuture<T> && future, std::shared_ptr<
QPromise<U>> promise,
504 Function && function)
507 then(std::move(future), std::forward<
decltype(function)>(function));
509 onFailed(std::move(thenFuture), [promise](
const QException & e) {
510 promise->setException(e);
515template <
class T,
class U,
class Function>
517 QFuture<T> && future, QThread * thread,
518 std::shared_ptr<
QPromise<U>> promise, Function && function)
521 then(std::move(future), thread, std::forward<Function>(function));
523 onFailed(std::move(thenFuture), thread, [promise](
const QException & e) {
524 promise->setException(e);
529template <
class T,
class U>
530void thenOrFailed(QFuture<T> && future, std::shared_ptr<
QPromise<U>> promise)
532 thenOrFailed(std::move(future), promise, [promise] { promise->finish(); });
535template <
class T,
class U>
537 QFuture<T> && future, QThread * thread,
541 std::move(future), thread, promise, [promise] { promise->finish(); });
Definition Qt5Promise.h:28