libQuotient
A Qt library for building matrix clients
Quotient::JobHandle< JobT > Class Template Reference

A job pointer and a QFuture in a single package. More...

#include <jobhandle.h>

Inheritance diagram for Quotient::JobHandle< JobT >:
Collaboration diagram for Quotient::JobHandle< JobT >:

Public Types

using pointer_type = QPointer< JobT >
 
using future_value_type = JobT *
 
using future_type = QFuture< future_value_type >
 

Public Member Functions

Q_IMPLICIT JobHandle (JobT *job=nullptr)
 
template<typename ConfigT , ResultHandler< JobT > FnT>
auto onResult (ConfigT config, FnT &&fn)
 Attach a continuation to a successful or unsuccessful completion of the future. More...
 
template<BoundResultHandler< JobT > FnT>
auto onResult (FnT &&fn)
 The overload for onResult matching 1-arg QFuture::then. More...
 
template<typename ConfigT , ResultHandler< JobT > SuccessFnT, ResultHandler< JobT > FailureFnT = Skip>
auto then (ConfigT config, SuccessFnT &&onSuccess, FailureFnT &&onFailure={}) requires requires(future_type f)
 Attach continuations depending on the job success or failure. More...
 
template<BoundResultHandler< JobT > SuccessFnT, BoundResultHandler< JobT > FailureFnT = Skip>
auto then (SuccessFnT &&onSuccess, FailureFnT &&onFailure={})
 The overload making the combined continuation as if with 1-arg QFuture::then. More...
 
template<typename FnT >
auto onFailure (auto config, FnT &&fn)
 Same as then(config, [] {}, fn) More...
 
template<typename FnT >
auto onFailure (FnT &&fn)
 Same as then([] {}, fn) More...
 
template<typename FnT >
auto onCanceled (QObject *context, FnT &&fn)
 
template<typename FnT >
auto onCanceled (FnT &&fn)
 
auto responseFuture ()
 Get a QFuture for the value returned by collectResponse() called on the underlying job. More...
 
void abandon ()
 Abandon the underlying job, if there's one pending. More...
 

Detailed Description

template<class JobT>
class Quotient::JobHandle< JobT >

A job pointer and a QFuture in a single package.

This class wraps a pointer to any job the same way QPointer does: it turns to nullptr when the job is destroyed. On top of that though, it provides you with an interface of QFuture as-if obtained by calling QtFuture::connect(job, &BaseJob::result).then([job] { return job; }); before any other slot is connected to it. In the end, you (still) get the interface of JobT at handle->, and handle. gives you the interface (very close to that, read below for differences) of QFuture<JobT*>.

You can mix usage of the two interfaces, bearing in mind that any continuation attached via the future interface will overtake anything connected to BaseJob::result but come behind anything connected to BaseJob::finished (that applies to onCanceled(), too).

QFuture is somewhat rigid in terms of what it accepts for (normal, i.e. not cancelled) continuations: the continuation function must accept a single argument of the type carried by the future, or of the future type itself. JobHandle allows normal continuation functions (i.e. those passed to then(), onResult() and onFailure()) to accept:

  • no parameters;
  • JobT* or any pointer it is convertible to (const JobT*, BaseJob* etc.);
  • the value returned by calling collectResponse() with the above pointer as the parameter.

Aside from free functions and function objects (including lambdas), you can also pass member functions of QObject-derived classes (connect() slot style) to all continuations, including onCanceled().

