diff options
-rw-r--r-- | async/autotests/asynctest.cpp | 21 | ||||
-rw-r--r-- | async/src/async.h | 26 | ||||
-rw-r--r-- | async/src/future.h | 18 |
3 files changed, 59 insertions, 6 deletions
diff --git a/async/autotests/asynctest.cpp b/async/autotests/asynctest.cpp index 1ee3843..6c4bbeb 100644 --- a/async/autotests/asynctest.cpp +++ b/async/autotests/asynctest.cpp | |||
@@ -44,6 +44,7 @@ private Q_SLOTS: | |||
44 | void testNestedAsync(); | 44 | void testNestedAsync(); |
45 | void testSyncEach(); | 45 | void testSyncEach(); |
46 | void testSyncReduce(); | 46 | void testSyncReduce(); |
47 | void testErrorHandler(); | ||
47 | }; | 48 | }; |
48 | 49 | ||
49 | void AsyncTest::testSyncPromises() | 50 | void AsyncTest::testSyncPromises() |
@@ -195,6 +196,26 @@ void AsyncTest::testSyncReduce() | |||
195 | QCOMPARE(future.value(), 10); | 196 | QCOMPARE(future.value(), 10); |
196 | } | 197 | } |
197 | 198 | ||
199 | void AsyncTest::testErrorHandler() | ||
200 | { | ||
201 | int error = 0; | ||
202 | auto job = Async::start<int>( | ||
203 | [](Async::Future<int> &f) { | ||
204 | f.setError(1, "error"); | ||
205 | }) | ||
206 | .then<int, int>( | ||
207 | [](int v, Async::Future<int> &f) { | ||
208 | f.setFinished(); | ||
209 | }, | ||
210 | [&error](int errorCode, const QString &errorMessage) { | ||
211 | error = errorCode; | ||
212 | } | ||
213 | ); | ||
214 | auto future = job.exec(); | ||
215 | future.waitForFinished(); | ||
216 | QVERIFY(error == 1); | ||
217 | QVERIFY(future.isFinished()); | ||
218 | } | ||
198 | 219 | ||
199 | 220 | ||
200 | QTEST_MAIN(AsyncTest); | 221 | QTEST_MAIN(AsyncTest); |
diff --git a/async/src/async.h b/async/src/async.h index 8fee0bc..e4b06a9 100644 --- a/async/src/async.h +++ b/async/src/async.h | |||
@@ -47,6 +47,7 @@ template<typename Out, typename In> | |||
47 | using EachTask = typename detail::identity<std::function<void(In, Async::Future<Out>&)>>::type; | 47 | using EachTask = typename detail::identity<std::function<void(In, Async::Future<Out>&)>>::type; |
48 | template<typename Out, typename In> | 48 | template<typename Out, typename In> |
49 | using ReduceTask = typename detail::identity<std::function<void(In, Async::Future<Out>&)>>::type; | 49 | using ReduceTask = typename detail::identity<std::function<void(In, Async::Future<Out>&)>>::type; |
50 | using ErrorHandler = std::function<void(int, const QString &)>; | ||
50 | 51 | ||
51 | namespace Private | 52 | namespace Private |
52 | { | 53 | { |
@@ -93,6 +94,7 @@ protected: | |||
93 | void exec(); | 94 | void exec(); |
94 | 95 | ||
95 | std::function<void(const In& ..., Async::Future<Out> &)> mFunc; | 96 | std::function<void(const In& ..., Async::Future<Out> &)> mFunc; |
97 | std::function<void(int, const QString &)> mErrorFunc; | ||
96 | Async::Future<PrevOut> *mPrevFuture; | 98 | Async::Future<PrevOut> *mPrevFuture; |
97 | Async::FutureWatcher<PrevOut> *mPrevFutureWatcher; | 99 | Async::FutureWatcher<PrevOut> *mPrevFutureWatcher; |
98 | }; | 100 | }; |
@@ -101,7 +103,7 @@ template<typename Out, typename ... In> | |||
101 | class ThenExecutor: public Executor<typename PreviousOut<In ...>::type, Out, In ...> | 103 | class ThenExecutor: public Executor<typename PreviousOut<In ...>::type, Out, In ...> |
102 | { | 104 | { |
103 | public: | 105 | public: |
104 | ThenExecutor(ThenTask<Out, In ...> then, ExecutorBase *parent = nullptr); | 106 | ThenExecutor(ThenTask<Out, In ...> then, ErrorHandler errorHandler = ErrorHandler(), ExecutorBase *parent = nullptr); |
105 | void previousFutureReady(); | 107 | void previousFutureReady(); |
106 | 108 | ||
107 | private: | 109 | private: |
@@ -221,9 +223,9 @@ class Job : public JobBase | |||
221 | 223 | ||
222 | public: | 224 | public: |
223 | template<typename OutOther, typename ... InOther> | 225 | template<typename OutOther, typename ... InOther> |
224 | Job<OutOther, InOther ...> then(ThenTask<OutOther, InOther ...> func) | 226 | Job<OutOther, InOther ...> then(ThenTask<OutOther, InOther ...> func, ErrorHandler errorFunc = ErrorHandler()) |
225 | { | 227 | { |
226 | return Job<OutOther, InOther ...>(new Private::ThenExecutor<OutOther, InOther ...>(func, mExecutor)); | 228 | return Job<OutOther, InOther ...>(new Private::ThenExecutor<OutOther, InOther ...>(func, errorFunc, mExecutor)); |
227 | } | 229 | } |
228 | 230 | ||
229 | template<typename OutOther, typename InOther> | 231 | template<typename OutOther, typename InOther> |
@@ -309,10 +311,11 @@ void Executor<PrevOut, Out, In ...>::exec() | |||
309 | } | 311 | } |
310 | 312 | ||
311 | template<typename Out, typename ... In> | 313 | template<typename Out, typename ... In> |
312 | ThenExecutor<Out, In ...>::ThenExecutor(ThenTask<Out, In ...> then, ExecutorBase* parent) | 314 | ThenExecutor<Out, In ...>::ThenExecutor(ThenTask<Out, In ...> then, ErrorHandler error, ExecutorBase* parent) |
313 | : Executor<typename PreviousOut<In ...>::type, Out, In ...>(parent) | 315 | : Executor<typename PreviousOut<In ...>::type, Out, In ...>(parent) |
314 | { | 316 | { |
315 | this->mFunc = then; | 317 | this->mFunc = then; |
318 | this->mErrorFunc = error; | ||
316 | } | 319 | } |
317 | 320 | ||
318 | template<typename Out, typename ... In> | 321 | template<typename Out, typename ... In> |
@@ -321,8 +324,19 @@ void ThenExecutor<Out, In ...>::previousFutureReady() | |||
321 | if (this->mPrevFuture) { | 324 | if (this->mPrevFuture) { |
322 | assert(this->mPrevFuture->isFinished()); | 325 | assert(this->mPrevFuture->isFinished()); |
323 | } | 326 | } |
324 | this->mFunc(this->mPrevFuture ? this->mPrevFuture->value() : In() ..., | 327 | if (this->mPrevFuture && this->mPrevFuture->errorCode()) { |
325 | *static_cast<Async::Future<Out>*>(this->mResult)); | 328 | if (this->mErrorFunc) { |
329 | this->mErrorFunc(this->mPrevFuture->errorCode(), this->mPrevFuture->errorMessage()); | ||
330 | } else { | ||
331 | static_cast<Async::Future<Out>*>(this->mResult)->setError(this->mPrevFuture->errorCode(), this->mPrevFuture->errorMessage()); | ||
332 | //propagate error if no error handler is available | ||
333 | this->mFunc(this->mPrevFuture ? this->mPrevFuture->value() : In() ..., | ||
334 | *static_cast<Async::Future<Out>*>(this->mResult)); | ||
335 | } | ||
336 | } else { | ||
337 | this->mFunc(this->mPrevFuture ? this->mPrevFuture->value() : In() ..., | ||
338 | *static_cast<Async::Future<Out>*>(this->mResult)); | ||
339 | } | ||
326 | } | 340 | } |
327 | 341 | ||
328 | template<typename PrevOut, typename Out, typename In> | 342 | template<typename PrevOut, typename Out, typename In> |
diff --git a/async/src/future.h b/async/src/future.h index 54580ad..098f6e8 100644 --- a/async/src/future.h +++ b/async/src/future.h | |||
@@ -36,6 +36,7 @@ public: | |||
36 | 36 | ||
37 | virtual void setFinished() = 0; | 37 | virtual void setFinished() = 0; |
38 | virtual bool isFinished() const = 0; | 38 | virtual bool isFinished() const = 0; |
39 | virtual void setError(int code = 1, const QString &message = QString()) = 0; | ||
39 | 40 | ||
40 | protected: | 41 | protected: |
41 | FutureBase(); | 42 | FutureBase(); |
@@ -69,6 +70,23 @@ public: | |||
69 | return d->finished; | 70 | return d->finished; |
70 | } | 71 | } |
71 | 72 | ||
73 | void setError(int errorCode, const QString &message) | ||
74 | { | ||
75 | d->errorCode = errorCode; | ||
76 | d->errorMessage = message; | ||
77 | setFinished(); | ||
78 | } | ||
79 | |||
80 | int errorCode() const | ||
81 | { | ||
82 | return d->errorCode; | ||
83 | } | ||
84 | |||
85 | QString errorMessage() const | ||
86 | { | ||
87 | return d->errorMessage; | ||
88 | } | ||
89 | |||
72 | void waitForFinished() | 90 | void waitForFinished() |
73 | { | 91 | { |
74 | if (isFinished()) { | 92 | if (isFinished()) { |