Allow undefined rejection reason

While not recommended because it makes tracking errors more difficult, it's now possible to reject a promise without explicit reason, in which case, a built-in `QPromiseUndefinedException` is thrown. This is done in anticipation of handling rejection signals without argument.
This commit is contained in:
Simon Brunel 2019-01-31 17:59:39 +01:00
parent 16229fc2c9
commit fa5a4192ff
5 changed files with 96 additions and 0 deletions

View File

@ -35,3 +35,35 @@ QPromise<int> promise([](const auto& resolve, const auto& reject) {
// {...} // {...}
}); });
``` ```
**Undefined rejection reason**
*Since: 0.5.0*
While not recommended because it makes tracking errors more difficult, it's also
possible to reject a promise without explicit reason, in which case, a built-in
`QPromiseUndefinedException` is thrown:
```cpp
QPromise<int> promise([](const QPromiseResolve<int>& resolve, const QPromiseReject<int>& reject) {
async_method([=](bool success, int result) {
if (success) {
resolve(result);
} else {
reject();
}
});
});
```
```cpp
// The exception can be caught explicitly
promise.fail([](const QPromiseUndefinedException&) {
// { ... }
})
// ... or implicitly (since undefined)
promise.fail([]() {
// { ... }
})
```

View File

@ -20,6 +20,16 @@ public:
} }
}; };
class QPromiseUndefinedException : public QException
{
public:
void raise() const Q_DECL_OVERRIDE { throw *this; }
QPromiseUndefinedException* clone() const Q_DECL_OVERRIDE
{
return new QPromiseUndefinedException(*this);
}
};
// QPromiseError is provided for backward compatibility and will be // QPromiseError is provided for backward compatibility and will be
// removed in the next major version: it wasn't intended to be used // removed in the next major version: it wasn't intended to be used
// directly and thus should not be part of the public API. // directly and thus should not be part of the public API.

View File

@ -1,6 +1,8 @@
#ifndef QTPROMISE_QPROMISERESOLVER_H #ifndef QTPROMISE_QPROMISERESOLVER_H
#define QTPROMISE_QPROMISERESOLVER_H #define QTPROMISE_QPROMISERESOLVER_H
#include "qpromiseerror.h"
// Qt // Qt
#include <QExplicitlySharedDataPointer> #include <QExplicitlySharedDataPointer>
@ -34,6 +36,17 @@ public:
} }
} }
void reject()
{
auto promise = m_d->promise;
if (promise) {
Q_ASSERT(promise->isPending());
promise->m_d->reject(QtPromise::QPromiseUndefinedException());
promise->m_d->dispatch();
release();
}
}
template <typename V> template <typename V>
void resolve(V&& value) void resolve(V&& value)
{ {
@ -115,6 +128,11 @@ public:
m_resolver.reject(std::forward<E>(error)); m_resolver.reject(std::forward<E>(error));
} }
void operator()() const
{
m_resolver.reject();
}
private: private:
mutable QtPromisePrivate::PromiseResolver<T> m_resolver; mutable QtPromisePrivate::PromiseResolver<T> m_resolver;
}; };

View File

@ -33,6 +33,8 @@ private Q_SLOTS:
void rejectSync_void(); void rejectSync_void();
void rejectAsync(); void rejectAsync();
void rejectAsync_void(); void rejectAsync_void();
void rejectUndefined();
void rejectUndefined_void();
void connectAndResolve(); void connectAndResolve();
void connectAndReject(); void connectAndReject();
}; };
@ -234,6 +236,30 @@ void tst_qpromise_construct::rejectThrowTwoArgs_void()
QCOMPARE(waitForError(p, QString()), QString("foo")); QCOMPARE(waitForError(p, QString()), QString("foo"));
} }
void tst_qpromise_construct::rejectUndefined()
{
QPromise<int> p([](const QPromiseResolve<int>&, const QPromiseReject<int>& reject) {
QtPromisePrivate::qtpromise_defer([=]() {
reject();
});
});
QCOMPARE(p.isPending(), true);
QCOMPARE(waitForRejected<QPromiseUndefinedException>(p), true);
}
void tst_qpromise_construct::rejectUndefined_void()
{
QPromise<void> p([](const QPromiseResolve<void>&, const QPromiseReject<void>& reject) {
QtPromisePrivate::qtpromise_defer([=]() {
reject();
});
});
QCOMPARE(p.isPending(), true);
QCOMPARE(waitForRejected<QPromiseUndefinedException>(p), true);
}
// https://github.com/simonbrunel/qtpromise/issues/6 // https://github.com/simonbrunel/qtpromise/issues/6
void tst_qpromise_construct::connectAndResolve() void tst_qpromise_construct::connectAndResolve()
{ {

View File

@ -44,4 +44,14 @@ static inline E waitForError(const QtPromise::QPromise<void>& promise, const E&
return error; return error;
} }
template <typename E, typename T>
static inline bool waitForRejected(const T& promise)
{
bool result = false;
promise.tapFail([&](const E&) {
result = true;
}).wait();
return result;
}
#endif // QTPROMISE_TESTS_AUTO_SHARED_UTILS_H #endif // QTPROMISE_TESTS_AUTO_SHARED_UTILS_H