mirror of
https://github.com/simonbrunel/qtpromise.git
synced 2025-07-01 06:41:55 +08:00
Compare commits
24 Commits
Author | SHA1 | Date | |
---|---|---|---|
67837827b1 | |||
e3f0f054af | |||
cbf4cc7867 | |||
963ec621e1 | |||
1f30224578 | |||
47b90fb532 | |||
63acdfaab9 | |||
700098ef7b | |||
6110cd40d3 | |||
a6d883acbd | |||
9119cc72f6 | |||
fa5a4192ff | |||
16229fc2c9 | |||
22faef4ac3 | |||
eebcb4f364 | |||
051fed5fbc | |||
f610826ef0 | |||
4fa7a37750 | |||
69c07855f4 | |||
4cfe2e54f4 | |||
54d88f16a3 | |||
bdf3619469 | |||
8da467e9da | |||
efb6001b9d |
27
.appveyor.yml
Normal file
27
.appveyor.yml
Normal file
@ -0,0 +1,27 @@
|
||||
image: Visual Studio 2015
|
||||
|
||||
init:
|
||||
- cmd: call "C:\Program Files (x86)\Microsoft Visual Studio "%VSVER%".0\VC\vcvarsall.bat" %ARCH%
|
||||
- cmd: qmake --version
|
||||
|
||||
# https://www.appveyor.com/docs/windows-images-software/#qt
|
||||
environment:
|
||||
PATH: '%PATH%;%QTDIR%\bin'
|
||||
matrix:
|
||||
- QTDIR: C:\Qt\5.6\msvc2013
|
||||
VSVER: 12
|
||||
ARCH: x86
|
||||
- QTDIR: C:\Qt\5.9\msvc2013_64
|
||||
VSVER: 12
|
||||
ARCH: x64
|
||||
- QTDIR: C:\Qt\latest\msvc2015_64
|
||||
VSVER: 14
|
||||
ARCH: x64
|
||||
|
||||
build_script:
|
||||
- cmd: qmake qtpromise.pro
|
||||
- cmd: nmake
|
||||
|
||||
test_script:
|
||||
- cmd: nmake check
|
||||
|
15
.travis.yml
15
.travis.yml
@ -4,12 +4,17 @@ language: cpp
|
||||
compiler: gcc
|
||||
|
||||
before_install:
|
||||
- sudo add-apt-repository -y ppa:beineri/opt-qt542-trusty
|
||||
- sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
||||
- sudo add-apt-repository -y ppa:beineri/opt-qt563-trusty
|
||||
- sudo apt-get update -qq
|
||||
|
||||
install:
|
||||
- sudo apt-get install -qq qt54base
|
||||
- source /opt/qt54/bin/qt54-env.sh
|
||||
- sudo apt-get install -qq gcc-4.9 g++-4.9
|
||||
- sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.9 90
|
||||
- sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.9 90
|
||||
- sudo update-alternatives --install /usr/bin/gcov gcov /usr/bin/gcov-4.9 90
|
||||
- sudo apt-get install -qq qt56base
|
||||
- source /opt/qt56/bin/qt56-env.sh
|
||||
- wget http://archive.ubuntu.com/ubuntu/pool/universe/l/lcov/lcov_1.13.orig.tar.gz
|
||||
- tar xf lcov_1.13.orig.tar.gz
|
||||
- cd lcov-1.13/
|
||||
@ -18,8 +23,8 @@ install:
|
||||
|
||||
before_script:
|
||||
- qmake --version
|
||||
- lcov --version
|
||||
- gcc --version
|
||||
- lcov --version && gcov --version
|
||||
- gcc --version && g++ --version
|
||||
|
||||
script:
|
||||
- qmake qtpromise.pro CONFIG+=coverage
|
||||
|
2
LICENSE
2
LICENSE
@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2017 Simon Brunel
|
||||
Copyright (c) 2019 Simon Brunel
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
|
13
README.md
13
README.md
@ -1,18 +1,21 @@
|
||||
<a href="https://promisesaplus.com/" title="Promises/A+ 1.1"><img src="https://promisesaplus.com/assets/logo-small.png" alt="Promises/A+" align="right"/></a>
|
||||
|
||||
# QtPromise
|
||||
|
||||
[](https://www.qpm.io/packages/com.github.simonbrunel.qtpromise/index.html) [](https://travis-ci.org/simonbrunel/qtpromise) [](https://codecov.io/gh/simonbrunel/qtpromise)
|
||||
|
||||
[Promises/A+](https://promisesaplus.com/) implementation for [Qt/C++](https://www.qt.io/).
|
||||
|
||||
Requires [Qt 5.4](https://www.qt.io/download/) (or later) with [C++11 support enabled](https://wiki.qt.io/How_to_use_C++11_in_your_Qt_Projects).
|
||||
Requires [Qt 5.6](https://www.qt.io/download/) (or later) with [C++11 support enabled](https://wiki.qt.io/How_to_use_C++11_in_your_Qt_Projects).
|
||||
|
||||
## Documentation
|
||||
|
||||
* [Getting Started](https://qtpromise.netlify.com/qtpromise/getting-started)
|
||||
* [Thread-Safety](https://qtpromise.netlify.com/qtpromise/thread-safety)
|
||||
* [QtConcurrent](https://qtpromise.netlify.com/qtpromise/qtconcurrent)
|
||||
* [API Reference](https://qtpromise.netlify.com/qtpromise/api-reference)
|
||||
* [Getting Started](https://qtpromise.netlify.com/qtpromise/getting-started.html)
|
||||
* [Qt Concurrent](https://qtpromise.netlify.com/qtpromise/qtconcurrent.html)
|
||||
* [Qt Signals](https://qtpromise.netlify.com/qtpromise/qtsignals.html)
|
||||
* [Thread-Safety](https://qtpromise.netlify.com/qtpromise/thread-safety.html)
|
||||
* [API Reference](https://qtpromise.netlify.com/qtpromise/api-reference.html)
|
||||
|
||||
## License
|
||||
|
||||
QtPromise is available under the [MIT license](LICENSE).
|
||||
|
40
book.json
40
book.json
@ -1,40 +0,0 @@
|
||||
{
|
||||
"title": "QtPromise",
|
||||
"description": "Promises/A+ implementation for Qt/C++",
|
||||
"author": "Simon Brunel",
|
||||
"gitbook": "3.2.3",
|
||||
"root": "docs",
|
||||
"plugins": [
|
||||
"-lunr",
|
||||
"-search",
|
||||
"search-plus",
|
||||
"anchorjs",
|
||||
"edit-link",
|
||||
"expand-active-chapter",
|
||||
"ga",
|
||||
"github"
|
||||
],
|
||||
"pluginsConfig": {
|
||||
"anchorjs": {
|
||||
"icon": "#",
|
||||
"placement": "left",
|
||||
"visible": "always"
|
||||
},
|
||||
"edit-link": {
|
||||
"base": "https://github.com/simonbrunel/qtpromise/edit/master/docs"
|
||||
},
|
||||
"ga": {
|
||||
"token": "UA-113899811-1",
|
||||
"configuration": "auto"
|
||||
},
|
||||
"github": {
|
||||
"url": "https://github.com/simonbrunel/qtpromise"
|
||||
},
|
||||
"theme-default": {
|
||||
"showLevel": false,
|
||||
"styles": {
|
||||
"website": "assets/style.css"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
70
docs/.vuepress/config.js
Normal file
70
docs/.vuepress/config.js
Normal file
@ -0,0 +1,70 @@
|
||||
module.exports = {
|
||||
title: 'QtPromise',
|
||||
description: 'Promises/A+ implementation for Qt/C++',
|
||||
ga: 'UA-113899811-1',
|
||||
head: [
|
||||
['link', { rel: 'icon', href: `/favicon.png` }],
|
||||
],
|
||||
themeConfig: {
|
||||
repo: 'simonbrunel/qtpromise',
|
||||
lastUpdated: 'Last Updated',
|
||||
editLinks: true,
|
||||
docsDir: 'docs',
|
||||
algolia: {
|
||||
apiKey: '0e6e9cccb8c2c360a5543e28c4e31cb8',
|
||||
indexName: 'qtpromise'
|
||||
},
|
||||
sidebar: [
|
||||
'qtpromise/getting-started',
|
||||
'qtpromise/qtconcurrent',
|
||||
'qtpromise/qtsignals',
|
||||
'qtpromise/thread-safety',
|
||||
'qtpromise/api-reference',
|
||||
{
|
||||
title: 'QPromise',
|
||||
children: [
|
||||
'qtpromise/qpromise/constructor',
|
||||
'qtpromise/qpromise/delay',
|
||||
'qtpromise/qpromise/each',
|
||||
'qtpromise/qpromise/fail',
|
||||
'qtpromise/qpromise/filter',
|
||||
'qtpromise/qpromise/finally',
|
||||
'qtpromise/qpromise/isfulfilled',
|
||||
'qtpromise/qpromise/ispending',
|
||||
'qtpromise/qpromise/isrejected',
|
||||
'qtpromise/qpromise/map',
|
||||
'qtpromise/qpromise/reduce',
|
||||
'qtpromise/qpromise/tap',
|
||||
'qtpromise/qpromise/tapfail',
|
||||
'qtpromise/qpromise/then',
|
||||
'qtpromise/qpromise/timeout',
|
||||
'qtpromise/qpromise/wait',
|
||||
'qtpromise/qpromise/reject.md',
|
||||
'qtpromise/qpromise/resolve.md'
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Helpers',
|
||||
children: [
|
||||
'qtpromise/helpers/all',
|
||||
'qtpromise/helpers/attempt',
|
||||
'qtpromise/helpers/connect',
|
||||
'qtpromise/helpers/each',
|
||||
'qtpromise/helpers/filter',
|
||||
'qtpromise/helpers/map',
|
||||
'qtpromise/helpers/reduce',
|
||||
'qtpromise/helpers/resolve'
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Exceptions',
|
||||
children: [
|
||||
'qtpromise/exceptions/canceled',
|
||||
'qtpromise/exceptions/context',
|
||||
'qtpromise/exceptions/timeout',
|
||||
'qtpromise/exceptions/undefined'
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
2
docs/.vuepress/override.styl
Normal file
2
docs/.vuepress/override.styl
Normal file
@ -0,0 +1,2 @@
|
||||
$accentColor = #23b223
|
||||
$textColor = #404244
|
BIN
docs/.vuepress/public/favicon.ico
Normal file
BIN
docs/.vuepress/public/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 34 KiB |
BIN
docs/.vuepress/public/favicon.png
Normal file
BIN
docs/.vuepress/public/favicon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 21 KiB |
4
docs/.vuepress/style.styl
Normal file
4
docs/.vuepress/style.styl
Normal file
@ -0,0 +1,4 @@
|
||||
@import 'override.styl'
|
||||
|
||||
.content a code
|
||||
color: $accentColor
|
@ -3,13 +3,7 @@
|
||||
# QtPromise
|
||||
[Promises/A+](https://promisesaplus.com/) implementation for [Qt/C++](https://www.qt.io/).
|
||||
|
||||
Requires [Qt 5.4](https://www.qt.io/download/) (or later) with [C++11 support enabled](https://wiki.qt.io/How_to_use_C++11_in_your_Qt_Projects).
|
||||
|
||||
## QtPromise for C++
|
||||
* [Getting Started](qtpromise/getting-started.md)
|
||||
* [Thread-Safety](qtpromise/thread-safety.md)
|
||||
* [QtConcurrent](qtpromise/qtconcurrent.md)
|
||||
* [API Reference](qtpromise/api-reference.md)
|
||||
Requires [Qt 5.6](https://www.qt.io/download/) (or later) with [C++11 support enabled](https://wiki.qt.io/How_to_use_C++11_in_your_Qt_Projects).
|
||||
|
||||
## License
|
||||
QtPromise is available under the [MIT license](https://github.com/simonbrunel/qtpromise/blob/master/LICENSE).
|
||||
|
@ -1,22 +0,0 @@
|
||||
### QtPromise for C++
|
||||
* [Getting Started](qtpromise/getting-started.md)
|
||||
* [QtConcurrent](qtpromise/qtconcurrent.md)
|
||||
* [Thread-Safety](qtpromise/thread-safety.md)
|
||||
* [API Reference](qtpromise/api-reference.md)
|
||||
* [QPromise](qtpromise/qpromise/constructor.md)
|
||||
* [.delay](qtpromise/qpromise/delay.md)
|
||||
* [.fail](qtpromise/qpromise/fail.md)
|
||||
* [.finally](qtpromise/qpromise/finally.md)
|
||||
* [.isFulfilled](qtpromise/qpromise/isfulfilled.md)
|
||||
* [.isPending](qtpromise/qpromise/ispending.md)
|
||||
* [.isRejected](qtpromise/qpromise/isrejected.md)
|
||||
* [.tap](qtpromise/qpromise/tap.md)
|
||||
* [.tapFail](qtpromise/qpromise/tapfail.md)
|
||||
* [.then](qtpromise/qpromise/then.md)
|
||||
* [.timeout](qtpromise/qpromise/timeout.md)
|
||||
* [.wait](qtpromise/qpromise/wait.md)
|
||||
* [::all (static)](qtpromise/qpromise/all.md)
|
||||
* [::reject (static)](qtpromise/qpromise/reject.md)
|
||||
* [::resolve (static)](qtpromise/qpromise/resolve.md)
|
||||
* [qPromise](qtpromise/helpers/qpromise.md)
|
||||
* [qPromiseAll](qtpromise/helpers/qpromiseall.md)
|
@ -1,15 +0,0 @@
|
||||
a.anchorjs-link {
|
||||
color: rgba(65, 131, 196, 0.1);
|
||||
font-weight: 400;
|
||||
text-decoration: none;
|
||||
transition: color 100ms ease-out;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
a.anchorjs-link:hover {
|
||||
color: rgba(65, 131, 196, 1);
|
||||
}
|
||||
|
||||
sup {
|
||||
font-size: 0.75em !important;
|
||||
}
|
@ -1,27 +1,49 @@
|
||||
## QPromise
|
||||
# API Reference
|
||||
|
||||
### Public Members
|
||||
## Functions
|
||||
|
||||
* [`QPromise<T>::QPromise`](qpromise/constructor.md)
|
||||
* [`QPromise<T>::delay`](qpromise/delay.md)
|
||||
* [`QPromise<T>::each`](qpromise/each.md)
|
||||
* [`QPromise<T>::fail`](qpromise/fail.md)
|
||||
* [`QPromise<T>::filter`](qpromise/filter.md)
|
||||
* [`QPromise<T>::finally`](qpromise/finally.md)
|
||||
* [`QPromise<T>::isFulfilled`](qpromise/isfulfilled.md)
|
||||
* [`QPromise<T>::isPending`](qpromise/ispending.md)
|
||||
* [`QPromise<T>::isRejected`](qpromise/isrejected.md)
|
||||
* [`QPromise<T>::map`](qpromise/map.md)
|
||||
* [`QPromise<T>::reduce`](qpromise/reduce.md)
|
||||
* [`QPromise<T>::tap`](qpromise/tap.md)
|
||||
* [`QPromise<T>::tapFail`](qpromise/tapfail.md)
|
||||
* [`QPromise<T>::then`](qpromise/then.md)
|
||||
* [`QPromise<T>::timeout`](qpromise/timeout.md)
|
||||
* [`QPromise<T>::wait`](qpromise/wait.md)
|
||||
|
||||
### Public Static Members
|
||||
## Static Functions
|
||||
|
||||
* [`[static] QPromise<T>::all`](qpromise/all.md)
|
||||
* [`[static] QPromise<T>::reject`](qpromise/reject.md)
|
||||
* [`[static] QPromise<T>::resolve`](qpromise/resolve.md)
|
||||
|
||||
## Helpers
|
||||
|
||||
* [`qPromise`](helpers/qpromise.md)
|
||||
* [`qPromiseAll`](helpers/qpromiseall.md)
|
||||
* [`QtPromise::all`](helpers/all.md)
|
||||
* [`QtPromise::attempt`](helpers/attempt.md)
|
||||
* [`QtPromise::connect`](helpers/connect.md)
|
||||
* [`QtPromise::each`](helpers/each.md)
|
||||
* [`QtPromise::filter`](helpers/filter.md)
|
||||
* [`QtPromise::map`](helpers/map.md)
|
||||
* [`QtPromise::reduce`](helpers/reduce.md)
|
||||
* [`QtPromise::resolve`](helpers/resolve.md)
|
||||
|
||||
## Exceptions
|
||||
|
||||
* [`QPromiseCanceledException`](exceptions/canceled.md)
|
||||
* [`QPromiseContextException`](exceptions/context.md)
|
||||
* [`QPromiseTimeoutException`](exceptions/timeout.md)
|
||||
* [`QPromiseUndefinedException`](exceptions/undefined.md)
|
||||
|
||||
## Deprecations
|
||||
|
||||
* `[static] QPromise<T>::all`: use [`QtPromise::all`](helpers/all.md) instead (since 0.5.0)
|
||||
* `QtPromise::qPromise`: use [`QtPromise::resolve`](helpers/resolve.md) instead (since 0.5.0)
|
||||
* `QtPromise::qPromiseAll`: use [`QtPromise::all`](helpers/all.md) instead (since 0.5.0)
|
||||
|
20
docs/qtpromise/exceptions/canceled.md
Normal file
20
docs/qtpromise/exceptions/canceled.md
Normal file
@ -0,0 +1,20 @@
|
||||
---
|
||||
title: QPromiseCanceledException
|
||||
---
|
||||
|
||||
# QPromiseCanceledException
|
||||
|
||||
*Since: 0.1.0*
|
||||
|
||||
This exception is thrown for promise created from a [`QFuture`](../qtconcurrent.md) which has been canceled (e.g. using [`QFuture::cancel()`](http://doc.qt.io/qt-5/qfuture.html#cancel)), for example:
|
||||
|
||||
```cpp
|
||||
auto output = QtPromise::resolve(future)
|
||||
.fail([](const QPromiseCanceledException&) {
|
||||
// `future` has been canceled!
|
||||
});
|
||||
```
|
||||
|
||||
::: tip NOTE
|
||||
QtPromise doesn't support promise cancelation (yet?)
|
||||
:::
|
17
docs/qtpromise/exceptions/context.md
Normal file
17
docs/qtpromise/exceptions/context.md
Normal file
@ -0,0 +1,17 @@
|
||||
---
|
||||
title: QPromiseContextException
|
||||
---
|
||||
|
||||
# QPromiseContextException
|
||||
|
||||
*Since: 0.5.0*
|
||||
|
||||
When a promise is created using [`QtPromise::connect()`](../helpers/connect.md), this exception is thrown when the `sender` object is destroyed, for example:
|
||||
|
||||
```cpp
|
||||
auto promise = QtPromise::connect(sender, &Object::finished, &Object::error);
|
||||
|
||||
promise.fail([](const QPromiseContextException&) {
|
||||
// 'sender' has been destroyed.
|
||||
})
|
||||
```
|
17
docs/qtpromise/exceptions/timeout.md
Normal file
17
docs/qtpromise/exceptions/timeout.md
Normal file
@ -0,0 +1,17 @@
|
||||
---
|
||||
title: QPromiseTimeoutException
|
||||
---
|
||||
|
||||
# QPromiseTimeoutException
|
||||
|
||||
*Since: 0.2.0*
|
||||
|
||||
This is the default exception thrown when reaching the time limit when using the [`QPromise::timeout()`](../qpromise/timeout.md) method, for example:
|
||||
|
||||
```cpp
|
||||
QPromise<int> input = {...}
|
||||
auto output = input.timeout(2000)
|
||||
.fail([](const QPromiseTimeoutException& e) {
|
||||
// operation timed out after 2s!
|
||||
});
|
||||
```
|
25
docs/qtpromise/exceptions/undefined.md
Normal file
25
docs/qtpromise/exceptions/undefined.md
Normal file
@ -0,0 +1,25 @@
|
||||
---
|
||||
title: QPromiseUndefinedException
|
||||
---
|
||||
|
||||
# QPromiseUndefinedException
|
||||
|
||||
*Since: 0.5.0*
|
||||
|
||||
This exception is thrown when rejecting a promise with no explicit reason, for example:
|
||||
|
||||
```cpp
|
||||
QPromise<int> promise([](const QPromiseResolve<int>& resolve, const QPromiseReject<int>& reject) {
|
||||
async_method([=](bool success, int result) {
|
||||
if (success) {
|
||||
resolve(result);
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
promise.fail([](const QPromiseUndefinedException&) {
|
||||
// promise rejected without reason!
|
||||
})
|
||||
```
|
@ -1,8 +1,10 @@
|
||||
# Getting Started
|
||||
|
||||
## Installation
|
||||
|
||||
QtPromise is a [header-only](https://en.wikipedia.org/wiki/Header-only) library, simply download the [latest release](https://github.com/simonbrunel/qtpromise/releases/latest) (or [`git submodule`](https://git-scm.com/docs/git-submodule)) and include `qtpromise.pri` from your project `.pro`.
|
||||
|
||||
## qpm
|
||||
### qpm
|
||||
|
||||
Alternatively and **only** if your project relies on [qpm](https://www.qpm.io/), you can install QtPromise as follow:
|
||||
|
||||
@ -54,7 +56,7 @@ The following method `uncompress` data in a separate thread and returns a [promi
|
||||
```cpp
|
||||
QPromise<Entries> uncompress(const QByteArray& data)
|
||||
{
|
||||
return qPromise(QtConcurrent::run([](const QByteArray& data) {
|
||||
return QtPromise::resolve(QtConcurrent::run([](const QByteArray& data) {
|
||||
Entries entries;
|
||||
|
||||
// {...} uncompress data and parse content.
|
||||
|
33
docs/qtpromise/helpers/all.md
Normal file
33
docs/qtpromise/helpers/all.md
Normal file
@ -0,0 +1,33 @@
|
||||
---
|
||||
title: all
|
||||
---
|
||||
|
||||
# QtPromise::all
|
||||
|
||||
*Since: 0.5.0*
|
||||
|
||||
```
|
||||
QtPromise::all(Sequence<QPromise<T>> promises) -> QPromise<QVector<T>>
|
||||
QtPromise::all(Sequence<QPromise<void>> promises) -> QPromise<void>
|
||||
```
|
||||
|
||||
Returns a `QPromise<QVector<T>>` (or `QPromise<void>`) that fulfills when **all** `promises` of (the same) type `T` have been fulfilled. The `output` value is a vector containing all the values of `promises`, in the same order, i.e., at the respective positions to the original sequence, regardless of completion order.
|
||||
|
||||
If any of the given `promises` fail, `output` immediately rejects with the error of the promise that rejected, whether or not the other promises are resolved.
|
||||
|
||||
`Sequence` is any STL compatible container (eg. `QVector`, `QList`, `std::vector`, etc.)
|
||||
|
||||
```cpp
|
||||
QVector<QPromise<QByteArray> > promises{
|
||||
download(QUrl("http://a...")),
|
||||
download(QUrl("http://b...")),
|
||||
download(QUrl("http://c..."))
|
||||
};
|
||||
|
||||
auto output = QtPromise::all(promises);
|
||||
|
||||
// output type: QPromise<QVector<QByteArray>>
|
||||
output.then([](const QVector<QByteArray>& res) {
|
||||
// {...}
|
||||
});
|
||||
```
|
42
docs/qtpromise/helpers/attempt.md
Normal file
42
docs/qtpromise/helpers/attempt.md
Normal file
@ -0,0 +1,42 @@
|
||||
---
|
||||
title: attempt
|
||||
---
|
||||
|
||||
# QtPromise::attempt
|
||||
|
||||
*Since: 0.4.0*
|
||||
|
||||
```cpp
|
||||
QtPromise::attempt(Functor functor, Args...) -> QPromise<R>
|
||||
|
||||
// With:
|
||||
// - Functor: Function(Args...) -> R | QPromise<R>
|
||||
```
|
||||
|
||||
Calls `functor` immediately and returns a promise fulfilled with the value returned by `functor`. Any synchronous exceptions will be turned into rejections on the returned promise. This is a convenient method that can be used instead of handling both synchronous and asynchronous exception flows.
|
||||
|
||||
The type `R` of the `output` promise depends on the type returned by the `functor` function. If `functor` returns a promise (or `QFuture`), the `output` promise is delayed and will be resolved by the returned promise.
|
||||
|
||||
```cpp
|
||||
QPromise<QByteArray> download(const QUrl& url);
|
||||
|
||||
QPromise<QByteArray> process(const QUrl& url)
|
||||
{
|
||||
return QtPromise::attempt([&]() {
|
||||
if (!url.isValid()) {
|
||||
throw InvalidUrlException();
|
||||
}
|
||||
|
||||
return download(url);
|
||||
}
|
||||
}
|
||||
|
||||
auto output = process(url);
|
||||
|
||||
// 'output' type: QPromise<QByteArray>
|
||||
output.then([](const QByteArray& res) {
|
||||
// {...}
|
||||
}).fail([](const InvalidUrlException& err) {
|
||||
// {...}
|
||||
});
|
||||
```
|
48
docs/qtpromise/helpers/connect.md
Normal file
48
docs/qtpromise/helpers/connect.md
Normal file
@ -0,0 +1,48 @@
|
||||
---
|
||||
title: connect
|
||||
---
|
||||
|
||||
# QtPromise::connect
|
||||
|
||||
*Since: 0.5.0*
|
||||
|
||||
```cpp
|
||||
(1) QtPromise::connect(QObject* sender, Signal(T) resolver) -> QPromise<T>
|
||||
(2) QtPromise::connect(QObject* sender, Signal(T) resolver, Signal(R) rejecter) -> QPromise<T>
|
||||
(3) QtPromise::connect(QObject* sender, Signal(T) resolver, QObject* sender2, Signal(R) rejecter) -> QPromise<T>
|
||||
```
|
||||
|
||||
Creates a `QPromise<T>` that will be fulfilled with the `resolver` signal's first argument, or a `QPromise<void>` if `resolver` doesn't provide any argument.
|
||||
|
||||
The second `(2)` and third `(3)` variants of this method will reject the `output` promise when the `rejecter` signal is emitted. The rejection reason is the value of the `rejecter` signal's first argument or [`QPromiseUndefinedException`](../exceptions/undefined) if `rejected` doesn't provide any argument.
|
||||
|
||||
Additionally, the `output` promise will be automatically rejected with [`QPromiseContextException`](../exceptions/context.md) if `sender` is destroyed before the promise is resolved (that doesn't apply to `sender2`).
|
||||
|
||||
```cpp
|
||||
class Sender : public QObject
|
||||
{
|
||||
Q_SIGNALS:
|
||||
void finished(const QByteArray&);
|
||||
void error(ErrorCode);
|
||||
};
|
||||
|
||||
auto sender = new Sender();
|
||||
auto output = QtPromise::connect(sender, &Sender::finished, &Sender::error);
|
||||
|
||||
// 'output' resolves as soon as one of the following events happens:
|
||||
// - the 'sender' object is destroyed, the promise is rejected
|
||||
// - the 'finished' signal is emitted, the promise is fulfilled
|
||||
// - the 'error' signal is emitted, the promise is rejected
|
||||
|
||||
// 'output' type: QPromise<QByteArray>
|
||||
output.then([](const QByteArray& res) {
|
||||
// 'res' is the first argument of the 'finished' signal.
|
||||
}).fail([](ErrorCode err) {
|
||||
// 'err' is the first argument of the 'error' signal.
|
||||
}).fail([](const QPromiseContextException& err) {
|
||||
// the 'sender' object has been destroyed before any of
|
||||
// the 'finished' or 'error' signals have been emitted.
|
||||
});
|
||||
```
|
||||
|
||||
See also the [`Qt Signals`](../qtsignals.md) section for more examples.
|
41
docs/qtpromise/helpers/each.md
Normal file
41
docs/qtpromise/helpers/each.md
Normal file
@ -0,0 +1,41 @@
|
||||
---
|
||||
title: each
|
||||
---
|
||||
|
||||
# QtPromise::each
|
||||
|
||||
*Since: 0.4.0*
|
||||
|
||||
```cpp
|
||||
QtPromise::each(Sequence<T> values, Functor functor) -> QPromise<Sequence<T>>
|
||||
|
||||
// With:
|
||||
// - Sequence: STL compatible container (e.g. QVector, etc.)
|
||||
// - Functor: Function(T value, int index) -> void | QPromise<void>
|
||||
```
|
||||
|
||||
Calls the given `functor` on each element in `values` then resolves to the original sequence unmodified. If `functor` throws, `output` is rejected with the new exception.
|
||||
|
||||
If `functor` returns a promise (or `QFuture`), the `output` promise is delayed until all the promises are resolved. If any of the promises fail, `output` immediately rejects with the error of the promise that rejected, whether or not the other promises are resolved.
|
||||
|
||||
```cpp
|
||||
auto output = QtPromise::each(QVector<QUrl>{
|
||||
QUrl("http://a..."),
|
||||
QUrl("http://b..."),
|
||||
QUrl("http://c...")
|
||||
}, [](const QUrl& url, ...) {
|
||||
return QPromise<void>([&](auto resolve, auto reject) {
|
||||
// process url asynchronously ...
|
||||
})
|
||||
});
|
||||
|
||||
// `output` resolves as soon as all promises returned by
|
||||
// `functor` are fulfilled or at least one is rejected.
|
||||
|
||||
// output type: QPromise<QVector<QUrl>>
|
||||
output.then([](const QVector<QUrl>& res) {
|
||||
// 'res' contains the original values
|
||||
});
|
||||
```
|
||||
|
||||
See also: [`QPromise<T>::each`](../qpromise/each.md)
|
46
docs/qtpromise/helpers/filter.md
Normal file
46
docs/qtpromise/helpers/filter.md
Normal file
@ -0,0 +1,46 @@
|
||||
---
|
||||
title: filter
|
||||
---
|
||||
|
||||
# QtPromise::filter
|
||||
|
||||
*Since: 0.4.0*
|
||||
|
||||
```cpp
|
||||
QtPromise::filter(Sequence<T> values, Filterer filterer) -> QPromise<Sequence<T>>
|
||||
|
||||
// With:
|
||||
// - Sequence: STL compatible container (e.g. QVector, etc.)
|
||||
// - Filterer: Function(T value, int index) -> bool
|
||||
```
|
||||
|
||||
Iterates over `values` and [filters the sequence](https://en.wikipedia.org/wiki/Filter_%28higher-order_function%29) to another using the given `filterer` function. If `filterer` returns `true`, a copy of the item is put in the `output` sequence, otherwise, the item will not appear in `output`. If `filterer` throws, `output` is rejected with the new exception.
|
||||
|
||||
If `filterer` returns a promise (or `QFuture`), the `output` promise is delayed until all the promises are resolved. If any of the promises fail, `output` immediately rejects with the error of the promise that rejected, whether or not the other promises are resolved.
|
||||
|
||||
```cpp
|
||||
auto output = QtPromise::filter(QVector{
|
||||
QUrl("http://a..."),
|
||||
QUrl("http://b..."),
|
||||
QUrl("http://c...")
|
||||
}, [](const QUrl& url, ...) {
|
||||
return QPromise<bool>([&](auto resolve, auto reject) {
|
||||
// resolve(true) if 'url' is reachable, else resolve(false)
|
||||
// {...}
|
||||
});
|
||||
});
|
||||
|
||||
// 'output' resolves as soon as all promises returned by
|
||||
// 'filterer' are fulfilled or at least one is rejected.
|
||||
|
||||
// 'output' type: QPromise<QVector<QUrl>>
|
||||
output.then([](const QVector<QUrl>& res) {
|
||||
// 'res' contains only reachable URLs
|
||||
});
|
||||
```
|
||||
|
||||
::: tip 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 `filterer`.
|
||||
:::
|
||||
|
||||
See also: [`QPromise<T>::filter`](../qpromise/filter.md)
|
46
docs/qtpromise/helpers/map.md
Normal file
46
docs/qtpromise/helpers/map.md
Normal file
@ -0,0 +1,46 @@
|
||||
---
|
||||
title: map
|
||||
---
|
||||
|
||||
# QtPromise::map
|
||||
|
||||
*Since: 0.4.0*
|
||||
|
||||
```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) {
|
||||
// {...}
|
||||
});
|
||||
```
|
||||
|
||||
::: tip 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)
|
@ -1,15 +0,0 @@
|
||||
## `qPromise`
|
||||
|
||||
```
|
||||
qPromise(T value) -> QPromise<R>
|
||||
```
|
||||
|
||||
Similar to the [`QPromise<T>::resolve`](../qpromise/resolve.md) static method, creates a promise resolved from a given `value` without the extra typing:
|
||||
|
||||
```cpp
|
||||
auto promise = qPromise(); // QPromise<void>
|
||||
auto promise = qPromise(42); // QPromise<int>
|
||||
auto promise = qPromise(QString("foo")); // QPromise<QString>
|
||||
```
|
||||
|
||||
This method also allows to convert `QFuture<T>` to `QPromise<T>` delayed until the `QFuture` is finished ([read more](../qtconcurrent.md#convert)).
|
@ -1,16 +0,0 @@
|
||||
## `qPromiseAll`
|
||||
|
||||
```
|
||||
qPromiseAll(Sequence<QPromise<T>> promises) -> QPromise<QVector<T>>
|
||||
qPromiseAll(Sequence<QPromise<void>> promises) -> QPromise<void>
|
||||
```
|
||||
|
||||
This method simply calls the appropriated [`QPromise<T>::all`](../qpromise/all.md) static method based on the given `QVector` type. In some cases, this method is more convenient than the static one since it avoid some extra typing:
|
||||
|
||||
```cpp
|
||||
QVector<QPromise<QByteArray> > promises{...}
|
||||
|
||||
auto output = qPromiseAll(promises);
|
||||
// eq. QPromise<QByteArray>::all(promises)
|
||||
```
|
||||
|
48
docs/qtpromise/helpers/reduce.md
Normal file
48
docs/qtpromise/helpers/reduce.md
Normal file
@ -0,0 +1,48 @@
|
||||
---
|
||||
title: reduce
|
||||
---
|
||||
|
||||
# QtPromise::reduce
|
||||
|
||||
*Since: 0.5.0*
|
||||
|
||||
```cpp
|
||||
QPromise::reduce(Sequence<T|QPromise<T>> values, Reducer reducer) -> QPromise<T>
|
||||
QPromise::reduce(Sequence<T|QPromise<T>> values, Reducer reducer, R|QPromise<R> initialValue) -> QPromise<R>
|
||||
|
||||
// With:
|
||||
// - Sequence: STL compatible container (e.g. QVector, etc.)
|
||||
// - Reducer: Function(T|R accumulator, T item, int index) -> R|QPromise<R>
|
||||
```
|
||||
|
||||
Iterates over `values` and [reduces the sequence to a single value](https://en.wikipedia.org/wiki/Fold_%28higher-order_function%29) using the given `reducer` function and an optional `initialValue`. The type returned by `reducer` determines the type of the `output` promise. If `reducer` throws, `output` is rejected with the new exception.
|
||||
|
||||
If `reducer` returns a promise (or `QFuture`), then the result of the promise is awaited, before continuing with next iteration. If any promise in the `values` sequence is rejected or a promise returned by the `reducer` function is rejected, `output` immediately rejects with the error of the promise that rejected.
|
||||
|
||||
```cpp
|
||||
// Concatenate the content of the given files, read asynchronously
|
||||
auto output = QtPromise::reduce(QList<QUrl>{
|
||||
"file:f0.txt", // contains "foo"
|
||||
"file:f1.txt", // contains "bar"
|
||||
"file:f2.txt" // contains "42"
|
||||
}, [](const QString& acc, const QString& cur, int idx) {
|
||||
return readAsync(cur).then([=](const QString& res) {
|
||||
return QString("%1;%2:%3").arg(acc).arg(idx).arg(res);
|
||||
});
|
||||
}, QString("index:text"));
|
||||
|
||||
// 'output' resolves as soon as all promises returned by
|
||||
// 'reducer' are fulfilled or at least one is rejected.
|
||||
|
||||
// 'output' type: QPromise<QString>
|
||||
output.then([](const QString& res) {
|
||||
// res == "index:text;0:foo;1:bar;2:42"
|
||||
// {...}
|
||||
});
|
||||
```
|
||||
|
||||
::: warning IMPORTANT
|
||||
The first time `reducer` is called, if no `initialValue` is provided, `accumulator` will be equal to the first value in the sequence, and `currentValue` to the second one (thus index will be `1`).
|
||||
:::
|
||||
|
||||
See also: [`QPromise<T>::reduce`](../qpromise/reduce.md)
|
21
docs/qtpromise/helpers/resolve.md
Normal file
21
docs/qtpromise/helpers/resolve.md
Normal file
@ -0,0 +1,21 @@
|
||||
---
|
||||
title: resolve
|
||||
---
|
||||
|
||||
# QtPromise::resolve
|
||||
|
||||
*Since: 0.5.0*
|
||||
|
||||
```
|
||||
QtPromise::resolve(T value) -> QPromise<R>
|
||||
```
|
||||
|
||||
Similar to the [`QPromise<T>::resolve`](../qpromise/resolve.md) static method, creates a promise resolved from a given `value` but without the extra typing:
|
||||
|
||||
```cpp
|
||||
auto promise = QtPromise::resolve(); // QPromise<void>
|
||||
auto promise = QtPromise::resolve(42); // QPromise<int>
|
||||
auto promise = QtPromise::resolve(QString("foo")); // QPromise<QString>
|
||||
```
|
||||
|
||||
This method also allows to convert `QFuture<T>` to `QPromise<T>`, delayed until the `QFuture` is finished ([read more](../qtconcurrent.md#convert)).
|
@ -1,4 +1,10 @@
|
||||
## `[static] QPromise<T>::all`
|
||||
---
|
||||
title: ::all [static]
|
||||
---
|
||||
|
||||
# QPromise::all [static]
|
||||
|
||||
*Since: 0.1.0*
|
||||
|
||||
```
|
||||
[static] QPromise<T>::all(Sequence<QPromise<T>> promises) -> QPromise<QVector<T>>
|
||||
@ -25,4 +31,4 @@ output.then([](const QVector<QByteArray>& res) {
|
||||
});
|
||||
```
|
||||
|
||||
See also: [`qPromiseAll`](../helpers/qpromiseall.md)
|
||||
See also: [`QtPromise::all`](../helpers/all.md)
|
||||
|
@ -1,6 +1,12 @@
|
||||
## `QPromise<T>::QPromise`
|
||||
---
|
||||
title: constructor
|
||||
---
|
||||
|
||||
```
|
||||
# QPromise::QPromise
|
||||
|
||||
*Since: 0.1.0*
|
||||
|
||||
```cpp
|
||||
QPromise<T>::QPromise(Function resolver)
|
||||
```
|
||||
|
||||
@ -18,7 +24,9 @@ QPromise<int> promise([](const QPromiseResolve<int>& resolve, const QPromiseReje
|
||||
});
|
||||
```
|
||||
|
||||
> **Note:** `QPromise<void>` is specialized to not contain any value, meaning that the `resolve` callback takes no argument.
|
||||
::: tip NOTE
|
||||
`QPromise<void>` is specialized to not contain any value, meaning that the `resolve` callback takes no argument.
|
||||
:::
|
||||
|
||||
**C++14**
|
||||
|
||||
@ -27,3 +35,33 @@ 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`](../exceptions/undefined.md) 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([]() {
|
||||
// { ... }
|
||||
})
|
||||
```
|
||||
|
@ -1,6 +1,12 @@
|
||||
## `QPromise<T>::delay`
|
||||
---
|
||||
title: .delay
|
||||
---
|
||||
|
||||
```
|
||||
# QPromise::delay
|
||||
|
||||
*Since: 0.2.0*
|
||||
|
||||
```cpp
|
||||
QPromise<T>::delay(int msec) -> QPromise<T>
|
||||
```
|
||||
|
||||
|
56
docs/qtpromise/qpromise/each.md
Normal file
56
docs/qtpromise/qpromise/each.md
Normal file
@ -0,0 +1,56 @@
|
||||
---
|
||||
title: .each
|
||||
---
|
||||
|
||||
# QPromise::each
|
||||
|
||||
*Since: 0.4.0*
|
||||
|
||||
```cpp
|
||||
QPromise<Sequence<T>>::each(Functor functor) -> QPromise<Sequence<T>>
|
||||
|
||||
// With:
|
||||
// - Sequence: STL compatible container
|
||||
// - Functor: Function(T value, int index) -> any
|
||||
```
|
||||
|
||||
::: warning IMPORTANT
|
||||
This method only applies to promise with sequence value.
|
||||
:::
|
||||
|
||||
Calls the given `functor` on each element in the promise value (i.e. `Sequence<T>`), then resolves to the original sequence unmodified. If `functor` throws, `output` is rejected with the new exception.
|
||||
|
||||
```cpp
|
||||
QPromise<QList<QByteArray>> input = {...}
|
||||
|
||||
auto output = input.each([](const QByteArray& value, int index) {
|
||||
// process value ...
|
||||
});
|
||||
|
||||
// output type: QPromise<QList<QByteArray>>
|
||||
output.then([](const QList<QByteArray>& res) {
|
||||
// 'res' contains the original values
|
||||
});
|
||||
```
|
||||
|
||||
If `functor` returns a promise (or `QFuture`), the `output` promise is delayed until all the promises are resolved. If any of the promises fail, `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.each([](const QUrl& url, ...) {
|
||||
return QPromise<void>([&](auto resolve, auto reject) {
|
||||
// process url asynchronously ...
|
||||
})
|
||||
});
|
||||
|
||||
// `output` resolves as soon as all promises returned by
|
||||
// `functor` are fulfilled or at least one is rejected.
|
||||
|
||||
// output type: QPromise<QList<QUrl>>
|
||||
output.then([](const QList<QUrl>& res) {
|
||||
// 'res' contains the original values
|
||||
});
|
||||
```
|
||||
|
||||
See also: [`QtPromise::each`](../helpers/each.md)
|
@ -1,6 +1,12 @@
|
||||
## `QPromise<T>::fail`
|
||||
---
|
||||
title: .fail
|
||||
---
|
||||
|
||||
```
|
||||
# QPromise::fail
|
||||
|
||||
*Since: 0.1.0*
|
||||
|
||||
```cpp
|
||||
QPromise<T>::fail(Function onRejected) -> QPromise<T>
|
||||
```
|
||||
|
||||
|
49
docs/qtpromise/qpromise/filter.md
Normal file
49
docs/qtpromise/qpromise/filter.md
Normal file
@ -0,0 +1,49 @@
|
||||
---
|
||||
title: .filter
|
||||
---
|
||||
|
||||
# QPromise::filter
|
||||
|
||||
*Since: 0.4.0*
|
||||
|
||||
```cpp
|
||||
QPromise<Sequence<T>>::filter(Filter filterer) -> QPromise<Sequence<T>>
|
||||
|
||||
// With:
|
||||
// - Sequence: STL compatible container (e.g. QVector, etc.)
|
||||
// - Filterer: Function(T value, int index) -> bool
|
||||
```
|
||||
|
||||
::: warning IMPORTANT
|
||||
This method only applies to promise with sequence value.
|
||||
:::
|
||||
|
||||
Iterates over all the promise values (i.e. `Sequence<T>`) and [filters the sequence](https://en.wikipedia.org/wiki/Filter_%28higher-order_function%29) to another using the given `filterer` function. If `filterer` returns `true`, a copy of the item is put in the `output` sequence, otherwise, the item will not appear in `output`. If `filterer` throws, `output` is rejected with the new exception.
|
||||
|
||||
If `filterer` returns a promise (or `QFuture`), the `output` promise is delayed until all the promises are resolved. If any of the promises fail, `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.filter([](const QUrl& url, ...) {
|
||||
return url.isValid(); // Keep only valid URLs
|
||||
}).filter([](const QUrl& url, ...) {
|
||||
return QPromise<bool>([&](auto resolve, auto reject) {
|
||||
// resolve(true) if `url` is reachable, else resolve(false)
|
||||
});
|
||||
});
|
||||
|
||||
// 'output' resolves as soon as all promises returned by
|
||||
// 'filterer' are fulfilled or at least one is rejected.
|
||||
|
||||
// 'output' type: QPromise<QList<QUrl>>
|
||||
output.then([](const QList<QUrl>& res) {
|
||||
// 'res' contains only reachable URLs
|
||||
});
|
||||
```
|
||||
|
||||
::: tip 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 `filterer`.
|
||||
:::
|
||||
|
||||
See also: [`QtPromise::filter`](../helpers/filter.md)
|
@ -1,6 +1,12 @@
|
||||
## `QPromise<T>::finally`
|
||||
---
|
||||
title: .finally
|
||||
---
|
||||
|
||||
```
|
||||
# QPromise::finally
|
||||
|
||||
*Since: 0.1.0*
|
||||
|
||||
```cpp
|
||||
QPromise<T>::finally(Function handler) -> QPromise<T>
|
||||
```
|
||||
|
||||
|
@ -1,6 +1,12 @@
|
||||
# `QPromise<T>::isFulfilled`
|
||||
---
|
||||
title: .isFulfilled
|
||||
---
|
||||
|
||||
```
|
||||
# QPromise::isFulfilled
|
||||
|
||||
*Since: 0.1.0*
|
||||
|
||||
```cpp
|
||||
QPromise<T>::isFulfilled() -> bool
|
||||
```
|
||||
|
||||
|
@ -1,6 +1,12 @@
|
||||
# `QPromise<T>::isPending`
|
||||
---
|
||||
title: .isPending
|
||||
---
|
||||
|
||||
```
|
||||
# QPromise::isPending
|
||||
|
||||
*Since: 0.1.0*
|
||||
|
||||
```cpp
|
||||
QPromise<T>::isPending() -> bool
|
||||
```
|
||||
|
||||
|
@ -1,6 +1,12 @@
|
||||
# `QPromise<T>::isRejected`
|
||||
---
|
||||
title: .isRejected
|
||||
---
|
||||
|
||||
```
|
||||
# QPromise::isRejected
|
||||
|
||||
*Since: 0.1.0*
|
||||
|
||||
```cpp
|
||||
QPromise<T>::isRejected() -> bool
|
||||
```
|
||||
|
||||
|
62
docs/qtpromise/qpromise/map.md
Normal file
62
docs/qtpromise/qpromise/map.md
Normal file
@ -0,0 +1,62 @@
|
||||
---
|
||||
title: .map
|
||||
---
|
||||
|
||||
# QPromise::map
|
||||
|
||||
*Since: 0.4.0*
|
||||
|
||||
```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>
|
||||
```
|
||||
|
||||
::: warning IMPORTANT
|
||||
This method only applies to promise with sequence value.
|
||||
:::
|
||||
|
||||
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) {
|
||||
// {...}
|
||||
});
|
||||
```
|
||||
|
||||
::: tip 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)
|
58
docs/qtpromise/qpromise/reduce.md
Normal file
58
docs/qtpromise/qpromise/reduce.md
Normal file
@ -0,0 +1,58 @@
|
||||
---
|
||||
title: .reduce
|
||||
---
|
||||
|
||||
# QPromise::reduce
|
||||
|
||||
*Since: 0.5.0*
|
||||
|
||||
```cpp
|
||||
QPromise<Sequence<T>>::reduce(Reducer reducer) -> QPromise<T>
|
||||
QPromise<Sequence<T>>::reduce(Reducer reducer, R|QPromise<R> initialValue) -> QPromise<R>
|
||||
|
||||
// With:
|
||||
// - Sequence: STL compatible container (e.g. QVector, etc.)
|
||||
// - Reducer: Function(T|R accumulator, T item, int index) -> R|QPromise<R>
|
||||
```
|
||||
|
||||
::: warning IMPORTANT
|
||||
This method only applies to promise with sequence value.
|
||||
:::
|
||||
|
||||
Iterates over all the promise values (i.e. `Sequence<T>`) and [reduces the sequence to a single value](https://en.wikipedia.org/wiki/Fold_%28higher-order_function%29) using the given `reducer` function and an optional `initialValue`. The type returned by `reducer` determines the type of the `output` promise.
|
||||
|
||||
See [`QtPromise::reduce`](../helpers/reduce.md) for details, this method is provided for convenience and is similar to:
|
||||
|
||||
```cpp
|
||||
promise.then([](const T& values) {
|
||||
return QtPromise::reduce(values, reducer, initialValue);
|
||||
})
|
||||
```
|
||||
|
||||
For example:
|
||||
|
||||
```cpp
|
||||
auto input = QtPromise::resolve(QList<QUrl>{
|
||||
"file:f0.txt", // contains "foo"
|
||||
"file:f1.txt", // contains "bar"
|
||||
"file:f2.txt" // contains "42"
|
||||
});
|
||||
|
||||
// Concatenate the content of the given files, read asynchronously
|
||||
auto output = input.reduce([](const QString& acc, const QString& cur, int idx) {
|
||||
return readAsync(cur).then([=](const QString& res) {
|
||||
return QString("%1;%2:%3").arg(acc).arg(idx).arg(res);
|
||||
});
|
||||
}, QString("index:text"));
|
||||
|
||||
// 'output' resolves as soon as all promises returned by
|
||||
// 'reducer' are fulfilled or at least one is rejected.
|
||||
|
||||
// 'output' type: QPromise<QString>
|
||||
output.then([](const QString& res) {
|
||||
// res == "index:text;0:foo;1:bar;2:42"
|
||||
// {...}
|
||||
});
|
||||
```
|
||||
|
||||
See also: [`QtPromise::reduce`](../helpers/reduce.md)
|
@ -1,6 +1,12 @@
|
||||
## `[static] QPromise<T>::reject`
|
||||
---
|
||||
title: ::reject [static]
|
||||
---
|
||||
|
||||
```
|
||||
# QPromise::reject [static]
|
||||
|
||||
*Since: 0.1.0*
|
||||
|
||||
```cpp
|
||||
[static] QPromise<T>::reject(any reason) -> QPromise<T>
|
||||
```
|
||||
|
||||
|
@ -1,4 +1,10 @@
|
||||
## `[static] QPromise<T>::resolve`
|
||||
---
|
||||
title: ::resolve [static]
|
||||
---
|
||||
|
||||
# QPromise::resolve [static]
|
||||
|
||||
*Since: 0.1.0*
|
||||
|
||||
```
|
||||
[static] QPromise<T>::resolve(T value) -> QPromise<T>
|
||||
@ -19,4 +25,4 @@ QPromise<int> compute(const QString& type)
|
||||
}
|
||||
```
|
||||
|
||||
See also: [`qPromise`](../helpers/qpromise.md)
|
||||
See also: [`QtPromise::resolve`](../helpers/resolve.md)
|
||||
|
@ -1,6 +1,12 @@
|
||||
## `QPromise<T>::tap`
|
||||
---
|
||||
title: .tap
|
||||
---
|
||||
|
||||
```
|
||||
# QPromise::tap
|
||||
|
||||
*Since: 0.2.0*
|
||||
|
||||
```cpp
|
||||
QPromise<T>::tap(Function handler) -> QPromise<T>
|
||||
```
|
||||
|
||||
|
@ -1,6 +1,12 @@
|
||||
## `QPromise<T>::tapFail`
|
||||
---
|
||||
title: .tapFail
|
||||
---
|
||||
|
||||
```
|
||||
# QPromise::tapFail
|
||||
|
||||
*Since: 0.4.0*
|
||||
|
||||
```cpp
|
||||
QPromise<T>::tapFail(Function handler) -> QPromise<T>
|
||||
```
|
||||
|
||||
|
@ -1,6 +1,12 @@
|
||||
## `QPromise<T>::then`
|
||||
---
|
||||
title: .then
|
||||
---
|
||||
|
||||
```
|
||||
# QPromise::then
|
||||
|
||||
*Since: 0.1.0*
|
||||
|
||||
```cpp
|
||||
QPromise<T>::then(Function onFulfilled, Function onRejected) -> QPromise<R>
|
||||
QPromise<T>::then(Function onFulfilled) -> QPromise<R>
|
||||
```
|
||||
@ -17,9 +23,9 @@ auto output = input.then([](int res) {
|
||||
});
|
||||
```
|
||||
|
||||
> **Note**: `onRejected` handler is optional, `output` will be rejected with the same reason as `input`.
|
||||
|
||||
> **Note**: it's recommended to use the [`fail`](fail.md) shorthand to handle errors.
|
||||
::: tip NOTE
|
||||
`onRejected` handler is optional, in which case `output` will be rejected with the same reason as `input`. Also note that it's recommended to use the [`fail`](fail.md) shorthand to handle errors.
|
||||
:::
|
||||
|
||||
The type `<R>` of the `output` promise depends on the return type of the `onFulfilled` handler:
|
||||
|
||||
@ -35,7 +41,9 @@ output.then([](const QString& res) {
|
||||
});
|
||||
```
|
||||
|
||||
> **Note**: only `onFulfilled` can change the promise type, `onRejected` **must** return the same type as `onFulfilled`. That also means if `onFulfilled` is `nullptr`, `onRejected` must return the same type as the `input` promise.
|
||||
::: tip NOTE
|
||||
Only `onFulfilled` can change the promise type, `onRejected` **must** return the same type as `onFulfilled`. That also means if `onFulfilled` is `nullptr`, `onRejected` must return the same type as the `input` promise.
|
||||
:::
|
||||
|
||||
```cpp
|
||||
QPromise<int> input = ...
|
||||
|
@ -1,10 +1,16 @@
|
||||
## `QPromise<T>::timeout`
|
||||
---
|
||||
title: .timeout
|
||||
---
|
||||
|
||||
```
|
||||
# QPromise::timeout
|
||||
|
||||
*Since: 0.2.0*
|
||||
|
||||
```cpp
|
||||
QPromise<T>::timeout(int msec, any error = QPromiseTimeoutException) -> QPromise<T>
|
||||
```
|
||||
|
||||
This method returns a promise that will be resolved with the `input` promise's fulfillment value or rejection reason. However, if the `input` promise is not fulfilled or rejected within `msec` milliseconds, the `output` promise is rejected with `error` as the reason (`QPromiseTimeoutException` by default).
|
||||
This method returns a promise that will be resolved with the `input` promise's fulfillment value or rejection reason. However, if the `input` promise is not fulfilled or rejected within `msec` milliseconds, the `output` promise is rejected with `error` as the reason ([`QPromiseTimeoutException`](../exceptions/timeout.md) by default).
|
||||
|
||||
```cpp
|
||||
QPromise<int> input = {...}
|
||||
|
@ -1,6 +1,12 @@
|
||||
## `QPromise<T>::wait`
|
||||
---
|
||||
title: .wait
|
||||
---
|
||||
|
||||
```
|
||||
# QPromise::wait
|
||||
|
||||
*Since: 0.1.0*
|
||||
|
||||
```cpp
|
||||
QPromise<T>::wait() -> QPromise<T>
|
||||
```
|
||||
|
||||
@ -9,7 +15,7 @@ This method holds the execution of the remaining code until the `input` promise
|
||||
```cpp
|
||||
int result = -1;
|
||||
|
||||
QPromise<int> input = qPromise(QtConcurrent::run([]() {
|
||||
QPromise<int> input = QtPromise::resolve(QtConcurrent::run([]() {
|
||||
return 42;
|
||||
})).tap([&](int res) {
|
||||
result = res;
|
||||
|
@ -1,10 +1,10 @@
|
||||
## QtConcurrent
|
||||
# Qt Concurrent
|
||||
|
||||
QtPromise integrates with [QtConcurrent](https://doc.qt.io/qt-5/qtconcurrent-index.html) to make easy chaining QFuture with QPromise.
|
||||
|
||||
## <a name="qtconcurrent-convert"></a> Convert
|
||||
|
||||
Converting `QFuture<T>` to `QPromise<T>` is done using the [`qPromise`](helpers/qpromise.md) helper:
|
||||
Converting `QFuture<T>` to `QPromise<T>` is done using the [`QtPromise::resolve`](helpers/resolve.md) helper:
|
||||
|
||||
```cpp
|
||||
QFuture<int> future = QtConcurrent::run([]() {
|
||||
@ -12,13 +12,13 @@ QFuture<int> future = QtConcurrent::run([]() {
|
||||
return 42;
|
||||
});
|
||||
|
||||
QPromise<int> promise = qPromise(future);
|
||||
QPromise<int> promise = QtPromise::resolve(future);
|
||||
```
|
||||
|
||||
or simply:
|
||||
|
||||
```cpp
|
||||
auto promise = qPromise(QtConcurrent::run([]() {
|
||||
auto promise = QtPromise::resolve(QtConcurrent::run([]() {
|
||||
// {...}
|
||||
}));
|
||||
```
|
||||
@ -46,7 +46,7 @@ The `output` promise is resolved when the `QFuture` is [finished](https://doc.qt
|
||||
|
||||
## Error
|
||||
|
||||
Exceptions thrown from a QtConcurrent thread reject the associated promise with the exception as the reason. Note that if you throw an exception that is not a subclass of `QException`, the promise with be rejected with [`QUnhandledException`](https://doc.qt.io/qt-5/qunhandledexception.html#details) (this restriction only applies to exceptions thrown from a QtConcurrent thread, [read more](https://doc.qt.io/qt-5/qexception.html#details)).
|
||||
Exceptions thrown from a QtConcurrent thread reject the associated promise with the exception as the reason. Note that if you throw an exception that is not a subclass of `QException`, the promise will be rejected with [`QUnhandledException`](https://doc.qt.io/qt-5/qunhandledexception.html#details) (this restriction only applies to exceptions thrown from a QtConcurrent thread, [read more](https://doc.qt.io/qt-5/qexception.html#details)).
|
||||
|
||||
```cpp
|
||||
QPromise<int> promise = ...
|
||||
|
89
docs/qtpromise/qtsignals.md
Normal file
89
docs/qtpromise/qtsignals.md
Normal file
@ -0,0 +1,89 @@
|
||||
# Qt Signals
|
||||
|
||||
QtPromise supports creating promises that are resolved or rejected by regular [Qt signals](https://doc.qt.io/qt-5/signalsandslots.html).
|
||||
|
||||
::: warning IMPORTANT
|
||||
A promise connected to a signal will be resolved (fulfilled or rejected) **only one time**, no matter if the signals are emitted multiple times. Internally, the promise is disconnected from all signals as soon as one signal is emitted.
|
||||
:::
|
||||
|
||||
## Resolve Signal
|
||||
|
||||
The [`QtPromise::connect()`](helpers/connect.md) helper allows to create a promise resolved from a single signal:
|
||||
|
||||
```cpp
|
||||
// [signal] Object::finished(const QByteArray&)
|
||||
auto output = QtPromise::connect(obj, &Object::finished);
|
||||
|
||||
// output type: QPromise<QByteArray>
|
||||
output.then([](const QByteArray& data) {
|
||||
// {...}
|
||||
});
|
||||
```
|
||||
|
||||
If the signal doesn't provide any argument, a `QPromise<void>` is returned:
|
||||
|
||||
```cpp
|
||||
// [signal] Object::done()
|
||||
auto output = QtPromise::connect(obj, &Object::done);
|
||||
|
||||
// output type: QPromise<void>
|
||||
output.then([]() {
|
||||
// {...}
|
||||
});
|
||||
```
|
||||
|
||||
::: tip NOTE
|
||||
QtPromise currently only supports single argument signals, which means that only the first argument is used to fulfill or reject the connected promise, other arguments being ignored.
|
||||
:::
|
||||
|
||||
## Reject Signal
|
||||
|
||||
The [`QtPromise::connect()`](helpers/connect.md) helper also allows to reject the promise from another signal:
|
||||
|
||||
```cpp
|
||||
// [signal] Object::finished(const QByteArray& data)
|
||||
// [signal] Object::error(ObjectError error)
|
||||
auto output = QtPromise::connect(obj, &Object::finished, &Object::error);
|
||||
|
||||
// output type: QPromise<QByteArray>
|
||||
output.then([](const QByteArray& data) {
|
||||
// {...}
|
||||
}).fail(const ObjectError& error) {
|
||||
// {...}
|
||||
});
|
||||
```
|
||||
|
||||
If the rejection signal doesn't provide any argument, the promise will be rejected
|
||||
with [`QPromiseUndefinedException`](../exceptions/undefined), for example:
|
||||
|
||||
```cpp
|
||||
// [signal] Object::finished()
|
||||
// [signal] Object::error()
|
||||
auto output = QtPromise::connect(obj, &Object::finished, &Object::error);
|
||||
|
||||
// output type: QPromise<QByteArray>
|
||||
output.then([]() {
|
||||
// {...}
|
||||
}).fail(const QPromiseUndefinedException& error) {
|
||||
// {...}
|
||||
});
|
||||
```
|
||||
|
||||
A third variant allows to connect the resolve and reject signals from different objects:
|
||||
|
||||
```cpp
|
||||
// [signal] ObjectA::finished(const QByteArray& data)
|
||||
// [signal] ObjectB::error(ObjectBError error)
|
||||
auto output = QtPromise::connect(objA, &ObjectA::finished, objB, &ObjectB::error);
|
||||
|
||||
// output type: QPromise<QByteArray>
|
||||
output.then([](const QByteArray& data) {
|
||||
// {...}
|
||||
}).fail(const ObjectBError& error) {
|
||||
// {...}
|
||||
});
|
||||
```
|
||||
|
||||
Additionally to the rejection signal, promises created using [`QtPromise::connect()`](helpers/connect.md) are automatically rejected with [`QPromiseContextException`](exceptions/context.md) if the sender is destroyed before fulfilling the promise.
|
||||
|
||||
See [`QtPromise::connect()`](helpers/connect.md) for more details.
|
@ -1,5 +1,7 @@
|
||||
## Thread-Safety
|
||||
# Thread-Safety
|
||||
|
||||
QPromise is thread-safe and can be copied and accessed across different threads. QPromise relies on [explicitly data sharing](https://doc.qt.io/qt-5/qexplicitlyshareddatapointer.html#details) and thus `auto p2 = p1` represents the same promise: when `p1` resolves, handlers registered on `p1` and `p2` are called, the fulfilled value being shared between both instances.
|
||||
|
||||
> **Note:** while it's safe to access the resolved value from different threads using [`then`](qpromise/then.md), QPromise provides no guarantee about the object being pointed to. Thread-safety and reentrancy rules for that object still apply.
|
||||
::: warning IMPORTANT
|
||||
While it's safe to access the resolved value from different threads using [`then`](qpromise/then.md), QPromise provides no guarantee about the object being pointed to. Thread-safety and reentrancy rules for that object still apply.
|
||||
:::
|
||||
|
@ -2,7 +2,8 @@
|
||||
#define QTPROMISE_MODULE_H
|
||||
|
||||
#include "../src/qtpromise/qpromise.h"
|
||||
#include "../src/qtpromise/qpromiseconnections.h"
|
||||
#include "../src/qtpromise/qpromisefuture.h"
|
||||
#include "../src/qtpromise/qpromisehelpers.h"
|
||||
|
||||
#endif // ifndef QTPROMISE_MODULE_H
|
||||
#endif // QTPROMISE_MODULE_H
|
||||
|
4
qpm.json
4
qpm.json
@ -10,9 +10,9 @@
|
||||
"url": "https://github.com/simonbrunel/qtpromise.git"
|
||||
},
|
||||
"version": {
|
||||
"label": "0.3.0"
|
||||
"label": "0.5.0"
|
||||
},
|
||||
"license": "MIT",
|
||||
"pri_filename": "qtpromise.pri",
|
||||
"webpage": "https://github.com/simonbrunel/qtpromise"
|
||||
"webpage": "https://qtpromise.netlify.com"
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
#ifndef QTPROMISE_QPROMISE_H
|
||||
#define QTPROMISE_QPROMISE_H
|
||||
|
||||
// QtPromise
|
||||
#include "qpromise_p.h"
|
||||
#include "qpromiseerror.h"
|
||||
#include "qpromiseexceptions.h"
|
||||
#include "qpromiseglobal.h"
|
||||
#include "qpromiseresolver.h"
|
||||
|
||||
// Qt
|
||||
#include <QExplicitlySharedDataPointer>
|
||||
@ -76,6 +76,7 @@ public: // STATIC
|
||||
protected:
|
||||
friend struct QtPromisePrivate::PromiseFulfill<QPromise<T>>;
|
||||
friend class QtPromisePrivate::PromiseResolver<T>;
|
||||
friend struct QtPromisePrivate::PromiseInspect;
|
||||
|
||||
QExplicitlySharedDataPointer<QtPromisePrivate::PromiseData<T>> m_d;
|
||||
};
|
||||
@ -87,9 +88,32 @@ public:
|
||||
template <typename F>
|
||||
QPromise(F&& resolver): QPromiseBase<T>(std::forward<F>(resolver)) { }
|
||||
|
||||
template <typename Functor>
|
||||
inline QPromise<T>
|
||||
each(Functor fn);
|
||||
|
||||
template <typename Functor>
|
||||
inline QPromise<T>
|
||||
filter(Functor fn);
|
||||
|
||||
template <typename Functor>
|
||||
inline typename QtPromisePrivate::PromiseMapper<T, Functor>::PromiseType
|
||||
map(Functor fn);
|
||||
|
||||
template <typename Functor, typename Input>
|
||||
inline typename QtPromisePrivate::PromiseDeduce<Input>::Type
|
||||
reduce(Functor fn, Input initial);
|
||||
|
||||
template <typename Functor, typename U = T>
|
||||
inline typename QtPromisePrivate::PromiseDeduce<typename U::value_type>::Type
|
||||
reduce(Functor fn);
|
||||
|
||||
public: // STATIC
|
||||
|
||||
// DEPRECATED (remove at version 1)
|
||||
template <template <typename, typename...> class Sequence = QVector, typename ...Args>
|
||||
inline static QPromise<QVector<T>> all(const Sequence<QPromise<T>, Args...>& promises);
|
||||
Q_DECL_DEPRECATED_X("Use QtPromise::all instead") static inline QPromise<QVector<T>>
|
||||
all(const Sequence<QPromise<T>, Args...>& promises);
|
||||
|
||||
inline static QPromise<T> resolve(const T& value);
|
||||
inline static QPromise<T> resolve(T&& value);
|
||||
@ -106,8 +130,11 @@ public:
|
||||
QPromise(F&& resolver): QPromiseBase<void>(std::forward<F>(resolver)) { }
|
||||
|
||||
public: // STATIC
|
||||
|
||||
// DEPRECATED (remove at version 1)
|
||||
template <template <typename, typename...> class Sequence = QVector, typename ...Args>
|
||||
inline static QPromise<void> all(const Sequence<QPromise<void>, Args...>& promises);
|
||||
Q_DECL_DEPRECATED_X("Use QtPromise::all instead") static inline QPromise<void>
|
||||
all(const Sequence<QPromise<void>, Args...>& promises);
|
||||
|
||||
inline static QPromise<void> resolve();
|
||||
|
||||
@ -119,4 +146,4 @@ private:
|
||||
|
||||
#include "qpromise.inl"
|
||||
|
||||
#endif // ifndef QTPROMISE_QPROMISE_H
|
||||
#endif // QTPROMISE_QPROMISE_H
|
||||
|
@ -1,3 +1,6 @@
|
||||
#include "qpromise.h"
|
||||
#include "qpromisehelpers.h"
|
||||
|
||||
// Qt
|
||||
#include <QCoreApplication>
|
||||
#include <QSharedPointer>
|
||||
@ -5,47 +8,6 @@
|
||||
|
||||
namespace QtPromise {
|
||||
|
||||
template <class T>
|
||||
class QPromiseResolve
|
||||
{
|
||||
public:
|
||||
QPromiseResolve(QtPromisePrivate::PromiseResolver<T> resolver)
|
||||
: m_resolver(std::move(resolver))
|
||||
{ }
|
||||
|
||||
template <typename V>
|
||||
void operator()(V&& value) const
|
||||
{
|
||||
m_resolver.resolve(std::forward<V>(value));
|
||||
}
|
||||
|
||||
void operator()() const
|
||||
{
|
||||
m_resolver.resolve();
|
||||
}
|
||||
|
||||
private:
|
||||
mutable QtPromisePrivate::PromiseResolver<T> m_resolver;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class QPromiseReject
|
||||
{
|
||||
public:
|
||||
QPromiseReject(QtPromisePrivate::PromiseResolver<T> resolver)
|
||||
: m_resolver(std::move(resolver))
|
||||
{ }
|
||||
|
||||
template <typename E>
|
||||
void operator()(E&& error) const
|
||||
{
|
||||
m_resolver.reject(std::forward<E>(error));
|
||||
}
|
||||
|
||||
private:
|
||||
mutable QtPromisePrivate::PromiseResolver<T> m_resolver;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
template <typename F, typename std::enable_if<QtPromisePrivate::ArgsOf<F>::count == 1, int>::type>
|
||||
inline QPromiseBase<T>::QPromiseBase(F callback)
|
||||
@ -194,40 +156,74 @@ inline QPromise<T> QPromiseBase<T>::reject(E&& error)
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <template <typename, typename...> class Sequence, typename ...Args>
|
||||
inline QPromise<QVector<T>> QPromise<T>::all(const Sequence<QPromise<T>, Args...>& promises)
|
||||
template <typename Functor>
|
||||
inline QPromise<T> QPromise<T>::each(Functor fn)
|
||||
{
|
||||
const int count = static_cast<int>(promises.size());
|
||||
if (count == 0) {
|
||||
return QPromise<QVector<T>>::resolve({});
|
||||
}
|
||||
|
||||
return QPromise<QVector<T>>([=](
|
||||
const QPromiseResolve<QVector<T>>& resolve,
|
||||
const QPromiseReject<QVector<T>>& reject) {
|
||||
|
||||
QSharedPointer<int> remaining(new int(count));
|
||||
QSharedPointer<QVector<T>> results(new QVector<T>(count));
|
||||
|
||||
return this->tap([=](const T& values) {
|
||||
int i = 0;
|
||||
for (const auto& promise: promises) {
|
||||
promise.then([=](const T& res) mutable {
|
||||
(*results)[i] = res;
|
||||
if (--(*remaining) == 0) {
|
||||
resolve(*results);
|
||||
}
|
||||
}, [=]() mutable {
|
||||
if (*remaining != -1) {
|
||||
*remaining = -1;
|
||||
reject(std::current_exception());
|
||||
}
|
||||
});
|
||||
|
||||
std::vector<QPromise<void>> promises;
|
||||
for (const auto& v : values) {
|
||||
promises.push_back(
|
||||
QtPromise::attempt(fn, v, i)
|
||||
.then([]() {
|
||||
// Cast to void in case fn returns a non promise value.
|
||||
// TODO remove when implicit cast is implemented.
|
||||
}));
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return QtPromise::all(promises);
|
||||
});
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename Functor>
|
||||
inline QPromise<T> QPromise<T>::filter(Functor fn)
|
||||
{
|
||||
return this->then([=](const T& values) {
|
||||
return QtPromise::filter(values, fn);
|
||||
});
|
||||
}
|
||||
|
||||
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 Functor, typename Input>
|
||||
inline typename QtPromisePrivate::PromiseDeduce<Input>::Type
|
||||
QPromise<T>::reduce(Functor fn, Input initial)
|
||||
{
|
||||
return this->then([=](const T& values) {
|
||||
return QtPromise::reduce(values, fn, initial);
|
||||
});
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename Functor, typename U>
|
||||
inline typename QtPromisePrivate::PromiseDeduce<typename U::value_type>::Type
|
||||
QPromise<T>::reduce(Functor fn)
|
||||
{
|
||||
return this->then([=](const T& values) {
|
||||
return QtPromise::reduce(values, fn);
|
||||
});
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <template <typename, typename...> class Sequence, typename ...Args>
|
||||
inline QPromise<QVector<T>> QPromise<T>::all(const Sequence<QPromise<T>, Args...>& promises)
|
||||
{
|
||||
return QtPromise::all(promises);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline QPromise<T> QPromise<T>::resolve(const T& value)
|
||||
{
|
||||
@ -247,37 +243,12 @@ inline QPromise<T> QPromise<T>::resolve(T&& value)
|
||||
template <template <typename, typename...> class Sequence, typename ...Args>
|
||||
inline QPromise<void> QPromise<void>::all(const Sequence<QPromise<void>, Args...>& promises)
|
||||
{
|
||||
const int count = static_cast<int>(promises.size());
|
||||
if (count == 0) {
|
||||
return QPromise<void>::resolve();
|
||||
}
|
||||
|
||||
return QPromise<void>([=](
|
||||
const QPromiseResolve<void>& resolve,
|
||||
const QPromiseReject<void>& reject) {
|
||||
|
||||
QSharedPointer<int> remaining(new int(count));
|
||||
|
||||
for (const auto& promise: promises) {
|
||||
promise.then([=]() {
|
||||
if (--(*remaining) == 0) {
|
||||
resolve();
|
||||
}
|
||||
}, [=]() {
|
||||
if (*remaining != -1) {
|
||||
*remaining = -1;
|
||||
reject(std::current_exception());
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
return QtPromise::all(promises);
|
||||
}
|
||||
|
||||
inline QPromise<void> QPromise<void>::resolve()
|
||||
{
|
||||
return QPromise<void>([](const QPromiseResolve<void>& resolve) {
|
||||
resolve();
|
||||
});
|
||||
return QtPromise::resolve();
|
||||
}
|
||||
|
||||
} // namespace QtPromise
|
||||
|
@ -1,7 +1,6 @@
|
||||
#ifndef QTPROMISE_QPROMISE_P_H
|
||||
#define QTPROMISE_QPROMISE_P_H
|
||||
|
||||
// QtPromise
|
||||
#include "qpromiseglobal.h"
|
||||
|
||||
// Qt
|
||||
@ -111,33 +110,54 @@ private:
|
||||
template <typename T>
|
||||
struct PromiseDeduce
|
||||
{
|
||||
using Type = QtPromise::QPromise<Unqualified<T>>;
|
||||
using Type = QtPromise::QPromise<T>;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct PromiseDeduce<T&>
|
||||
: public PromiseDeduce<T>
|
||||
{ };
|
||||
|
||||
template <typename T>
|
||||
struct PromiseDeduce<const T>
|
||||
: public PromiseDeduce<T>
|
||||
{ };
|
||||
|
||||
template <typename T>
|
||||
struct PromiseDeduce<const volatile T>
|
||||
: public PromiseDeduce<T>
|
||||
{ };
|
||||
|
||||
template <typename T>
|
||||
struct PromiseDeduce<QtPromise::QPromise<T>>
|
||||
: public PromiseDeduce<T>
|
||||
{ };
|
||||
|
||||
template <typename Functor, typename... Args>
|
||||
struct PromiseFunctor
|
||||
{
|
||||
using ResultType = typename std::result_of<Functor(Args...)>::type;
|
||||
using PromiseType = typename PromiseDeduce<ResultType>::Type;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct PromiseFulfill
|
||||
{
|
||||
static void call(
|
||||
T&& value,
|
||||
const QtPromise::QPromiseResolve<T>& resolve,
|
||||
const QtPromise::QPromiseReject<T>&)
|
||||
template <typename V, typename TResolve, typename TReject>
|
||||
static void call(V&& value, const TResolve& resolve, const TReject&)
|
||||
{
|
||||
resolve(std::move(value));
|
||||
resolve(std::forward<V>(value));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct PromiseFulfill<QtPromise::QPromise<T>>
|
||||
{
|
||||
template <typename TResolve, typename TReject>
|
||||
static void call(
|
||||
const QtPromise::QPromise<T>& promise,
|
||||
const QtPromise::QPromiseResolve<T>& resolve,
|
||||
const QtPromise::QPromiseReject<T>& reject)
|
||||
const TResolve& resolve,
|
||||
const TReject& reject)
|
||||
{
|
||||
if (promise.isFulfilled()) {
|
||||
resolve(promise.m_d->value());
|
||||
@ -176,51 +196,17 @@ struct PromiseFulfill<QtPromise::QPromise<void>>
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename TRes>
|
||||
template <typename Result>
|
||||
struct PromiseDispatch
|
||||
{
|
||||
using Promise = typename PromiseDeduce<TRes>::Type;
|
||||
using ResType = Unqualified<TRes>;
|
||||
|
||||
template <typename THandler, typename TResolve, typename TReject>
|
||||
static void call(const T& value, THandler handler, const TResolve& resolve, const TReject& reject)
|
||||
template <typename Resolve, typename Reject, typename Functor, typename... Args>
|
||||
static void call(const Resolve& resolve, const Reject& reject, Functor fn, Args&&... args)
|
||||
{
|
||||
try {
|
||||
PromiseFulfill<ResType>::call(handler(value), resolve, reject);
|
||||
} catch (...) {
|
||||
reject(std::current_exception());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct PromiseDispatch<T, void>
|
||||
{
|
||||
using Promise = QtPromise::QPromise<void>;
|
||||
|
||||
template <typename THandler, typename TResolve, typename TReject>
|
||||
static void call(const T& value, THandler handler, const TResolve& resolve, const TReject& reject)
|
||||
{
|
||||
try {
|
||||
handler(value);
|
||||
resolve();
|
||||
} catch (...) {
|
||||
reject(std::current_exception());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename TRes>
|
||||
struct PromiseDispatch<void, TRes>
|
||||
{
|
||||
using Promise = typename PromiseDeduce<TRes>::Type;
|
||||
using ResType = Unqualified<TRes>;
|
||||
|
||||
template <typename THandler, typename TResolve, typename TReject>
|
||||
static void call(THandler handler, const TResolve& resolve, const TReject& reject)
|
||||
{
|
||||
try {
|
||||
PromiseFulfill<ResType>::call(handler(), resolve, reject);
|
||||
PromiseFulfill<Unqualified<Result>>::call(
|
||||
fn(std::forward<Args>(args)...),
|
||||
resolve,
|
||||
reject);
|
||||
} catch (...) {
|
||||
reject(std::current_exception());
|
||||
}
|
||||
@ -228,15 +214,13 @@ struct PromiseDispatch<void, TRes>
|
||||
};
|
||||
|
||||
template <>
|
||||
struct PromiseDispatch<void, void>
|
||||
struct PromiseDispatch<void>
|
||||
{
|
||||
using Promise = QtPromise::QPromise<void>;
|
||||
|
||||
template <typename THandler, typename TResolve, typename TReject>
|
||||
static void call(THandler handler, const TResolve& resolve, const TReject& reject)
|
||||
template <typename Resolve, typename Reject, typename Functor, typename... Args>
|
||||
static void call(const Resolve& resolve, const Reject& reject, Functor fn, Args&&... args)
|
||||
{
|
||||
try {
|
||||
handler();
|
||||
fn(std::forward<Args>(args)...);
|
||||
resolve();
|
||||
} catch (...) {
|
||||
reject(std::current_exception());
|
||||
@ -248,7 +232,7 @@ template <typename T, typename THandler, typename TArg = typename ArgsOf<THandle
|
||||
struct PromiseHandler
|
||||
{
|
||||
using ResType = typename std::result_of<THandler(T)>::type;
|
||||
using Promise = typename PromiseDispatch<T, ResType>::Promise;
|
||||
using Promise = typename PromiseDeduce<ResType>::Type;
|
||||
|
||||
template <typename TResolve, typename TReject>
|
||||
static std::function<void(const T&)> create(
|
||||
@ -257,7 +241,7 @@ struct PromiseHandler
|
||||
const TReject& reject)
|
||||
{
|
||||
return [=](const T& value) {
|
||||
PromiseDispatch<T, ResType>::call(value, std::move(handler), resolve, reject);
|
||||
PromiseDispatch<ResType>::call(resolve, reject, handler, value);
|
||||
};
|
||||
}
|
||||
};
|
||||
@ -266,7 +250,7 @@ template <typename T, typename THandler>
|
||||
struct PromiseHandler<T, THandler, void>
|
||||
{
|
||||
using ResType = typename std::result_of<THandler()>::type;
|
||||
using Promise = typename PromiseDispatch<T, ResType>::Promise;
|
||||
using Promise = typename PromiseDeduce<ResType>::Type;
|
||||
|
||||
template <typename TResolve, typename TReject>
|
||||
static std::function<void(const T&)> create(
|
||||
@ -275,7 +259,7 @@ struct PromiseHandler<T, THandler, void>
|
||||
const TReject& reject)
|
||||
{
|
||||
return [=](const T&) {
|
||||
PromiseDispatch<void, ResType>::call(handler, resolve, reject);
|
||||
PromiseDispatch<ResType>::call(resolve, reject, handler);
|
||||
};
|
||||
}
|
||||
};
|
||||
@ -284,7 +268,7 @@ template <typename THandler>
|
||||
struct PromiseHandler<void, THandler, void>
|
||||
{
|
||||
using ResType = typename std::result_of<THandler()>::type;
|
||||
using Promise = typename PromiseDispatch<void, ResType>::Promise;
|
||||
using Promise = typename PromiseDeduce<ResType>::Type;
|
||||
|
||||
template <typename TResolve, typename TReject>
|
||||
static std::function<void()> create(
|
||||
@ -293,7 +277,7 @@ struct PromiseHandler<void, THandler, void>
|
||||
const TReject& reject)
|
||||
{
|
||||
return [=]() {
|
||||
PromiseDispatch<void, ResType>::call(handler, resolve, reject);
|
||||
PromiseDispatch<ResType>::call(resolve, reject, handler);
|
||||
};
|
||||
}
|
||||
};
|
||||
@ -351,7 +335,7 @@ struct PromiseCatcher
|
||||
try {
|
||||
error.rethrow();
|
||||
} catch (const TArg& error) {
|
||||
PromiseDispatch<TArg, ResType>::call(error, handler, resolve, reject);
|
||||
PromiseDispatch<ResType>::call(resolve, reject, handler, error);
|
||||
} catch (...) {
|
||||
reject(std::current_exception());
|
||||
}
|
||||
@ -374,7 +358,7 @@ struct PromiseCatcher<T, THandler, void>
|
||||
try {
|
||||
error.rethrow();
|
||||
} catch (...) {
|
||||
PromiseDispatch<void, ResType>::call(handler, resolve, reject);
|
||||
PromiseDispatch<ResType>::call(resolve, reject, handler);
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -397,6 +381,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, typename F>
|
||||
@ -562,68 +558,15 @@ protected:
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class PromiseResolver
|
||||
struct PromiseInspect
|
||||
{
|
||||
public:
|
||||
PromiseResolver(QtPromise::QPromise<T> promise)
|
||||
: m_d(new Data())
|
||||
template <typename T>
|
||||
static inline PromiseData<T>* get(const QtPromise::QPromise<T>& p)
|
||||
{
|
||||
m_d->promise = new QtPromise::QPromise<T>(std::move(promise));
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
void reject(E&& error)
|
||||
{
|
||||
auto promise = m_d->promise;
|
||||
if (promise) {
|
||||
Q_ASSERT(promise->isPending());
|
||||
promise->m_d->reject(std::forward<E>(error));
|
||||
promise->m_d->dispatch();
|
||||
release();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename V>
|
||||
void resolve(V&& value)
|
||||
{
|
||||
auto promise = m_d->promise;
|
||||
if (promise) {
|
||||
Q_ASSERT(promise->isPending());
|
||||
promise->m_d->resolve(std::forward<V>(value));
|
||||
promise->m_d->dispatch();
|
||||
release();
|
||||
}
|
||||
}
|
||||
|
||||
void resolve()
|
||||
{
|
||||
auto promise = m_d->promise;
|
||||
if (promise) {
|
||||
Q_ASSERT(promise->isPending());
|
||||
promise->m_d->resolve();
|
||||
promise->m_d->dispatch();
|
||||
release();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
struct Data : public QSharedData
|
||||
{
|
||||
QtPromise::QPromise<T>* promise = nullptr;
|
||||
};
|
||||
|
||||
QExplicitlySharedDataPointer<Data> m_d;
|
||||
|
||||
void release()
|
||||
{
|
||||
Q_ASSERT(m_d->promise);
|
||||
Q_ASSERT(!m_d->promise->isPending());
|
||||
delete m_d->promise;
|
||||
m_d->promise = nullptr;
|
||||
return p.m_d.data();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace QtPromise
|
||||
} // namespace QtPromisePrivate
|
||||
|
||||
#endif // ifndef QTPROMISE_QPROMISE_H
|
||||
#endif // QTPROMISE_QPROMISE_H
|
||||
|
48
src/qtpromise/qpromiseconnections.h
Normal file
48
src/qtpromise/qpromiseconnections.h
Normal file
@ -0,0 +1,48 @@
|
||||
#ifndef QTPROMISE_QPROMISECONNECTIONS_H
|
||||
#define QTPROMISE_QPROMISECONNECTIONS_H
|
||||
|
||||
// Qt
|
||||
#include <QSharedPointer>
|
||||
|
||||
namespace QtPromise {
|
||||
|
||||
class QPromiseConnections
|
||||
{
|
||||
public:
|
||||
QPromiseConnections() : m_d(new Data()) { }
|
||||
|
||||
int count() const { return m_d->connections.count(); }
|
||||
|
||||
void disconnect() const { m_d->disconnect(); }
|
||||
|
||||
void operator<<(QMetaObject::Connection&& other) const
|
||||
{
|
||||
m_d->connections.append(std::move(other));
|
||||
}
|
||||
|
||||
private:
|
||||
struct Data
|
||||
{
|
||||
QVector<QMetaObject::Connection> connections;
|
||||
|
||||
~Data() {
|
||||
if (!connections.empty()) {
|
||||
qWarning("QPromiseConnections: destroyed with unhandled connections.");
|
||||
disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
void disconnect() {
|
||||
for (const auto& connection: connections) {
|
||||
QObject::disconnect(connection);
|
||||
}
|
||||
connections.clear();
|
||||
}
|
||||
};
|
||||
|
||||
QSharedPointer<Data> m_d;
|
||||
};
|
||||
|
||||
} // namespace QtPromise
|
||||
|
||||
#endif // QTPROMISE_QPROMISECONNECTIONS_H
|
@ -1,31 +0,0 @@
|
||||
#ifndef QTPROMISE_QPROMISEERROR_H
|
||||
#define QTPROMISE_QPROMISEERROR_H
|
||||
|
||||
// QtPromise
|
||||
#include "qpromise_p.h"
|
||||
#include "qpromiseglobal.h"
|
||||
|
||||
// Qt
|
||||
#include <QException>
|
||||
|
||||
namespace QtPromise {
|
||||
|
||||
class QPromiseTimeoutException : public QException
|
||||
{
|
||||
public:
|
||||
void raise() const Q_DECL_OVERRIDE { throw *this; }
|
||||
QPromiseTimeoutException* clone() const Q_DECL_OVERRIDE
|
||||
{
|
||||
return new QPromiseTimeoutException(*this);
|
||||
}
|
||||
};
|
||||
|
||||
// QPromiseError is provided for backward compatibility and will be
|
||||
// removed in the next major version: it wasn't intended to be used
|
||||
// directly and thus should not be part of the public API.
|
||||
// TODO Remove QPromiseError at version 1.0
|
||||
using QPromiseError = QtPromisePrivate::PromiseError;
|
||||
|
||||
} // namespace QtPromise
|
||||
|
||||
#endif // QTPROMISE_QPROMISEERROR_H
|
60
src/qtpromise/qpromiseexceptions.h
Normal file
60
src/qtpromise/qpromiseexceptions.h
Normal file
@ -0,0 +1,60 @@
|
||||
#ifndef QTPROMISE_QPROMISEEXCEPTIONS_H
|
||||
#define QTPROMISE_QPROMISEEXCEPTIONS_H
|
||||
|
||||
#include "qpromise_p.h"
|
||||
#include "qpromiseglobal.h"
|
||||
|
||||
// Qt
|
||||
#include <QException>
|
||||
|
||||
namespace QtPromise {
|
||||
|
||||
class QPromiseCanceledException : public QException
|
||||
{
|
||||
public:
|
||||
void raise() const Q_DECL_OVERRIDE { throw *this; }
|
||||
QPromiseCanceledException* clone() const Q_DECL_OVERRIDE
|
||||
{
|
||||
return new QPromiseCanceledException(*this);
|
||||
}
|
||||
};
|
||||
|
||||
class QPromiseContextException : public QException
|
||||
{
|
||||
public:
|
||||
void raise() const Q_DECL_OVERRIDE { throw *this; }
|
||||
QPromiseContextException* clone() const Q_DECL_OVERRIDE
|
||||
{
|
||||
return new QPromiseContextException(*this);
|
||||
}
|
||||
};
|
||||
|
||||
class QPromiseTimeoutException : public QException
|
||||
{
|
||||
public:
|
||||
void raise() const Q_DECL_OVERRIDE { throw *this; }
|
||||
QPromiseTimeoutException* clone() const Q_DECL_OVERRIDE
|
||||
{
|
||||
return new QPromiseTimeoutException(*this);
|
||||
}
|
||||
};
|
||||
|
||||
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
|
||||
// removed in the next major version: it wasn't intended to be used
|
||||
// directly and thus should not be part of the public API.
|
||||
// TODO Remove QPromiseError at version 1.0
|
||||
using QPromiseError = QtPromisePrivate::PromiseError;
|
||||
|
||||
} // namespace QtPromise
|
||||
|
||||
#endif // QTPROMISE_QPROMISEEXCEPTIONS_H
|
@ -1,24 +1,12 @@
|
||||
#ifndef QTPROMISE_QPROMISEFUTURE_P_H
|
||||
#define QTPROMISE_QPROMISEFUTURE_P_H
|
||||
|
||||
#include "qpromiseexceptions.h"
|
||||
|
||||
// Qt
|
||||
#include <QFutureWatcher>
|
||||
#include <QFuture>
|
||||
|
||||
namespace QtPromise {
|
||||
|
||||
class QPromiseCanceledException : public QException
|
||||
{
|
||||
public:
|
||||
void raise() const Q_DECL_OVERRIDE { throw *this; }
|
||||
QPromiseCanceledException* clone() const Q_DECL_OVERRIDE
|
||||
{
|
||||
return new QPromiseCanceledException(*this);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace QtPromise
|
||||
|
||||
namespace QtPromisePrivate {
|
||||
|
||||
template <typename T>
|
||||
|
@ -122,4 +122,4 @@ struct ArgsOf<const volatile T&&> : public ArgsOf<T>
|
||||
|
||||
} // namespace QtPromisePrivate
|
||||
|
||||
#endif // ifndef QTPROMISE_QPROMISEGLOBAL_H
|
||||
#endif // QTPROMISE_QPROMISEGLOBAL_H
|
||||
|
@ -1,41 +1,297 @@
|
||||
#ifndef QTPROMISE_QPROMISEHELPERS_H
|
||||
#define QTPROMISE_QPROMISEHELPERS_H
|
||||
|
||||
// QtPromise
|
||||
#include "qpromise_p.h"
|
||||
#include "qpromisehelpers_p.h"
|
||||
|
||||
namespace QtPromise {
|
||||
|
||||
template <typename T>
|
||||
static inline typename QtPromisePrivate::PromiseDeduce<T>::Type qPromise(T&& value)
|
||||
static inline typename QtPromisePrivate::PromiseDeduce<T>::Type
|
||||
resolve(T&& value)
|
||||
{
|
||||
using namespace QtPromisePrivate;
|
||||
using Promise = typename PromiseDeduce<T>::Type;
|
||||
return Promise([&](
|
||||
const QPromiseResolve<typename Promise::Type>& resolve,
|
||||
const QPromiseReject<typename Promise::Type>& reject) {
|
||||
PromiseFulfill<T>::call(std::forward<T>(value), resolve, reject);
|
||||
using PromiseType = typename PromiseDeduce<T>::Type;
|
||||
using ValueType = typename PromiseType::Type;
|
||||
using ResolveType = QPromiseResolve<ValueType>;
|
||||
using RejectType = QPromiseReject<ValueType>;
|
||||
|
||||
return PromiseType([&](ResolveType&& resolve, RejectType&& reject) {
|
||||
PromiseFulfill<Unqualified<T>>::call(
|
||||
std::forward<T>(value),
|
||||
std::forward<ResolveType>(resolve),
|
||||
std::forward<RejectType>(reject));
|
||||
});
|
||||
}
|
||||
|
||||
static inline QPromise<void> qPromise()
|
||||
template <typename T>
|
||||
static inline QPromise<T>
|
||||
resolve(QPromise<T> value)
|
||||
{
|
||||
return QPromise<void>([](
|
||||
const QPromiseResolve<void>& resolve) {
|
||||
return std::move(value);
|
||||
}
|
||||
|
||||
static inline QPromise<void>
|
||||
resolve()
|
||||
{
|
||||
return QPromise<void>([](const QPromiseResolve<void>& resolve) {
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
|
||||
template <typename T, template <typename, typename...> class Sequence = QVector, typename ...Args>
|
||||
static inline QPromise<QVector<T>> qPromiseAll(const Sequence<QPromise<T>, Args...>& promises)
|
||||
static inline QPromise<QVector<T>>
|
||||
all(const Sequence<QPromise<T>, Args...>& promises)
|
||||
{
|
||||
return QPromise<T>::all(promises);
|
||||
const int count = static_cast<int>(promises.size());
|
||||
if (count == 0) {
|
||||
return QtPromise::resolve(QVector<T>{});
|
||||
}
|
||||
|
||||
return QPromise<QVector<T>>([=](
|
||||
const QPromiseResolve<QVector<T>>& resolve,
|
||||
const QPromiseReject<QVector<T>>& reject) {
|
||||
|
||||
QSharedPointer<int> remaining(new int(count));
|
||||
QSharedPointer<QVector<T>> results(new QVector<T>(count));
|
||||
|
||||
int i = 0;
|
||||
for (const auto& promise: promises) {
|
||||
promise.then([=](const T& res) mutable {
|
||||
(*results)[i] = res;
|
||||
if (--(*remaining) == 0) {
|
||||
resolve(*results);
|
||||
}
|
||||
}, [=]() mutable {
|
||||
if (*remaining != -1) {
|
||||
*remaining = -1;
|
||||
reject(std::current_exception());
|
||||
}
|
||||
});
|
||||
|
||||
i++;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
template <template <typename, typename...> class Sequence = QVector, typename ...Args>
|
||||
static inline QPromise<void> qPromiseAll(const Sequence<QPromise<void>, Args...>& promises)
|
||||
static inline QPromise<void>
|
||||
all(const Sequence<QPromise<void>, Args...>& promises)
|
||||
{
|
||||
return QPromise<void>::all(promises);
|
||||
const int count = static_cast<int>(promises.size());
|
||||
if (count == 0) {
|
||||
return QtPromise::resolve();
|
||||
}
|
||||
|
||||
return QPromise<void>([=](
|
||||
const QPromiseResolve<void>& resolve,
|
||||
const QPromiseReject<void>& reject) {
|
||||
|
||||
QSharedPointer<int> remaining(new int(count));
|
||||
|
||||
for (const auto& promise: promises) {
|
||||
promise.then([=]() {
|
||||
if (--(*remaining) == 0) {
|
||||
resolve();
|
||||
}
|
||||
}, [=]() {
|
||||
if (*remaining != -1) {
|
||||
*remaining = -1;
|
||||
reject(std::current_exception());
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
template <typename Functor, typename... Args>
|
||||
static inline typename QtPromisePrivate::PromiseFunctor<Functor, Args...>::PromiseType
|
||||
attempt(Functor&& fn, Args&&... args)
|
||||
{
|
||||
using namespace QtPromisePrivate;
|
||||
using FunctorType = PromiseFunctor<Functor, Args...>;
|
||||
using PromiseType = typename FunctorType::PromiseType;
|
||||
using ValueType = typename PromiseType::Type;
|
||||
|
||||
// NOTE: std::forward<T<U>>: MSVC 2013 fails when forwarding
|
||||
// template type (error: "expects 4 arguments - 0 provided").
|
||||
// However it succeeds with type alias.
|
||||
// TODO: should we expose QPromise::ResolveType & RejectType?
|
||||
using ResolveType = QPromiseResolve<ValueType>;
|
||||
using RejectType = QPromiseReject<ValueType>;
|
||||
|
||||
return PromiseType(
|
||||
[&](ResolveType&& resolve, RejectType&& reject) {
|
||||
PromiseDispatch<typename FunctorType::ResultType>::call(
|
||||
std::forward<ResolveType>(resolve),
|
||||
std::forward<RejectType>(reject),
|
||||
std::forward<Functor>(fn),
|
||||
std::forward<Args>(args)...);
|
||||
});
|
||||
}
|
||||
|
||||
template <typename Sender, typename Signal>
|
||||
static inline typename QtPromisePrivate::PromiseFromSignal<Signal>
|
||||
connect(const Sender* sender, Signal signal)
|
||||
{
|
||||
using namespace QtPromisePrivate;
|
||||
using T = typename PromiseFromSignal<Signal>::Type;
|
||||
|
||||
return QPromise<T>(
|
||||
[&](const QPromiseResolve<T>& resolve, const QPromiseReject<T>& reject) {
|
||||
QPromiseConnections connections;
|
||||
connectSignalToResolver(connections, resolve, sender, signal);
|
||||
connectDestroyedToReject(connections, reject, sender);
|
||||
});
|
||||
}
|
||||
|
||||
template <typename FSender, typename FSignal, typename RSender, typename RSignal>
|
||||
static inline typename QtPromisePrivate::PromiseFromSignal<FSignal>
|
||||
connect(const FSender* fsender, FSignal fsignal, const RSender* rsender, RSignal rsignal)
|
||||
{
|
||||
using namespace QtPromisePrivate;
|
||||
using T = typename PromiseFromSignal<FSignal>::Type;
|
||||
|
||||
return QPromise<T>(
|
||||
[&](const QPromiseResolve<T>& resolve, const QPromiseReject<T>& reject) {
|
||||
QPromiseConnections connections;
|
||||
connectSignalToResolver(connections, resolve, fsender, fsignal);
|
||||
connectSignalToResolver(connections, reject, rsender, rsignal);
|
||||
connectDestroyedToReject(connections, reject, fsender);
|
||||
});
|
||||
}
|
||||
|
||||
template <typename Sender, typename FSignal, typename RSignal>
|
||||
static inline typename QtPromisePrivate::PromiseFromSignal<FSignal>
|
||||
connect(const Sender* sender, FSignal fsignal, RSignal rsignal)
|
||||
{
|
||||
return connect(sender, fsignal, sender, rsignal);
|
||||
}
|
||||
|
||||
template <typename Sequence, typename Functor>
|
||||
static inline QPromise<Sequence>
|
||||
each(const Sequence& values, Functor&& fn)
|
||||
{
|
||||
return QPromise<Sequence>::resolve(values).each(std::forward<Functor>(fn));
|
||||
}
|
||||
|
||||
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 QtPromise::all(promises);
|
||||
}
|
||||
|
||||
template <typename Sequence, typename Functor>
|
||||
static inline QPromise<Sequence>
|
||||
filter(const Sequence& values, Functor fn)
|
||||
{
|
||||
return QtPromise::map(values, fn)
|
||||
.then([=](const QVector<bool>& filters) {
|
||||
Sequence filtered;
|
||||
|
||||
auto filter = filters.begin();
|
||||
for (auto& value : values) {
|
||||
if (*filter) {
|
||||
filtered.push_back(std::move(value));
|
||||
}
|
||||
|
||||
filter++;
|
||||
}
|
||||
|
||||
return filtered;
|
||||
});
|
||||
}
|
||||
|
||||
template <typename T, template <typename...> class Sequence = QVector, typename Reducer, typename Input, typename ...Args>
|
||||
static inline typename QtPromisePrivate::PromiseDeduce<Input>::Type
|
||||
reduce(const Sequence<T, Args...>& values, Reducer fn, Input initial)
|
||||
{
|
||||
using namespace QtPromisePrivate;
|
||||
using PromiseType = typename PromiseDeduce<T>::Type;
|
||||
using ValueType = typename PromiseType::Type;
|
||||
|
||||
int idx = 0;
|
||||
|
||||
auto promise = QtPromise::resolve(std::move(initial));
|
||||
for (const auto& value : values) {
|
||||
auto input = QtPromise::resolve(value);
|
||||
promise = promise.then([=]() {
|
||||
return input.then([=](const ValueType& cur) {
|
||||
return fn(PromiseInspect::get(promise)->value().data(), cur, idx);
|
||||
});
|
||||
});
|
||||
|
||||
idx++;
|
||||
}
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
template <typename T, template <typename...> class Sequence = QVector, typename Reducer, typename ...Args>
|
||||
static inline typename QtPromisePrivate::PromiseDeduce<T>::Type
|
||||
reduce(const Sequence<T, Args...>& values, Reducer fn)
|
||||
{
|
||||
using namespace QtPromisePrivate;
|
||||
using PromiseType = typename PromiseDeduce<T>::Type;
|
||||
using ValueType = typename PromiseType::Type;
|
||||
|
||||
Q_ASSERT(values.size());
|
||||
|
||||
int idx = 1;
|
||||
|
||||
auto it = values.begin();
|
||||
auto promise = QtPromise::resolve(*it);
|
||||
for (++it; it != values.end(); ++it) {
|
||||
auto input = QtPromise::resolve(*it);
|
||||
promise = promise.then([=]() {
|
||||
return input.then([=](const ValueType& cur) {
|
||||
return fn(PromiseInspect::get(promise)->value().data(), cur, idx);
|
||||
});
|
||||
});
|
||||
|
||||
idx++;
|
||||
}
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
// DEPRECATIONS (remove at version 1)
|
||||
|
||||
template <typename... Args>
|
||||
Q_DECL_DEPRECATED_X("Use QtPromise::resolve instead")
|
||||
static inline auto
|
||||
qPromise(Args&&... args)
|
||||
-> decltype(QtPromise::resolve(std::forward<Args>(args)...))
|
||||
{
|
||||
return QtPromise::resolve(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
Q_DECL_DEPRECATED_X("Use QtPromise::all instead")
|
||||
static inline auto
|
||||
qPromiseAll(Args&&... args)
|
||||
-> decltype(QtPromise::all(std::forward<Args>(args)...))
|
||||
{
|
||||
return QtPromise::all(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
} // namespace QtPromise
|
||||
|
91
src/qtpromise/qpromisehelpers_p.h
Normal file
91
src/qtpromise/qpromisehelpers_p.h
Normal file
@ -0,0 +1,91 @@
|
||||
#ifndef QTPROMISE_QPROMISEHELPERS_P_H
|
||||
#define QTPROMISE_QPROMISEHELPERS_P_H
|
||||
|
||||
#include "qpromiseconnections.h"
|
||||
#include "qpromiseexceptions.h"
|
||||
|
||||
namespace QtPromisePrivate {
|
||||
|
||||
// TODO: Suppress QPrivateSignal trailing private signal args
|
||||
// TODO: Support deducing tuple from args (might require MSVC2017)
|
||||
|
||||
template <typename Signal>
|
||||
using PromiseFromSignal = typename QtPromise::QPromise<Unqualified<typename ArgsOf<Signal>::first>>;
|
||||
|
||||
// Connect signal() to QPromiseResolve
|
||||
template <typename Sender, typename Signal>
|
||||
typename std::enable_if<(ArgsOf<Signal>::count == 0)>::type
|
||||
connectSignalToResolver(
|
||||
const QtPromise::QPromiseConnections& connections,
|
||||
const QtPromise::QPromiseResolve<void>& resolve,
|
||||
const Sender* sender,
|
||||
Signal signal)
|
||||
{
|
||||
connections << QObject::connect(sender, signal, [=]() {
|
||||
connections.disconnect();
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
|
||||
// Connect signal() to QPromiseReject
|
||||
template <typename T, typename Sender, typename Signal>
|
||||
typename std::enable_if<(ArgsOf<Signal>::count == 0)>::type
|
||||
connectSignalToResolver(
|
||||
const QtPromise::QPromiseConnections& connections,
|
||||
const QtPromise::QPromiseReject<T>& reject,
|
||||
const Sender* sender,
|
||||
Signal signal)
|
||||
{
|
||||
connections << QObject::connect(sender, signal, [=]() {
|
||||
connections.disconnect();
|
||||
reject(QtPromise::QPromiseUndefinedException());
|
||||
});
|
||||
}
|
||||
|
||||
// Connect signal(args...) to QPromiseResolve
|
||||
template <typename T, typename Sender, typename Signal>
|
||||
typename std::enable_if<(ArgsOf<Signal>::count >= 1)>::type
|
||||
connectSignalToResolver(
|
||||
const QtPromise::QPromiseConnections& connections,
|
||||
const QtPromise::QPromiseResolve<T>& resolve,
|
||||
const Sender* sender,
|
||||
Signal signal)
|
||||
{
|
||||
connections << QObject::connect(sender, signal, [=](const T& value) {
|
||||
connections.disconnect();
|
||||
resolve(value);
|
||||
});
|
||||
}
|
||||
|
||||
// Connect signal(args...) to QPromiseReject
|
||||
template <typename T, typename Sender, typename Signal>
|
||||
typename std::enable_if<(ArgsOf<Signal>::count >= 1)>::type
|
||||
connectSignalToResolver(
|
||||
const QtPromise::QPromiseConnections& connections,
|
||||
const QtPromise::QPromiseReject<T>& reject,
|
||||
const Sender* sender,
|
||||
Signal signal)
|
||||
{
|
||||
using V = Unqualified<typename ArgsOf<Signal>::first>;
|
||||
connections << QObject::connect(sender, signal, [=](const V& value) {
|
||||
connections.disconnect();
|
||||
reject(value);
|
||||
});
|
||||
}
|
||||
|
||||
// Connect QObject::destroyed signal to QPromiseReject
|
||||
template <typename T, typename Sender>
|
||||
void connectDestroyedToReject(
|
||||
const QtPromise::QPromiseConnections& connections,
|
||||
const QtPromise::QPromiseReject<T>& reject,
|
||||
const Sender* sender)
|
||||
{
|
||||
connections << QObject::connect(sender, &QObject::destroyed, [=]() {
|
||||
connections.disconnect();
|
||||
reject(QtPromise::QPromiseContextException());
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace QtPromisePrivate
|
||||
|
||||
#endif // QTPROMISE_QPROMISEHELPERS_P_H
|
142
src/qtpromise/qpromiseresolver.h
Normal file
142
src/qtpromise/qpromiseresolver.h
Normal file
@ -0,0 +1,142 @@
|
||||
#ifndef QTPROMISE_QPROMISERESOLVER_H
|
||||
#define QTPROMISE_QPROMISERESOLVER_H
|
||||
|
||||
#include "qpromiseexceptions.h"
|
||||
|
||||
// Qt
|
||||
#include <QExplicitlySharedDataPointer>
|
||||
|
||||
namespace QtPromise {
|
||||
|
||||
template <typename T> class QPromise;
|
||||
|
||||
} // namespace QtPromise
|
||||
|
||||
namespace QtPromisePrivate {
|
||||
|
||||
template <typename T>
|
||||
class PromiseResolver
|
||||
{
|
||||
public:
|
||||
PromiseResolver(QtPromise::QPromise<T> promise)
|
||||
: m_d(new Data())
|
||||
{
|
||||
m_d->promise = new QtPromise::QPromise<T>(std::move(promise));
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
void reject(E&& error)
|
||||
{
|
||||
auto promise = m_d->promise;
|
||||
if (promise) {
|
||||
Q_ASSERT(promise->isPending());
|
||||
promise->m_d->reject(std::forward<E>(error));
|
||||
promise->m_d->dispatch();
|
||||
release();
|
||||
}
|
||||
}
|
||||
|
||||
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>
|
||||
void resolve(V&& value)
|
||||
{
|
||||
auto promise = m_d->promise;
|
||||
if (promise) {
|
||||
Q_ASSERT(promise->isPending());
|
||||
promise->m_d->resolve(std::forward<V>(value));
|
||||
promise->m_d->dispatch();
|
||||
release();
|
||||
}
|
||||
}
|
||||
|
||||
void resolve()
|
||||
{
|
||||
auto promise = m_d->promise;
|
||||
if (promise) {
|
||||
Q_ASSERT(promise->isPending());
|
||||
promise->m_d->resolve();
|
||||
promise->m_d->dispatch();
|
||||
release();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
struct Data : public QSharedData
|
||||
{
|
||||
QtPromise::QPromise<T>* promise = nullptr;
|
||||
};
|
||||
|
||||
QExplicitlySharedDataPointer<Data> m_d;
|
||||
|
||||
void release()
|
||||
{
|
||||
Q_ASSERT(m_d->promise);
|
||||
Q_ASSERT(!m_d->promise->isPending());
|
||||
delete m_d->promise;
|
||||
m_d->promise = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
} // QtPromisePrivate
|
||||
|
||||
namespace QtPromise {
|
||||
|
||||
template <class T>
|
||||
class QPromiseResolve
|
||||
{
|
||||
public:
|
||||
QPromiseResolve(QtPromisePrivate::PromiseResolver<T> resolver)
|
||||
: m_resolver(std::move(resolver))
|
||||
{ }
|
||||
|
||||
template <typename V>
|
||||
void operator()(V&& value) const
|
||||
{
|
||||
m_resolver.resolve(std::forward<V>(value));
|
||||
}
|
||||
|
||||
void operator()() const
|
||||
{
|
||||
m_resolver.resolve();
|
||||
}
|
||||
|
||||
private:
|
||||
mutable QtPromisePrivate::PromiseResolver<T> m_resolver;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class QPromiseReject
|
||||
{
|
||||
public:
|
||||
QPromiseReject(QtPromisePrivate::PromiseResolver<T> resolver)
|
||||
: m_resolver(std::move(resolver))
|
||||
{ }
|
||||
|
||||
template <typename E>
|
||||
void operator()(E&& error) const
|
||||
{
|
||||
m_resolver.reject(std::forward<E>(error));
|
||||
}
|
||||
|
||||
void operator()() const
|
||||
{
|
||||
m_resolver.reject();
|
||||
}
|
||||
|
||||
private:
|
||||
mutable QtPromisePrivate::PromiseResolver<T> m_resolver;
|
||||
};
|
||||
|
||||
} // namespace QtPromise
|
||||
|
||||
#endif // QTPROMISE_QPROMISERESOLVER_H
|
@ -2,7 +2,10 @@ HEADERS += \
|
||||
$$PWD/qpromise.h \
|
||||
$$PWD/qpromise.inl \
|
||||
$$PWD/qpromise_p.h \
|
||||
$$PWD/qpromiseerror.h \
|
||||
$$PWD/qpromiseconnections.h \
|
||||
$$PWD/qpromiseexceptions.h \
|
||||
$$PWD/qpromisefuture.h \
|
||||
$$PWD/qpromiseglobal.h \
|
||||
$$PWD/qpromisehelpers.h
|
||||
$$PWD/qpromisehelpers.h \
|
||||
$$PWD/qpromisehelpers_p.h \
|
||||
$$PWD/qpromiseresolver.h
|
||||
|
@ -1,3 +1,5 @@
|
||||
#include "../shared/data.h"
|
||||
|
||||
// QtPromise
|
||||
#include <QtPromise>
|
||||
|
||||
@ -20,7 +22,6 @@ class tst_benchmark : public QObject
|
||||
|
||||
private Q_SLOTS:
|
||||
void valueResolve();
|
||||
void valueResolveStatic();
|
||||
void valueReject();
|
||||
void valueThen();
|
||||
void valueFinally();
|
||||
@ -34,72 +35,6 @@ private Q_SLOTS:
|
||||
QTEST_MAIN(tst_benchmark)
|
||||
#include "tst_benchmark.moc"
|
||||
|
||||
struct Logs {
|
||||
int ctor = 0;
|
||||
int copy = 0;
|
||||
int move = 0;
|
||||
int refs = 0;
|
||||
|
||||
void reset() {
|
||||
ctor = 0;
|
||||
copy = 0;
|
||||
move = 0;
|
||||
refs = 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct Logger
|
||||
{
|
||||
Logger() { logs().ctor++; logs().refs++; }
|
||||
Logger(const Logger&) { logs().copy++; logs().refs++; }
|
||||
Logger(Logger&&) { logs().move++; logs().refs++; }
|
||||
~Logger() { logs().refs--; }
|
||||
|
||||
Logger& operator=(const Logger&) { logs().copy++; return *this; }
|
||||
Logger& operator=(Logger&&) { logs().move++; return *this; }
|
||||
|
||||
public: // STATICS
|
||||
static Logs& logs() { static Logs logs; return logs; }
|
||||
};
|
||||
|
||||
struct Data : public Logger
|
||||
{
|
||||
Data(int v): Logger(), m_value(v) {}
|
||||
int value() const { return m_value; }
|
||||
|
||||
// MSVC 2013 doesn't support implicit generation of the move constructor and
|
||||
// operator, so we need to explicitly define these methods and thus the copy
|
||||
// constructor and operator also need to be explicitly defined (error C2280).
|
||||
// https://stackoverflow.com/a/26581337
|
||||
|
||||
Data(const Data& other)
|
||||
: Logger(other)
|
||||
, m_value(other.m_value)
|
||||
{ }
|
||||
|
||||
Data(Data&& other) : Logger(std::forward<Data>(other))
|
||||
{
|
||||
qSwap(m_value, other.m_value);
|
||||
}
|
||||
|
||||
Data& operator=(const Data& other)
|
||||
{
|
||||
Logger::operator=(other);
|
||||
m_value = other.m_value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Data& operator=(Data&& other)
|
||||
{
|
||||
Logger::operator=(std::forward<Data>(other));
|
||||
qSwap(m_value, other.m_value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
int m_value;
|
||||
};
|
||||
|
||||
void tst_benchmark::valueResolve()
|
||||
{
|
||||
{ // should move the value when resolved by rvalue
|
||||
@ -127,31 +62,6 @@ void tst_benchmark::valueResolve()
|
||||
}
|
||||
}
|
||||
|
||||
void tst_benchmark::valueResolveStatic()
|
||||
{
|
||||
{ // should move the value when resolved by rvalue
|
||||
Data::logs().reset();
|
||||
QPromise<Data>::resolve(Data(42)).wait();
|
||||
|
||||
QCOMPARE(Data::logs().ctor, 1);
|
||||
QCOMPARE(Data::logs().copy, 0);
|
||||
QCOMPARE(Data::logs().move, 1); // move value to the promise data
|
||||
QCOMPARE(Data::logs().refs, 0);
|
||||
}
|
||||
{ // should create one copy of the value when resolved by lvalue
|
||||
{
|
||||
Data::logs().reset();
|
||||
Data value(42);
|
||||
QPromise<Data>::resolve(value).wait();
|
||||
}
|
||||
|
||||
QCOMPARE(Data::logs().ctor, 1);
|
||||
QCOMPARE(Data::logs().copy, 1); // copy value to the promise data
|
||||
QCOMPARE(Data::logs().move, 0);
|
||||
QCOMPARE(Data::logs().refs, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_benchmark::valueReject()
|
||||
{
|
||||
{ // should not create any data if rejected
|
||||
|
5
tests/auto/qtpromise/deprecations/deprecations.pri
Normal file
5
tests/auto/qtpromise/deprecations/deprecations.pri
Normal file
@ -0,0 +1,5 @@
|
||||
include(../qtpromise.pri)
|
||||
|
||||
DEFINES -= QT_DEPRECATED_WARNINGS
|
||||
gcc:QMAKE_CXXFLAGS += -Wno-deprecated-declarations
|
||||
msvc:QMAKE_CXXFLAGS -= -wd4996
|
3
tests/auto/qtpromise/deprecations/deprecations.pro
Normal file
3
tests/auto/qtpromise/deprecations/deprecations.pro
Normal file
@ -0,0 +1,3 @@
|
||||
TEMPLATE = subdirs
|
||||
SUBDIRS += \
|
||||
helpers
|
4
tests/auto/qtpromise/deprecations/helpers/helpers.pro
Normal file
4
tests/auto/qtpromise/deprecations/helpers/helpers.pro
Normal file
@ -0,0 +1,4 @@
|
||||
TEMPLATE = subdirs
|
||||
SUBDIRS += \
|
||||
qpromise \
|
||||
qpromiseall
|
@ -0,0 +1,5 @@
|
||||
QT += concurrent
|
||||
TARGET = tst_deprecations_helpers_qpromise
|
||||
SOURCES += $$PWD/tst_qpromise.cpp
|
||||
|
||||
include(../../deprecations.pri)
|
@ -0,0 +1,268 @@
|
||||
#include "../../../shared/data.h"
|
||||
#include "../../../shared/utils.h"
|
||||
|
||||
// QtPromise
|
||||
#include <QtPromise>
|
||||
|
||||
// Qt
|
||||
#include <QtConcurrent>
|
||||
#include <QtTest>
|
||||
|
||||
// STL
|
||||
#include <memory>
|
||||
|
||||
using namespace QtPromise;
|
||||
|
||||
class tst_deprecations_helpers_qpromise : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private Q_SLOTS:
|
||||
void value();
|
||||
void noValue();
|
||||
void moveRValue();
|
||||
void copyLValue();
|
||||
void qtSharedPtr();
|
||||
void stdSharedPtr();
|
||||
void typedPromise();
|
||||
void voidPromise();
|
||||
void typedFuture();
|
||||
void voidFuture();
|
||||
};
|
||||
|
||||
QTEST_MAIN(tst_deprecations_helpers_qpromise)
|
||||
#include "tst_qpromise.moc"
|
||||
|
||||
void tst_deprecations_helpers_qpromise::value()
|
||||
{
|
||||
int v0 = 42;
|
||||
const int v1 = 42;
|
||||
|
||||
auto p0 = qPromise(42);
|
||||
auto p1 = qPromise(v0);
|
||||
auto p2 = qPromise(v1);
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<int>>::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<int>>::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p2), QPromise<int>>::value));
|
||||
|
||||
for (const auto& p : {p0, p1, p2}) {
|
||||
QCOMPARE(p.isFulfilled(), true);
|
||||
}
|
||||
for (const auto& p : {p0, p1, p2}) {
|
||||
QCOMPARE(waitForValue(p, -1), 42);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_deprecations_helpers_qpromise::noValue()
|
||||
{
|
||||
auto p = qPromise();
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value));
|
||||
|
||||
QCOMPARE(p.isFulfilled(), true);
|
||||
QCOMPARE(waitForValue(p, -1, 42), 42);
|
||||
}
|
||||
|
||||
void tst_deprecations_helpers_qpromise::moveRValue()
|
||||
{
|
||||
Data::logs().reset();
|
||||
|
||||
{
|
||||
auto p = qPromise(Data(42)).wait();
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<Data>>::value));
|
||||
}
|
||||
|
||||
QCOMPARE(Data::logs().ctor, 1);
|
||||
QCOMPARE(Data::logs().copy, 0);
|
||||
QCOMPARE(Data::logs().move, 1);
|
||||
QCOMPARE(Data::logs().refs, 0);
|
||||
}
|
||||
|
||||
void tst_deprecations_helpers_qpromise::copyLValue()
|
||||
{
|
||||
Data::logs().reset();
|
||||
|
||||
{
|
||||
Data value(42);
|
||||
auto p = qPromise(value).wait();
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<Data>>::value));
|
||||
}
|
||||
|
||||
QCOMPARE(Data::logs().ctor, 1);
|
||||
QCOMPARE(Data::logs().copy, 1);
|
||||
QCOMPARE(Data::logs().move, 0);
|
||||
QCOMPARE(Data::logs().refs, 0);
|
||||
}
|
||||
|
||||
// https://github.com/simonbrunel/qtpromise/issues/6
|
||||
void tst_deprecations_helpers_qpromise::qtSharedPtr()
|
||||
{
|
||||
Data::logs().reset();
|
||||
|
||||
QWeakPointer<Data> wptr;
|
||||
|
||||
{
|
||||
QSharedPointer<Data> sptr0(new Data(42));
|
||||
const QSharedPointer<Data> sptr1 = sptr0;
|
||||
|
||||
auto p0 = qPromise(QSharedPointer<Data>(new Data(42)));
|
||||
auto p1 = qPromise(sptr0);
|
||||
auto p2 = qPromise(sptr1);
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<QSharedPointer<Data>>>::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<QSharedPointer<Data>>>::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p2), QPromise<QSharedPointer<Data>>>::value));
|
||||
|
||||
QCOMPARE(waitForValue(p1, QSharedPointer<Data>()), sptr0);
|
||||
QCOMPARE(waitForValue(p2, QSharedPointer<Data>()), sptr1);
|
||||
|
||||
wptr = sptr0;
|
||||
|
||||
QCOMPARE(wptr.isNull(), false);
|
||||
QCOMPARE(Data::logs().refs, 2);
|
||||
}
|
||||
|
||||
QCOMPARE(wptr.isNull(), true);
|
||||
|
||||
QCOMPARE(Data::logs().ctor, 2);
|
||||
QCOMPARE(Data::logs().copy, 0);
|
||||
QCOMPARE(Data::logs().move, 0);
|
||||
QCOMPARE(Data::logs().refs, 0);
|
||||
}
|
||||
|
||||
// https://github.com/simonbrunel/qtpromise/issues/6
|
||||
void tst_deprecations_helpers_qpromise::stdSharedPtr()
|
||||
{
|
||||
Data::logs().reset();
|
||||
|
||||
std::weak_ptr<Data> wptr;
|
||||
|
||||
{
|
||||
std::shared_ptr<Data> sptr0(new Data(42));
|
||||
const std::shared_ptr<Data> sptr1 = sptr0;
|
||||
|
||||
auto p0 = qPromise(std::shared_ptr<Data>(new Data(42)));
|
||||
auto p1 = qPromise(sptr0);
|
||||
auto p2 = qPromise(sptr1);
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<std::shared_ptr<Data>>>::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<std::shared_ptr<Data>>>::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p2), QPromise<std::shared_ptr<Data>>>::value));
|
||||
|
||||
QCOMPARE(waitForValue(p1, std::shared_ptr<Data>()), sptr0);
|
||||
QCOMPARE(waitForValue(p2, std::shared_ptr<Data>()), sptr1);
|
||||
|
||||
wptr = sptr0;
|
||||
|
||||
QCOMPARE(wptr.use_count(), 4l);
|
||||
QCOMPARE(Data::logs().refs, 2);
|
||||
}
|
||||
|
||||
QCOMPARE(wptr.use_count(), 0l);
|
||||
|
||||
QCOMPARE(Data::logs().ctor, 2);
|
||||
QCOMPARE(Data::logs().copy, 0);
|
||||
QCOMPARE(Data::logs().move, 0);
|
||||
QCOMPARE(Data::logs().refs, 0);
|
||||
}
|
||||
|
||||
void tst_deprecations_helpers_qpromise::typedPromise()
|
||||
{
|
||||
auto resolver = [](const QPromiseResolve<int>& resolve) {
|
||||
QtPromisePrivate::qtpromise_defer([=](){
|
||||
resolve(42);
|
||||
});
|
||||
};
|
||||
|
||||
QPromise<int> v0(resolver);
|
||||
const QPromise<int> v1 = v0;
|
||||
|
||||
auto p0 = qPromise(QPromise<int>(resolver));
|
||||
auto p1 = qPromise(v0);
|
||||
auto p2 = qPromise(v1);
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<int>>::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<int>>::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p2), QPromise<int>>::value));
|
||||
|
||||
for (const auto& promise : {p0, p1, p2}) {
|
||||
QCOMPARE(promise.isPending(), true);
|
||||
}
|
||||
for (const auto& promise : {p0, p1, p2}) {
|
||||
QCOMPARE(waitForValue(promise, -1), 42);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_deprecations_helpers_qpromise::voidPromise()
|
||||
{
|
||||
auto resolver = [](const QPromiseResolve<void>& resolve) {
|
||||
QtPromisePrivate::qtpromise_defer([=](){
|
||||
resolve();
|
||||
});
|
||||
};
|
||||
|
||||
QPromise<void> v0(resolver);
|
||||
const QPromise<void> v1 = v0;
|
||||
|
||||
auto p0 = qPromise(QPromise<void>(resolver));
|
||||
auto p1 = qPromise(v0);
|
||||
auto p2 = qPromise(v1);
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<void>>::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<void>>::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p2), QPromise<void>>::value));
|
||||
|
||||
for (const auto& promise : {p0, p1, p2}) {
|
||||
QCOMPARE(promise.isPending(), true);
|
||||
}
|
||||
for (const auto& promise : {p0, p1, p2}) {
|
||||
QCOMPARE(waitForValue(promise, -1, 42), 42);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_deprecations_helpers_qpromise::typedFuture()
|
||||
{
|
||||
auto fn = [](){ return 42; };
|
||||
QFuture<int> v0 = QtConcurrent::run(fn);
|
||||
const QFuture<int> v1 = v0;
|
||||
|
||||
auto p0 = qPromise(QtConcurrent::run(fn));
|
||||
auto p1 = qPromise(v0);
|
||||
auto p2 = qPromise(v1);
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<int>>::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<int>>::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p2), QPromise<int>>::value));
|
||||
|
||||
for (const auto& promise : {p0, p1, p2}) {
|
||||
QCOMPARE(promise.isPending(), true);
|
||||
}
|
||||
for (const auto& promise : {p0, p1, p2}) {
|
||||
QCOMPARE(waitForValue(promise, -1), 42);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_deprecations_helpers_qpromise::voidFuture()
|
||||
{
|
||||
auto fn = [](){ };
|
||||
QFuture<void> v0 = QtConcurrent::run(fn);
|
||||
const QFuture<void> v1 = v0;
|
||||
|
||||
auto p0 = qPromise(QtConcurrent::run(fn));
|
||||
auto p1 = qPromise(v0);
|
||||
auto p2 = qPromise(v1);
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<void>>::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<void>>::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p2), QPromise<void>>::value));
|
||||
|
||||
for (const auto& promise : {p0, p1, p2}) {
|
||||
QCOMPARE(promise.isPending(), true);
|
||||
}
|
||||
for (const auto& promise : {p0, p1, p2}) {
|
||||
QCOMPARE(waitForValue(promise, -1, 42), 42);
|
||||
}
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
TARGET = tst_deprecations_helpers_qpromiseall
|
||||
SOURCES += $$PWD/tst_qpromiseall.cpp
|
||||
|
||||
include(../../deprecations.pri)
|
@ -0,0 +1,220 @@
|
||||
#include "../../../shared/utils.h"
|
||||
|
||||
// QtPromise
|
||||
#include <QtPromise>
|
||||
|
||||
// Qt
|
||||
#include <QtTest>
|
||||
|
||||
using namespace QtPromise;
|
||||
|
||||
class tst_deprecations_helpers_qpromiseall : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private Q_SLOTS:
|
||||
void emptySequence();
|
||||
void emptySequence_void();
|
||||
void allPromisesSucceed();
|
||||
void allPromisesSucceed_void();
|
||||
void atLeastOnePromiseReject();
|
||||
void atLeastOnePromiseReject_void();
|
||||
void preserveOrder();
|
||||
void sequenceTypes();
|
||||
void sequenceTypes_void();
|
||||
};
|
||||
|
||||
QTEST_MAIN(tst_deprecations_helpers_qpromiseall)
|
||||
#include "tst_qpromiseall.moc"
|
||||
|
||||
namespace {
|
||||
|
||||
template <class Sequence>
|
||||
struct SequenceTester
|
||||
{
|
||||
Q_STATIC_ASSERT((std::is_same<typename Sequence::value_type, QPromise<int>>::value));
|
||||
|
||||
static void exec()
|
||||
{
|
||||
Sequence promises{
|
||||
QtPromise::resolve(42),
|
||||
QtPromise::resolve(43),
|
||||
QtPromise::resolve(44)
|
||||
};
|
||||
|
||||
promises.push_back(QtPromise::resolve(45));
|
||||
promises.insert(++promises.begin(), QtPromise::resolve(46));
|
||||
promises.pop_back();
|
||||
|
||||
auto p = qPromiseAll(promises);
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(p.isPending(), true);
|
||||
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({42, 46, 43, 44}));
|
||||
}
|
||||
};
|
||||
|
||||
template <template <typename, typename...> class Sequence, typename ...Args>
|
||||
struct SequenceTester<Sequence<QPromise<void>, Args...>>
|
||||
{
|
||||
static void exec()
|
||||
{
|
||||
Sequence<QPromise<void>, Args...> promises{
|
||||
QtPromise::resolve(),
|
||||
QtPromise::resolve(),
|
||||
QtPromise::resolve()
|
||||
};
|
||||
|
||||
promises.push_back(QtPromise::resolve());
|
||||
promises.insert(++promises.begin(), QtPromise::resolve());
|
||||
promises.pop_back();
|
||||
|
||||
auto p = qPromiseAll(promises);
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value));
|
||||
QCOMPARE(p.isPending(), true);
|
||||
QCOMPARE(waitForValue(p, -1, 42), 42);
|
||||
}
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
void tst_deprecations_helpers_qpromiseall::emptySequence()
|
||||
{
|
||||
auto p = qPromiseAll(QVector<QPromise<int>>());
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(p.isFulfilled(), true);
|
||||
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({}));
|
||||
}
|
||||
|
||||
void tst_deprecations_helpers_qpromiseall::emptySequence_void()
|
||||
{
|
||||
auto p = qPromiseAll(QVector<QPromise<void>>());
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value));
|
||||
QCOMPARE(p.isFulfilled(), true);
|
||||
QCOMPARE(waitForValue(p, -1, 42), 42);
|
||||
}
|
||||
|
||||
void tst_deprecations_helpers_qpromiseall::allPromisesSucceed()
|
||||
{
|
||||
auto p0 = QtPromise::resolve(42);
|
||||
auto p1 = QtPromise::resolve(44);
|
||||
auto p2 = QPromise<int>([](const QPromiseResolve<int>& resolve) {
|
||||
QtPromisePrivate::qtpromise_defer([=](){
|
||||
resolve(43);
|
||||
});
|
||||
});
|
||||
|
||||
auto p = qPromiseAll(QVector<QPromise<int>>{p0, p2, p1});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(p0.isFulfilled(), true);
|
||||
QCOMPARE(p1.isFulfilled(), true);
|
||||
QCOMPARE(p2.isPending(), true);
|
||||
QCOMPARE(p.isPending(), true);
|
||||
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({42, 43, 44}));
|
||||
QCOMPARE(p2.isFulfilled(), true);
|
||||
}
|
||||
|
||||
void tst_deprecations_helpers_qpromiseall::allPromisesSucceed_void()
|
||||
{
|
||||
auto p0 = QtPromise::resolve();
|
||||
auto p1 = QtPromise::resolve();
|
||||
auto p2 = QPromise<void>([](const QPromiseResolve<void>& resolve) {
|
||||
QtPromisePrivate::qtpromise_defer([=](){
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
auto p = qPromiseAll(QVector<QPromise<void>>{p0, p2, p1});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value));
|
||||
QCOMPARE(p0.isFulfilled(), true);
|
||||
QCOMPARE(p1.isFulfilled(), true);
|
||||
QCOMPARE(p2.isPending(), true);
|
||||
QCOMPARE(p.isPending(), true);
|
||||
QCOMPARE(waitForValue(p, -1, 42), 42);
|
||||
QCOMPARE(p2.isFulfilled(), true);
|
||||
}
|
||||
|
||||
void tst_deprecations_helpers_qpromiseall::atLeastOnePromiseReject()
|
||||
{
|
||||
auto p0 = QtPromise::resolve(42);
|
||||
auto p1 = QtPromise::resolve(44);
|
||||
auto p2 = QPromise<int>([](const QPromiseResolve<int>&, const QPromiseReject<int>& reject) {
|
||||
QtPromisePrivate::qtpromise_defer([=](){
|
||||
reject(QString("foo"));
|
||||
});
|
||||
});
|
||||
|
||||
auto p = qPromiseAll(QVector<QPromise<int>>{p0, p2, p1});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(p0.isFulfilled(), true);
|
||||
QCOMPARE(p1.isFulfilled(), true);
|
||||
QCOMPARE(p2.isPending(), true);
|
||||
QCOMPARE(p.isPending(), true);
|
||||
QCOMPARE(waitForError(p, QString()), QString("foo"));
|
||||
QCOMPARE(p2.isRejected(), true);
|
||||
}
|
||||
|
||||
void tst_deprecations_helpers_qpromiseall::atLeastOnePromiseReject_void()
|
||||
{
|
||||
auto p0 = QtPromise::resolve();
|
||||
auto p1 = QtPromise::resolve();
|
||||
auto p2 = QPromise<void>([](const QPromiseResolve<void>&, const QPromiseReject<void>& reject) {
|
||||
QtPromisePrivate::qtpromise_defer([=](){
|
||||
reject(QString("foo"));
|
||||
});
|
||||
});
|
||||
|
||||
auto p = qPromiseAll(QVector<QPromise<void>>{p0, p2, p1});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value));
|
||||
QCOMPARE(p0.isFulfilled(), true);
|
||||
QCOMPARE(p1.isFulfilled(), true);
|
||||
QCOMPARE(p2.isPending(), true);
|
||||
QCOMPARE(p.isPending(), true);
|
||||
QCOMPARE(waitForError(p, QString()), QString("foo"));
|
||||
QCOMPARE(p2.isRejected(), true);
|
||||
}
|
||||
|
||||
void tst_deprecations_helpers_qpromiseall::preserveOrder()
|
||||
{
|
||||
auto p0 = QtPromise::resolve(42).delay(500);
|
||||
auto p1 = QtPromise::resolve(43).delay(100);
|
||||
auto p2 = QtPromise::resolve(44).delay(250);
|
||||
|
||||
auto p = qPromiseAll(QVector<QPromise<int>>{p0, p1, p2});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(p0.isPending(), true);
|
||||
QCOMPARE(p1.isPending(), true);
|
||||
QCOMPARE(p2.isPending(), true);
|
||||
QCOMPARE(p.isPending(), true);
|
||||
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({42, 43, 44}));
|
||||
QCOMPARE(p0.isFulfilled(), true);
|
||||
QCOMPARE(p1.isFulfilled(), true);
|
||||
QCOMPARE(p2.isFulfilled(), true);
|
||||
}
|
||||
|
||||
// QVector::push_back/append isn't supported since it requires a default
|
||||
// constructor (see https://github.com/simonbrunel/qtpromise/issues/3)
|
||||
|
||||
void tst_deprecations_helpers_qpromiseall::sequenceTypes()
|
||||
{
|
||||
SequenceTester<QList<QPromise<int>>>::exec();
|
||||
//SequenceTester<QVector<QPromise<int>>>::exec();
|
||||
SequenceTester<std::list<QPromise<int>>>::exec();
|
||||
SequenceTester<std::vector<QPromise<int>>>::exec();
|
||||
}
|
||||
|
||||
void tst_deprecations_helpers_qpromiseall::sequenceTypes_void()
|
||||
{
|
||||
SequenceTester<QList<QPromise<void>>>::exec();
|
||||
//SequenceTester<QVector<QPromise<void>>>::exec();
|
||||
SequenceTester<std::list<QPromise<void>>>::exec();
|
||||
SequenceTester<std::vector<QPromise<void>>>::exec();
|
||||
}
|
4
tests/auto/qtpromise/deprecations/qpromise/all/all.pro
Normal file
4
tests/auto/qtpromise/deprecations/qpromise/all/all.pro
Normal file
@ -0,0 +1,4 @@
|
||||
TARGET = tst_deprecations_qpromise_all
|
||||
SOURCES += $$PWD/tst_all.cpp
|
||||
|
||||
include(../../deprecations.pri)
|
229
tests/auto/qtpromise/deprecations/qpromise/all/tst_all.cpp
Normal file
229
tests/auto/qtpromise/deprecations/qpromise/all/tst_all.cpp
Normal file
@ -0,0 +1,229 @@
|
||||
#include "../../../shared/utils.h"
|
||||
|
||||
// QtPromise
|
||||
#include <QtPromise>
|
||||
|
||||
// Qt
|
||||
#include <QtTest>
|
||||
|
||||
using namespace QtPromise;
|
||||
|
||||
class tst_deprecations_qpromise_all : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private Q_SLOTS:
|
||||
void emptySequence();
|
||||
void emptySequence_void();
|
||||
void allPromisesSucceed();
|
||||
void allPromisesSucceed_void();
|
||||
void atLeastOnePromiseReject();
|
||||
void atLeastOnePromiseReject_void();
|
||||
void preserveOrder();
|
||||
void sequenceTypes();
|
||||
void sequenceTypes_void();
|
||||
};
|
||||
|
||||
QTEST_MAIN(tst_deprecations_qpromise_all)
|
||||
#include "tst_all.moc"
|
||||
|
||||
namespace {
|
||||
|
||||
template <class Sequence>
|
||||
struct SequenceTester
|
||||
{
|
||||
Q_STATIC_ASSERT((std::is_same<typename Sequence::value_type, QPromise<int>>::value));
|
||||
|
||||
static void exec()
|
||||
{
|
||||
Sequence promises{
|
||||
QtPromise::resolve(42),
|
||||
QtPromise::resolve(43),
|
||||
QtPromise::resolve(44)
|
||||
};
|
||||
|
||||
promises.push_back(QtPromise::resolve(45));
|
||||
promises.insert(++promises.begin(), QtPromise::resolve(46));
|
||||
promises.pop_back();
|
||||
|
||||
auto p = QPromise<int>::all(promises);
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
|
||||
QCOMPARE(p.isPending(), true);
|
||||
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({42, 46, 43, 44}));
|
||||
}
|
||||
};
|
||||
|
||||
template <template <typename, typename...> class Sequence, typename ...Args>
|
||||
struct SequenceTester<Sequence<QPromise<void>, Args...>>
|
||||
{
|
||||
static void exec()
|
||||
{
|
||||
Sequence<QPromise<void>, Args...> promises{
|
||||
QtPromise::resolve(),
|
||||
QtPromise::resolve(),
|
||||
QtPromise::resolve()
|
||||
};
|
||||
|
||||
promises.push_back(QtPromise::resolve());
|
||||
promises.insert(++promises.begin(), QtPromise::resolve());
|
||||
promises.pop_back();
|
||||
|
||||
auto p = QPromise<void>::all(promises);
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value));
|
||||
|
||||
QCOMPARE(p.isPending(), true);
|
||||
QCOMPARE(waitForValue(p, -1, 42), 42);
|
||||
}
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
void tst_deprecations_qpromise_all::emptySequence()
|
||||
{
|
||||
auto p = QPromise<int>::all({});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
|
||||
QCOMPARE(p.isFulfilled(), true);
|
||||
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>{});
|
||||
}
|
||||
|
||||
void tst_deprecations_qpromise_all::emptySequence_void()
|
||||
{
|
||||
auto p = QPromise<void>::all({});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value));
|
||||
|
||||
QCOMPARE(p.isFulfilled(), true);
|
||||
QCOMPARE(waitForValue(p, -1, 42), 42);
|
||||
}
|
||||
|
||||
void tst_deprecations_qpromise_all::allPromisesSucceed()
|
||||
{
|
||||
auto p0 = QtPromise::resolve(42);
|
||||
auto p1 = QtPromise::resolve(44);
|
||||
auto p2 = QPromise<int>([](const QPromiseResolve<int>& resolve) {
|
||||
QtPromisePrivate::qtpromise_defer([=](){
|
||||
resolve(43);
|
||||
});
|
||||
});
|
||||
|
||||
auto p = QPromise<int>::all({p0, p2, p1});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
|
||||
QCOMPARE(p0.isFulfilled(), true);
|
||||
QCOMPARE(p1.isFulfilled(), true);
|
||||
QCOMPARE(p2.isPending(), true);
|
||||
QCOMPARE(p.isPending(), true);
|
||||
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({42, 43, 44}));
|
||||
QCOMPARE(p2.isFulfilled(), true);
|
||||
}
|
||||
|
||||
void tst_deprecations_qpromise_all::allPromisesSucceed_void()
|
||||
{
|
||||
auto p0 = QtPromise::resolve();
|
||||
auto p1 = QtPromise::resolve();
|
||||
auto p2 = QPromise<void>([](const QPromiseResolve<void>& resolve) {
|
||||
QtPromisePrivate::qtpromise_defer([=](){
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
auto p = QPromise<void>::all({p0, p2, p1});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value));
|
||||
|
||||
QCOMPARE(p0.isFulfilled(), true);
|
||||
QCOMPARE(p1.isFulfilled(), true);
|
||||
QCOMPARE(p2.isPending(), true);
|
||||
QCOMPARE(p.isPending(), true);
|
||||
QCOMPARE(waitForValue(p, -1, 42), 42);
|
||||
QCOMPARE(p2.isFulfilled(), true);
|
||||
}
|
||||
|
||||
void tst_deprecations_qpromise_all::atLeastOnePromiseReject()
|
||||
{
|
||||
auto p0 = QtPromise::resolve(42);
|
||||
auto p1 = QtPromise::resolve(44);
|
||||
auto p2 = QPromise<int>([](const QPromiseResolve<int>&, const QPromiseReject<int>& reject) {
|
||||
QtPromisePrivate::qtpromise_defer([=](){
|
||||
reject(QString("foo"));
|
||||
});
|
||||
});
|
||||
|
||||
auto p = QPromise<int>::all({p0, p2, p1});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
|
||||
QCOMPARE(p0.isFulfilled(), true);
|
||||
QCOMPARE(p1.isFulfilled(), true);
|
||||
QCOMPARE(p2.isPending(), true);
|
||||
QCOMPARE(p.isPending(), true);
|
||||
QCOMPARE(waitForError(p, QString()), QString("foo"));
|
||||
QCOMPARE(p2.isRejected(), true);
|
||||
}
|
||||
|
||||
void tst_deprecations_qpromise_all::atLeastOnePromiseReject_void()
|
||||
{
|
||||
auto p0 = QtPromise::resolve();
|
||||
auto p1 = QtPromise::resolve();
|
||||
auto p2 = QPromise<void>([](const QPromiseResolve<void>&, const QPromiseReject<void>& reject) {
|
||||
QtPromisePrivate::qtpromise_defer([=](){
|
||||
reject(QString("foo"));
|
||||
});
|
||||
});
|
||||
|
||||
auto p = QPromise<void>::all({p0, p2, p1});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value));
|
||||
|
||||
QCOMPARE(p0.isFulfilled(), true);
|
||||
QCOMPARE(p1.isFulfilled(), true);
|
||||
QCOMPARE(p2.isPending(), true);
|
||||
QCOMPARE(p.isPending(), true);
|
||||
QCOMPARE(waitForError(p, QString()), QString("foo"));
|
||||
QCOMPARE(p2.isRejected(), true);
|
||||
}
|
||||
|
||||
void tst_deprecations_qpromise_all::preserveOrder()
|
||||
{
|
||||
auto p0 = QtPromise::resolve(42).delay(500);
|
||||
auto p1 = QtPromise::resolve(43).delay(100);
|
||||
auto p2 = QtPromise::resolve(44).delay(250);
|
||||
|
||||
auto p = QPromise<int>::all({p0, p1, p2});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
|
||||
QCOMPARE(p0.isPending(), true);
|
||||
QCOMPARE(p1.isPending(), true);
|
||||
QCOMPARE(p2.isPending(), true);
|
||||
QCOMPARE(p.isPending(), true);
|
||||
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({42, 43, 44}));
|
||||
QCOMPARE(p0.isFulfilled(), true);
|
||||
QCOMPARE(p1.isFulfilled(), true);
|
||||
QCOMPARE(p2.isFulfilled(), true);
|
||||
}
|
||||
|
||||
// QVector::push_back/append isn't supported since it requires a default
|
||||
// constructor (see https://github.com/simonbrunel/qtpromise/issues/3)
|
||||
|
||||
void tst_deprecations_qpromise_all::sequenceTypes()
|
||||
{
|
||||
SequenceTester<QList<QPromise<int>>>::exec();
|
||||
//SequenceTester<QVector<QPromise<int>>>::exec();
|
||||
SequenceTester<std::list<QPromise<int>>>::exec();
|
||||
SequenceTester<std::vector<QPromise<int>>>::exec();
|
||||
}
|
||||
|
||||
void tst_deprecations_qpromise_all::sequenceTypes_void()
|
||||
{
|
||||
SequenceTester<QList<QPromise<void>>>::exec();
|
||||
//SequenceTester<QVector<QPromise<void>>>::exec();
|
||||
SequenceTester<std::list<QPromise<void>>>::exec();
|
||||
SequenceTester<std::vector<QPromise<void>>>::exec();
|
||||
}
|
3
tests/auto/qtpromise/deprecations/qpromise/qpromise.pro
Normal file
3
tests/auto/qtpromise/deprecations/qpromise/qpromise.pro
Normal file
@ -0,0 +1,3 @@
|
||||
TEMPLATE = subdirs
|
||||
SUBDIRS += \
|
||||
all
|
5
tests/auto/qtpromise/exceptions/exceptions.pro
Normal file
5
tests/auto/qtpromise/exceptions/exceptions.pro
Normal file
@ -0,0 +1,5 @@
|
||||
QT += concurrent
|
||||
TARGET = tst_exceptions
|
||||
SOURCES += $$PWD/tst_exceptions.cpp
|
||||
|
||||
include(../qtpromise.pri)
|
58
tests/auto/qtpromise/exceptions/tst_exceptions.cpp
Normal file
58
tests/auto/qtpromise/exceptions/tst_exceptions.cpp
Normal file
@ -0,0 +1,58 @@
|
||||
#include "../shared/utils.h"
|
||||
|
||||
// QtPromise
|
||||
#include <QtPromise>
|
||||
|
||||
// Qt
|
||||
#include <QtConcurrent>
|
||||
#include <QtTest>
|
||||
|
||||
using namespace QtPromise;
|
||||
|
||||
class tst_exceptions : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private Q_SLOTS:
|
||||
void canceled();
|
||||
void context();
|
||||
void timeout();
|
||||
void undefined();
|
||||
|
||||
}; // class tst_exceptions
|
||||
|
||||
QTEST_MAIN(tst_exceptions)
|
||||
#include "tst_exceptions.moc"
|
||||
|
||||
namespace {
|
||||
|
||||
template <class E>
|
||||
void verify()
|
||||
{
|
||||
auto p = QtPromise::resolve(QtConcurrent::run([]() { throw E(); }));
|
||||
QCOMPARE(p.isPending(), true);
|
||||
QCOMPARE(waitForRejected<E>(p), true);
|
||||
QCOMPARE(p.isRejected(), true);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
void tst_exceptions::canceled()
|
||||
{
|
||||
verify<QPromiseCanceledException>();
|
||||
}
|
||||
|
||||
void tst_exceptions::context()
|
||||
{
|
||||
verify<QPromiseContextException>();
|
||||
}
|
||||
|
||||
void tst_exceptions::timeout()
|
||||
{
|
||||
verify<QPromiseTimeoutException>();
|
||||
}
|
||||
|
||||
void tst_exceptions::undefined()
|
||||
{
|
||||
verify<QPromiseUndefinedException>();
|
||||
}
|
@ -52,7 +52,7 @@ QTEST_MAIN(tst_future)
|
||||
void tst_future::fulfilled()
|
||||
{
|
||||
int result = -1;
|
||||
auto p = qPromise(QtConcurrent::run([]() {
|
||||
auto p = QtPromise::resolve(QtConcurrent::run([]() {
|
||||
return 42;
|
||||
}));
|
||||
|
||||
@ -70,7 +70,7 @@ void tst_future::fulfilled()
|
||||
void tst_future::fulfilled_void()
|
||||
{
|
||||
int result = -1;
|
||||
auto p = qPromise(QtConcurrent::run([]() { }));
|
||||
auto p = QtPromise::resolve(QtConcurrent::run([]() { }));
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value));
|
||||
QCOMPARE(p.isPending(), true);
|
||||
@ -86,7 +86,7 @@ void tst_future::fulfilled_void()
|
||||
void tst_future::rejected()
|
||||
{
|
||||
QString error;
|
||||
auto p = qPromise(QtConcurrent::run([]() {
|
||||
auto p = QtPromise::resolve(QtConcurrent::run([]() {
|
||||
throw MyException("foo");
|
||||
return 42;
|
||||
}));
|
||||
@ -106,7 +106,7 @@ void tst_future::rejected()
|
||||
void tst_future::rejected_void()
|
||||
{
|
||||
QString error;
|
||||
auto p = qPromise(QtConcurrent::run([]() {
|
||||
auto p = QtPromise::resolve(QtConcurrent::run([]() {
|
||||
throw MyException("foo");
|
||||
}));
|
||||
|
||||
@ -125,7 +125,7 @@ void tst_future::rejected_void()
|
||||
void tst_future::unhandled()
|
||||
{
|
||||
QString error;
|
||||
auto p = qPromise(QtConcurrent::run([]() {
|
||||
auto p = QtPromise::resolve(QtConcurrent::run([]() {
|
||||
throw QString("foo");
|
||||
return 42;
|
||||
}));
|
||||
@ -149,7 +149,7 @@ void tst_future::unhandled()
|
||||
void tst_future::unhandled_void()
|
||||
{
|
||||
QString error;
|
||||
auto p = qPromise(QtConcurrent::run([]() {
|
||||
auto p = QtPromise::resolve(QtConcurrent::run([]() {
|
||||
throw QString("foo");
|
||||
}));
|
||||
|
||||
@ -169,7 +169,7 @@ void tst_future::unhandled_void()
|
||||
void tst_future::canceled()
|
||||
{
|
||||
QString error;
|
||||
auto p = qPromise(QFuture<int>()); // Constructs an empty, canceled future.
|
||||
auto p = QtPromise::resolve(QFuture<int>()); // Constructs an empty, canceled future.
|
||||
|
||||
QCOMPARE(p.isPending(), true);
|
||||
|
||||
@ -185,7 +185,7 @@ void tst_future::canceled()
|
||||
void tst_future::canceled_void()
|
||||
{
|
||||
QString error;
|
||||
auto p = qPromise(QFuture<void>()); // Constructs an empty, canceled future.
|
||||
auto p = QtPromise::resolve(QFuture<void>()); // Constructs an empty, canceled future.
|
||||
|
||||
QCOMPARE(p.isPending(), true);
|
||||
|
||||
@ -200,7 +200,7 @@ void tst_future::canceled_void()
|
||||
void tst_future::canceledFromThread()
|
||||
{
|
||||
QString error;
|
||||
auto p = qPromise(QtConcurrent::run([]() {
|
||||
auto p = QtPromise::resolve(QtConcurrent::run([]() {
|
||||
throw QPromiseCanceledException();
|
||||
}));
|
||||
|
||||
@ -217,7 +217,7 @@ void tst_future::canceledFromThread()
|
||||
void tst_future::then()
|
||||
{
|
||||
QString result;
|
||||
auto input = qPromise(42);
|
||||
auto input = QtPromise::resolve(42);
|
||||
auto output = input.then([](int res) {
|
||||
return QtConcurrent::run([=]() {
|
||||
return QString("foo%1").arg(res);
|
||||
@ -238,7 +238,7 @@ void tst_future::then()
|
||||
void tst_future::then_void()
|
||||
{
|
||||
QString result;
|
||||
auto input = qPromise();
|
||||
auto input = QtPromise::resolve();
|
||||
auto output = input.then([&]() {
|
||||
return QtConcurrent::run([&]() {
|
||||
result = "foo";
|
||||
@ -300,7 +300,7 @@ void tst_future::fail_void()
|
||||
|
||||
void tst_future::finally()
|
||||
{
|
||||
auto input = qPromise(42);
|
||||
auto input = QtPromise::resolve(42);
|
||||
auto output = input.finally([]() {
|
||||
return QtConcurrent::run([]() {
|
||||
return QString("foo");
|
||||
@ -323,7 +323,7 @@ void tst_future::finally()
|
||||
|
||||
void tst_future::finallyRejected()
|
||||
{
|
||||
auto input = qPromise(42);
|
||||
auto input = QtPromise::resolve(42);
|
||||
auto output = input.finally([]() {
|
||||
return QtConcurrent::run([]() {
|
||||
throw MyException("foo");
|
||||
|
@ -1,4 +1,4 @@
|
||||
TARGET = tst_qpromise_all
|
||||
TARGET = tst_helpers_all
|
||||
SOURCES += $$PWD/tst_all.cpp
|
||||
|
||||
include(../../qtpromise.pri)
|
220
tests/auto/qtpromise/helpers/all/tst_all.cpp
Normal file
220
tests/auto/qtpromise/helpers/all/tst_all.cpp
Normal file
@ -0,0 +1,220 @@
|
||||
#include "../../shared/utils.h"
|
||||
|
||||
// QtPromise
|
||||
#include <QtPromise>
|
||||
|
||||
// Qt
|
||||
#include <QtTest>
|
||||
|
||||
using namespace QtPromise;
|
||||
|
||||
class tst_helpers_all : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private Q_SLOTS:
|
||||
void emptySequence();
|
||||
void emptySequence_void();
|
||||
void allPromisesSucceed();
|
||||
void allPromisesSucceed_void();
|
||||
void atLeastOnePromiseReject();
|
||||
void atLeastOnePromiseReject_void();
|
||||
void preserveOrder();
|
||||
void sequenceTypes();
|
||||
void sequenceTypes_void();
|
||||
};
|
||||
|
||||
QTEST_MAIN(tst_helpers_all)
|
||||
#include "tst_all.moc"
|
||||
|
||||
namespace {
|
||||
|
||||
template <class Sequence>
|
||||
struct SequenceTester
|
||||
{
|
||||
Q_STATIC_ASSERT((std::is_same<typename Sequence::value_type, QPromise<int>>::value));
|
||||
|
||||
static void exec()
|
||||
{
|
||||
Sequence promises{
|
||||
QtPromise::resolve(42),
|
||||
QtPromise::resolve(43),
|
||||
QtPromise::resolve(44)
|
||||
};
|
||||
|
||||
promises.push_back(QtPromise::resolve(45));
|
||||
promises.insert(++promises.begin(), QtPromise::resolve(46));
|
||||
promises.pop_back();
|
||||
|
||||
auto p = QtPromise::all(promises);
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(p.isPending(), true);
|
||||
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({42, 46, 43, 44}));
|
||||
}
|
||||
};
|
||||
|
||||
template <template <typename, typename...> class Sequence, typename ...Args>
|
||||
struct SequenceTester<Sequence<QPromise<void>, Args...>>
|
||||
{
|
||||
static void exec()
|
||||
{
|
||||
Sequence<QPromise<void>, Args...> promises{
|
||||
QtPromise::resolve(),
|
||||
QtPromise::resolve(),
|
||||
QtPromise::resolve()
|
||||
};
|
||||
|
||||
promises.push_back(QtPromise::resolve());
|
||||
promises.insert(++promises.begin(), QtPromise::resolve());
|
||||
promises.pop_back();
|
||||
|
||||
auto p = QtPromise::all(promises);
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value));
|
||||
QCOMPARE(p.isPending(), true);
|
||||
QCOMPARE(waitForValue(p, -1, 42), 42);
|
||||
}
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
void tst_helpers_all::emptySequence()
|
||||
{
|
||||
auto p = QtPromise::all(QVector<QPromise<int>>());
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(p.isFulfilled(), true);
|
||||
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({}));
|
||||
}
|
||||
|
||||
void tst_helpers_all::emptySequence_void()
|
||||
{
|
||||
auto p = QtPromise::all(QVector<QPromise<void>>());
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value));
|
||||
QCOMPARE(p.isFulfilled(), true);
|
||||
QCOMPARE(waitForValue(p, -1, 42), 42);
|
||||
}
|
||||
|
||||
void tst_helpers_all::allPromisesSucceed()
|
||||
{
|
||||
auto p0 = QtPromise::resolve(42);
|
||||
auto p1 = QtPromise::resolve(44);
|
||||
auto p2 = QPromise<int>([](const QPromiseResolve<int>& resolve) {
|
||||
QtPromisePrivate::qtpromise_defer([=](){
|
||||
resolve(43);
|
||||
});
|
||||
});
|
||||
|
||||
auto p = QtPromise::all(QVector<QPromise<int>>{p0, p2, p1});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(p0.isFulfilled(), true);
|
||||
QCOMPARE(p1.isFulfilled(), true);
|
||||
QCOMPARE(p2.isPending(), true);
|
||||
QCOMPARE(p.isPending(), true);
|
||||
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({42, 43, 44}));
|
||||
QCOMPARE(p2.isFulfilled(), true);
|
||||
}
|
||||
|
||||
void tst_helpers_all::allPromisesSucceed_void()
|
||||
{
|
||||
auto p0 = QtPromise::resolve();
|
||||
auto p1 = QtPromise::resolve();
|
||||
auto p2 = QPromise<void>([](const QPromiseResolve<void>& resolve) {
|
||||
QtPromisePrivate::qtpromise_defer([=](){
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
auto p = QtPromise::all(QVector<QPromise<void>>{p0, p2, p1});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value));
|
||||
QCOMPARE(p0.isFulfilled(), true);
|
||||
QCOMPARE(p1.isFulfilled(), true);
|
||||
QCOMPARE(p2.isPending(), true);
|
||||
QCOMPARE(p.isPending(), true);
|
||||
QCOMPARE(waitForValue(p, -1, 42), 42);
|
||||
QCOMPARE(p2.isFulfilled(), true);
|
||||
}
|
||||
|
||||
void tst_helpers_all::atLeastOnePromiseReject()
|
||||
{
|
||||
auto p0 = QtPromise::resolve(42);
|
||||
auto p1 = QtPromise::resolve(44);
|
||||
auto p2 = QPromise<int>([](const QPromiseResolve<int>&, const QPromiseReject<int>& reject) {
|
||||
QtPromisePrivate::qtpromise_defer([=](){
|
||||
reject(QString("foo"));
|
||||
});
|
||||
});
|
||||
|
||||
auto p = QtPromise::all(QVector<QPromise<int>>{p0, p2, p1});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(p0.isFulfilled(), true);
|
||||
QCOMPARE(p1.isFulfilled(), true);
|
||||
QCOMPARE(p2.isPending(), true);
|
||||
QCOMPARE(p.isPending(), true);
|
||||
QCOMPARE(waitForError(p, QString()), QString("foo"));
|
||||
QCOMPARE(p2.isRejected(), true);
|
||||
}
|
||||
|
||||
void tst_helpers_all::atLeastOnePromiseReject_void()
|
||||
{
|
||||
auto p0 = QtPromise::resolve();
|
||||
auto p1 = QtPromise::resolve();
|
||||
auto p2 = QPromise<void>([](const QPromiseResolve<void>&, const QPromiseReject<void>& reject) {
|
||||
QtPromisePrivate::qtpromise_defer([=](){
|
||||
reject(QString("foo"));
|
||||
});
|
||||
});
|
||||
|
||||
auto p = QtPromise::all(QVector<QPromise<void>>{p0, p2, p1});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value));
|
||||
QCOMPARE(p0.isFulfilled(), true);
|
||||
QCOMPARE(p1.isFulfilled(), true);
|
||||
QCOMPARE(p2.isPending(), true);
|
||||
QCOMPARE(p.isPending(), true);
|
||||
QCOMPARE(waitForError(p, QString()), QString("foo"));
|
||||
QCOMPARE(p2.isRejected(), true);
|
||||
}
|
||||
|
||||
void tst_helpers_all::preserveOrder()
|
||||
{
|
||||
auto p0 = QtPromise::resolve(42).delay(500);
|
||||
auto p1 = QtPromise::resolve(43).delay(100);
|
||||
auto p2 = QtPromise::resolve(44).delay(250);
|
||||
|
||||
auto p = QtPromise::all(QVector<QPromise<int>>{p0, p1, p2});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(p0.isPending(), true);
|
||||
QCOMPARE(p1.isPending(), true);
|
||||
QCOMPARE(p2.isPending(), true);
|
||||
QCOMPARE(p.isPending(), true);
|
||||
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({42, 43, 44}));
|
||||
QCOMPARE(p0.isFulfilled(), true);
|
||||
QCOMPARE(p1.isFulfilled(), true);
|
||||
QCOMPARE(p2.isFulfilled(), true);
|
||||
}
|
||||
|
||||
// QVector::push_back/append isn't supported since it requires a default
|
||||
// constructor (see https://github.com/simonbrunel/qtpromise/issues/3)
|
||||
|
||||
void tst_helpers_all::sequenceTypes()
|
||||
{
|
||||
SequenceTester<QList<QPromise<int>>>::exec();
|
||||
//SequenceTester<QVector<QPromise<int>>>::exec();
|
||||
SequenceTester<std::list<QPromise<int>>>::exec();
|
||||
SequenceTester<std::vector<QPromise<int>>>::exec();
|
||||
}
|
||||
|
||||
void tst_helpers_all::sequenceTypes_void()
|
||||
{
|
||||
SequenceTester<QList<QPromise<void>>>::exec();
|
||||
//SequenceTester<QVector<QPromise<void>>>::exec();
|
||||
SequenceTester<std::list<QPromise<void>>>::exec();
|
||||
SequenceTester<std::vector<QPromise<void>>>::exec();
|
||||
}
|
5
tests/auto/qtpromise/helpers/attempt/attempt.pro
Normal file
5
tests/auto/qtpromise/helpers/attempt/attempt.pro
Normal file
@ -0,0 +1,5 @@
|
||||
QT += concurrent
|
||||
TARGET = tst_helpers_attempt
|
||||
SOURCES += $$PWD/tst_attempt.cpp
|
||||
|
||||
include(../../qtpromise.pri)
|
98
tests/auto/qtpromise/helpers/attempt/tst_attempt.cpp
Normal file
98
tests/auto/qtpromise/helpers/attempt/tst_attempt.cpp
Normal file
@ -0,0 +1,98 @@
|
||||
#include "../../shared/utils.h"
|
||||
|
||||
// QtPromise
|
||||
#include <QtPromise>
|
||||
|
||||
// Qt
|
||||
#include <QtConcurrent>
|
||||
#include <QtTest>
|
||||
|
||||
// STL
|
||||
#include <memory>
|
||||
|
||||
using namespace QtPromise;
|
||||
|
||||
class tst_helpers_attempt : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private Q_SLOTS:
|
||||
void voidResult();
|
||||
void typedResult();
|
||||
void futureResult();
|
||||
void promiseResult();
|
||||
void functorThrows();
|
||||
void callWithParams();
|
||||
};
|
||||
|
||||
QTEST_MAIN(tst_helpers_attempt)
|
||||
#include "tst_attempt.moc"
|
||||
|
||||
void tst_helpers_attempt::voidResult()
|
||||
{
|
||||
auto p = QtPromise::attempt([]() {});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value));
|
||||
QCOMPARE(p.isFulfilled(), true);
|
||||
QCOMPARE(waitForValue(p, -1, 42), 42);
|
||||
}
|
||||
|
||||
void tst_helpers_attempt::typedResult()
|
||||
{
|
||||
auto p = QtPromise::attempt([]() {
|
||||
return QString("foo");
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QString>>::value));
|
||||
QCOMPARE(p.isFulfilled(), true);
|
||||
QCOMPARE(waitForValue(p, QString()), QString("foo"));
|
||||
}
|
||||
|
||||
void tst_helpers_attempt::futureResult()
|
||||
{
|
||||
auto p = QtPromise::attempt([]() {
|
||||
return QtConcurrent::run([]() {
|
||||
return QString("foo");
|
||||
});
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QString>>::value));
|
||||
QCOMPARE(p.isPending(), true);
|
||||
QCOMPARE(waitForValue(p, QString()), QString("foo"));
|
||||
}
|
||||
|
||||
void tst_helpers_attempt::promiseResult()
|
||||
{
|
||||
auto p = QtPromise::attempt([]() {
|
||||
return QtPromise::resolve(42).delay(200);
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<int>>::value));
|
||||
QCOMPARE(p.isPending(), true);
|
||||
QCOMPARE(waitForValue(p, -1), 42);
|
||||
}
|
||||
|
||||
void tst_helpers_attempt::functorThrows()
|
||||
{
|
||||
auto p = QtPromise::attempt([]() {
|
||||
if (true) {
|
||||
throw QString("bar");
|
||||
}
|
||||
return 42;
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<int>>::value));
|
||||
QCOMPARE(p.isRejected(), true);
|
||||
QCOMPARE(waitForError(p, QString()), QString("bar"));
|
||||
}
|
||||
|
||||
void tst_helpers_attempt::callWithParams()
|
||||
{
|
||||
auto p = QtPromise::attempt([&](int i, const QString& s) {
|
||||
return QString("%1:%2").arg(i).arg(s);
|
||||
}, 42, "foo");
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QString>>::value));
|
||||
QCOMPARE(p.isFulfilled(), true);
|
||||
QCOMPARE(waitForValue(p, QString()), QString("42:foo"));
|
||||
}
|
4
tests/auto/qtpromise/helpers/connect/connect.pro
Normal file
4
tests/auto/qtpromise/helpers/connect/connect.pro
Normal file
@ -0,0 +1,4 @@
|
||||
TARGET = tst_helpers_connect
|
||||
SOURCES += $$PWD/tst_connect.cpp
|
||||
|
||||
include(../../qtpromise.pri)
|
211
tests/auto/qtpromise/helpers/connect/tst_connect.cpp
Normal file
211
tests/auto/qtpromise/helpers/connect/tst_connect.cpp
Normal file
@ -0,0 +1,211 @@
|
||||
#include "../../shared/object.h"
|
||||
#include "../../shared/utils.h"
|
||||
|
||||
// QtPromise
|
||||
#include <QtPromise>
|
||||
|
||||
// Qt
|
||||
#include <QtTest>
|
||||
|
||||
using namespace QtPromise;
|
||||
|
||||
class tst_helpers_connect : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private Q_SLOTS:
|
||||
// connect(QObject* sender, Signal resolver)
|
||||
void resolveOneSenderNoArg();
|
||||
void resolveOneSenderOneArg();
|
||||
void resolveOneSenderManyArgs();
|
||||
|
||||
// connect(QObject* sender, Signal resolver, Signal rejecter)
|
||||
void rejectOneSenderNoArg();
|
||||
void rejectOneSenderOneArg();
|
||||
void rejectOneSenderManyArgs();
|
||||
void rejectOneSenderDestroyed();
|
||||
|
||||
// connect(QObject* s0, Signal resolver, QObject* s1, Signal rejecter)
|
||||
void rejectTwoSendersNoArg();
|
||||
void rejectTwoSendersOneArg();
|
||||
void rejectTwoSendersManyArgs();
|
||||
void rejectTwoSendersDestroyed();
|
||||
};
|
||||
|
||||
QTEST_MAIN(tst_helpers_connect)
|
||||
#include "tst_connect.moc"
|
||||
|
||||
void tst_helpers_connect::resolveOneSenderNoArg()
|
||||
{
|
||||
Object sender;
|
||||
QtPromisePrivate::qtpromise_defer([&]() {
|
||||
Q_EMIT sender.noArgSignal();
|
||||
});
|
||||
|
||||
auto p = QtPromise::connect(&sender, &Object::noArgSignal);
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value));
|
||||
QCOMPARE(sender.hasConnections(), true);
|
||||
QCOMPARE(p.isPending(), true);
|
||||
QCOMPARE(waitForValue(p, -1, 42), 42);
|
||||
QCOMPARE(sender.hasConnections(), false);
|
||||
}
|
||||
|
||||
void tst_helpers_connect::resolveOneSenderOneArg()
|
||||
{
|
||||
Object sender;
|
||||
QtPromisePrivate::qtpromise_defer([&]() {
|
||||
Q_EMIT sender.oneArgSignal("foo");
|
||||
});
|
||||
|
||||
auto p = QtPromise::connect(&sender, &Object::oneArgSignal);
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QString>>::value));
|
||||
QCOMPARE(sender.hasConnections(), true);
|
||||
QCOMPARE(p.isPending(), true);
|
||||
QCOMPARE(waitForValue(p, QString()), QString("foo"));
|
||||
QCOMPARE(sender.hasConnections(), false);
|
||||
}
|
||||
|
||||
void tst_helpers_connect::resolveOneSenderManyArgs()
|
||||
{
|
||||
Object sender;
|
||||
QtPromisePrivate::qtpromise_defer([&]() {
|
||||
Q_EMIT sender.twoArgsSignal(42, "foo");
|
||||
});
|
||||
|
||||
auto p = QtPromise::connect(&sender, &Object::twoArgsSignal);
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<int>>::value));
|
||||
QCOMPARE(sender.hasConnections(), true);
|
||||
QCOMPARE(p.isPending(), true);
|
||||
QCOMPARE(waitForValue(p, -1), 42);
|
||||
QCOMPARE(sender.hasConnections(), false);
|
||||
}
|
||||
|
||||
void tst_helpers_connect::rejectOneSenderNoArg()
|
||||
{
|
||||
Object sender;
|
||||
QtPromisePrivate::qtpromise_defer([&]() {
|
||||
Q_EMIT sender.noArgSignal();
|
||||
});
|
||||
|
||||
auto p = QtPromise::connect(&sender, &Object::oneArgSignal, &Object::noArgSignal);
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QString>>::value));
|
||||
QCOMPARE(sender.hasConnections(), true);
|
||||
QCOMPARE(p.isPending(), true);
|
||||
QCOMPARE(waitForRejected<QPromiseUndefinedException>(p), true);
|
||||
QCOMPARE(sender.hasConnections(), false);
|
||||
}
|
||||
|
||||
void tst_helpers_connect::rejectOneSenderOneArg()
|
||||
{
|
||||
Object sender;
|
||||
QtPromisePrivate::qtpromise_defer([&]() {
|
||||
Q_EMIT sender.oneArgSignal("bar");
|
||||
});
|
||||
|
||||
auto p = QtPromise::connect(&sender, &Object::noArgSignal, &Object::oneArgSignal);
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value));
|
||||
QCOMPARE(sender.hasConnections(), true);
|
||||
QCOMPARE(p.isPending(), true);
|
||||
QCOMPARE(waitForError(p, QString()), QString("bar"));
|
||||
QCOMPARE(sender.hasConnections(), false);
|
||||
}
|
||||
|
||||
void tst_helpers_connect::rejectOneSenderManyArgs()
|
||||
{
|
||||
Object sender;
|
||||
QtPromisePrivate::qtpromise_defer([&]() {
|
||||
Q_EMIT sender.twoArgsSignal(42, "bar");
|
||||
});
|
||||
|
||||
auto p = QtPromise::connect(&sender, &Object::noArgSignal, &Object::twoArgsSignal);
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value));
|
||||
QCOMPARE(sender.hasConnections(), true);
|
||||
QCOMPARE(p.isPending(), true);
|
||||
QCOMPARE(waitForError(p, -1), 42);
|
||||
QCOMPARE(sender.hasConnections(), false);
|
||||
}
|
||||
|
||||
void tst_helpers_connect::rejectOneSenderDestroyed()
|
||||
{
|
||||
Object* sender = new Object();
|
||||
QtPromisePrivate::qtpromise_defer([&]() {
|
||||
sender->deleteLater();
|
||||
});
|
||||
|
||||
auto p = QtPromise::connect(sender, &Object::twoArgsSignal);
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<int>>::value));
|
||||
QCOMPARE(p.isPending(), true);
|
||||
QCOMPARE(waitForRejected<QPromiseContextException>(p), true);
|
||||
}
|
||||
|
||||
void tst_helpers_connect::rejectTwoSendersNoArg()
|
||||
{
|
||||
Object s0, s1;
|
||||
QtPromisePrivate::qtpromise_defer([&]() {
|
||||
Q_EMIT s1.noArgSignal();
|
||||
});
|
||||
|
||||
auto p = QtPromise::connect(&s0, &Object::noArgSignal, &s1, &Object::noArgSignal);
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value));
|
||||
QCOMPARE(s0.hasConnections(), true);
|
||||
QCOMPARE(s1.hasConnections(), true);
|
||||
QCOMPARE(p.isPending(), true);
|
||||
QCOMPARE(waitForRejected<QPromiseUndefinedException>(p), true);
|
||||
QCOMPARE(s0.hasConnections(), false);
|
||||
QCOMPARE(s1.hasConnections(), false);
|
||||
}
|
||||
|
||||
void tst_helpers_connect::rejectTwoSendersOneArg()
|
||||
{
|
||||
Object s0, s1;
|
||||
QtPromisePrivate::qtpromise_defer([&]() {
|
||||
Q_EMIT s1.oneArgSignal("bar");
|
||||
});
|
||||
|
||||
auto p = QtPromise::connect(&s0, &Object::noArgSignal, &s1, &Object::oneArgSignal);
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value));
|
||||
QCOMPARE(s0.hasConnections(), true);
|
||||
QCOMPARE(s1.hasConnections(), true);
|
||||
QCOMPARE(p.isPending(), true);
|
||||
QCOMPARE(waitForError(p, QString()), QString("bar"));
|
||||
QCOMPARE(s0.hasConnections(), false);
|
||||
QCOMPARE(s1.hasConnections(), false);
|
||||
}
|
||||
|
||||
void tst_helpers_connect::rejectTwoSendersManyArgs()
|
||||
{
|
||||
Object s0, s1;
|
||||
QtPromisePrivate::qtpromise_defer([&]() {
|
||||
Q_EMIT s1.twoArgsSignal(42, "bar");
|
||||
});
|
||||
|
||||
auto p = QtPromise::connect(&s0, &Object::noArgSignal, &s1, &Object::twoArgsSignal);
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value));
|
||||
QCOMPARE(s0.hasConnections(), true);
|
||||
QCOMPARE(s1.hasConnections(), true);
|
||||
QCOMPARE(p.isPending(), true);
|
||||
QCOMPARE(waitForError(p, -1), 42);
|
||||
QCOMPARE(s0.hasConnections(), false);
|
||||
QCOMPARE(s1.hasConnections(), false);
|
||||
}
|
||||
|
||||
void tst_helpers_connect::rejectTwoSendersDestroyed()
|
||||
{
|
||||
Object* s0 = new Object();
|
||||
Object* s1 = new Object();
|
||||
|
||||
QtPromisePrivate::qtpromise_defer([&]() {
|
||||
QObject::connect(s1, &QObject::destroyed, [&]() {
|
||||
// Let's first delete s1, then resolve s0 and make sure
|
||||
// we don't reject when the rejecter object is destroyed.
|
||||
Q_EMIT s0->noArgSignal();
|
||||
});
|
||||
|
||||
s1->deleteLater();
|
||||
});
|
||||
|
||||
auto p = QtPromise::connect(s0, &Object::noArgSignal, s1, &Object::twoArgsSignal);
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value));
|
||||
QCOMPARE(p.isPending(), true);
|
||||
QCOMPARE(waitForValue(p, -1, 42), 42);
|
||||
}
|
4
tests/auto/qtpromise/helpers/each/each.pro
Normal file
4
tests/auto/qtpromise/helpers/each/each.pro
Normal file
@ -0,0 +1,4 @@
|
||||
TARGET = tst_qpromise_each
|
||||
SOURCES += $$PWD/tst_each.cpp
|
||||
|
||||
include(../../qtpromise.pri)
|
153
tests/auto/qtpromise/helpers/each/tst_each.cpp
Normal file
153
tests/auto/qtpromise/helpers/each/tst_each.cpp
Normal file
@ -0,0 +1,153 @@
|
||||
#include "../../shared/utils.h"
|
||||
|
||||
// QtPromise
|
||||
#include <QtPromise>
|
||||
|
||||
// Qt
|
||||
#include <QtTest>
|
||||
|
||||
using namespace QtPromise;
|
||||
|
||||
class tst_helpers_each : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private Q_SLOTS:
|
||||
void emptySequence();
|
||||
void preserveValues();
|
||||
void ignoreResult();
|
||||
void delayedFulfilled();
|
||||
void delayedRejected();
|
||||
void functorThrows();
|
||||
void functorArguments();
|
||||
void sequenceTypes();
|
||||
};
|
||||
|
||||
QTEST_MAIN(tst_helpers_each)
|
||||
#include "tst_each.moc"
|
||||
|
||||
namespace {
|
||||
|
||||
template <class Sequence>
|
||||
struct SequenceTester
|
||||
{
|
||||
static void exec()
|
||||
{
|
||||
QVector<int> values;
|
||||
auto p = QtPromise::each(Sequence{42, 43, 44}, [&](int v, int i) {
|
||||
values << i << v;
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<Sequence>>::value));
|
||||
QCOMPARE(waitForValue(p, Sequence()), Sequence({42, 43, 44}));
|
||||
QCOMPARE(values, QVector<int>({0, 42, 1, 43, 2, 44}));
|
||||
}
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
void tst_helpers_each::emptySequence()
|
||||
{
|
||||
QVector<int> values;
|
||||
auto p = QtPromise::each(QVector<int>{}, [&](int v, ...) {
|
||||
values << v;
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>());
|
||||
QCOMPARE(values, QVector<int>({}));
|
||||
}
|
||||
|
||||
void tst_helpers_each::preserveValues()
|
||||
{
|
||||
QVector<int> values;
|
||||
auto p = QtPromise::each(QVector<int>{42, 43, 44}, [&](int v, ...) {
|
||||
values << v + 1;
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({42, 43, 44}));
|
||||
QCOMPARE(values, QVector<int>({43, 44, 45}));
|
||||
}
|
||||
|
||||
void tst_helpers_each::ignoreResult()
|
||||
{
|
||||
QVector<int> values;
|
||||
auto p = QtPromise::each(QVector<int>{42, 43, 44}, [&](int v, ...) {
|
||||
values << v + 1;
|
||||
return "Foo";
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({42, 43, 44}));
|
||||
QCOMPARE(values, QVector<int>({43, 44, 45}));
|
||||
}
|
||||
|
||||
void tst_helpers_each::delayedFulfilled()
|
||||
{
|
||||
QMap<int, int> values;
|
||||
auto p = QtPromise::each(QVector<int>{42, 43, 44}, [&](int v, int index) {
|
||||
return QPromise<int>([&](const QPromiseResolve<int>& resolve) {
|
||||
QtPromisePrivate::qtpromise_defer([=, &values]() {
|
||||
values[v] = index;
|
||||
resolve(42);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({42, 43, 44}));
|
||||
QMap<int, int> expected{{42, 0}, {43, 1}, {44, 2}};
|
||||
QCOMPARE(values, expected);
|
||||
}
|
||||
|
||||
void tst_helpers_each::delayedRejected()
|
||||
{
|
||||
auto p = QtPromise::each(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_each::functorThrows()
|
||||
{
|
||||
auto p = QtPromise::each(QVector<int>{42, 43, 44}, [](int v, ...) {
|
||||
if (v == 44) {
|
||||
throw QString("foo");
|
||||
}
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(waitForError(p, QString()), QString("foo"));
|
||||
}
|
||||
|
||||
void tst_helpers_each::functorArguments()
|
||||
{
|
||||
QVector<int> values;
|
||||
auto p = QtPromise::each(QVector<int>{42, 43, 44}, [&](int v, int i) {
|
||||
values << i << v;
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({42, 43, 44}));
|
||||
QCOMPARE(values, QVector<int>({0, 42, 1, 43, 2, 44}));
|
||||
}
|
||||
|
||||
void tst_helpers_each::sequenceTypes()
|
||||
{
|
||||
SequenceTester<QList<int>>::exec();
|
||||
SequenceTester<QVector<int>>::exec();
|
||||
SequenceTester<std::list<int>>::exec();
|
||||
SequenceTester<std::vector<int>>::exec();
|
||||
}
|
4
tests/auto/qtpromise/helpers/filter/filter.pro
Normal file
4
tests/auto/qtpromise/helpers/filter/filter.pro
Normal file
@ -0,0 +1,4 @@
|
||||
TARGET = tst_helpers_filter
|
||||
SOURCES += $$PWD/tst_filter.cpp
|
||||
|
||||
include(../../qtpromise.pri)
|
146
tests/auto/qtpromise/helpers/filter/tst_filter.cpp
Normal file
146
tests/auto/qtpromise/helpers/filter/tst_filter.cpp
Normal file
@ -0,0 +1,146 @@
|
||||
#include "../../shared/utils.h"
|
||||
|
||||
// QtPromise
|
||||
#include <QtPromise>
|
||||
|
||||
// Qt
|
||||
#include <QtTest>
|
||||
|
||||
using namespace QtPromise;
|
||||
|
||||
class tst_helpers_filter : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private Q_SLOTS:
|
||||
void emptySequence();
|
||||
void filterValues();
|
||||
void delayedFulfilled();
|
||||
void delayedRejected();
|
||||
void functorThrows();
|
||||
void functorArguments();
|
||||
void preserveOrder();
|
||||
void sequenceTypes();
|
||||
};
|
||||
|
||||
QTEST_MAIN(tst_helpers_filter)
|
||||
#include "tst_filter.moc"
|
||||
|
||||
namespace {
|
||||
|
||||
template <class Sequence>
|
||||
struct SequenceTester
|
||||
{
|
||||
static void exec()
|
||||
{
|
||||
auto inputs = Sequence{42, 43, 44, 45, 46, 47, 48, 49, 50, 51};
|
||||
auto p = QtPromise::filter(inputs, [](int v, ...) {
|
||||
return v % 3 == 0;
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<Sequence>>::value));
|
||||
QCOMPARE(waitForValue(p, Sequence()), Sequence({42, 45, 48, 51}));
|
||||
}
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
#include <QtConcurrent/QtConcurrent>
|
||||
|
||||
void tst_helpers_filter::emptySequence()
|
||||
{
|
||||
auto p = QtPromise::filter(QVector<int>{}, [](int v, ...) {
|
||||
return v % 2 == 0;
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>{});
|
||||
}
|
||||
|
||||
void tst_helpers_filter::filterValues()
|
||||
{
|
||||
auto p = QtPromise::filter(QVector<int>{42, 43, 44}, [](int v, ...) {
|
||||
return v % 2 == 0;
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({42, 44}));
|
||||
}
|
||||
|
||||
void tst_helpers_filter::delayedFulfilled()
|
||||
{
|
||||
auto p = QtPromise::filter(QVector<int>{42, 43, 44}, [](int v, ...) {
|
||||
return QPromise<bool>([&](const QPromiseResolve<bool>& resolve) {
|
||||
QtPromisePrivate::qtpromise_defer([=]() {
|
||||
resolve(v % 2 == 0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({42, 44}));
|
||||
}
|
||||
|
||||
void tst_helpers_filter::delayedRejected()
|
||||
{
|
||||
auto p = QtPromise::filter(QVector<int>{42, 43, 44}, [](int v, ...) {
|
||||
return QPromise<bool>([&](
|
||||
const QPromiseResolve<bool>& resolve,
|
||||
const QPromiseReject<bool>& reject) {
|
||||
QtPromisePrivate::qtpromise_defer([=]() {
|
||||
if (v == 44) {
|
||||
reject(QString("foo"));
|
||||
}
|
||||
resolve(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(waitForError(p, QString()), QString("foo"));
|
||||
}
|
||||
|
||||
void tst_helpers_filter::functorThrows()
|
||||
{
|
||||
auto p = QtPromise::filter(QVector<int>{42, 43, 44}, [](int v, ...) {
|
||||
if (v == 44) {
|
||||
throw QString("foo");
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(waitForError(p, QString()), QString("foo"));
|
||||
}
|
||||
|
||||
void tst_helpers_filter::functorArguments()
|
||||
{
|
||||
QMap<int, int> args;
|
||||
auto p = QtPromise::filter(QVector<int>{42, 43, 44}, [&](int v, int i) {
|
||||
args[v] = i;
|
||||
return i % 2 == 0;
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({42, 44}));
|
||||
QMap<int, int> expected{{42, 0}, {43, 1}, {44, 2}};
|
||||
QCOMPARE(args, expected);
|
||||
}
|
||||
|
||||
void tst_helpers_filter::preserveOrder()
|
||||
{
|
||||
auto p = QtPromise::filter(QVector<int>{500, 100, 300, 250, 400}, [](int v, ...) {
|
||||
return QPromise<bool>::resolve(v > 200).delay(v);
|
||||
});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({500, 300, 250, 400}));
|
||||
}
|
||||
|
||||
void tst_helpers_filter::sequenceTypes()
|
||||
{
|
||||
SequenceTester<QList<int>>::exec();
|
||||
SequenceTester<QVector<int>>::exec();
|
||||
SequenceTester<std::list<int>>::exec();
|
||||
SequenceTester<std::vector<int>>::exec();
|
||||
}
|
@ -1,4 +1,11 @@
|
||||
TARGET = tst_helpers
|
||||
SOURCES += $$PWD/tst_helpers.cpp
|
||||
|
||||
include(../qtpromise.pri)
|
||||
TEMPLATE = subdirs
|
||||
SUBDIRS += \
|
||||
all \
|
||||
attempt \
|
||||
connect \
|
||||
each \
|
||||
filter \
|
||||
map \
|
||||
reduce \
|
||||
reject \
|
||||
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)
|
150
tests/auto/qtpromise/helpers/map/tst_map.cpp
Normal file
150
tests/auto/qtpromise/helpers/map/tst_map.cpp
Normal file
@ -0,0 +1,150 @@
|
||||
#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/helpers/reduce/reduce.pro
Normal file
4
tests/auto/qtpromise/helpers/reduce/reduce.pro
Normal file
@ -0,0 +1,4 @@
|
||||
TARGET = tst_helpers_reduce
|
||||
SOURCES += $$PWD/tst_reduce.cpp
|
||||
|
||||
include(../../qtpromise.pri)
|
271
tests/auto/qtpromise/helpers/reduce/tst_reduce.cpp
Normal file
271
tests/auto/qtpromise/helpers/reduce/tst_reduce.cpp
Normal file
@ -0,0 +1,271 @@
|
||||
#include "../../shared/data.h"
|
||||
#include "../../shared/utils.h"
|
||||
|
||||
// QtPromise
|
||||
#include <QtPromise>
|
||||
|
||||
// Qt
|
||||
#include <QtTest>
|
||||
|
||||
using namespace QtPromise;
|
||||
|
||||
class tst_helpers_reduce : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private Q_SLOTS:
|
||||
void emptySequence();
|
||||
void regularValues();
|
||||
void promiseValues();
|
||||
void convertResultType();
|
||||
void delayedInitialValue();
|
||||
void delayedFulfilled();
|
||||
void delayedRejected();
|
||||
void functorThrows();
|
||||
void sequenceTypes();
|
||||
};
|
||||
|
||||
QTEST_MAIN(tst_helpers_reduce)
|
||||
#include "tst_reduce.moc"
|
||||
|
||||
namespace {
|
||||
|
||||
template <class Sequence>
|
||||
struct SequenceTester
|
||||
{
|
||||
static void exec()
|
||||
{
|
||||
Sequence inputs{
|
||||
QtPromise::resolve(4).delay(400),
|
||||
QtPromise::resolve(6).delay(300),
|
||||
QtPromise::resolve(8).delay(200)
|
||||
};
|
||||
QVector<int> v0;
|
||||
QVector<int> v1;
|
||||
|
||||
auto p0 = QtPromise::reduce(inputs, [&](int acc, int cur, int idx) {
|
||||
v0 << acc << cur << idx;
|
||||
return acc + cur + idx;
|
||||
});
|
||||
auto p1 = QtPromise::reduce(inputs, [&](int acc, int cur, int idx) {
|
||||
v1 << acc << cur << idx;
|
||||
return acc + cur + idx;
|
||||
}, QtPromise::resolve(2).delay(100));
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<int>>::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<int>>::value));
|
||||
|
||||
QCOMPARE(p0.isPending(), true);
|
||||
QCOMPARE(p1.isPending(), true);
|
||||
QCOMPARE(waitForValue(p0, -1), 21);
|
||||
QCOMPARE(waitForValue(p1, -1), 23);
|
||||
QCOMPARE(v0, QVector<int>({4, 6, 1, 11, 8, 2}));
|
||||
QCOMPARE(v1, QVector<int>({2, 4, 0, 6, 6, 1, 13, 8, 2}));
|
||||
}
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
void tst_helpers_reduce::emptySequence()
|
||||
{
|
||||
bool called = false;
|
||||
|
||||
auto p = QtPromise::reduce(QVector<int>{}, [&](...) {
|
||||
called = true;
|
||||
return 43;
|
||||
}, 42);
|
||||
|
||||
// NOTE(SB): reduce() on an empty sequence without an initial value is an error!
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<int>>::value));
|
||||
|
||||
QCOMPARE(waitForValue(p, -1), 42);
|
||||
QCOMPARE(called, false);
|
||||
}
|
||||
|
||||
void tst_helpers_reduce::regularValues()
|
||||
{
|
||||
QVector<int> inputs{4, 6, 8};
|
||||
QVector<int> v0;
|
||||
QVector<int> v1;
|
||||
|
||||
auto p0 = QtPromise::reduce(inputs, [&](int acc, int cur, int idx) {
|
||||
v0 << acc << cur << idx;
|
||||
return acc + cur + idx;
|
||||
});
|
||||
auto p1 = QtPromise::reduce(inputs, [&](int acc, int cur, int idx) {
|
||||
v1 << acc << cur << idx;
|
||||
return acc + cur + idx;
|
||||
}, 2);
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<int>>::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<int>>::value));
|
||||
|
||||
QCOMPARE(p0.isPending(), true);
|
||||
QCOMPARE(p1.isPending(), true);
|
||||
QCOMPARE(waitForValue(p0, -1), 21);
|
||||
QCOMPARE(waitForValue(p1, -1), 23);
|
||||
QCOMPARE(v0, QVector<int>({4, 6, 1, 11, 8, 2}));
|
||||
QCOMPARE(v1, QVector<int>({2, 4, 0, 6, 6, 1, 13, 8, 2}));
|
||||
}
|
||||
|
||||
void tst_helpers_reduce::promiseValues()
|
||||
{
|
||||
QVector<QPromise<int>> inputs{
|
||||
QtPromise::resolve(4).delay(400),
|
||||
QtPromise::resolve(6).delay(300),
|
||||
QtPromise::resolve(8).delay(200)
|
||||
};
|
||||
QVector<int> v0;
|
||||
QVector<int> v1;
|
||||
|
||||
auto p0 = QtPromise::reduce(inputs, [&](int acc, int cur, int idx) {
|
||||
v0 << acc << cur << idx;
|
||||
return acc + cur + idx;
|
||||
});
|
||||
auto p1 = QtPromise::reduce(inputs, [&](int acc, int cur, int idx) {
|
||||
v1 << acc << cur << idx;
|
||||
return acc + cur + idx;
|
||||
}, 2);
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<int>>::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<int>>::value));
|
||||
|
||||
QCOMPARE(p0.isPending(), true);
|
||||
QCOMPARE(p1.isPending(), true);
|
||||
QCOMPARE(waitForValue(p0, -1), 21);
|
||||
QCOMPARE(waitForValue(p1, -1), 23);
|
||||
QCOMPARE(v0, QVector<int>({4, 6, 1, 11, 8, 2}));
|
||||
QCOMPARE(v1, QVector<int>({2, 4, 0, 6, 6, 1, 13, 8, 2}));
|
||||
}
|
||||
|
||||
void tst_helpers_reduce::convertResultType()
|
||||
{
|
||||
QVector<int> inputs{4, 6, 8};
|
||||
|
||||
auto p = QtPromise::reduce(inputs, [&](const QString& acc, int cur, int idx) {
|
||||
return QString("%1:%2:%3").arg(acc).arg(cur).arg(idx);
|
||||
}, QString("foo"));
|
||||
|
||||
// NOTE(SB): when no initial value is given, the result type is the sequence type.
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QString>>::value));
|
||||
|
||||
QCOMPARE(p.isPending(), true);
|
||||
QCOMPARE(waitForValue(p, QString()), QString("foo:4:0:6:1:8:2"));
|
||||
}
|
||||
|
||||
void tst_helpers_reduce::delayedInitialValue()
|
||||
{
|
||||
QVector<int> values;
|
||||
|
||||
auto p = QtPromise::reduce(QVector<int>{4, 6, 8}, [&](int acc, int cur, int idx) {
|
||||
values << acc << cur << idx;
|
||||
return acc + cur + idx;
|
||||
}, QtPromise::resolve(2).delay(100));
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<int>>::value));
|
||||
|
||||
QCOMPARE(p.isPending(), true);
|
||||
QCOMPARE(waitForValue(p, -1), 23);
|
||||
QCOMPARE(values, QVector<int>({2, 4, 0, 6, 6, 1, 13, 8, 2}));
|
||||
}
|
||||
|
||||
void tst_helpers_reduce::delayedFulfilled()
|
||||
{
|
||||
QVector<int> inputs{4, 6, 8};
|
||||
QVector<int> v0;
|
||||
QVector<int> v1;
|
||||
|
||||
auto p0 = QtPromise::reduce(inputs, [&](int acc, int cur, int idx) {
|
||||
v0 << acc << cur << idx;
|
||||
return QtPromise::resolve(acc + cur + idx).delay(100);
|
||||
});
|
||||
auto p1 = QtPromise::reduce(inputs, [&](int acc, int cur, int idx) {
|
||||
v1 << acc << cur << idx;
|
||||
return QtPromise::resolve(acc + cur + idx).delay(100);
|
||||
}, 2);
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<int>>::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<int>>::value));
|
||||
|
||||
QCOMPARE(p0.isPending(), true);
|
||||
QCOMPARE(p1.isPending(), true);
|
||||
QCOMPARE(waitForValue(p0, -1), 21);
|
||||
QCOMPARE(waitForValue(p1, -1), 23);
|
||||
QCOMPARE(v0, QVector<int>({4, 6, 1, 11, 8, 2}));
|
||||
QCOMPARE(v1, QVector<int>({2, 4, 0, 6, 6, 1, 13, 8, 2}));
|
||||
}
|
||||
|
||||
void tst_helpers_reduce::delayedRejected()
|
||||
{
|
||||
QVector<int> inputs{4, 6, 8};
|
||||
QVector<int> v0;
|
||||
QVector<int> v1;
|
||||
|
||||
auto p0 = QtPromise::reduce(inputs, [&](int acc, int cur, int idx) {
|
||||
v0 << acc << cur << idx;
|
||||
if (cur == 6) {
|
||||
return QPromise<int>::reject(QString("foo"));
|
||||
}
|
||||
return QtPromise::resolve(acc + cur + idx);
|
||||
});
|
||||
auto p1 = QtPromise::reduce(inputs, [&](int acc, int cur, int idx) {
|
||||
v1 << acc << cur << idx;
|
||||
if (cur == 6) {
|
||||
return QPromise<int>::reject(QString("bar"));
|
||||
}
|
||||
return QtPromise::resolve(acc + cur + idx);
|
||||
}, 2);
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<int>>::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<int>>::value));
|
||||
|
||||
QCOMPARE(p0.isPending(), true);
|
||||
QCOMPARE(p1.isPending(), true);
|
||||
QCOMPARE(waitForError(p0, QString()), QString("foo"));
|
||||
QCOMPARE(waitForError(p1, QString()), QString("bar"));
|
||||
QCOMPARE(v0, QVector<int>({4, 6, 1}));
|
||||
QCOMPARE(v1, QVector<int>({2, 4, 0, 6, 6, 1}));
|
||||
}
|
||||
|
||||
void tst_helpers_reduce::functorThrows()
|
||||
{
|
||||
QVector<int> inputs{4, 6, 8};
|
||||
QVector<int> v0;
|
||||
QVector<int> v1;
|
||||
|
||||
auto p0 = QtPromise::reduce(inputs, [&](int acc, int cur, int idx) {
|
||||
v0 << acc << cur << idx;
|
||||
if (cur == 6) {
|
||||
throw QString("foo");
|
||||
}
|
||||
return acc + cur + idx;
|
||||
});
|
||||
auto p1 = QtPromise::reduce(inputs, [&](int acc, int cur, int idx) {
|
||||
v1 << acc << cur << idx;
|
||||
if (cur == 6) {
|
||||
throw QString("bar");
|
||||
}
|
||||
return acc + cur + idx;
|
||||
}, 2);
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<int>>::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<int>>::value));
|
||||
|
||||
QCOMPARE(p0.isPending(), true);
|
||||
QCOMPARE(p1.isPending(), true);
|
||||
QCOMPARE(waitForError(p0, QString()), QString("foo"));
|
||||
QCOMPARE(waitForError(p1, QString()), QString("bar"));
|
||||
QCOMPARE(v0, QVector<int>({4, 6, 1}));
|
||||
QCOMPARE(v1, QVector<int>({2, 4, 0, 6, 6, 1}));
|
||||
}
|
||||
|
||||
void tst_helpers_reduce::sequenceTypes()
|
||||
{
|
||||
SequenceTester<QLinkedList<QPromise<int>>>::exec();
|
||||
SequenceTester<QList<QPromise<int>>>::exec();
|
||||
SequenceTester<QVector<QPromise<int>>>::exec();
|
||||
SequenceTester<std::list<QPromise<int>>>::exec();
|
||||
SequenceTester<std::vector<QPromise<int>>>::exec();
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
TARGET = tst_qpromise_reject
|
||||
TARGET = tst_helpers_reject
|
||||
SOURCES += $$PWD/tst_reject.cpp
|
||||
|
||||
include(../../qtpromise.pri)
|
@ -1,4 +1,3 @@
|
||||
// Tests
|
||||
#include "../../shared/utils.h"
|
||||
|
||||
// QtPromise
|
||||
@ -12,7 +11,7 @@
|
||||
|
||||
using namespace QtPromise;
|
||||
|
||||
class tst_qpromise_reject : public QObject
|
||||
class tst_helpers_reject : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@ -22,10 +21,10 @@ private Q_SLOTS:
|
||||
void rejectWithStdSharedPtr();
|
||||
};
|
||||
|
||||
QTEST_MAIN(tst_qpromise_reject)
|
||||
QTEST_MAIN(tst_helpers_reject)
|
||||
#include "tst_reject.moc"
|
||||
|
||||
void tst_qpromise_reject::rejectWithValue()
|
||||
void tst_helpers_reject::rejectWithValue()
|
||||
{
|
||||
auto p = QPromise<int>::reject(42);
|
||||
|
||||
@ -34,7 +33,7 @@ void tst_qpromise_reject::rejectWithValue()
|
||||
}
|
||||
|
||||
// https://github.com/simonbrunel/qtpromise/issues/6
|
||||
void tst_qpromise_reject::rejectWithQSharedPtr()
|
||||
void tst_helpers_reject::rejectWithQSharedPtr()
|
||||
{
|
||||
QWeakPointer<int> wptr;
|
||||
|
||||
@ -54,7 +53,7 @@ void tst_qpromise_reject::rejectWithQSharedPtr()
|
||||
}
|
||||
|
||||
// https://github.com/simonbrunel/qtpromise/issues/6
|
||||
void tst_qpromise_reject::rejectWithStdSharedPtr()
|
||||
void tst_helpers_reject::rejectWithStdSharedPtr()
|
||||
{
|
||||
std::weak_ptr<int> wptr;
|
||||
|
5
tests/auto/qtpromise/helpers/resolve/resolve.pro
Normal file
5
tests/auto/qtpromise/helpers/resolve/resolve.pro
Normal file
@ -0,0 +1,5 @@
|
||||
QT += concurrent
|
||||
TARGET = tst_helpers_resolve
|
||||
SOURCES += $$PWD/tst_resolve.cpp
|
||||
|
||||
include(../../qtpromise.pri)
|
268
tests/auto/qtpromise/helpers/resolve/tst_resolve.cpp
Normal file
268
tests/auto/qtpromise/helpers/resolve/tst_resolve.cpp
Normal file
@ -0,0 +1,268 @@
|
||||
#include "../../shared/data.h"
|
||||
#include "../../shared/utils.h"
|
||||
|
||||
// QtPromise
|
||||
#include <QtPromise>
|
||||
|
||||
// Qt
|
||||
#include <QtConcurrent>
|
||||
#include <QtTest>
|
||||
|
||||
// STL
|
||||
#include <memory>
|
||||
|
||||
using namespace QtPromise;
|
||||
|
||||
class tst_helpers_resolve : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private Q_SLOTS:
|
||||
void value();
|
||||
void noValue();
|
||||
void moveRValue();
|
||||
void copyLValue();
|
||||
void qtSharedPtr();
|
||||
void stdSharedPtr();
|
||||
void typedPromise();
|
||||
void voidPromise();
|
||||
void typedFuture();
|
||||
void voidFuture();
|
||||
};
|
||||
|
||||
QTEST_MAIN(tst_helpers_resolve)
|
||||
#include "tst_resolve.moc"
|
||||
|
||||
void tst_helpers_resolve::value()
|
||||
{
|
||||
int v0 = 42;
|
||||
const int v1 = 42;
|
||||
|
||||
auto p0 = QtPromise::resolve(42);
|
||||
auto p1 = QtPromise::resolve(v0);
|
||||
auto p2 = QtPromise::resolve(v1);
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<int>>::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<int>>::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p2), QPromise<int>>::value));
|
||||
|
||||
for (const auto& p : {p0, p1, p2}) {
|
||||
QCOMPARE(p.isFulfilled(), true);
|
||||
}
|
||||
for (const auto& p : {p0, p1, p2}) {
|
||||
QCOMPARE(waitForValue(p, -1), 42);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_helpers_resolve::noValue()
|
||||
{
|
||||
auto p = QtPromise::resolve();
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value));
|
||||
|
||||
QCOMPARE(p.isFulfilled(), true);
|
||||
QCOMPARE(waitForValue(p, -1, 42), 42);
|
||||
}
|
||||
|
||||
void tst_helpers_resolve::moveRValue()
|
||||
{
|
||||
Data::logs().reset();
|
||||
|
||||
{
|
||||
auto p = QtPromise::resolve(Data(42)).wait();
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<Data>>::value));
|
||||
}
|
||||
|
||||
QCOMPARE(Data::logs().ctor, 1);
|
||||
QCOMPARE(Data::logs().copy, 0);
|
||||
QCOMPARE(Data::logs().move, 1);
|
||||
QCOMPARE(Data::logs().refs, 0);
|
||||
}
|
||||
|
||||
void tst_helpers_resolve::copyLValue()
|
||||
{
|
||||
Data::logs().reset();
|
||||
|
||||
{
|
||||
Data value(42);
|
||||
auto p = QtPromise::resolve(value).wait();
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<Data>>::value));
|
||||
}
|
||||
|
||||
QCOMPARE(Data::logs().ctor, 1);
|
||||
QCOMPARE(Data::logs().copy, 1);
|
||||
QCOMPARE(Data::logs().move, 0);
|
||||
QCOMPARE(Data::logs().refs, 0);
|
||||
}
|
||||
|
||||
// https://github.com/simonbrunel/qtpromise/issues/6
|
||||
void tst_helpers_resolve::qtSharedPtr()
|
||||
{
|
||||
Data::logs().reset();
|
||||
|
||||
QWeakPointer<Data> wptr;
|
||||
|
||||
{
|
||||
QSharedPointer<Data> sptr0(new Data(42));
|
||||
const QSharedPointer<Data> sptr1 = sptr0;
|
||||
|
||||
auto p0 = QtPromise::resolve(QSharedPointer<Data>(new Data(42)));
|
||||
auto p1 = QtPromise::resolve(sptr0);
|
||||
auto p2 = QtPromise::resolve(sptr1);
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<QSharedPointer<Data>>>::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<QSharedPointer<Data>>>::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p2), QPromise<QSharedPointer<Data>>>::value));
|
||||
|
||||
QCOMPARE(waitForValue(p1, QSharedPointer<Data>()), sptr0);
|
||||
QCOMPARE(waitForValue(p2, QSharedPointer<Data>()), sptr1);
|
||||
|
||||
wptr = sptr0;
|
||||
|
||||
QCOMPARE(wptr.isNull(), false);
|
||||
QCOMPARE(Data::logs().refs, 2);
|
||||
}
|
||||
|
||||
QCOMPARE(wptr.isNull(), true);
|
||||
|
||||
QCOMPARE(Data::logs().ctor, 2);
|
||||
QCOMPARE(Data::logs().copy, 0);
|
||||
QCOMPARE(Data::logs().move, 0);
|
||||
QCOMPARE(Data::logs().refs, 0);
|
||||
}
|
||||
|
||||
// https://github.com/simonbrunel/qtpromise/issues/6
|
||||
void tst_helpers_resolve::stdSharedPtr()
|
||||
{
|
||||
Data::logs().reset();
|
||||
|
||||
std::weak_ptr<Data> wptr;
|
||||
|
||||
{
|
||||
std::shared_ptr<Data> sptr0(new Data(42));
|
||||
const std::shared_ptr<Data> sptr1 = sptr0;
|
||||
|
||||
auto p0 = QtPromise::resolve(std::shared_ptr<Data>(new Data(42)));
|
||||
auto p1 = QtPromise::resolve(sptr0);
|
||||
auto p2 = QtPromise::resolve(sptr1);
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<std::shared_ptr<Data>>>::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<std::shared_ptr<Data>>>::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p2), QPromise<std::shared_ptr<Data>>>::value));
|
||||
|
||||
QCOMPARE(waitForValue(p1, std::shared_ptr<Data>()), sptr0);
|
||||
QCOMPARE(waitForValue(p2, std::shared_ptr<Data>()), sptr1);
|
||||
|
||||
wptr = sptr0;
|
||||
|
||||
QCOMPARE(wptr.use_count(), 4l);
|
||||
QCOMPARE(Data::logs().refs, 2);
|
||||
}
|
||||
|
||||
QCOMPARE(wptr.use_count(), 0l);
|
||||
|
||||
QCOMPARE(Data::logs().ctor, 2);
|
||||
QCOMPARE(Data::logs().copy, 0);
|
||||
QCOMPARE(Data::logs().move, 0);
|
||||
QCOMPARE(Data::logs().refs, 0);
|
||||
}
|
||||
|
||||
void tst_helpers_resolve::typedPromise()
|
||||
{
|
||||
auto resolver = [](const QPromiseResolve<int>& resolve) {
|
||||
QtPromisePrivate::qtpromise_defer([=](){
|
||||
resolve(42);
|
||||
});
|
||||
};
|
||||
|
||||
QPromise<int> v0(resolver);
|
||||
const QPromise<int> v1 = v0;
|
||||
|
||||
auto p0 = QtPromise::resolve(QPromise<int>(resolver));
|
||||
auto p1 = QtPromise::resolve(v0);
|
||||
auto p2 = QtPromise::resolve(v1);
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<int>>::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<int>>::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p2), QPromise<int>>::value));
|
||||
|
||||
for (const auto& promise : {p0, p1, p2}) {
|
||||
QCOMPARE(promise.isPending(), true);
|
||||
}
|
||||
for (const auto& promise : {p0, p1, p2}) {
|
||||
QCOMPARE(waitForValue(promise, -1), 42);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_helpers_resolve::voidPromise()
|
||||
{
|
||||
auto resolver = [](const QPromiseResolve<void>& resolve) {
|
||||
QtPromisePrivate::qtpromise_defer([=](){
|
||||
resolve();
|
||||
});
|
||||
};
|
||||
|
||||
QPromise<void> v0(resolver);
|
||||
const QPromise<void> v1 = v0;
|
||||
|
||||
auto p0 = QtPromise::resolve(QPromise<void>(resolver));
|
||||
auto p1 = QtPromise::resolve(v0);
|
||||
auto p2 = QtPromise::resolve(v1);
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<void>>::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<void>>::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p2), QPromise<void>>::value));
|
||||
|
||||
for (const auto& promise : {p0, p1, p2}) {
|
||||
QCOMPARE(promise.isPending(), true);
|
||||
}
|
||||
for (const auto& promise : {p0, p1, p2}) {
|
||||
QCOMPARE(waitForValue(promise, -1, 42), 42);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_helpers_resolve::typedFuture()
|
||||
{
|
||||
auto fn = [](){ return 42; };
|
||||
QFuture<int> v0 = QtConcurrent::run(fn);
|
||||
const QFuture<int> v1 = v0;
|
||||
|
||||
auto p0 = QtPromise::resolve(QtConcurrent::run(fn));
|
||||
auto p1 = QtPromise::resolve(v0);
|
||||
auto p2 = QtPromise::resolve(v1);
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<int>>::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<int>>::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p2), QPromise<int>>::value));
|
||||
|
||||
for (const auto& promise : {p0, p1, p2}) {
|
||||
QCOMPARE(promise.isPending(), true);
|
||||
}
|
||||
for (const auto& promise : {p0, p1, p2}) {
|
||||
QCOMPARE(waitForValue(promise, -1), 42);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_helpers_resolve::voidFuture()
|
||||
{
|
||||
auto fn = [](){ };
|
||||
QFuture<void> v0 = QtConcurrent::run(fn);
|
||||
const QFuture<void> v1 = v0;
|
||||
|
||||
auto p0 = QtPromise::resolve(QtConcurrent::run(fn));
|
||||
auto p1 = QtPromise::resolve(v0);
|
||||
auto p2 = QtPromise::resolve(v1);
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<void>>::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<void>>::value));
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p2), QPromise<void>>::value));
|
||||
|
||||
for (const auto& promise : {p0, p1, p2}) {
|
||||
QCOMPARE(promise.isPending(), true);
|
||||
}
|
||||
for (const auto& promise : {p0, p1, p2}) {
|
||||
QCOMPARE(waitForValue(promise, -1, 42), 42);
|
||||
}
|
||||
}
|
@ -1,244 +0,0 @@
|
||||
// QtPromise
|
||||
#include <QtPromise>
|
||||
|
||||
// Qt
|
||||
#include <QtTest>
|
||||
|
||||
using namespace QtPromise;
|
||||
|
||||
class tst_helpers : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private Q_SLOTS:
|
||||
void resolve();
|
||||
void resolve_void();
|
||||
void resolve_promise();
|
||||
void resolve_promise_void();
|
||||
|
||||
void allFulfilled();
|
||||
void allFulfilled_void();
|
||||
void allRejected();
|
||||
void allRejected_void();
|
||||
void allEmpty();
|
||||
void allEmpty_void();
|
||||
|
||||
}; // class tst_helpers
|
||||
|
||||
QTEST_MAIN(tst_helpers)
|
||||
#include "tst_helpers.moc"
|
||||
|
||||
void tst_helpers::resolve()
|
||||
{
|
||||
int value = -1;
|
||||
auto p = QtPromise::qPromise(42);
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<int>>::value));
|
||||
|
||||
QCOMPARE(p.isFulfilled(), true);
|
||||
|
||||
p.then([&](int res) {
|
||||
value = res;
|
||||
}).wait();
|
||||
|
||||
QCOMPARE(value, 42);
|
||||
}
|
||||
|
||||
void tst_helpers::resolve_void()
|
||||
{
|
||||
int value = -1;
|
||||
auto p = QtPromise::qPromise();
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value));
|
||||
|
||||
QCOMPARE(p.isFulfilled(), true);
|
||||
|
||||
p.then([&]() {
|
||||
value = 42;
|
||||
}).wait();
|
||||
|
||||
QCOMPARE(value, 42);
|
||||
}
|
||||
|
||||
void tst_helpers::resolve_promise()
|
||||
{
|
||||
QString value;
|
||||
auto p = QtPromise::qPromise(
|
||||
QPromise<QString>([](const QPromiseResolve<QString>& resolve) {
|
||||
QtPromisePrivate::qtpromise_defer([=](){
|
||||
resolve("foo");
|
||||
});
|
||||
}));
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QString>>::value));
|
||||
|
||||
QCOMPARE(p.isPending(), true);
|
||||
|
||||
p.then([&](const QString& res) {
|
||||
value = res;
|
||||
}).wait();
|
||||
|
||||
QCOMPARE(p.isFulfilled(), true);
|
||||
QCOMPARE(value, QString("foo"));
|
||||
}
|
||||
|
||||
void tst_helpers::resolve_promise_void()
|
||||
{
|
||||
QList<int> values;
|
||||
auto p = QtPromise::qPromise(
|
||||
QPromise<void>([&](const QPromiseResolve<void>& resolve) {
|
||||
QtPromisePrivate::qtpromise_defer([=, &values](){
|
||||
values << 42;
|
||||
resolve();
|
||||
});
|
||||
}));
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value));
|
||||
|
||||
QCOMPARE(p.isPending(), true);
|
||||
|
||||
p.then([&]() {
|
||||
values << 43;
|
||||
}).wait();
|
||||
|
||||
QCOMPARE(p.isFulfilled(), true);
|
||||
QCOMPARE(values, QList<int>({42, 43}));
|
||||
}
|
||||
|
||||
void tst_helpers::allFulfilled()
|
||||
{
|
||||
auto p0 = QtPromise::qPromise(42);
|
||||
auto p1 = QtPromise::qPromise(44);
|
||||
auto p2 = QPromise<int>([](const QPromiseResolve<int>& resolve) {
|
||||
QtPromisePrivate::qtpromise_defer([=](){
|
||||
resolve(43);
|
||||
});
|
||||
});
|
||||
|
||||
auto p = qPromiseAll(QVector<QPromise<int>>{p0, p2, p1});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
|
||||
QCOMPARE(p.isPending(), true);
|
||||
QCOMPARE(p0.isFulfilled(), true);
|
||||
QCOMPARE(p1.isFulfilled(), true);
|
||||
QCOMPARE(p2.isPending(), true);
|
||||
|
||||
QVector<int> values;
|
||||
p.then([&](const QVector<int>& res) {
|
||||
values = res;
|
||||
}).wait();
|
||||
|
||||
QCOMPARE(p.isFulfilled(), true);
|
||||
QCOMPARE(p2.isFulfilled(), true);
|
||||
QCOMPARE(values, QVector<int>({42, 43, 44}));
|
||||
}
|
||||
|
||||
void tst_helpers::allFulfilled_void()
|
||||
{
|
||||
auto p0 = QtPromise::qPromise();
|
||||
auto p1 = QtPromise::qPromise();
|
||||
auto p2 = QPromise<void>([](const QPromiseResolve<void>& resolve) {
|
||||
QtPromisePrivate::qtpromise_defer([=](){
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
auto p = qPromiseAll(QVector<QPromise<void>>{p0, p2, p1});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value));
|
||||
|
||||
QCOMPARE(p.isPending(), true);
|
||||
QCOMPARE(p0.isFulfilled(), true);
|
||||
QCOMPARE(p1.isFulfilled(), true);
|
||||
QCOMPARE(p2.isPending(), true);
|
||||
|
||||
p.wait();
|
||||
|
||||
QCOMPARE(p.isFulfilled(), true);
|
||||
QCOMPARE(p2.isFulfilled(), true);
|
||||
}
|
||||
|
||||
void tst_helpers::allRejected()
|
||||
{
|
||||
auto p0 = QtPromise::qPromise(42);
|
||||
auto p1 = QtPromise::qPromise(44);
|
||||
auto p2 = QPromise<int>([](const QPromiseResolve<int>&, const QPromiseReject<int>& reject) {
|
||||
QtPromisePrivate::qtpromise_defer([=](){
|
||||
reject(QString("foo"));
|
||||
});
|
||||
});
|
||||
|
||||
auto p = qPromiseAll(QVector<QPromise<int>>{p0, p2, p1});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
|
||||
QCOMPARE(p.isPending(), true);
|
||||
QCOMPARE(p0.isFulfilled(), true);
|
||||
QCOMPARE(p1.isFulfilled(), true);
|
||||
QCOMPARE(p2.isPending(), true);
|
||||
|
||||
QString error;
|
||||
p.fail([&](const QString& err) {
|
||||
error = err;
|
||||
return QVector<int>();
|
||||
}).wait();
|
||||
|
||||
QCOMPARE(p.isRejected(), true);
|
||||
QCOMPARE(p2.isRejected(), true);
|
||||
QCOMPARE(error, QString("foo"));
|
||||
}
|
||||
|
||||
void tst_helpers::allRejected_void()
|
||||
{
|
||||
auto p0 = QtPromise::qPromise();
|
||||
auto p1 = QtPromise::qPromise();
|
||||
auto p2 = QPromise<void>([](const QPromiseResolve<void>&, const QPromiseReject<void>& reject) {
|
||||
QtPromisePrivate::qtpromise_defer([=](){
|
||||
reject(QString("foo"));
|
||||
});
|
||||
});
|
||||
|
||||
auto p = qPromiseAll(QVector<QPromise<void>>{p0, p2, p1});
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value));
|
||||
|
||||
QCOMPARE(p.isPending(), true);
|
||||
QCOMPARE(p0.isFulfilled(), true);
|
||||
QCOMPARE(p1.isFulfilled(), true);
|
||||
QCOMPARE(p2.isPending(), true);
|
||||
|
||||
QString error;
|
||||
p.fail([&](const QString& err) {
|
||||
error = err;
|
||||
}).wait();
|
||||
|
||||
QCOMPARE(p.isRejected(), true);
|
||||
QCOMPARE(p2.isRejected(), true);
|
||||
QCOMPARE(error, QString("foo"));
|
||||
}
|
||||
|
||||
void tst_helpers::allEmpty()
|
||||
{
|
||||
auto p = qPromiseAll(QVector<QPromise<int>>());
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
|
||||
QCOMPARE(p.isFulfilled(), true);
|
||||
|
||||
QVector<int> values;
|
||||
p.then([&](const QVector<int>& res) {
|
||||
values = res;
|
||||
}).wait();
|
||||
|
||||
QCOMPARE(values, QVector<int>());
|
||||
}
|
||||
|
||||
void tst_helpers::allEmpty_void()
|
||||
{
|
||||
auto p = qPromiseAll(QVector<QPromise<void>>());
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value));
|
||||
|
||||
QCOMPARE(p.isFulfilled(), true);
|
||||
}
|
@ -1,103 +0,0 @@
|
||||
// Tests
|
||||
#include "../../shared/utils.h"
|
||||
|
||||
// QtPromise
|
||||
#include <QtPromise>
|
||||
|
||||
// Qt
|
||||
#include <QtTest>
|
||||
|
||||
using namespace QtPromise;
|
||||
|
||||
class tst_qpromise_all : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private Q_SLOTS:
|
||||
void qList();
|
||||
//void qVector();
|
||||
void stdList();
|
||||
void stdVector();
|
||||
};
|
||||
|
||||
QTEST_MAIN(tst_qpromise_all)
|
||||
#include "tst_all.moc"
|
||||
|
||||
namespace {
|
||||
|
||||
template <class Sequence>
|
||||
struct SequenceTester
|
||||
{
|
||||
};
|
||||
|
||||
template <template <typename, typename...> class Sequence, typename ...Args>
|
||||
struct SequenceTester<Sequence<QPromise<int>, Args...>>
|
||||
{
|
||||
static void exec()
|
||||
{
|
||||
Sequence<QPromise<int>, Args...> promises{
|
||||
QPromise<int>::resolve(42),
|
||||
QPromise<int>::resolve(43),
|
||||
QPromise<int>::resolve(44)
|
||||
};
|
||||
|
||||
promises.push_back(QPromise<int>::resolve(45));
|
||||
promises.insert(++promises.begin(), QPromise<int>::resolve(46));
|
||||
promises.pop_back();
|
||||
|
||||
auto p = QPromise<int>::all(promises);
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({42, 46, 43, 44}));
|
||||
}
|
||||
};
|
||||
|
||||
template <template <typename, typename...> class Sequence, typename ...Args>
|
||||
struct SequenceTester<Sequence<QPromise<void>, Args...>>
|
||||
{
|
||||
static void exec()
|
||||
{
|
||||
Sequence<QPromise<void>, Args...> promises{
|
||||
QPromise<void>::resolve(),
|
||||
QPromise<void>::resolve(),
|
||||
QPromise<void>::resolve()
|
||||
};
|
||||
|
||||
promises.push_back(QPromise<void>::resolve());
|
||||
promises.insert(++promises.begin(), QPromise<void>::resolve());
|
||||
promises.pop_back();
|
||||
|
||||
auto p = QPromise<void>::all(promises);
|
||||
|
||||
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value));
|
||||
QCOMPARE(waitForValue(p, -1, 42), 42);
|
||||
}
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
void tst_qpromise_all::qList()
|
||||
{
|
||||
SequenceTester<QList<QPromise<int>>>::exec();
|
||||
SequenceTester<QList<QPromise<void>>>::exec();
|
||||
}
|
||||
|
||||
// QVector::push_back/append isn't supported since it requires a default
|
||||
// constructor (see https://github.com/simonbrunel/qtpromise/issues/3)
|
||||
//void tst_qpromise_all::qVector()
|
||||
//{
|
||||
// SequenceTester<QVector<QPromise<int>>>::exec();
|
||||
// SequenceTester<QVector<QPromise<void>>>::exec();
|
||||
//}
|
||||
|
||||
void tst_qpromise_all::stdList()
|
||||
{
|
||||
SequenceTester<std::list<QPromise<int>>>::exec();
|
||||
SequenceTester<std::list<QPromise<void>>>::exec();
|
||||
}
|
||||
|
||||
void tst_qpromise_all::stdVector()
|
||||
{
|
||||
SequenceTester<std::vector<QPromise<int>>>::exec();
|
||||
SequenceTester<std::vector<QPromise<void>>>::exec();
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user