QCoro 0.5.0 Release Announcement
Major features:
- .then() continuation for
Task<T>
- All asynchronous operations now return
Task<T>
- Timeouts for many operations
- Support for
QThread
.then() continuation for Task
Sometimes it's not possible to co_await
a coroutine - usually because you need to integrate with a 3rd party code
that is not coroutine-ready. A good example might be implementing QAbstractItemModel
, where none of the virtual
methods are coroutines and thus it's not possible to use co_await
in them.
To still make it possible to all coroutines from such code, QCoro::Task<T>
now has a new method: .then()
,
which allows attaching a continuation callback that will be invoked by QCoro when the coroutine represented
by the Task
finishes.
void notACoroutine() {
someCoroutineReturningQString().then([](const QString &result) {
// Will be invoked when the someCoroutine() finishes.
// The result of the coroutine is passed as an argument to the continuation.
});
}
The continuation itself might be a coroutine, and the result of the .then()
member function is again a Task<R>
(where R
is the return type of the continuation callback), so it is possible to chain multiple continuations
as well as co_await
ing the entire chain.
All asynchronous operations now return Task<T>
Up until now each operation from the QCoro wrapper types returned a special awaitable - for example,
QCoroIODevice::read()
returned QCoro::detail::QCoroIODevice::ReadOperation
. In most cases users of QCoro do
not need to concern themselves with that type, since they can still directly co_await
the returned awaitable.
However, it unnecessarily leaks implementation details of QCoro into public API and it makes it harded to return a coroutine from a non-coroutine function.
As of QCoro 0.5.0, all the operations now return Task<T>
, which makes the API consistent. As a secondary effect,
all the operations can have a chained continuation using the .then()
continuation, as described above.
Timeout support for many operations
Qt doesn't allow specifying timeout for many operations, because they are typically non-blocking. But the timeout
makes sense in most QCoro cases, because they are combination of wait + the non-blocking operation. Let's take
QIODevice::read()
for example: the Qt version doesn't have any timeout, because the call will never block - if
there's nothing to read, it simply returns an empty QByteArray
.
On the other hand, QCoroIODevice::read()
is an asynchronous operation, because under to hood, it's a coroutine
that asynchronously calls a sequence of
device->waitForReadyRead();
device->read();
Since QIODevice::waitForReadyRead()
takes a timeout argument, it makes sense for QCoroIODevice::read()
to also take (an optional) timeout argument. This and many other operations have gained support for timeout.
Support for QThread
It's been a while since I added a new wrapper for a Qt class, so QCoro 0.5.0 adds wrapper for QThread
. It's
now possible to co_await
thread start and end:
std::unique_ptr<QThread> thread(QThread::create([]() {
...
});
ui->setLabel(tr("Starting thread...");
thread->start();
co_await qCoro(thread)->waitForStarted();
ui->setLabel(tr("Calculating..."));
co_await qCoro(thread)->waitForFinished();
ui->setLabel(tr("Finished!"));
Full changelog
Thanks to everyone who contributed to QCoro!