JobHandle doesn't support passing its full type to continuation functions like QFuture does, as there's no case for that (we don't need to deal with exceptions).

This extended interface helps with migration of the current code that connect()s to the job completion signals. The existing code will (mostly) run fine without changes; the only thing that will stop working is using auto* for a variable initialised from Connection::callApi (plain auto still works). If you want to migrate the existing code to the future-like interface, just replace:

auto j = callApi<Job>(jobParams...);
connect(j, &BaseJob::result, object, slot);
void result(Quotient::BaseJob *job)
The job has finished with a result, successful or unsuccessful.

with callApi<Job>(jobParams...).onResult(object, slot); - that's all. If you have a connection to BaseJob::success, use then() instead of onResult(), and if you only connect to BaseJob::failure, onFailure() is at your service. And you can also combine the two using then(), e.g.:

callApi<Job>(jobParams...).then([this] { /* on success... */ },
[this] { /* on failure... */ });

One more extension to QFuture is the way the returned value is treated:

  • if your function returns void the continuation will have type JobHandler<JobT> and carry the same pointer as before;
  • if your function returns a JobHandle (e.g. from another call to Connection::callApi), it will be automatically rewrapped into a QFuture, because QFuture<JobHandle<AnotherJobT>> is rather unwieldy for any intents and purposes, and JobHandle<AnotherJobT> would have a very weird QPointer interface as that new job doesn't even exist when continuation is constructed;
  • otherwise, the return value is wrapped in a "normal" QFuture, JobHandle waves you good-bye and further continuations will follow pristine QFuture rules.

Definition at line 73 of file jobhandle.h.

Member Typedef Documentation

◆ future_type

template<class JobT >
using Quotient::JobHandle< JobT >::future_type = QFuture<future_value_type>

Definition at line 77 of file jobhandle.h.

◆ future_value_type

template<class JobT >
using Quotient::JobHandle< JobT >::future_value_type = JobT*

Definition at line 76 of file jobhandle.h.

◆ pointer_type

template<class JobT >
using Quotient::JobHandle< JobT >::pointer_type = QPointer<JobT>

Definition at line 75 of file jobhandle.h.

Constructor & Destructor Documentation

◆ JobHandle()

template<class JobT >
Q_IMPLICIT Quotient::JobHandle< JobT >::JobHandle ( JobT *  job = nullptr)
inline

Definition at line 93 of file jobhandle.h.

Member Function Documentation

◆ abandon()

template<class JobT >
void Quotient::JobHandle< JobT >::abandon ( )
inline

Abandon the underlying job, if there's one pending.

Unlike cancel() that only applies to the current future object but not the upstream chain, this actually goes up to the job and calls abandon() on it, thereby cancelling the entire chain of futures attached to it.

See also
BaseJob::abandon

Definition at line 201 of file jobhandle.h.

◆ onCanceled() [1/2]

template<class JobT >
template<typename FnT >
auto Quotient::JobHandle< JobT >::onCanceled ( FnT &&  fn)
inline

Same as QFuture::onCanceled but accepts QObject-derived member functions and rewraps returned values

Definition at line 184 of file jobhandle.h.

◆ onCanceled() [2/2]

template<class JobT >
template<typename FnT >
auto Quotient::JobHandle< JobT >::onCanceled ( QObject *  context,
FnT &&  fn 
)
inline

Same as QFuture::onCanceled but accepts QObject-derived member functions and rewraps returned values

Definition at line 175 of file jobhandle.h.

◆ onFailure() [1/2]

template<class JobT >
template<typename FnT >
auto Quotient::JobHandle< JobT >::onFailure ( auto  config,
FnT &&  fn 
)
inline

Same as then(config, [] {}, fn)

Definition at line 160 of file jobhandle.h.

◆ onFailure() [2/2]

template<class JobT >
template<typename FnT >
auto Quotient::JobHandle< JobT >::onFailure ( FnT &&  fn)
inline

Same as then([] {}, fn)

Definition at line 167 of file jobhandle.h.

◆ onResult() [1/2]

template<class JobT >
template<typename ConfigT , ResultHandler< JobT > FnT>
auto Quotient::JobHandle< JobT >::onResult ( ConfigT  config,
FnT &&  fn 
)
inline

Attach a continuation to a successful or unsuccessful completion of the future.

The continuation passed via fn should be an invokable that accepts one of the following: 1) no arguments - this is meant to simplify transition from job completion handlers connect()ed to BaseJob::result, BaseJob::success or BaseJob::failure. 2) a pointer to a (const, if you want) job object - this can be either BaseJob*, JobT* (recommended), or anything in between. Unlike slot functions connected to BaseJob signals, this option allows you to access the specific job type so you don't need to carry the original job pointer in a lambda - JobHandle does it for you. This is meant to be a transitional form on the way to (3); eventually we should migrate to (1)+(3) entirely. 3) the type returned by collectResponse() if it's well-formed (it is for all generated jobs, needs overloading for manual jobs).

Note
The continuation returned from onResult() will not be triggered if/when the future is cancelled or the underlying job is abandoned; use onCanceled() to catch cancellations. You can also connect to BaseJob::finished using the QPointer interface of the handle if you need to do something before any continuation attached to his job kicks in.
Parameters
configpassed directly to QFuture::then() as the first argument (see the documentation on QFuture::then() for accepted types) and can also be used as the object for a slot-like member function in QObject::connect() fashion
fnthe continuation function to attach to the future; can be a member function if config is a pointer to an QObject-derived class
Returns
if fn returns void, a new JobHandle for the same job, with the continuation attached; otherwise, the return value of fn wrapped in a plain QFuture

Definition at line 122 of file jobhandle.h.

◆ onResult() [2/2]

template<class JobT >
template<BoundResultHandler< JobT > FnT>
auto Quotient::JobHandle< JobT >::onResult ( FnT &&  fn)
inline

The overload for onResult matching 1-arg QFuture::then.

Definition at line 129 of file jobhandle.h.

◆ responseFuture()

template<class JobT >
auto Quotient::JobHandle< JobT >::responseFuture ( )
inline

Get a QFuture for the value returned by collectResponse() called on the underlying job.

Definition at line 190 of file jobhandle.h.

◆ then() [1/2]

template<class JobT >
template<typename ConfigT , ResultHandler< JobT > SuccessFnT, ResultHandler< JobT > FailureFnT = Skip>
auto Quotient::JobHandle< JobT >::then ( ConfigT  config,
SuccessFnT &&  onSuccess,
FailureFnT &&  onFailure = {} 
)
inline

Attach continuations depending on the job success or failure.

This is inspired by then() in JavaScript; beyond the first argument passed through to QFuture::then, it accepts two more arguments (onFailure is optional), combining them in a single continuation: if the job ends with success, onSuccess is called; if the job fails, onFailure is called. The requirements to both functions are the same as to the single function passed to onResult().

Definition at line 142 of file jobhandle.h.

◆ then() [2/2]

template<class JobT >
template<BoundResultHandler< JobT > SuccessFnT, BoundResultHandler< JobT > FailureFnT = Skip>
auto Quotient::JobHandle< JobT >::then ( SuccessFnT &&  onSuccess,
FailureFnT &&  onFailure = {} 
)
inline

The overload making the combined continuation as if with 1-arg QFuture::then.

Definition at line 152 of file jobhandle.h.


The documentation for this class was generated from the following file: