mirror of
https://github.com/simonbrunel/qtpromise.git
synced 2024-11-24 11:40:41 +08:00
Implement QPromise<Sequence<T>>::map(mapper) (#15)
Iterate over all the promise value (i.e. `Sequence<T>`) and map the sequence to another using the given `mapper` function. Also provide a static helper to directly map values (`QtPromise::map(values, mapper)`).
This commit is contained in:
parent
4cfe2e54f4
commit
69c07855f4
@ -10,6 +10,7 @@
|
|||||||
* [.isFulfilled](qtpromise/qpromise/isfulfilled.md)
|
* [.isFulfilled](qtpromise/qpromise/isfulfilled.md)
|
||||||
* [.isPending](qtpromise/qpromise/ispending.md)
|
* [.isPending](qtpromise/qpromise/ispending.md)
|
||||||
* [.isRejected](qtpromise/qpromise/isrejected.md)
|
* [.isRejected](qtpromise/qpromise/isrejected.md)
|
||||||
|
* [.map](qtpromise/qpromise/map.md)
|
||||||
* [.tap](qtpromise/qpromise/tap.md)
|
* [.tap](qtpromise/qpromise/tap.md)
|
||||||
* [.tapFail](qtpromise/qpromise/tapfail.md)
|
* [.tapFail](qtpromise/qpromise/tapfail.md)
|
||||||
* [.then](qtpromise/qpromise/then.md)
|
* [.then](qtpromise/qpromise/then.md)
|
||||||
@ -20,3 +21,4 @@
|
|||||||
* [::resolve (static)](qtpromise/qpromise/resolve.md)
|
* [::resolve (static)](qtpromise/qpromise/resolve.md)
|
||||||
* [qPromise](qtpromise/helpers/qpromise.md)
|
* [qPromise](qtpromise/helpers/qpromise.md)
|
||||||
* [qPromiseAll](qtpromise/helpers/qpromiseall.md)
|
* [qPromiseAll](qtpromise/helpers/qpromiseall.md)
|
||||||
|
* [QtPromise::map](qtpromise/helpers/map.md)
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
* [`QPromise<T>::isFulfilled`](qpromise/isfulfilled.md)
|
* [`QPromise<T>::isFulfilled`](qpromise/isfulfilled.md)
|
||||||
* [`QPromise<T>::isPending`](qpromise/ispending.md)
|
* [`QPromise<T>::isPending`](qpromise/ispending.md)
|
||||||
* [`QPromise<T>::isRejected`](qpromise/isrejected.md)
|
* [`QPromise<T>::isRejected`](qpromise/isrejected.md)
|
||||||
|
* [`QPromise<T>::map`](qpromise/map.md)
|
||||||
* [`QPromise<T>::tap`](qpromise/tap.md)
|
* [`QPromise<T>::tap`](qpromise/tap.md)
|
||||||
* [`QPromise<T>::tapFail`](qpromise/tapfail.md)
|
* [`QPromise<T>::tapFail`](qpromise/tapfail.md)
|
||||||
* [`QPromise<T>::then`](qpromise/then.md)
|
* [`QPromise<T>::then`](qpromise/then.md)
|
||||||
@ -25,3 +26,4 @@
|
|||||||
|
|
||||||
* [`qPromise`](helpers/qpromise.md)
|
* [`qPromise`](helpers/qpromise.md)
|
||||||
* [`qPromiseAll`](helpers/qpromiseall.md)
|
* [`qPromiseAll`](helpers/qpromiseall.md)
|
||||||
|
* [`QtPromise::map`](helpers/map.md)
|
||||||
|
43
docs/qtpromise/helpers/map.md
Normal file
43
docs/qtpromise/helpers/map.md
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
## `QtPromise::map`
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
QtPromise::map(Sequence<T> values, Mapper mapper) -> QPromise<QVector<R>>
|
||||||
|
|
||||||
|
// With:
|
||||||
|
// - Sequence: STL compatible container (e.g. QVector, etc.)
|
||||||
|
// - Mapper: Function(T value, int index) -> R | QPromise<R>
|
||||||
|
```
|
||||||
|
|
||||||
|
Iterates over `values` and [maps the sequence](https://en.wikipedia.org/wiki/Map_%28higher-order_function%29)
|
||||||
|
to another using the given `mapper` function. The type returned by `mapper` determines the type
|
||||||
|
of the `output` promise. If `mapper` throws, `output` is rejected with the new exception.
|
||||||
|
|
||||||
|
If `mapper` returns a promise (or `QFuture`), the `output` promise is delayed until all the
|
||||||
|
promises are resolved. If any of the promises fails, `output` immediately rejects with the
|
||||||
|
error of the promise that rejected, whether or not the other promises are resolved.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto output = QtPromise::map(QVector{
|
||||||
|
QUrl("http://a..."),
|
||||||
|
QUrl("http://b..."),
|
||||||
|
QUrl("http://c...")
|
||||||
|
}, [](const QUrl& url, ...) {
|
||||||
|
return QPromise<QByteArray>([&](auto resolve, auto reject) {
|
||||||
|
// download content at url and resolve
|
||||||
|
// {...}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 'output' resolves as soon as all promises returned by
|
||||||
|
// 'mapper' are fulfilled or at least one is rejected.
|
||||||
|
|
||||||
|
// 'output' type: QPromise<QVector<QByteArray>>
|
||||||
|
output.then([](const QVector<QByteArray>& res) {
|
||||||
|
// {...}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
> **Note:** the order of the output sequence values is guarantee to be the same as the original
|
||||||
|
sequence, regardless of completion order of the promises returned by `mapper`.
|
||||||
|
|
||||||
|
See also: [`QPromise<T>::map`](../qpromise/map.md)
|
57
docs/qtpromise/qpromise/map.md
Normal file
57
docs/qtpromise/qpromise/map.md
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
## `QPromise<Sequence<T>>::map`
|
||||||
|
|
||||||
|
> **Important:** applies only to promise with sequence value.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
QPromise<Sequence<T>>::map(Mapper mapper) -> QPromise<QVector<R>>
|
||||||
|
|
||||||
|
// With:
|
||||||
|
// - Sequence: STL compatible container (e.g. QVector, etc.)
|
||||||
|
// - Mapper: Function(T value, int index) -> R | QPromise<R>
|
||||||
|
```
|
||||||
|
|
||||||
|
Iterates over all the promise values (i.e. `Sequence<T>`) and [maps the sequence](https://en.wikipedia.org/wiki/Map_%28higher-order_function%29)
|
||||||
|
to another using the given `mapper` function. The type returned by `mapper` determines the type
|
||||||
|
of the `output` promise. If `mapper` throws, `output` is rejected with the new exception.
|
||||||
|
|
||||||
|
If `mapper` returns a promise (or `QFuture`), the `output` promise is delayed until all the
|
||||||
|
promises are resolved. If any of the promises fails, `output` immediately rejects with the
|
||||||
|
error of the promise that rejected, whether or not the other promises are resolved.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
QPromise<QList<QUrl>> input = {...}
|
||||||
|
|
||||||
|
auto output = input.map([](const QUrl& url, int index) {
|
||||||
|
return QPromise<QByteArray>([&](auto resolve, auto reject) {
|
||||||
|
// download content at 'url' and resolve
|
||||||
|
// {...}
|
||||||
|
});
|
||||||
|
}).map([](const QByteArray& value, ...) {
|
||||||
|
// process the downloaded QByteArray
|
||||||
|
// {...}
|
||||||
|
return DownloadResult(value);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 'output' resolves as soon as all promises returned by
|
||||||
|
// 'mapper' are fulfilled or at least one is rejected.
|
||||||
|
|
||||||
|
// 'output' type: QPromise<QVector<DownloadResult>>
|
||||||
|
output.then([](const QVector<DownloadResult>& res) {
|
||||||
|
// {...}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
> **Note:** the order of the output sequence values is guarantee to be the same as the original
|
||||||
|
sequence, regardless of completion order of the promises returned by `mapper`.
|
||||||
|
|
||||||
|
This function is provided for convenience and is similar to:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
promise.then([](const Sequence<T>& values) {
|
||||||
|
return QtPromise::map(values, [](const T& value, int index) {
|
||||||
|
return // {...}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
See also: [`QtPromise::map`](../helpers/map.md)
|
@ -88,6 +88,10 @@ public:
|
|||||||
template <typename F>
|
template <typename F>
|
||||||
QPromise(F&& resolver): QPromiseBase<T>(std::forward<F>(resolver)) { }
|
QPromise(F&& resolver): QPromiseBase<T>(std::forward<F>(resolver)) { }
|
||||||
|
|
||||||
|
template <typename Functor>
|
||||||
|
inline typename QtPromisePrivate::PromiseMapper<T, Functor>::PromiseType
|
||||||
|
map(Functor fn);
|
||||||
|
|
||||||
public: // STATIC
|
public: // STATIC
|
||||||
template <template <typename, typename...> class Sequence = QVector, typename ...Args>
|
template <template <typename, typename...> class Sequence = QVector, typename ...Args>
|
||||||
inline static QPromise<QVector<T>> all(const Sequence<QPromise<T>, Args...>& promises);
|
inline static QPromise<QVector<T>> all(const Sequence<QPromise<T>, Args...>& promises);
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include "qpromise.h"
|
#include "qpromise.h"
|
||||||
|
#include "qpromisehelpers.h"
|
||||||
|
|
||||||
// Qt
|
// Qt
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
@ -154,6 +155,16 @@ inline QPromise<T> QPromiseBase<T>::reject(E&& error)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
template <typename Functor>
|
||||||
|
inline typename QtPromisePrivate::PromiseMapper<T, Functor>::PromiseType
|
||||||
|
QPromise<T>::map(Functor fn)
|
||||||
|
{
|
||||||
|
return this->then([=](const T& values) {
|
||||||
|
return QtPromise::map(values, fn);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
template <template <typename, typename...> class Sequence, typename ...Args>
|
template <template <typename, typename...> class Sequence, typename ...Args>
|
||||||
inline QPromise<QVector<T>> QPromise<T>::all(const Sequence<QPromise<T>, Args...>& promises)
|
inline QPromise<QVector<T>> QPromise<T>::all(const Sequence<QPromise<T>, Args...>& promises)
|
||||||
|
@ -397,6 +397,18 @@ struct PromiseCatcher<T, std::nullptr_t, void>
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename T, typename F>
|
||||||
|
struct PromiseMapper
|
||||||
|
{ };
|
||||||
|
|
||||||
|
template <typename T, typename F, template <typename, typename...> class Sequence, typename ...Args>
|
||||||
|
struct PromiseMapper<Sequence<T, Args...>, F>
|
||||||
|
{
|
||||||
|
using ReturnType = typename std::result_of<F(T, int)>::type;
|
||||||
|
using ResultType = QVector<typename PromiseDeduce<ReturnType>::Type::Type>;
|
||||||
|
using PromiseType = QtPromise::QPromise<ResultType>;
|
||||||
|
};
|
||||||
|
|
||||||
template <typename T> class PromiseData;
|
template <typename T> class PromiseData;
|
||||||
|
|
||||||
template <typename T, typename F>
|
template <typename T, typename F>
|
||||||
|
@ -38,6 +38,31 @@ static inline QPromise<void> qPromiseAll(const Sequence<QPromise<void>, Args...>
|
|||||||
return QPromise<void>::all(promises);
|
return QPromise<void>::all(promises);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename Sequence, typename Functor>
|
||||||
|
static inline typename QtPromisePrivate::PromiseMapper<Sequence, Functor>::PromiseType
|
||||||
|
map(const Sequence& values, Functor fn)
|
||||||
|
{
|
||||||
|
using namespace QtPromisePrivate;
|
||||||
|
using MapperType = PromiseMapper<Sequence, Functor>;
|
||||||
|
using ResType = typename MapperType::ResultType::value_type;
|
||||||
|
using RetType = typename MapperType::ReturnType;
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
std::vector<QPromise<ResType>> promises;
|
||||||
|
for (const auto& v : values) {
|
||||||
|
promises.push_back(QPromise<ResType>([&](
|
||||||
|
const QPromiseResolve<ResType>& resolve,
|
||||||
|
const QPromiseReject<ResType>& reject) {
|
||||||
|
PromiseFulfill<RetType>::call(fn(v, i), resolve, reject);
|
||||||
|
}));
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return QPromise<ResType>::all(promises);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace QtPromise
|
} // namespace QtPromise
|
||||||
|
|
||||||
#endif // QTPROMISE_QPROMISEHELPERS_H
|
#endif // QTPROMISE_QPROMISEHELPERS_H
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
TEMPLATE = subdirs
|
TEMPLATE = subdirs
|
||||||
SUBDIRS += \
|
SUBDIRS += \
|
||||||
all \
|
all \
|
||||||
|
map \
|
||||||
reject \
|
reject \
|
||||||
resolve
|
resolve
|
||||||
|
4
tests/auto/qtpromise/helpers/map/map.pro
Normal file
4
tests/auto/qtpromise/helpers/map/map.pro
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
TARGET = tst_helpers_map
|
||||||
|
SOURCES += $$PWD/tst_map.cpp
|
||||||
|
|
||||||
|
include(../../qtpromise.pri)
|
151
tests/auto/qtpromise/helpers/map/tst_map.cpp
Normal file
151
tests/auto/qtpromise/helpers/map/tst_map.cpp
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
// Tests
|
||||||
|
#include "../../shared/utils.h"
|
||||||
|
|
||||||
|
// QtPromise
|
||||||
|
#include <QtPromise>
|
||||||
|
|
||||||
|
// Qt
|
||||||
|
#include <QtTest>
|
||||||
|
|
||||||
|
using namespace QtPromise;
|
||||||
|
|
||||||
|
class tst_helpers_map : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
void emptySequence();
|
||||||
|
void modifyValues();
|
||||||
|
void convertValues();
|
||||||
|
void delayedFulfilled();
|
||||||
|
void delayedRejected();
|
||||||
|
void functorThrows();
|
||||||
|
void functorArguments();
|
||||||
|
void preserveOrder();
|
||||||
|
void sequenceTypes();
|
||||||
|
};
|
||||||
|
|
||||||
|
QTEST_MAIN(tst_helpers_map)
|
||||||
|
#include "tst_map.moc"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
template <class Sequence>
|
||||||
|
struct SequenceTester
|
||||||
|
{
|
||||||
|
static void exec()
|
||||||
|
{
|
||||||
|
auto p = QtPromise::map(Sequence{42, 43, 44}, [](int v, ...) {
|
||||||
|
return QString::number(v + 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<QString>>>::value));
|
||||||
|
QCOMPARE(waitForValue(p, QVector<QString>()), QVector<QString>({"43", "44", "45"}));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
|
void tst_helpers_map::emptySequence()
|
||||||
|
{
|
||||||
|
auto p = QtPromise::map(QVector<int>{}, [](int v, ...) {
|
||||||
|
return v + 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||||
|
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({}));
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_helpers_map::modifyValues()
|
||||||
|
{
|
||||||
|
auto p = QtPromise::map(QVector<int>{42, 43, 44}, [](int v, ...) {
|
||||||
|
return v + 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||||
|
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({43, 44, 45}));
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_helpers_map::convertValues()
|
||||||
|
{
|
||||||
|
auto p = QtPromise::map(QVector<int>{42, 43, 44}, [](int v, ...) {
|
||||||
|
return QString::number(v + 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<QString>>>::value));
|
||||||
|
QCOMPARE(waitForValue(p, QVector<QString>()), QVector<QString>({"43", "44", "45"}));
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_helpers_map::delayedFulfilled()
|
||||||
|
{
|
||||||
|
auto p = QtPromise::map(QVector<int>{42, 43, 44}, [](int v, ...) {
|
||||||
|
return QPromise<int>([&](const QPromiseResolve<int>& resolve) {
|
||||||
|
QtPromisePrivate::qtpromise_defer([=]() {
|
||||||
|
resolve(v + 1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||||
|
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({43, 44, 45}));
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_helpers_map::delayedRejected()
|
||||||
|
{
|
||||||
|
auto p = QtPromise::map(QVector<int>{42, 43, 44}, [](int v, ...) {
|
||||||
|
return QPromise<int>([&](
|
||||||
|
const QPromiseResolve<int>& resolve,
|
||||||
|
const QPromiseReject<int>& reject) {
|
||||||
|
QtPromisePrivate::qtpromise_defer([=]() {
|
||||||
|
if (v == 43) {
|
||||||
|
reject(QString("foo"));
|
||||||
|
}
|
||||||
|
resolve(v);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||||
|
QCOMPARE(waitForError(p, QString()), QString("foo"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_helpers_map::functorThrows()
|
||||||
|
{
|
||||||
|
auto p = QtPromise::map(QVector<int>{42, 43, 44}, [](int v, ...) {
|
||||||
|
if (v == 43) {
|
||||||
|
throw QString("foo");
|
||||||
|
}
|
||||||
|
return v + 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||||
|
QCOMPARE(waitForError(p, QString()), QString("foo"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_helpers_map::functorArguments()
|
||||||
|
{
|
||||||
|
auto p = QtPromise::map(QVector<int>{42, 42, 42}, [](int v, int i) {
|
||||||
|
return v * i;
|
||||||
|
});
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||||
|
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({0, 42, 84}));
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_helpers_map::preserveOrder()
|
||||||
|
{
|
||||||
|
auto p = QtPromise::map(QVector<int>{500, 100, 250}, [](int v, ...) {
|
||||||
|
return QPromise<int>::resolve(v + 1).delay(v);
|
||||||
|
});
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||||
|
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({501, 101, 251}));
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_helpers_map::sequenceTypes()
|
||||||
|
{
|
||||||
|
SequenceTester<QList<int>>::exec();
|
||||||
|
SequenceTester<QVector<int>>::exec();
|
||||||
|
SequenceTester<std::list<int>>::exec();
|
||||||
|
SequenceTester<std::vector<int>>::exec();
|
||||||
|
}
|
4
tests/auto/qtpromise/qpromise/map/map.pro
Normal file
4
tests/auto/qtpromise/qpromise/map/map.pro
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
TARGET = tst_qpromise_map
|
||||||
|
SOURCES += $$PWD/tst_map.cpp
|
||||||
|
|
||||||
|
include(../../qtpromise.pri)
|
157
tests/auto/qtpromise/qpromise/map/tst_map.cpp
Normal file
157
tests/auto/qtpromise/qpromise/map/tst_map.cpp
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
// Tests
|
||||||
|
#include "../../shared/utils.h"
|
||||||
|
|
||||||
|
// QtPromise
|
||||||
|
#include <QtPromise>
|
||||||
|
|
||||||
|
// Qt
|
||||||
|
#include <QtTest>
|
||||||
|
|
||||||
|
using namespace QtPromise;
|
||||||
|
|
||||||
|
class tst_qpromise_map : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
void emptySequence();
|
||||||
|
void modifyValues();
|
||||||
|
void convertValues();
|
||||||
|
void delayedFulfilled();
|
||||||
|
void delayedRejected();
|
||||||
|
void functorThrows();
|
||||||
|
void functorArguments();
|
||||||
|
void preserveOrder();
|
||||||
|
void sequenceTypes();
|
||||||
|
};
|
||||||
|
|
||||||
|
QTEST_MAIN(tst_qpromise_map)
|
||||||
|
#include "tst_map.moc"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
template <class Sequence>
|
||||||
|
struct SequenceTester
|
||||||
|
{
|
||||||
|
static void exec()
|
||||||
|
{
|
||||||
|
auto p = QtPromise::qPromise(Sequence{42, 43, 44}).map([](int v, ...) {
|
||||||
|
return QString::number(v + 1);
|
||||||
|
}).map([](const QString& v, int i) {
|
||||||
|
return QtPromise::qPromise(QString("%1:%2").arg(i).arg(v));
|
||||||
|
}).map([](const QString& v, ...) {
|
||||||
|
return QtPromise::qPromise((v + "!").toUtf8());
|
||||||
|
}).map([](const QByteArray& v, ...) {
|
||||||
|
return QString::fromUtf8(v);
|
||||||
|
});
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<QString>>>::value));
|
||||||
|
QCOMPARE(waitForValue(p, QVector<QString>()), QVector<QString>({"0:43!", "1:44!", "2:45!"}));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
|
void tst_qpromise_map::emptySequence()
|
||||||
|
{
|
||||||
|
auto p = QtPromise::qPromise(QVector<int>{}).map([](int v, ...) {
|
||||||
|
return v + 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||||
|
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({}));
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_qpromise_map::modifyValues()
|
||||||
|
{
|
||||||
|
auto p = QtPromise::qPromise(QVector<int>{42, 43, 44}).map([](int v, ...) {
|
||||||
|
return v + 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||||
|
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({43, 44, 45}));
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_qpromise_map::convertValues()
|
||||||
|
{
|
||||||
|
auto p = QtPromise::qPromise(QVector<int>{42, 43, 44}).map([](int v, ...) {
|
||||||
|
return QString::number(v + 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<QString>>>::value));
|
||||||
|
QCOMPARE(waitForValue(p, QVector<QString>()), QVector<QString>({"43", "44", "45"}));
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_qpromise_map::delayedFulfilled()
|
||||||
|
{
|
||||||
|
auto p = QtPromise::qPromise(QVector<int>{42, 43, 44}).map([](int v, ...) {
|
||||||
|
return QPromise<int>([&](const QPromiseResolve<int>& resolve) {
|
||||||
|
QtPromisePrivate::qtpromise_defer([=]() {
|
||||||
|
resolve(v + 1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||||
|
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({43, 44, 45}));
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_qpromise_map::delayedRejected()
|
||||||
|
{
|
||||||
|
auto p = QtPromise::qPromise(QVector<int>{42, 43, 44}).map([](int v, ...) {
|
||||||
|
return QPromise<int>([&](
|
||||||
|
const QPromiseResolve<int>& resolve,
|
||||||
|
const QPromiseReject<int>& reject) {
|
||||||
|
QtPromisePrivate::qtpromise_defer([=]() {
|
||||||
|
if (v == 43) {
|
||||||
|
reject(QString("foo"));
|
||||||
|
}
|
||||||
|
resolve(v);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||||
|
QCOMPARE(waitForError(p, QString()), QString("foo"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_qpromise_map::functorThrows()
|
||||||
|
{
|
||||||
|
auto p = QtPromise::qPromise(QVector<int>{42, 43, 44}).map([](int v, ...) {
|
||||||
|
if (v == 43) {
|
||||||
|
throw QString("foo");
|
||||||
|
}
|
||||||
|
return v + 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||||
|
QCOMPARE(waitForError(p, QString()), QString("foo"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_qpromise_map::functorArguments()
|
||||||
|
{
|
||||||
|
auto p1 = QtPromise::qPromise(QVector<int>{42, 42, 42}).map([](int v, int i) {
|
||||||
|
return v * i;
|
||||||
|
});
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<QVector<int>>>::value));
|
||||||
|
QCOMPARE(waitForValue(p1, QVector<int>()), QVector<int>({0, 42, 84}));
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_qpromise_map::preserveOrder()
|
||||||
|
{
|
||||||
|
auto p = QtPromise::qPromise(QVector<int>{250, 500, 100}).map([](int v, ...) {
|
||||||
|
return QtPromise::qPromise(v + 1).delay(v);
|
||||||
|
});
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||||
|
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({251, 501, 101}));
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_qpromise_map::sequenceTypes()
|
||||||
|
{
|
||||||
|
SequenceTester<QList<int>>::exec();
|
||||||
|
SequenceTester<QVector<int>>::exec();
|
||||||
|
SequenceTester<std::list<int>>::exec();
|
||||||
|
SequenceTester<std::vector<int>>::exec();
|
||||||
|
}
|
@ -4,6 +4,7 @@ SUBDIRS += \
|
|||||||
delay \
|
delay \
|
||||||
fail \
|
fail \
|
||||||
finally \
|
finally \
|
||||||
|
map \
|
||||||
operators \
|
operators \
|
||||||
tap \
|
tap \
|
||||||
tapfail \
|
tapfail \
|
||||||
|
Loading…
Reference in New Issue
Block a user