mirror of
https://github.com/simonbrunel/qtpromise.git
synced 2024-11-22 02:34:30 +08:00
Implement QPromise::tap(handler)
This `handler` allows to observe the value of the `input` promise, without changing the propagated value. The `output` promise will be resolved with the same value as the `input` promise (the `handler` returned value will be ignored). However, if `handler` throws, `output` is rejected with the new exception. Unlike `finally`, this handler is not called for rejections.
This commit is contained in:
parent
25d2bad54f
commit
c55fa03e7b
13
README.md
13
README.md
@ -300,6 +300,19 @@ auto output = input.finally([]() {
|
||||
|
||||
If `handler` returns a promise (or QFuture), the `output` promise is delayed until the returned promise is resolved and under the same conditions: the delayed value is ignored, the error transmitted to the `output` promise.
|
||||
|
||||
### <a name="qpromise-tap"></a> `QPromise<T>::tap(handler) -> QPromise<T>`
|
||||
This `handler` allows to observe the value of the `input` promise, without changing the propagated value. The `output` promise will be resolved with the same value as the `input` promise (the `handler` returned value will be ignored). However, if `handler` throws, `output` is rejected with the new exception. Unlike [`finally`](#qpromise-finally), this handler is **not** called for rejections.
|
||||
|
||||
```cpp
|
||||
auto output = input.tap([](int res) {
|
||||
log(res);
|
||||
}).then([](int res) {
|
||||
// {...}
|
||||
});
|
||||
```
|
||||
|
||||
If `handler` returns a promise (or QFuture), the `output` promise is delayed until the returned promise is resolved and under the same conditions: the delayed value is ignored, the error transmitted to the `output` promise.
|
||||
|
||||
### <a name="qpromise-wait"></a> `QPromise<T>::wait() -> QPromise<T>`
|
||||
This method holds the execution of the remaining code **without** blocking the event loop of the current thread:
|
||||
|
||||
|
@ -43,6 +43,9 @@ public:
|
||||
template <typename THandler>
|
||||
inline QPromise<T> finally(THandler handler) const;
|
||||
|
||||
template <typename THandler>
|
||||
inline QPromise<T> tap(THandler handler) const;
|
||||
|
||||
inline QPromise<T> wait() const;
|
||||
|
||||
void swap(QPromiseBase<T>& other) { qSwap(m_d, other.m_d); }
|
||||
|
@ -139,6 +139,16 @@ inline QPromise<T> QPromiseBase<T>::finally(THandler handler) const
|
||||
});
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename THandler>
|
||||
inline QPromise<T> QPromiseBase<T>::tap(THandler handler) const
|
||||
{
|
||||
QPromise<T> p = *this;
|
||||
return p.then(handler).then([=]() {
|
||||
return p;
|
||||
});
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline QPromise<T> QPromiseBase<T>::wait() const
|
||||
{
|
||||
|
@ -15,6 +15,7 @@ private Q_SLOTS:
|
||||
void valueReject();
|
||||
void valueThen();
|
||||
void valueFinally();
|
||||
void valueTap();
|
||||
void valueDelayed();
|
||||
void errorReject();
|
||||
void errorThen();
|
||||
@ -224,6 +225,36 @@ void tst_benchmark::valueFinally()
|
||||
}
|
||||
}
|
||||
|
||||
void tst_benchmark::valueTap()
|
||||
{
|
||||
{ // should not copy the value on continutation if fulfilled
|
||||
int value = -1;
|
||||
Data::logs().reset();
|
||||
QPromise<Data>::resolve(Data(42)).tap([&](const Data& res) {
|
||||
value = res.value();
|
||||
}).wait();
|
||||
|
||||
QCOMPARE(Data::logs().ctor, 1);
|
||||
QCOMPARE(Data::logs().copy, 0);
|
||||
QCOMPARE(Data::logs().move, 1); // move value to the input and output promise data
|
||||
QCOMPARE(Data::logs().refs, 0);
|
||||
QCOMPARE(value, 42);
|
||||
}
|
||||
{ // should not create value on continutation if rejected
|
||||
int value = -1;
|
||||
Data::logs().reset();
|
||||
QPromise<Data>::reject(QString("foo")).tap([&](const Data& res) {
|
||||
value = res.value();
|
||||
}).wait();
|
||||
|
||||
QCOMPARE(Data::logs().ctor, 0);
|
||||
QCOMPARE(Data::logs().copy, 0);
|
||||
QCOMPARE(Data::logs().move, 0);
|
||||
QCOMPARE(Data::logs().refs, 0);
|
||||
QCOMPARE(value, -1);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_benchmark::errorReject()
|
||||
{
|
||||
{ // should create one copy of the error when rejected by rvalue
|
||||
|
@ -39,6 +39,15 @@ private Q_SLOTS:
|
||||
void finallyDelayedResolved();
|
||||
void finallyDelayedRejected();
|
||||
|
||||
void tapFulfilled();
|
||||
void tapFulfilled_void();
|
||||
void tapRejected();
|
||||
void tapRejected_void();
|
||||
void tapThrows();
|
||||
void tapThrows_void();
|
||||
void tapDelayedResolved();
|
||||
void tapDelayedRejected();
|
||||
|
||||
}; // class tst_qpromise
|
||||
|
||||
QTEST_MAIN(tst_qpromise)
|
||||
@ -528,3 +537,120 @@ void tst_qpromise::finallyDelayedRejected()
|
||||
QCOMPARE(p.isRejected(), true);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_qpromise::tapFulfilled()
|
||||
{
|
||||
int value = -1;
|
||||
auto p = QPromise<int>::resolve(42).tap([&](int res) {
|
||||
value = res + 1;
|
||||
return 8;
|
||||
});
|
||||
|
||||
QCOMPARE(waitForValue(p, 42), 42);
|
||||
QCOMPARE(p.isFulfilled(), true);
|
||||
QCOMPARE(value, 43);
|
||||
}
|
||||
|
||||
void tst_qpromise::tapFulfilled_void()
|
||||
{
|
||||
int value = -1;
|
||||
auto p = QPromise<void>::resolve().tap([&]() {
|
||||
value = 43;
|
||||
return 8;
|
||||
});
|
||||
|
||||
QCOMPARE(waitForValue(p, -1, 42), 42);
|
||||
QCOMPARE(p.isFulfilled(), true);
|
||||
QCOMPARE(value, 43);
|
||||
}
|
||||
|
||||
void tst_qpromise::tapRejected()
|
||||
{
|
||||
int value = -1;
|
||||
auto p = QPromise<int>::reject(QString("foo")).tap([&](int res) {
|
||||
value = res + 1;
|
||||
});
|
||||
|
||||
QCOMPARE(waitForError(p, QString()), QString("foo"));
|
||||
QCOMPARE(p.isRejected(), true);
|
||||
QCOMPARE(value, -1);
|
||||
}
|
||||
|
||||
void tst_qpromise::tapRejected_void()
|
||||
{
|
||||
int value = -1;
|
||||
auto p = QPromise<void>::reject(QString("foo")).tap([&]() {
|
||||
value = 43;
|
||||
});
|
||||
|
||||
QCOMPARE(waitForError(p, QString()), QString("foo"));
|
||||
QCOMPARE(p.isRejected(), true);
|
||||
QCOMPARE(value, -1);
|
||||
}
|
||||
|
||||
void tst_qpromise::tapThrows()
|
||||
{
|
||||
auto p = QPromise<int>::resolve(42).tap([&](int) {
|
||||
throw QString("foo");
|
||||
});
|
||||
|
||||
QCOMPARE(waitForError(p, QString()), QString("foo"));
|
||||
QCOMPARE(p.isRejected(), true);
|
||||
}
|
||||
|
||||
void tst_qpromise::tapThrows_void()
|
||||
{
|
||||
auto p = QPromise<void>::resolve().tap([&]() {
|
||||
throw QString("foo");
|
||||
});
|
||||
|
||||
QCOMPARE(waitForError(p, QString()), QString("foo"));
|
||||
QCOMPARE(p.isRejected(), true);
|
||||
}
|
||||
|
||||
void tst_qpromise::tapDelayedResolved()
|
||||
{
|
||||
QVector<int> values;
|
||||
auto p = QPromise<int>::resolve(1).tap([&](int) {
|
||||
QPromise<int> p([&](const QPromiseResolve<int>& resolve) {
|
||||
qtpromise_defer([=, &values]() {
|
||||
values << 3;
|
||||
resolve(4); // ignored!
|
||||
});
|
||||
});
|
||||
|
||||
values << 2;
|
||||
return p;
|
||||
});
|
||||
|
||||
p.then([&](int r) {
|
||||
values << r;
|
||||
}).wait();
|
||||
|
||||
QCOMPARE(p.isFulfilled(), true);
|
||||
QCOMPARE(values, QVector<int>({2, 3, 1}));
|
||||
}
|
||||
|
||||
void tst_qpromise::tapDelayedRejected()
|
||||
{
|
||||
QVector<int> values;
|
||||
auto p = QPromise<int>::resolve(1).tap([&](int) {
|
||||
QPromise<int> p([&](const QPromiseResolve<int>&, const QPromiseReject<int>& reject) {
|
||||
qtpromise_defer([=, &values]() {
|
||||
values << 3;
|
||||
reject(QString("foo"));
|
||||
});
|
||||
});
|
||||
|
||||
values << 2;
|
||||
return p;
|
||||
});
|
||||
|
||||
p.then([&](int r) {
|
||||
values << r;
|
||||
}).wait();
|
||||
|
||||
QCOMPARE(waitForError(p, QString()), QString("foo"));
|
||||
QCOMPARE(p.isRejected(), true);
|
||||
QCOMPARE(values, QVector<int>({2, 3}));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user