mirror of
https://github.com/simonbrunel/qtpromise.git
synced 2025-07-03 15:55:25 +08:00
Add support for creating promises from Qt signals (#25)
Introduce a new `QtPromise::connect()` helper that allows to create a promise resolved from a single signal and optionally, rejected by another one (from a different object or not). The promise type is determined by the type of the first signal argument (other arguments are currently ignored). A `QPromise<void>` is returned if the resolve signal doesn't provide any argument. If the rejection is emitted before the promise is resolved, the promise will be rejected with the value of the first argument (other arguments being ignored). If the rejection signal doesn't provide any argument, the promise will be rejected with `QPromiseUndefinedException` if the signal is emitted. Additionally, the promise will be automatically rejected with `QPromiseContextException` if the source object is destroyed before the promise is resolved.
This commit is contained in:
@ -17,6 +17,7 @@ module.exports = {
|
||||
sidebar: [
|
||||
'qtpromise/getting-started',
|
||||
'qtpromise/qtconcurrent',
|
||||
'qtpromise/qtsignals',
|
||||
'qtpromise/thread-safety',
|
||||
'qtpromise/api-reference',
|
||||
{
|
||||
@ -46,6 +47,7 @@ module.exports = {
|
||||
title: 'Helpers',
|
||||
children: [
|
||||
'qtpromise/helpers/attempt',
|
||||
'qtpromise/helpers/connect',
|
||||
'qtpromise/helpers/each',
|
||||
'qtpromise/helpers/filter',
|
||||
'qtpromise/helpers/map',
|
||||
@ -57,6 +59,7 @@ module.exports = {
|
||||
title: 'Exceptions',
|
||||
children: [
|
||||
'qtpromise/exceptions/canceled',
|
||||
'qtpromise/exceptions/context',
|
||||
'qtpromise/exceptions/timeout',
|
||||
'qtpromise/exceptions/undefined'
|
||||
]
|
||||
|
@ -27,6 +27,7 @@
|
||||
## Helpers
|
||||
|
||||
* [`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)
|
||||
|
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.
|
||||
})
|
||||
```
|
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.
|
@ -1,4 +1,4 @@
|
||||
# QtConcurrent
|
||||
# Qt Concurrent
|
||||
|
||||
QtPromise integrates with [QtConcurrent](https://doc.qt.io/qt-5/qtconcurrent-index.html) to make easy chaining QFuture with QPromise.
|
||||
|
||||
|
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.
|
Reference in New Issue
Block a user