summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Vrátil <dvratil@redhat.com>2015-05-18 15:20:35 +0200
committerDan Vrátil <dvratil@redhat.com>2015-05-18 15:20:35 +0200
commit5e580299e342bd77fc7479bbfd235f4446d7f05b (patch)
tree648aacd4de1f239d72be89ab9f2d4a97867d7920
parentb43c0cf97615957e097daef29ff8febc1ec884c8 (diff)
downloadsink-5e580299e342bd77fc7479bbfd235f4446d7f05b.tar.gz
sink-5e580299e342bd77fc7479bbfd235f4446d7f05b.zip
KAsync has moved to it's own kasync.git repository
-rw-r--r--CMakeLists.txt7
-rw-r--r--async/CMakeLists.txt73
-rw-r--r--async/KF5AsyncConfig.cmake.in3
-rw-r--r--async/autotests/CMakeLists.txt13
-rw-r--r--async/autotests/asynctest.cpp859
-rw-r--r--async/autotests/kjobtest.cpp69
-rw-r--r--async/autotests/testkjob.cpp28
-rw-r--r--async/autotests/testkjob.h48
-rw-r--r--async/src/CMakeLists.txt63
-rw-r--r--async/src/async.cpp148
-rw-r--r--async/src/async.h874
-rw-r--r--async/src/async_impl.h81
-rw-r--r--async/src/debug.cpp75
-rw-r--r--async/src/debug.h82
-rw-r--r--async/src/future.cpp158
-rw-r--r--async/src/future.h257
-rw-r--r--common/CMakeLists.txt2
-rw-r--r--common/clientapi.h4
-rw-r--r--common/facade.h3
-rw-r--r--common/pipeline.cpp1
-rw-r--r--common/pipeline.h3
-rw-r--r--common/resource.h3
-rw-r--r--common/resourceaccess.h3
-rw-r--r--examples/dummyresource/resourcefacade.h3
-rw-r--r--examples/dummyresource/resourcefactory.h3
-rw-r--r--synchronizer/CMakeLists.txt2
26 files changed, 19 insertions, 2846 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index dcc5224..45a6ef5 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,4 +1,4 @@
1cmake_minimum_required(VERSION 2.8) 1cmake_minimum_required(VERSION 2.8.12)
2 2
3 3
4# ECM setup 4# ECM setup
@@ -19,7 +19,7 @@ include(KDEInstallDirs)
19# include(KDECMakeSettings) 19# include(KDECMakeSettings)
20 20
21find_package(Qt5 COMPONENTS REQUIRED Core Widgets Network) 21find_package(Qt5 COMPONENTS REQUIRED Core Widgets Network)
22 22find_package(KF5 COMPONENTS REQUIRED Async)
23find_package(FlatBuffers REQUIRED) 23find_package(FlatBuffers REQUIRED)
24function(generate_flatbuffers _target) 24function(generate_flatbuffers _target)
25 foreach(fbs ${ARGN}) 25 foreach(fbs ${ARGN})
@@ -59,7 +59,4 @@ add_subdirectory(examples)
59# some tests 59# some tests
60add_subdirectory(tests) 60add_subdirectory(tests)
61 61
62# async library prototype
63add_subdirectory(async)
64
65feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) 62feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES)
diff --git a/async/CMakeLists.txt b/async/CMakeLists.txt
deleted file mode 100644
index 6a93a2c..0000000
--- a/async/CMakeLists.txt
+++ /dev/null
@@ -1,73 +0,0 @@
1project(KAsync)
2
3cmake_minimum_required(VERSION 2.8.12)
4
5# ECM setup
6find_package(ECM 5.10.0 CONFIG REQUIRED)
7set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH})
8
9include(GenerateExportHeader)
10include(ECMGenerateHeaders)
11include(ECMGeneratePriFile)
12include(ECMPackageConfigHelpers)
13include(ECMSetupVersion)
14include(FeatureSummary)
15include(KDEInstallDirs)
16include(KDECMakeSettings)
17include(KDEFrameworkCompilerSettings)
18
19set(KASYNC_VERSION "4.99.0")
20
21set(KF5_VERSION "5.10.0")
22set(QT_REQUIRED_VERSION "5.2.0")
23
24ecm_setup_version(${KASYNC_VERSION}
25 VARIABLE_PREFIX KASYNC
26 VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/kasync_version.h"
27 PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KF5AsyncConfigVersion.cmake"
28 SOVERSION 5
29)
30
31
32########### Find packages ###########
33find_package(Qt5 ${QT_REQUIRED_VERSION} REQUIRED COMPONENTS Core Test)
34
35option(WITH_KJOB "Enable native support for KJob in libasync API (enabled by default)" ON)
36if (WITH_KJOB)
37 find_package(KF5CoreAddons REQUIRED ${KF5_VERSION})
38 add_definitions(-DWITH_KJOB)
39endif()
40
41########### Targets ###########
42add_subdirectory(src)
43add_subdirectory(autotests)
44
45
46########### CMake Config Files ###########
47set(CMAKECONFIG_INSTALL_DIR "${KDE_INSTALL_CMAKEPACKAGEDIR}/KF5Async")
48
49ecm_configure_package_config_file(
50 "${CMAKE_CURRENT_SOURCE_DIR}/KF5AsyncConfig.cmake.in"
51 "${CMAKE_CURRENT_BINARY_DIR}/KF5AsyncConfig.cmake"
52 INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR}
53)
54
55install(FILES
56 "${CMAKE_CURRENT_BINARY_DIR}/KF5AsyncConfig.cmake"
57 "${CMAKE_CURRENT_BINARY_DIR}/KF5AsyncConfigVersion.cmake"
58 DESTINATION "${CMAKECONFIG_INSTALL_DIR}"
59 COMPONENT Devel
60)
61
62install(EXPORT
63 KF5AsyncTargets
64 DESTINATION "${CMAKECONFIG_INSTALL_DIR}"
65 FILE KF5AsyncTargets.cmake
66 NAMESPACE KF5::)
67
68install(FILES
69 ${CMAKE_CURRENT_BINARY_DIR}/kasync_version.h
70 DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5} COMPONENT Devel
71)
72
73feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES)
diff --git a/async/KF5AsyncConfig.cmake.in b/async/KF5AsyncConfig.cmake.in
deleted file mode 100644
index d11b836..0000000
--- a/async/KF5AsyncConfig.cmake.in
+++ /dev/null
@@ -1,3 +0,0 @@
1@PACKAGE_INIT@
2
3include("${CMAKE_CURRENT_LIST_DIR}/KF5AsyncTargets.cmake")
diff --git a/async/autotests/CMakeLists.txt b/async/autotests/CMakeLists.txt
deleted file mode 100644
index b2209ab..0000000
--- a/async/autotests/CMakeLists.txt
+++ /dev/null
@@ -1,13 +0,0 @@
1include(ECMAddTests)
2
3ecm_add_test(asynctest.cpp
4 TEST_NAME asynctest
5 LINK_LIBRARIES KF5Async Qt5::Test
6)
7
8if (WITH_KJOB)
9 ecm_add_test(kjobtest.cpp testkjob.cpp
10 TEST_NAME kjobtest
11 LINK_LIBRARIES KF5Async Qt5::Test KF5::CoreAddons
12 )
13endif()
diff --git a/async/autotests/asynctest.cpp b/async/autotests/asynctest.cpp
deleted file mode 100644
index ffc732c..0000000
--- a/async/autotests/asynctest.cpp
+++ /dev/null
@@ -1,859 +0,0 @@
1/*
2 * Copyright 2014 Daniel Vrátil <dvratil@redhat.com>
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of
7 * the License or (at your option) version 3 or any later version
8 * accepted by the membership of KDE e.V. (or its successor approved
9 * by the membership of KDE e.V.), which shall act as a proxy
10 * defined in Section 14 of version 3 of the license.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#include "../src/async.h"
23
24#include <QObject>
25#include <QString>
26#include <QTimer>
27#include <QtTest/QTest>
28#include <QDebug>
29
30#include <functional>
31
32class AsyncTest : public QObject
33{
34 Q_OBJECT
35
36public:
37 AsyncTest()
38 {}
39
40 ~AsyncTest()
41 {}
42
43private Q_SLOTS:
44 void testSyncPromises();
45 void testAsyncPromises();
46 void testAsyncPromises2();
47 void testNestedAsync();
48 void testStartValue();
49
50 void testAsyncThen();
51 void testSyncThen();
52 void testJoinedThen();
53 void testVoidThen();
54
55 void testAsyncEach();
56 void testSyncEach();
57 void testJoinedEach();
58 void testVoidEachThen();
59 void testAsyncVoidEachThen();
60
61 void testAsyncReduce();
62 void testSyncReduce();
63 void testJoinedReduce();
64 void testVoidReduce();
65
66 void testProgressReporting();
67 void testErrorHandler();
68 void testErrorPropagation();
69 void testErrorHandlerAsync();
70 void testErrorPropagationAsync();
71 void testNestedErrorPropagation();
72
73 void testChainingRunningJob();
74 void testChainingFinishedJob();
75
76 void testLifetimeWithoutHandle();
77 void testLifetimeWithHandle();
78
79 void benchmarkSyncThenExecutor();
80
81private:
82 template<typename T>
83 class AsyncSimulator {
84 public:
85 AsyncSimulator(KAsync::Future<T> &future, const T &result)
86 : mFuture(future)
87 , mResult(result)
88 {
89 QObject::connect(&mTimer, &QTimer::timeout,
90 [this]() {
91 mFuture.setValue(mResult);
92 mFuture.setFinished();
93 });
94 QObject::connect(&mTimer, &QTimer::timeout,
95 [this]() {
96 delete this;
97 });
98 mTimer.setSingleShot(true);
99 mTimer.start(200);
100 }
101
102 AsyncSimulator(KAsync::Future<T> &future, std::function<void(KAsync::Future<T>&)> callback)
103 : mFuture(future)
104 , mCallback(callback)
105 {
106 QObject::connect(&mTimer, &QTimer::timeout,
107 [this]() {
108 mCallback(mFuture);
109 });
110 QObject::connect(&mTimer, &QTimer::timeout,
111 [this]() {
112 delete this;
113 });
114 mTimer.setSingleShot(true);
115 mTimer.start(200);
116 }
117
118 private:
119 KAsync::Future<T> mFuture;
120 std::function<void(KAsync::Future<T>&)> mCallback;
121 T mResult;
122 QTimer mTimer;
123 };
124};
125
126
127template<>
128class AsyncTest::AsyncSimulator<void> {
129public:
130 AsyncSimulator(KAsync::Future<void> &future)
131 : mFuture(future)
132 {
133 QObject::connect(&mTimer, &QTimer::timeout,
134 [this]() {
135 mFuture.setFinished();
136 });
137 QObject::connect(&mTimer, &QTimer::timeout,
138 [this]() {
139 delete this;
140 });
141 mTimer.setSingleShot(true);
142 mTimer.start(200);
143 }
144
145private:
146 KAsync::Future<void> mFuture;
147 QTimer mTimer;
148};
149
150
151
152void AsyncTest::testSyncPromises()
153{
154 auto baseJob = KAsync::start<int>(
155 [](KAsync::Future<int> &f) {
156 f.setValue(42);
157 f.setFinished();
158 })
159 .then<QString, int>(
160 [](int v, KAsync::Future<QString> &f) {
161 f.setValue(QLatin1String("Result is ") + QString::number(v));
162 f.setFinished();
163 });
164
165 auto job = baseJob.then<QString, QString>(
166 [](const QString &v, KAsync::Future<QString> &f) {
167 f.setValue(v.toUpper());
168 f.setFinished();
169 });
170
171 KAsync::Future<QString> future = job.exec();
172
173 QVERIFY(future.isFinished());
174 QCOMPARE(future.value(), QString::fromLatin1("RESULT IS 42"));
175}
176
177void AsyncTest::testAsyncPromises()
178{
179 auto job = KAsync::start<int>(
180 [](KAsync::Future<int> &future) {
181 new AsyncSimulator<int>(future, 42);
182 });
183
184 KAsync::Future<int> future = job.exec();
185
186 future.waitForFinished();
187 QCOMPARE(future.value(), 42);
188}
189
190void AsyncTest::testAsyncPromises2()
191{
192 bool done = false;
193
194 auto job = KAsync::start<int>(
195 [](KAsync::Future<int> &future) {
196 new AsyncSimulator<int>(future, 42);
197 }
198 ).then<int, int>([&done](int result, KAsync::Future<int> &future) {
199 done = true;
200 future.setValue(result);
201 future.setFinished();
202 });
203 auto future = job.exec();
204
205 QTRY_VERIFY(done);
206 QCOMPARE(future.value(), 42);
207}
208
209void AsyncTest::testNestedAsync()
210{
211 bool done = false;
212
213 auto job = KAsync::start<int>(
214 [](KAsync::Future<int> &future) {
215 auto innerJob = KAsync::start<int>([](KAsync::Future<int> &innerFuture) {
216 new AsyncSimulator<int>(innerFuture, 42);
217 }).then<void>([&future](KAsync::Future<void> &innerThenFuture) {
218 future.setFinished();
219 innerThenFuture.setFinished();
220 });
221 innerJob.exec().waitForFinished();
222 }
223 ).then<int, int>([&done](int result, KAsync::Future<int> &future) {
224 done = true;
225 future.setValue(result);
226 future.setFinished();
227 });
228 job.exec();
229
230 QTRY_VERIFY(done);
231}
232
233void AsyncTest::testStartValue()
234{
235 auto job = KAsync::start<int, int>(
236 [](int in, KAsync::Future<int> &future) {
237 future.setValue(in);
238 future.setFinished();
239 });
240
241 auto future = job.exec(42);
242 QVERIFY(future.isFinished());
243 QCOMPARE(future.value(), 42);
244}
245
246
247
248
249
250void AsyncTest::testAsyncThen()
251{
252 auto job = KAsync::start<int>(
253 [](KAsync::Future<int> &future) {
254 new AsyncSimulator<int>(future, 42);
255 });
256
257 auto future = job.exec();
258 future.waitForFinished();
259
260 QVERIFY(future.isFinished());
261 QCOMPARE(future.value(), 42);
262}
263
264
265void AsyncTest::testSyncThen()
266{
267 auto job = KAsync::start<int>(
268 []() -> int {
269 return 42;
270 })
271 .then<int, int>(
272 [](int in) -> int {
273 return in * 2;
274 });
275
276 auto future = job.exec();
277 QVERIFY(future.isFinished());
278 QCOMPARE(future.value(), 84);
279}
280
281void AsyncTest::testJoinedThen()
282{
283 auto job1 = KAsync::start<int, int>(
284 [](int in, KAsync::Future<int> &future) {
285 new AsyncSimulator<int>(future, in * 2);
286 });
287
288 auto job2 = KAsync::start<int>(
289 [](KAsync::Future<int> &future) {
290 new AsyncSimulator<int>(future, 42);
291 })
292 .then<int>(job1);
293
294 auto future = job2.exec();
295 future.waitForFinished();
296
297 QVERIFY(future.isFinished());
298 QCOMPARE(future.value(), 84);
299}
300
301void AsyncTest::testVoidThen()
302{
303 int check = 0;
304
305 auto job = KAsync::start<void>(
306 [&check](KAsync::Future<void> &future) {
307 new AsyncSimulator<void>(future);
308 ++check;
309 })
310 .then<void>(
311 [&check](KAsync::Future<void> &future) {
312 new AsyncSimulator<void>(future);
313 ++check;
314 })
315 .then<void>(
316 [&check]() {
317 ++check;
318 });
319
320 auto future = job.exec();
321 future.waitForFinished();
322
323 QVERIFY(future.isFinished());
324 QCOMPARE(check, 3);
325}
326
327
328
329void AsyncTest::testAsyncEach()
330{
331 auto job = KAsync::start<QList<int>>(
332 [](KAsync::Future<QList<int>> &future) {
333 new AsyncSimulator<QList<int>>(future, { 1, 2, 3, 4 });
334 })
335 .each<QList<int>, int>(
336 [](const int &v, KAsync::Future<QList<int>> &future) {
337 new AsyncSimulator<QList<int>>(future, { v + 1 });
338 });
339
340 auto future = job.exec();
341 future.waitForFinished();
342
343 const QList<int> expected({ 2, 3, 4, 5 });
344 QVERIFY(future.isFinished());
345 QCOMPARE(future.value(), expected);
346}
347
348void AsyncTest::testSyncEach()
349{
350 auto job = KAsync::start<QList<int>>(
351 []() -> QList<int> {
352 return { 1, 2, 3, 4 };
353 })
354 .each<QList<int>, int>(
355 [](const int &v) -> QList<int> {
356 return { v + 1 };
357 });
358
359 KAsync::Future<QList<int>> future = job.exec();
360
361 const QList<int> expected({ 2, 3, 4, 5 });
362 QVERIFY(future.isFinished());
363 QCOMPARE(future.value(), expected);
364}
365
366void AsyncTest::testJoinedEach()
367{
368 auto job1 = KAsync::start<QList<int>, int>(
369 [](int v, KAsync::Future<QList<int>> &future) {
370 new AsyncSimulator<QList<int>>(future, { v * 2 });
371 });
372
373 auto job = KAsync::start<QList<int>>(
374 []() -> QList<int> {
375 return { 1, 2, 3, 4 };
376 })
377 .each(job1);
378
379 auto future = job.exec();
380 future.waitForFinished();
381
382 const QList<int> expected({ 2, 4, 6, 8 });
383 QVERIFY(future.isFinished());
384 QCOMPARE(future.value(), expected);
385}
386
387void AsyncTest::testVoidEachThen()
388{
389 QList<int> check;
390 auto job = KAsync::start<QList<int>>(
391 []() -> QList<int> {
392 return { 1, 2, 3, 4 };
393 }).each<void, int>(
394 [&check](const int &v) {
395 check << v;
396 }).then<void>([](){});
397
398 auto future = job.exec();
399
400 const QList<int> expected({ 1, 2, 3, 4 });
401 QVERIFY(future.isFinished());
402 QCOMPARE(check, expected);
403}
404
405void AsyncTest::testAsyncVoidEachThen()
406{
407 bool completedJob = false;
408 QList<int> check;
409 auto job = KAsync::start<QList<int>>(
410 [](KAsync::Future<QList<int> > &future) {
411 new AsyncSimulator<QList<int>>(future, { 1, 2, 3, 4 });
412 }).each<void, int>(
413 [&check](const int &v, KAsync::Future<void> &future) {
414 check << v;
415 new AsyncSimulator<void>(future);
416 }).then<void>([&completedJob](KAsync::Future<void> &future) {
417 completedJob = true;
418 future.setFinished();
419 });
420
421 auto future = job.exec();
422 future.waitForFinished();
423
424 const QList<int> expected({ 1, 2, 3, 4 });
425 QVERIFY(future.isFinished());
426 QVERIFY(completedJob);
427 QCOMPARE(check, expected);
428}
429
430
431
432
433
434void AsyncTest::testAsyncReduce()
435{
436 auto job = KAsync::start<QList<int>>(
437 [](KAsync::Future<QList<int>> &future) {
438 new AsyncSimulator<QList<int>>(future, { 1, 2, 3, 4 });
439 })
440 .reduce<int, QList<int>>(
441 [](const QList<int> &list, KAsync::Future<int> &future) {
442 new AsyncSimulator<int>(future,
443 [list](KAsync::Future<int> &future) {
444 int sum = 0;
445 for (int i : list) sum += i;
446 future.setValue(sum);
447 future.setFinished();
448 }
449 );
450 });
451
452 KAsync::Future<int> future = job.exec();
453 future.waitForFinished();
454
455 QVERIFY(future.isFinished());
456 QCOMPARE(future.value(), 10);
457}
458
459void AsyncTest::testSyncReduce()
460{
461 auto job = KAsync::start<QList<int>>(
462 []() -> QList<int> {
463 return { 1, 2, 3, 4 };
464 })
465 .reduce<int, QList<int>>(
466 [](const QList<int> &list) -> int {
467 int sum = 0;
468 for (int i : list) sum += i;
469 return sum;
470 });
471
472 KAsync::Future<int> future = job.exec();
473
474 QVERIFY(future.isFinished());
475 QCOMPARE(future.value(), 10);
476}
477
478
479void AsyncTest::testJoinedReduce()
480{
481 auto job1 = KAsync::start<int, QList<int>>(
482 [](const QList<int> &list, KAsync::Future<int> &future) {
483 int sum = 0;
484 for (int i : list) sum += i;
485 new AsyncSimulator<int>(future, sum);
486 });
487
488 auto job = KAsync::start<QList<int>>(
489 []() -> QList<int> {
490 return { 1, 2, 3, 4 };
491 })
492 .reduce(job1);
493
494 auto future = job.exec();
495 future.waitForFinished();
496
497 QVERIFY(future.isFinished());
498 QCOMPARE(future.value(), 10);
499}
500
501void AsyncTest::testVoidReduce()
502{
503// This must not compile (reduce with void result makes no sense)
504#ifdef TEST_BUILD_FAIL
505 auto job = KAsync::start<QList<int>>(
506 []() -> QList<int> {
507 return { 1, 2, 3, 4 };
508 })
509 .reduce<void, QList<int>>(
510 [](const QList<int> &list) -> int {
511 return;
512 });
513
514 auto future = job.exec();
515 QVERIFY(future.isFinished());
516#endif
517}
518
519
520void AsyncTest::testProgressReporting()
521{
522 static int progress;
523 progress = 0;
524
525 auto job = KAsync::start<void>(
526 [](KAsync::Future<void> &f) {
527 QTimer *timer = new QTimer();
528 connect(timer, &QTimer::timeout,
529 [&f, timer]() {
530 f.setProgress(++progress);
531 if (progress == 100) {
532 timer->stop();
533 timer->deleteLater();
534 f.setFinished();
535 }
536 });
537 timer->start(1);
538 });
539
540 int progressCheck = 0;
541 KAsync::FutureWatcher<void> watcher;
542 connect(&watcher, &KAsync::FutureWatcher<void>::futureProgress,
543 [&progressCheck](qreal progress) {
544 progressCheck++;
545 // FIXME: Don't use Q_ASSERT in unit tests
546 Q_ASSERT((int) progress == progressCheck);
547 });
548 watcher.setFuture(job.exec());
549 watcher.future().waitForFinished();
550
551 QVERIFY(watcher.future().isFinished());
552 QCOMPARE(progressCheck, 100);
553}
554
555void AsyncTest::testErrorHandler()
556{
557
558 {
559 auto job = KAsync::start<int>(
560 [](KAsync::Future<int> &f) {
561 f.setError(1, QLatin1String("error"));
562 });
563
564 auto future = job.exec();
565 QVERIFY(future.isFinished());
566 QCOMPARE(future.errorCode(), 1);
567 QCOMPARE(future.errorMessage(), QString::fromLatin1("error"));
568 }
569
570 {
571 int error = 0;
572 auto job = KAsync::start<int>(
573 [](KAsync::Future<int> &f) {
574 f.setError(1, QLatin1String("error"));
575 },
576 [&error](int errorCode, const QString &errorMessage) {
577 error += errorCode;
578 }
579 );
580
581 auto future = job.exec();
582 QVERIFY(future.isFinished());
583 QCOMPARE(error, 1);
584 QCOMPARE(future.errorCode(), 1);
585 QCOMPARE(future.errorMessage(), QString::fromLatin1("error"));
586 }
587}
588
589void AsyncTest::testErrorPropagation()
590{
591 int error = 0;
592 bool called = false;
593 auto job = KAsync::start<int>(
594 [](KAsync::Future<int> &f) {
595 f.setError(1, QLatin1String("error"));
596 })
597 .then<int, int>(
598 [&called](int v, KAsync::Future<int> &f) {
599 called = true;
600 f.setFinished();
601 },
602 [&error](int errorCode, const QString &errorMessage) {
603 error += errorCode;
604 }
605 );
606 auto future = job.exec();
607 QVERIFY(future.isFinished());
608 QCOMPARE(future.errorCode(), 1);
609 QCOMPARE(future.errorMessage(), QString::fromLatin1("error"));
610 QCOMPARE(called, false);
611 QCOMPARE(error, 1);
612}
613
614void AsyncTest::testErrorHandlerAsync()
615{
616 {
617 auto job = KAsync::start<int>(
618 [](KAsync::Future<int> &f) {
619 new AsyncSimulator<int>(f,
620 [](KAsync::Future<int> &f) {
621 f.setError(1, QLatin1String("error"));
622 }
623 );
624 }
625 );
626
627 auto future = job.exec();
628 future.waitForFinished();
629
630 QVERIFY(future.isFinished());
631 QCOMPARE(future.errorCode(), 1);
632 QCOMPARE(future.errorMessage(), QString::fromLatin1("error"));
633 }
634
635 {
636 int error = 0;
637 auto job = KAsync::start<int>(
638 [](KAsync::Future<int> &f) {
639 new AsyncSimulator<int>(f,
640 [](KAsync::Future<int> &f) {
641 f.setError(1, QLatin1String("error"));
642 }
643 );
644 },
645 [&error](int errorCode, const QString &errorMessage) {
646 error += errorCode;
647 }
648 );
649
650 auto future = job.exec();
651 future.waitForFinished();
652
653 QVERIFY(future.isFinished());
654 QCOMPARE(error, 1);
655 QCOMPARE(future.errorCode(), 1);
656 QCOMPARE(future.errorMessage(), QString::fromLatin1("error"));
657 }
658}
659
660void AsyncTest::testErrorPropagationAsync()
661{
662 int error = 0;
663 bool called = false;
664 auto job = KAsync::start<int>(
665 [](KAsync::Future<int> &f) {
666 new AsyncSimulator<int>(f,
667 [](KAsync::Future<int> &f) {
668 f.setError(1, QLatin1String("error"));
669 }
670 );
671 })
672 .then<int, int>(
673 [&called](int v, KAsync::Future<int> &f) {
674 called = true;
675 f.setFinished();
676 },
677 [&error](int errorCode, const QString &errorMessage) {
678 error += errorCode;
679 }
680 );
681
682 auto future = job.exec();
683 future.waitForFinished();
684
685 QVERIFY(future.isFinished());
686 QCOMPARE(future.errorCode(), 1);
687 QCOMPARE(future.errorMessage(), QString::fromLatin1("error"));
688 QCOMPARE(called, false);
689 QCOMPARE(error, 1);
690}
691
692void AsyncTest::testNestedErrorPropagation()
693{
694 int error = 0;
695 auto job = KAsync::start<void>([](){})
696 .then<void>(KAsync::error<void>(1, QLatin1String("error"))) //Nested job that throws error
697 .then<void>([](KAsync::Future<void> &future) {
698 //We should never get here
699 Q_ASSERT(false);
700 },
701 [&error](int errorCode, const QString &errorMessage) {
702 error += errorCode;
703 }
704 );
705 auto future = job.exec();
706
707 future.waitForFinished();
708
709 QVERIFY(future.isFinished());
710 QCOMPARE(future.errorCode(), 1);
711 QCOMPARE(future.errorMessage(), QString::fromLatin1("error"));
712 QCOMPARE(error, 1);
713}
714
715
716
717
718void AsyncTest::testChainingRunningJob()
719{
720 int check = 0;
721
722 auto job = KAsync::start<int>(
723 [&check](KAsync::Future<int> &future) {
724 QTimer *timer = new QTimer();
725 QObject::connect(timer, &QTimer::timeout,
726 [&future, &check]() {
727 ++check;
728 future.setValue(42);
729 future.setFinished();
730 });
731 QObject::connect(timer, &QTimer::timeout,
732 timer, &QObject::deleteLater);
733 timer->setSingleShot(true);
734 timer->start(500);
735 });
736
737 auto future1 = job.exec();
738 QTest::qWait(200);
739
740 auto job2 = job.then<int, int>(
741 [&check](int in) -> int {
742 ++check;
743 return in * 2;
744 });
745
746 auto future2 = job2.exec();
747 QVERIFY(!future1.isFinished());
748 future2.waitForFinished();
749
750 QEXPECT_FAIL("", "Chaining new job to a running job no longer executes the new job. "
751 "This is a trade-off for being able to re-execute single job multiple times.",
752 Abort);
753
754 QCOMPARE(check, 2);
755
756 QVERIFY(future1.isFinished());
757 QVERIFY(future2.isFinished());
758 QCOMPARE(future1.value(), 42);
759 QCOMPARE(future2.value(), 84);
760}
761
762void AsyncTest::testChainingFinishedJob()
763{
764 int check = 0;
765
766 auto job = KAsync::start<int>(
767 [&check]() -> int {
768 ++check;
769 return 42;
770 });
771
772 auto future1 = job.exec();
773 QVERIFY(future1.isFinished());
774
775 auto job2 = job.then<int, int>(
776 [&check](int in) -> int {
777 ++check;
778 return in * 2;
779 });
780
781 auto future2 = job2.exec();
782 QVERIFY(future2.isFinished());
783
784 QEXPECT_FAIL("", "Resuming finished job by chaining a new job and calling exec() is no longer suppported. "
785 "This is a trade-off for being able to re-execute single job multiple times.",
786 Abort);
787
788 QCOMPARE(check, 2);
789
790 QCOMPARE(future1.value(), 42);
791 QCOMPARE(future2.value(), 84);
792}
793
794/*
795 * We want to be able to execute jobs without keeping a handle explicitly alive.
796 * If the future handle inside the continuation would keep the executor alive, that would probably already work.
797 */
798void AsyncTest::testLifetimeWithoutHandle()
799{
800 bool done = false;
801 {
802 auto job = KAsync::start<void>([&done](KAsync::Future<void> &future) {
803 QTimer *timer = new QTimer();
804 QObject::connect(timer, &QTimer::timeout,
805 [&future, &done]() {
806 done = true;
807 future.setFinished();
808 });
809 QObject::connect(timer, &QTimer::timeout,
810 timer, &QObject::deleteLater);
811 timer->setSingleShot(true);
812 timer->start(500);
813 });
814 job.exec();
815 }
816
817 QTRY_VERIFY(done);
818}
819
820/*
821 * The future handle should keep the executor alive, and the future reference should probably not become invalid inside the continuation,
822 * until the job is done (alternatively a copy of the future inside the continuation should work as well).
823 */
824void AsyncTest::testLifetimeWithHandle()
825{
826 KAsync::Future<void> future;
827 {
828 auto job = KAsync::start<void>([](KAsync::Future<void> &future) {
829 QTimer *timer = new QTimer();
830 QObject::connect(timer, &QTimer::timeout,
831 [&future]() {
832 future.setFinished();
833 });
834 QObject::connect(timer, &QTimer::timeout,
835 timer, &QObject::deleteLater);
836 timer->setSingleShot(true);
837 timer->start(500);
838 });
839 future = job.exec();
840 }
841
842 QTRY_VERIFY(future.isFinished());
843}
844
845void AsyncTest::benchmarkSyncThenExecutor()
846{
847 auto job = KAsync::start<int>(
848 []() -> int {
849 return 0;
850 });
851
852 QBENCHMARK {
853 job.exec();
854 }
855}
856
857QTEST_MAIN(AsyncTest);
858
859#include "asynctest.moc"
diff --git a/async/autotests/kjobtest.cpp b/async/autotests/kjobtest.cpp
deleted file mode 100644
index 15e50de..0000000
--- a/async/autotests/kjobtest.cpp
+++ /dev/null
@@ -1,69 +0,0 @@
1/*
2 * Copyright 2015 Daniel Vrátil <dvratil@redhat.com>
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of
7 * the License or (at your option) version 3 or any later version
8 * accepted by the membership of KDE e.V. (or its successor approved
9 * by the membership of KDE e.V.), which shall act as a proxy
10 * defined in Section 14 of version 3 of the license.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#include "../src/async.h"
23#include "testkjob.h"
24
25#include <QtTest/QTest>
26
27class KJobTest : public QObject
28{
29 Q_OBJECT
30
31public:
32 KJobTest()
33 {}
34
35 ~KJobTest()
36 {}
37
38private Q_SLOTS:
39 void testSingleKJob();
40 void testKJobChain();
41
42};
43
44void KJobTest::testSingleKJob()
45{
46 auto job = KAsync::start<int, TestKJob, &TestKJob::result, int>();
47
48 auto future = job.exec(42);
49 future.waitForFinished();
50
51 QVERIFY(future.isFinished());
52 QCOMPARE(future.value(), 42);
53}
54
55void KJobTest::testKJobChain()
56{
57 auto job = KAsync::start<int, TestKJob, &TestKJob::result, int>()
58 .then<int, TestKJob, &TestKJob::result, int>();
59
60 auto future = job.exec(42);
61 future.waitForFinished();
62
63 QVERIFY(future.isFinished());
64 QCOMPARE(future.value(), 42);
65}
66
67QTEST_MAIN(KJobTest)
68
69#include "kjobtest.moc" \ No newline at end of file
diff --git a/async/autotests/testkjob.cpp b/async/autotests/testkjob.cpp
deleted file mode 100644
index b86f913..0000000
--- a/async/autotests/testkjob.cpp
+++ /dev/null
@@ -1,28 +0,0 @@
1#include "testkjob.h"
2
3TestKJob::TestKJob(int result)
4 : mResult(result)
5{
6 connect(&mTimer, &QTimer::timeout,
7 this, &TestKJob::onTimeout);
8 mTimer.setSingleShot(true);
9 mTimer.setInterval(200);
10}
11
12TestKJob::~TestKJob()
13{}
14
15void TestKJob::start()
16{
17 mTimer.start();
18}
19
20int TestKJob::result()
21{
22 return mResult;
23}
24
25void TestKJob::onTimeout()
26{
27 emitResult();
28} \ No newline at end of file
diff --git a/async/autotests/testkjob.h b/async/autotests/testkjob.h
deleted file mode 100644
index eead98e..0000000
--- a/async/autotests/testkjob.h
+++ /dev/null
@@ -1,48 +0,0 @@
1/*
2 * Copyright 2015 Daniel Vrátil <dvratil@redhat.com>
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of
7 * the License or (at your option) version 3 or any later version
8 * accepted by the membership of KDE e.V. (or its successor approved
9 * by the membership of KDE e.V.), which shall act as a proxy
10 * defined in Section 14 of version 3 of the license.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#ifndef TESTKJOB_H
23#define TESTKJOB_H
24
25#include <KJob>
26#include <QTimer>
27
28class TestKJob : public KJob
29{
30 Q_OBJECT
31
32public:
33 TestKJob(int result);
34 ~TestKJob();
35
36 void start();
37
38 int result();
39
40private Q_SLOTS:
41 void onTimeout();
42
43private:
44 int mResult;
45 QTimer mTimer;
46};
47
48#endif // TESTKJOB_H \ No newline at end of file
diff --git a/async/src/CMakeLists.txt b/async/src/CMakeLists.txt
deleted file mode 100644
index 05d08b6..0000000
--- a/async/src/CMakeLists.txt
+++ /dev/null
@@ -1,63 +0,0 @@
1set(kasync_SRCS
2 async.cpp
3 future.cpp
4 debug.cpp
5)
6
7set(kasync_priv_HEADERS
8 async_impl.h
9 debug.h
10)
11
12ecm_generate_headers(kasync_HEADERS
13 HEADER_NAMES
14 Async
15 Future
16)
17
18
19add_library(KF5Async ${kasync_SRCS})
20add_library(KF5::Async ALIAS KF5Async)
21
22generate_export_header(KF5Async BASE_NAME kasync)
23
24target_include_directories(KF5Async INTERFACE "$<INSTALL_INTERFACE:${KDE_INSTALL_INCLUDEDIR_KF5}/Async>")
25target_include_directories(KF5Async PUBLIC "$<BUILD_INTERFACE:${KAsync_SOURCE_DIR}/src>")
26
27target_link_libraries(KF5Async
28 PUBLIC
29 Qt5::Core
30)
31if (WITH_KJOB)
32 target_link_libraries(KF5Async PUBLIC KF5::CoreAddons)
33endif ()
34
35
36set_target_properties(KF5Async PROPERTIES
37 VERSION ${KASYNC_VERSION_STRING}
38 SOVERSION ${KASYNC_SOVERSION}
39 EXPORT_NAME KAsync
40)
41
42ecm_generate_pri_file(BASE_NAME KAsync
43 LIB_NAME KF5Async
44 FILENAME_VAR PRI_FILENAME
45)
46
47install(TARGETS
48 KF5Async
49 EXPORT KF5AsyncTargets ${KF5_INSTALL_TARGETS_DEFAULT_ARGS}
50)
51
52install(FILES
53 ${CMAKE_CURRENT_BINARY_DIR}/kasync_export.h
54 ${kasync_HEADERS}
55 ${kasync_priv_HEADERS}
56 DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/Async
57 COMPONENT Devel
58)
59
60install(FILES
61 ${PRI_FILENAME}
62 DESTINATION ${ECM_MKSPECS_INSTALL_DIR}
63)
diff --git a/async/src/async.cpp b/async/src/async.cpp
deleted file mode 100644
index c57c9ad..0000000
--- a/async/src/async.cpp
+++ /dev/null
@@ -1,148 +0,0 @@
1/*
2 * Copyright 2014 Daniel Vrátil <dvratil@redhat.com>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public License as
6 * published by the Free Software Foundation; either version 2 of
7 * the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public License
15 * along with this library. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "async.h"
19
20#include <QCoreApplication>
21#include <QDebug>
22#include <QEventLoop>
23#include <QTimer>
24
25using namespace KAsync;
26
27Private::Execution::Execution(const Private::ExecutorBasePtr &executor)
28 : executor(executor)
29 , resultBase(nullptr)
30 , isRunning(false)
31 , isFinished(false)
32{
33}
34
35Private::Execution::~Execution()
36{
37 if (resultBase) {
38 resultBase->releaseExecution();
39 delete resultBase;
40 }
41 prevExecution.reset();
42}
43
44void Private::Execution::setFinished()
45{
46 isFinished = true;
47 //executor.clear();
48#ifndef QT_NO_DEBUG
49 if (tracer) {
50 delete tracer;
51 }
52#endif
53}
54
55void Private::Execution::releaseFuture()
56{
57 resultBase = 0;
58}
59
60bool Private::Execution::errorWasHandled() const
61{
62 Execution *exec = const_cast<Execution*>(this);
63 while (exec) {
64 if (exec->executor->hasErrorFunc()) {
65 return true;
66 }
67 exec = exec->prevExecution.data();
68 }
69 return false;
70}
71
72
73
74
75
76Private::ExecutorBase::ExecutorBase(const ExecutorBasePtr &parent)
77 : mPrev(parent)
78{
79}
80
81Private::ExecutorBase::~ExecutorBase()
82{
83}
84
85
86
87
88JobBase::JobBase(const Private::ExecutorBasePtr &executor)
89 : mExecutor(executor)
90{
91}
92
93JobBase::~JobBase()
94{
95}
96
97static void asyncWhile(const std::function<void(std::function<void(bool)>)> &body, const std::function<void()> &completionHandler) {
98 body([body, completionHandler](bool complete) {
99 if (complete) {
100 completionHandler();
101 } else {
102 asyncWhile(body, completionHandler);
103 }
104 });
105}
106
107Job<void> KAsync::dowhile(Condition condition, ThenTask<void> body)
108{
109 return KAsync::start<void>([body, condition](KAsync::Future<void> &future) {
110 asyncWhile([condition, body](std::function<void(bool)> whileCallback) {
111 KAsync::start<void>(body).then<void>([whileCallback, condition]() {
112 whileCallback(!condition());
113 }).exec();
114 },
115 [&future]() { //while complete
116 future.setFinished();
117 });
118 });
119}
120
121Job<void> KAsync::dowhile(ThenTask<bool> body)
122{
123 return KAsync::start<void>([body](KAsync::Future<void> &future) {
124 asyncWhile([body](std::function<void(bool)> whileCallback) {
125 KAsync::start<bool>(body).then<bool, bool>([whileCallback](bool result) {
126 whileCallback(!result);
127 //FIXME this return value is only required because .then<bool, void> doesn't work
128 return true;
129 }).exec();
130 },
131 [&future]() { //while complete
132 future.setFinished();
133 });
134 });
135}
136
137Job<void> KAsync::wait(int delay)
138{
139 auto timer = QSharedPointer<QTimer>::create();
140 return KAsync::start<void>([timer, delay](KAsync::Future<void> &future) {
141 timer->setSingleShot(true);
142 QObject::connect(timer.data(), &QTimer::timeout, [&future]() {
143 future.setFinished();
144 });
145 timer->start(delay);
146 });
147}
148
diff --git a/async/src/async.h b/async/src/async.h
deleted file mode 100644
index 152f98e..0000000
--- a/async/src/async.h
+++ /dev/null
@@ -1,874 +0,0 @@
1/*
2 * Copyright 2014 - 2015 Daniel Vrátil <dvratil@redhat.com>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public License as
6 * published by the Free Software Foundation; either version 2 of
7 * the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public License
15 * along with this library. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#ifndef KASYNC_H
19#define KASYNC_H
20
21#include "kasync_export.h"
22
23#include <functional>
24#include <list>
25#include <type_traits>
26#include <cassert>
27#include <iterator>
28
29#include "future.h"
30#include "debug.h"
31#include "async_impl.h"
32
33#include <QVector>
34#include <QObject>
35#include <QSharedPointer>
36
37#include <QDebug>
38
39#ifdef WITH_KJOB
40#include <KJob>
41#endif
42
43
44/*
45 * API to help write async code.
46 *
47 * This API is based around jobs that take lambdas to execute asynchronous tasks. Each async operation can take a continuation,
48 * that can then be used to execute further async operations. That way it is possible to build async chains of operations,
49 * that can be stored and executed later on. Jobs can be composed, similarly to functions.
50 *
51 * Relations between the components:
52 * * Job: API wrapper around Executors chain. Can be destroyed while still running,
53 * because the actual execution happens in the background
54 * * Executor: Describes task to execute. Executors form a linked list matching the
55 * order in which they will be executed. The Executor chain is destroyed when
56 * the parent Job is destroyed. However if the Job is still running it is
57 * guaranteed that the Executor chain will not be destroyed until the execution
58 * is finished.
59 * * Execution: The running execution of the task stored in Executor. Each call to Job::exec()
60 * instantiates new Execution chain, which makes it possible for the Job to be
61 * executed multiple times (even in parallel).
62 * * Future: Representation of the result that is being calculated
63 *
64 *
65 * TODO: Composed progress reporting
66 * TODO: Possibility to abort a job through future (perhaps optional?)
67 * TODO: Support for timeout, specified during exec call, after which the error handler gets called with a defined errorCode.
68 */
69namespace KAsync {
70
71template<typename PrevOut, typename Out, typename ... In>
72class Executor;
73
74class JobBase;
75
76template<typename Out, typename ... In>
77class Job;
78
79template<typename Out, typename ... In>
80using ThenTask = typename detail::identity<std::function<void(In ..., KAsync::Future<Out>&)>>::type;
81template<typename Out, typename ... In>
82using SyncThenTask = typename detail::identity<std::function<Out(In ...)>>::type;
83template<typename Out, typename In>
84using EachTask = typename detail::identity<std::function<void(In, KAsync::Future<Out>&)>>::type;
85template<typename Out, typename In>
86using SyncEachTask = typename detail::identity<std::function<Out(In)>>::type;
87template<typename Out, typename In>
88using ReduceTask = typename detail::identity<std::function<void(In, KAsync::Future<Out>&)>>::type;
89template<typename Out, typename In>
90using SyncReduceTask = typename detail::identity<std::function<Out(In)>>::type;
91
92using ErrorHandler = std::function<void(int, const QString &)>;
93using Condition = std::function<bool()>;
94
95namespace Private
96{
97
98class ExecutorBase;
99typedef QSharedPointer<ExecutorBase> ExecutorBasePtr;
100
101struct KASYNC_EXPORT Execution {
102 Execution(const ExecutorBasePtr &executor);
103 ~Execution();
104 void setFinished();
105
106 template<typename T>
107 KAsync::Future<T>* result() const
108 {
109 return static_cast<KAsync::Future<T>*>(resultBase);
110 }
111
112 void releaseFuture();
113 bool errorWasHandled() const;
114
115 ExecutorBasePtr executor;
116 FutureBase *resultBase;
117 bool isRunning;
118 bool isFinished;
119
120 ExecutionPtr prevExecution;
121
122#ifndef QT_NO_DEBUG
123 Tracer *tracer;
124#endif
125};
126
127
128typedef QSharedPointer<Execution> ExecutionPtr;
129
130class KASYNC_EXPORT ExecutorBase
131{
132 template<typename PrevOut, typename Out, typename ... In>
133 friend class Executor;
134
135 template<typename Out, typename ... In>
136 friend class KAsync::Job;
137
138 friend class Execution;
139 friend class KAsync::Tracer;
140
141public:
142 virtual ~ExecutorBase();
143 virtual ExecutionPtr exec(const ExecutorBasePtr &self) = 0;
144
145protected:
146 ExecutorBase(const ExecutorBasePtr &parent);
147
148 template<typename T>
149 KAsync::Future<T>* createFuture(const ExecutionPtr &execution) const;
150
151 virtual bool hasErrorFunc() const = 0;
152 virtual bool handleError(const ExecutionPtr &execution) = 0;
153
154 ExecutorBasePtr mPrev;
155
156#ifndef QT_NO_DEBUG
157 QString mExecutorName;
158#endif
159};
160
161template<typename PrevOut, typename Out, typename ... In>
162class Executor : public ExecutorBase
163{
164protected:
165 Executor(ErrorHandler errorFunc, const Private::ExecutorBasePtr &parent)
166 : ExecutorBase(parent)
167 , mErrorFunc(errorFunc)
168 {}
169
170 virtual ~Executor() {}
171 virtual void run(const ExecutionPtr &execution) = 0;
172
173 ExecutionPtr exec(const ExecutorBasePtr &self);
174 bool hasErrorFunc() const { return (bool) mErrorFunc; }
175 bool handleError(const ExecutionPtr &execution);
176
177 std::function<void(int, const QString &)> mErrorFunc;
178};
179
180template<typename Out, typename ... In>
181class ThenExecutor: public Executor<typename detail::prevOut<In ...>::type, Out, In ...>
182{
183public:
184 ThenExecutor(ThenTask<Out, In ...> then, ErrorHandler errorFunc, const ExecutorBasePtr &parent);
185 void run(const ExecutionPtr &execution);
186private:
187 ThenTask<Out, In ...> mFunc;
188};
189
190template<typename PrevOut, typename Out, typename In>
191class EachExecutor : public Executor<PrevOut, Out, In>
192{
193public:
194 EachExecutor(EachTask<Out, In> each, ErrorHandler errorFunc, const ExecutorBasePtr &parent);
195 void run(const ExecutionPtr &execution);
196private:
197 EachTask<Out, In> mFunc;
198 QVector<KAsync::FutureWatcher<Out>*> mFutureWatchers;
199};
200
201template<typename Out, typename In>
202class ReduceExecutor : public ThenExecutor<Out, In>
203{
204public:
205 ReduceExecutor(ReduceTask<Out, In> reduce, ErrorHandler errorFunc, const ExecutorBasePtr &parent);
206private:
207 ReduceTask<Out, In> mFunc;
208};
209
210template<typename Out, typename ... In>
211class SyncThenExecutor : public Executor<typename detail::prevOut<In ...>::type, Out, In ...>
212{
213public:
214 SyncThenExecutor(SyncThenTask<Out, In ...> then, ErrorHandler errorFunc, const ExecutorBasePtr &parent);
215 void run(const ExecutionPtr &execution);
216
217private:
218 void run(const ExecutionPtr &execution, std::false_type); // !std::is_void<Out>
219 void run(const ExecutionPtr &execution, std::true_type); // std::is_void<Out>
220 SyncThenTask<Out, In ...> mFunc;
221};
222
223template<typename Out, typename In>
224class SyncReduceExecutor : public SyncThenExecutor<Out, In>
225{
226public:
227 SyncReduceExecutor(SyncReduceTask<Out, In> reduce, ErrorHandler errorFunc, const ExecutorBasePtr &parent);
228private:
229 SyncReduceTask<Out, In> mFunc;
230};
231
232template<typename PrevOut, typename Out, typename In>
233class SyncEachExecutor : public Executor<PrevOut, Out, In>
234{
235public:
236 SyncEachExecutor(SyncEachTask<Out, In> each, ErrorHandler errorFunc, const ExecutorBasePtr &parent);
237 void run(const ExecutionPtr &execution);
238private:
239 void run(KAsync::Future<Out> *future, const typename PrevOut::value_type &arg, std::false_type); // !std::is_void<Out>
240 void run(KAsync::Future<Out> *future, const typename PrevOut::value_type &arg, std::true_type); // std::is_void<Out>
241 SyncEachTask<Out, In> mFunc;
242};
243
244} // namespace Private
245
246/**
247 * Start an asynchronous job sequence.
248 *
249 * KAsync::start() is your starting point to build a chain of jobs to be executed
250 * asynchronously.
251 *
252 * @param func An asynchronous function to be executed. The function must have
253 * void return type, and accept exactly one argument of type @p KAsync::Future<In>,
254 * where @p In is type of the result.
255 */
256template<typename Out, typename ... In>
257Job<Out, In ...> start(ThenTask<Out, In ...> func, ErrorHandler errorFunc = ErrorHandler());
258
259template<typename Out, typename ... In>
260Job<Out, In ...> start(SyncThenTask<Out, In ...> func, ErrorHandler errorFunc = ErrorHandler());
261
262#ifdef WITH_KJOB
263template<typename ReturnType, typename KJobType, ReturnType (KJobType::*KJobResultMethod)(), typename ... Args>
264Job<ReturnType, Args ...> start();
265#endif
266
267/**
268 * Async while loop.
269 *
270 * The loop continues while @param condition returns true.
271 */
272KASYNC_EXPORT Job<void> dowhile(Condition condition, ThenTask<void> func);
273
274/**
275 * Async while loop.
276 *
277 * Loop continues while body returns true.
278 */
279KASYNC_EXPORT Job<void> dowhile(ThenTask<bool> body);
280
281/**
282 * Iterate over a container.
283 *
284 * Use in conjunction with .each
285 */
286template<typename Out>
287Job<Out> iterate(const Out &container);
288
289/**
290 * Async delay.
291 */
292KASYNC_EXPORT Job<void> wait(int delay);
293
294/**
295 * A null job.
296 *
297 * An async noop.
298 *
299 */
300template<typename Out>
301Job<Out> null();
302
303/**
304 * An error job.
305 *
306 * An async error.
307 *
308 */
309template<typename Out>
310Job<Out> error(int errorCode = 1, const QString &errorMessage = QString());
311
312class KASYNC_EXPORT JobBase
313{
314 template<typename Out, typename ... In>
315 friend class Job;
316
317public:
318 JobBase(const Private::ExecutorBasePtr &executor);
319 ~JobBase();
320
321protected:
322 Private::ExecutorBasePtr mExecutor;
323};
324
325/**
326 * An Asynchronous job
327 *
328 * A single instance of Job represents a single method that will be executed
329 * asynchrously. The Job is started by @p Job::exec(), which returns @p KAsync::Future
330 * immediatelly. The Future will be set to finished state once the asynchronous
331 * task has finished. You can use @p KAsync::Future::waitForFinished() to wait for
332 * for the Future in blocking manner.
333 *
334 * It is possible to chain multiple Jobs one after another in different fashion
335 * (sequential, parallel, etc.). Calling Job::exec() will then return a pending
336 * @p KAsync::Future, and will execute the entire chain of jobs.
337 *
338 * @code
339 * auto job = Job::start<QList<int>>(
340 * [](KAsync::Future<QList<int>> &future) {
341 * MyREST::PendingUsers *pu = MyREST::requestListOfUsers();
342 * QObject::connect(pu, &PendingOperation::finished,
343 * [&](PendingOperation *pu) {
344 * future->setValue(dynamic_cast<MyREST::PendingUsers*>(pu)->userIds());
345 * future->setFinished();
346 * });
347 * })
348 * .each<QList<MyREST::User>, int>(
349 * [](const int &userId, KAsync::Future<QList<MyREST::User>> &future) {
350 * MyREST::PendingUser *pu = MyREST::requestUserDetails(userId);
351 * QObject::connect(pu, &PendingOperation::finished,
352 * [&](PendingOperation *pu) {
353 * future->setValue(Qlist<MyREST::User>() << dynamic_cast<MyREST::PendingUser*>(pu)->user());
354 * future->setFinished();
355 * });
356 * });
357 *
358 * KAsync::Future<QList<MyREST::User>> usersFuture = job.exec();
359 * usersFuture.waitForFinished();
360 * QList<MyRest::User> users = usersFuture.value();
361 * @endcode
362 *
363 * In the example above, calling @p job.exec() will first invoke the first job,
364 * which will retrieve a list of IDs, and then will invoke the second function
365 * for each single entry in the list returned by the first function.
366 */
367template<typename Out, typename ... In>
368class Job : public JobBase
369{
370 template<typename OutOther, typename ... InOther>
371 friend class Job;
372
373 template<typename OutOther, typename ... InOther>
374 friend Job<OutOther, InOther ...> start(KAsync::ThenTask<OutOther, InOther ...> func, ErrorHandler errorFunc);
375
376 template<typename OutOther, typename ... InOther>
377 friend Job<OutOther, InOther ...> start(KAsync::SyncThenTask<OutOther, InOther ...> func, ErrorHandler errorFunc);
378
379#ifdef WITH_KJOB
380 template<typename ReturnType, typename KJobType, ReturnType (KJobType::*KJobResultMethod)(), typename ... Args>
381 friend Job<ReturnType, Args ...> start();
382#endif
383
384public:
385 template<typename OutOther, typename ... InOther>
386 Job<OutOther, InOther ...> then(ThenTask<OutOther, InOther ...> func, ErrorHandler errorFunc = ErrorHandler())
387 {
388 return Job<OutOther, InOther ...>(Private::ExecutorBasePtr(
389 new Private::ThenExecutor<OutOther, InOther ...>(func, errorFunc, mExecutor)));
390 }
391
392 template<typename OutOther, typename ... InOther>
393 Job<OutOther, InOther ...> then(SyncThenTask<OutOther, InOther ...> func, ErrorHandler errorFunc = ErrorHandler())
394 {
395 return Job<OutOther, InOther ...>(Private::ExecutorBasePtr(
396 new Private::SyncThenExecutor<OutOther, InOther ...>(func, errorFunc, mExecutor)));
397 }
398
399 template<typename OutOther, typename ... InOther>
400 Job<OutOther, InOther ...> then(Job<OutOther, InOther ...> otherJob, ErrorHandler errorFunc = ErrorHandler())
401 {
402 return then<OutOther, InOther ...>(nestedJobWrapper<OutOther, InOther ...>(otherJob), errorFunc);
403 }
404
405#ifdef WITH_KJOB
406 template<typename ReturnType, typename KJobType, ReturnType (KJobType::*KJobResultMethod)(), typename ... Args>
407 Job<ReturnType, Args ...> then()
408 {
409 return start<ReturnType, KJobType, KJobResultMethod, Args ...>();
410 }
411#endif
412
413 template<typename OutOther, typename InOther>
414 Job<OutOther, InOther> each(EachTask<OutOther, InOther> func, ErrorHandler errorFunc = ErrorHandler())
415 {
416 eachInvariants<OutOther>();
417 return Job<OutOther, InOther>(Private::ExecutorBasePtr(
418 new Private::EachExecutor<Out, OutOther, InOther>(func, errorFunc, mExecutor)));
419 }
420
421 template<typename OutOther, typename InOther>
422 Job<OutOther, InOther> each(SyncEachTask<OutOther, InOther> func, ErrorHandler errorFunc = ErrorHandler())
423 {
424 eachInvariants<OutOther>();
425 return Job<OutOther, InOther>(Private::ExecutorBasePtr(
426 new Private::SyncEachExecutor<Out, OutOther, InOther>(func, errorFunc, mExecutor)));
427 }
428
429 template<typename OutOther, typename InOther>
430 Job<OutOther, InOther> each(Job<OutOther, InOther> otherJob, ErrorHandler errorFunc = ErrorHandler())
431 {
432 eachInvariants<OutOther>();
433 return each<OutOther, InOther>(nestedJobWrapper<OutOther, InOther>(otherJob), errorFunc);
434 }
435
436 template<typename OutOther, typename InOther>
437 Job<OutOther, InOther> reduce(ReduceTask<OutOther, InOther> func, ErrorHandler errorFunc = ErrorHandler())
438 {
439 reduceInvariants<InOther>();
440 return Job<OutOther, InOther>(Private::ExecutorBasePtr(
441 new Private::ReduceExecutor<OutOther, InOther>(func, errorFunc, mExecutor)));
442 }
443
444 template<typename OutOther, typename InOther>
445 Job<OutOther, InOther> reduce(SyncReduceTask<OutOther, InOther> func, ErrorHandler errorFunc = ErrorHandler())
446 {
447 reduceInvariants<InOther>();
448 return Job<OutOther, InOther>(Private::ExecutorBasePtr(
449 new Private::SyncReduceExecutor<OutOther, InOther>(func, errorFunc, mExecutor)));
450 }
451
452 template<typename OutOther, typename InOther>
453 Job<OutOther, InOther> reduce(Job<OutOther, InOther> otherJob, ErrorHandler errorFunc = ErrorHandler())
454 {
455 return reduce<OutOther, InOther>(nestedJobWrapper<OutOther, InOther>(otherJob), errorFunc);
456 }
457
458 template<typename FirstIn>
459 KAsync::Future<Out> exec(FirstIn in)
460 {
461 // Inject a fake sync executor that will return the initial value
462 Private::ExecutorBasePtr first = mExecutor;
463 while (first->mPrev) {
464 first = first->mPrev;
465 }
466 auto init = new Private::SyncThenExecutor<FirstIn>(
467 [in]() -> FirstIn {
468 return in;
469 },
470 ErrorHandler(), Private::ExecutorBasePtr());
471 first->mPrev = Private::ExecutorBasePtr(init);
472
473 auto result = exec();
474 // Remove the injected executor
475 first->mPrev.reset();
476 return result;
477 }
478
479 KAsync::Future<Out> exec()
480 {
481 Private::ExecutionPtr execution = mExecutor->exec(mExecutor);
482 KAsync::Future<Out> result = *execution->result<Out>();
483
484 return result;
485 }
486
487private:
488 Job(Private::ExecutorBasePtr executor)
489 : JobBase(executor)
490 {}
491
492 template<typename OutOther>
493 void eachInvariants()
494 {
495 static_assert(detail::isIterable<Out>::value,
496 "The 'Each' task can only be connected to a job that returns a list or an array.");
497 static_assert(std::is_void<OutOther>::value || detail::isIterable<OutOther>::value,
498 "The result type of 'Each' task must be void, a list or an array.");
499 }
500
501 template<typename InOther>
502 void reduceInvariants()
503 {
504 static_assert(KAsync::detail::isIterable<Out>::value,
505 "The 'Result' task can only be connected to a job that returns a list or an array");
506 static_assert(std::is_same<typename Out::value_type, typename InOther::value_type>::value,
507 "The return type of previous task must be compatible with input type of this task");
508 }
509
510 template<typename OutOther, typename ... InOther>
511 inline std::function<void(InOther ..., KAsync::Future<OutOther>&)> nestedJobWrapper(Job<OutOther, InOther ...> otherJob) {
512 return [otherJob](InOther ... in, KAsync::Future<OutOther> &future) {
513 // copy by value is const
514 auto job = otherJob;
515 FutureWatcher<OutOther> *watcher = new FutureWatcher<OutOther>();
516 QObject::connect(watcher, &FutureWatcherBase::futureReady,
517 [watcher, future]() {
518 // FIXME: We pass future by value, because using reference causes the
519 // future to get deleted before this lambda is invoked, leading to crash
520 // in copyFutureValue()
521 // copy by value is const
522 auto outFuture = future;
523 KAsync::detail::copyFutureValue(watcher->future(), outFuture);
524 if (watcher->future().errorCode()) {
525 outFuture.setError(watcher->future().errorCode(), watcher->future().errorMessage());
526 } else {
527 outFuture.setFinished();
528 }
529 delete watcher;
530 });
531 watcher->setFuture(job.exec(in ...));
532 };
533 }
534};
535
536} // namespace KAsync
537
538
539// ********** Out of line definitions ****************
540
541namespace KAsync {
542
543template<typename Out, typename ... In>
544Job<Out, In ...> start(ThenTask<Out, In ...> func, ErrorHandler error)
545{
546 return Job<Out, In...>(Private::ExecutorBasePtr(
547 new Private::ThenExecutor<Out, In ...>(func, error, Private::ExecutorBasePtr())));
548}
549
550template<typename Out, typename ... In>
551Job<Out, In ...> start(SyncThenTask<Out, In ...> func, ErrorHandler error)
552{
553 return Job<Out, In...>(Private::ExecutorBasePtr(
554 new Private::SyncThenExecutor<Out, In ...>(func, error, Private::ExecutorBasePtr())));
555}
556
557#ifdef WITH_KJOB
558template<typename ReturnType, typename KJobType, ReturnType (KJobType::*KJobResultMethod)(), typename ... Args>
559Job<ReturnType, Args ...> start()
560{
561 return Job<ReturnType, Args ...>(Private::ExecutorBasePtr(
562 new Private::ThenExecutor<ReturnType, Args ...>([](const Args & ... args, KAsync::Future<ReturnType> &future)
563 {
564 KJobType *job = new KJobType(args ...);
565 job->connect(job, &KJob::finished,
566 [&future](KJob *job) {
567 if (job->error()) {
568 future.setError(job->error(), job->errorString());
569 } else {
570 future.setValue((static_cast<KJobType*>(job)->*KJobResultMethod)());
571 future.setFinished();
572 }
573 });
574 job->start();
575 }, ErrorHandler(), Private::ExecutorBasePtr())));
576}
577#endif
578
579
580template<typename Out>
581Job<Out> null()
582{
583 return KAsync::start<Out>(
584 [](KAsync::Future<Out> &future) {
585 future.setFinished();
586 });
587}
588
589template<typename Out>
590Job<Out> error(int errorCode, const QString &errorMessage)
591{
592 return KAsync::start<Out>(
593 [errorCode, errorMessage](KAsync::Future<Out> &future) {
594 future.setError(errorCode, errorMessage);
595 });
596}
597
598template<typename Out>
599Job<Out> iterate(const Out &container)
600{
601 return KAsync::start<Out>(
602 [container]() {
603 return container;
604 });
605}
606
607
608namespace Private {
609
610template<typename T>
611KAsync::Future<T>* ExecutorBase::createFuture(const ExecutionPtr &execution) const
612{
613 return new KAsync::Future<T>(execution);
614}
615
616template<typename PrevOut, typename Out, typename ... In>
617ExecutionPtr Executor<PrevOut, Out, In ...>::exec(const ExecutorBasePtr &self)
618{
619 // Passing 'self' to execution ensures that the Executor chain remains
620 // valid until the entire execution is finished
621 ExecutionPtr execution = ExecutionPtr::create(self);
622#ifndef QT_NO_DEBUG
623 execution->tracer = new Tracer(execution.data()); // owned by execution
624#endif
625
626 // chainup
627 execution->prevExecution = mPrev ? mPrev->exec(mPrev) : ExecutionPtr();
628
629 execution->resultBase = ExecutorBase::createFuture<Out>(execution);
630 auto fw = new KAsync::FutureWatcher<Out>();
631 QObject::connect(fw, &KAsync::FutureWatcher<Out>::futureReady,
632 [fw, execution, this]() {
633 handleError(execution);
634 execution->setFinished();
635 delete fw;
636 });
637 fw->setFuture(*execution->result<Out>());
638
639 KAsync::Future<PrevOut> *prevFuture = execution->prevExecution ? execution->prevExecution->result<PrevOut>() : nullptr;
640 if (!prevFuture || prevFuture->isFinished()) {
641 if (prevFuture) { // prevFuture implies execution->prevExecution
642 if (prevFuture->errorCode()) {
643 // Propagate the errorCode and message to the outer Future
644 execution->resultBase->setError(prevFuture->errorCode(), prevFuture->errorMessage());
645 if (!execution->errorWasHandled()) {
646 if (handleError(execution)) {
647 return execution;
648 }
649 } else {
650 return execution;
651 }
652 } else {
653 // Propagate error (if any)
654 }
655 }
656
657 execution->isRunning = true;
658 run(execution);
659 } else {
660 auto prevFutureWatcher = new KAsync::FutureWatcher<PrevOut>();
661 QObject::connect(prevFutureWatcher, &KAsync::FutureWatcher<PrevOut>::futureReady,
662 [prevFutureWatcher, execution, this]() {
663 auto prevFuture = prevFutureWatcher->future();
664 assert(prevFuture.isFinished());
665 delete prevFutureWatcher;
666 auto prevExecutor = execution->executor->mPrev;
667 if (prevFuture.errorCode()) {
668 execution->resultBase->setError(prevFuture.errorCode(), prevFuture.errorMessage());
669 if (!execution->errorWasHandled()) {
670 if (handleError(execution)) {
671 return;
672 }
673 } else {
674 return;
675 }
676 }
677
678
679 // propagate error (if any)
680 execution->isRunning = true;
681 run(execution);
682 });
683
684 prevFutureWatcher->setFuture(*static_cast<KAsync::Future<PrevOut>*>(prevFuture));
685 }
686
687 return execution;
688}
689
690template<typename PrevOut, typename Out, typename ... In>
691bool Executor<PrevOut, Out, In ...>::handleError(const ExecutionPtr &execution)
692{
693 assert(execution->resultBase->isFinished());
694 if (execution->resultBase->errorCode()) {
695 if (mErrorFunc) {
696 mErrorFunc(execution->resultBase->errorCode(),
697 execution->resultBase->errorMessage());
698 return true;
699 }
700 }
701
702 return false;
703}
704
705
706template<typename Out, typename ... In>
707ThenExecutor<Out, In ...>::ThenExecutor(ThenTask<Out, In ...> then, ErrorHandler error, const ExecutorBasePtr &parent)
708 : Executor<typename detail::prevOut<In ...>::type, Out, In ...>(error, parent)
709 , mFunc(then)
710{
711 STORE_EXECUTOR_NAME("ThenExecutor", Out, In ...);
712}
713
714template<typename Out, typename ... In>
715void ThenExecutor<Out, In ...>::run(const ExecutionPtr &execution)
716{
717 KAsync::Future<typename detail::prevOut<In ...>::type> *prevFuture = nullptr;
718 if (execution->prevExecution) {
719 prevFuture = execution->prevExecution->result<typename detail::prevOut<In ...>::type>();
720 assert(prevFuture->isFinished());
721 }
722
723 ThenExecutor<Out, In ...>::mFunc(prevFuture ? prevFuture->value() : In() ..., *execution->result<Out>());
724}
725
726template<typename PrevOut, typename Out, typename In>
727EachExecutor<PrevOut, Out, In>::EachExecutor(EachTask<Out, In> each, ErrorHandler error, const ExecutorBasePtr &parent)
728 : Executor<PrevOut, Out, In>(error, parent)
729 , mFunc(each)
730{
731 STORE_EXECUTOR_NAME("EachExecutor", PrevOut, Out, In);
732}
733
734template<typename PrevOut, typename Out, typename In>
735void EachExecutor<PrevOut, Out, In>::run(const ExecutionPtr &execution)
736{
737 assert(execution->prevExecution);
738 auto prevFuture = execution->prevExecution->result<PrevOut>();
739 assert(prevFuture->isFinished());
740
741 auto out = execution->result<Out>();
742 if (prevFuture->value().isEmpty()) {
743 out->setFinished();
744 return;
745 }
746
747 for (auto arg : prevFuture->value()) {
748 //We have to manually manage the lifetime of these temporary futures
749 KAsync::Future<Out> *future = new KAsync::Future<Out>();
750 EachExecutor<PrevOut, Out, In>::mFunc(arg, *future);
751 auto fw = new KAsync::FutureWatcher<Out>();
752 mFutureWatchers.append(fw);
753 QObject::connect(fw, &KAsync::FutureWatcher<Out>::futureReady,
754 [out, fw, this, future]() {
755 assert(fw->future().isFinished());
756 const int index = mFutureWatchers.indexOf(fw);
757 assert(index > -1);
758 mFutureWatchers.removeAt(index);
759 KAsync::detail::aggregateFutureValue<Out>(fw->future(), *out);
760 if (mFutureWatchers.isEmpty()) {
761 out->setFinished();
762 }
763 delete fw;
764 delete future;
765 });
766 fw->setFuture(*future);
767 }
768}
769
770template<typename Out, typename In>
771ReduceExecutor<Out, In>::ReduceExecutor(ReduceTask<Out, In> reduce, ErrorHandler errorFunc, const ExecutorBasePtr &parent)
772 : ThenExecutor<Out, In>(reduce, errorFunc, parent)
773{
774 STORE_EXECUTOR_NAME("ReduceExecutor", Out, In);
775}
776
777template<typename Out, typename ... In>
778SyncThenExecutor<Out, In ...>::SyncThenExecutor(SyncThenTask<Out, In ...> then, ErrorHandler errorFunc, const ExecutorBasePtr &parent)
779 : Executor<typename detail::prevOut<In ...>::type, Out, In ...>(errorFunc, parent)
780 , mFunc(then)
781{
782 STORE_EXECUTOR_NAME("SyncThenExecutor", Out, In ...);
783}
784
785template<typename Out, typename ... In>
786void SyncThenExecutor<Out, In ...>::run(const ExecutionPtr &execution)
787{
788 if (execution->prevExecution) {
789 assert(execution->prevExecution->resultBase->isFinished());
790 }
791
792 run(execution, std::is_void<Out>());
793 execution->resultBase->setFinished();
794}
795
796template<typename Out, typename ... In>
797void SyncThenExecutor<Out, In ...>::run(const ExecutionPtr &execution, std::false_type)
798{
799 KAsync::Future<typename detail::prevOut<In ...>::type> *prevFuture =
800 execution->prevExecution
801 ? execution->prevExecution->result<typename detail::prevOut<In ...>::type>()
802 : nullptr;
803 (void) prevFuture; // silence 'set but not used' warning
804 KAsync::Future<Out> *future = execution->result<Out>();
805 future->setValue(SyncThenExecutor<Out, In...>::mFunc(prevFuture ? prevFuture->value() : In() ...));
806}
807
808template<typename Out, typename ... In>
809void SyncThenExecutor<Out, In ...>::run(const ExecutionPtr &execution, std::true_type)
810{
811 KAsync::Future<typename detail::prevOut<In ...>::type> *prevFuture =
812 execution->prevExecution
813 ? execution->prevExecution->result<typename detail::prevOut<In ...>::type>()
814 : nullptr;
815 (void) prevFuture; // silence 'set but not used' warning
816 SyncThenExecutor<Out, In ...>::mFunc(prevFuture ? prevFuture->value() : In() ...);
817}
818
819template<typename PrevOut, typename Out, typename In>
820SyncEachExecutor<PrevOut, Out, In>::SyncEachExecutor(SyncEachTask<Out, In> each, ErrorHandler errorFunc, const ExecutorBasePtr &parent)
821 : Executor<PrevOut, Out, In>(errorFunc, parent)
822 , mFunc(each)
823{
824 STORE_EXECUTOR_NAME("SyncEachExecutor", PrevOut, Out, In);
825}
826
827template<typename PrevOut, typename Out, typename In>
828void SyncEachExecutor<PrevOut, Out, In>::run(const ExecutionPtr &execution)
829{
830 assert(execution->prevExecution);
831 auto *prevFuture = execution->prevExecution->result<PrevOut>();
832 assert(prevFuture->isFinished());
833
834 auto out = execution->result<Out>();
835 if (prevFuture->value().isEmpty()) {
836 out->setFinished();
837 return;
838 }
839
840 for (auto arg : prevFuture->value()) {
841 run(out, arg, std::is_void<Out>());
842 }
843 out->setFinished();
844}
845
846template<typename PrevOut, typename Out, typename In>
847void SyncEachExecutor<PrevOut, Out, In>::run(KAsync::Future<Out> *out, const typename PrevOut::value_type &arg, std::false_type)
848{
849 out->setValue(out->value() + SyncEachExecutor<PrevOut, Out, In>::mFunc(arg));
850}
851
852template<typename PrevOut, typename Out, typename In>
853void SyncEachExecutor<PrevOut, Out, In>::run(KAsync::Future<Out> * /* unused */, const typename PrevOut::value_type &arg, std::true_type)
854{
855 SyncEachExecutor<PrevOut, Out, In>::mFunc(arg);
856}
857
858template<typename Out, typename In>
859SyncReduceExecutor<Out, In>::SyncReduceExecutor(SyncReduceTask<Out, In> reduce, ErrorHandler errorFunc, const ExecutorBasePtr &parent)
860 : SyncThenExecutor<Out, In>(reduce, errorFunc, parent)
861{
862 STORE_EXECUTOR_NAME("SyncReduceExecutor", Out, In);
863}
864
865
866} // namespace Private
867
868} // namespace KAsync
869
870
871
872#endif // KASYNC_H
873
874
diff --git a/async/src/async_impl.h b/async/src/async_impl.h
deleted file mode 100644
index 5b4e393..0000000
--- a/async/src/async_impl.h
+++ /dev/null
@@ -1,81 +0,0 @@
1/*
2 * Copyright 2014 - 2015 Daniel Vrátil <dvratil@redhat.com>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public License as
6 * published by the Free Software Foundation; either version 2 of
7 * the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public License
15 * along with this library. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#ifndef KASYNC_IMPL_H
19#define KASYNC_IMPL_H
20
21#include "async.h"
22#include <type_traits>
23
24namespace KAsync {
25
26namespace detail {
27
28template<typename T>
29struct identity
30{
31 typedef T type;
32};
33
34template<typename T, typename Enable = void>
35struct isIterable {
36 enum { value = 0 };
37};
38
39template<typename T>
40struct isIterable<T, typename std::conditional<false, typename T::iterator, void>::type> {
41 enum { value = 1 };
42};
43
44template<typename ... T>
45struct prevOut {
46 using type = typename std::tuple_element<0, std::tuple<T ..., void>>::type;
47};
48
49template<typename T>
50inline typename std::enable_if<!std::is_void<T>::value, void>::type
51copyFutureValue(const KAsync::Future<T> &in, KAsync::Future<T> &out)
52{
53 out.setValue(in.value());
54}
55
56template<typename T>
57inline typename std::enable_if<std::is_void<T>::value, void>::type
58copyFutureValue(const KAsync::Future<T> &in, KAsync::Future<T> &out)
59{
60 // noop
61}
62
63template<typename T>
64inline typename std::enable_if<!std::is_void<T>::value, void>::type
65aggregateFutureValue(const KAsync::Future<T> &in, KAsync::Future<T> &out)
66{
67 out.setValue(out.value() + in.value());
68}
69
70template<typename T>
71inline typename std::enable_if<std::is_void<T>::value, void>::type
72aggregateFutureValue(const KAsync::Future<T> &in, KAsync::Future<T> &out)
73{
74 // noop
75}
76
77} // namespace Detail
78
79} // namespace KAsync
80
81#endif // KASYNC_IMPL_H
diff --git a/async/src/debug.cpp b/async/src/debug.cpp
deleted file mode 100644
index 64a3a3b..0000000
--- a/async/src/debug.cpp
+++ /dev/null
@@ -1,75 +0,0 @@
1/*
2 * Copyright 2015 Daniel Vrátil <dvratil@redhat.com>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public License as
6 * published by the Free Software Foundation; either version 2 of
7 * the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public License
15 * along with this library. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "debug.h"
19#include "async.h"
20
21#include <QStringBuilder>
22
23#ifdef __GNUG__
24#include <cxxabi.h>
25#include <memory>
26#endif
27
28namespace KAsync
29{
30
31Q_LOGGING_CATEGORY(Debug, "org.kde.async", QtWarningMsg);
32Q_LOGGING_CATEGORY(Trace, "org.kde.async.trace", QtWarningMsg);
33
34QString demangleName(const char *name)
35{
36#ifdef __GNUG__
37 int status = 1; // uses -3 to 0 error codes
38 std::unique_ptr<char, void(*)(void*)> demangled(abi::__cxa_demangle(name, 0, 0, &status), std::free);
39 if (status == 0) {
40 return QString::fromLatin1(demangled.get());
41 }
42#endif
43 return QString::fromLatin1(name);
44}
45
46}
47
48using namespace KAsync;
49
50int Tracer::lastId = 0;
51
52Tracer::Tracer(Private::Execution *execution)
53 : mId(lastId++)
54 , mExecution(execution)
55{
56 msg(KAsync::Tracer::Start);
57}
58
59Tracer::~Tracer()
60{
61 msg(KAsync::Tracer::End);
62 // FIXME: Does this work on parallel executions?
63 --lastId;
64 --mId;
65}
66
67void Tracer::msg(Tracer::MsgType msgType)
68{
69#ifndef QT_NO_DEBUG
70 qCDebug(Trace).nospace() << (QString().fill(QLatin1Char(' '), mId * 2) %
71 (msgType == KAsync::Tracer::Start ? QStringLiteral(" START ") : QStringLiteral(" END ")) %
72 QString::number(mId) % QStringLiteral(" ") %
73 mExecution->executor->mExecutorName);
74#endif
75}
diff --git a/async/src/debug.h b/async/src/debug.h
deleted file mode 100644
index b2b2ff7..0000000
--- a/async/src/debug.h
+++ /dev/null
@@ -1,82 +0,0 @@
1/*
2 * Copyright 2015 Daniel Vrátil <dvratil@redhat.com>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public License as
6 * published by the Free Software Foundation; either version 2 of
7 * the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public License
15 * along with this library. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#ifndef KASYNC_DEBUG_H
19#define KASYNC_DEBUG_H
20
21#include "kasync_export.h"
22
23#include <QLoggingCategory>
24#include <QStringBuilder>
25
26#ifndef QT_NO_DEBUG
27#include <typeinfo>
28#endif
29
30namespace KAsync
31{
32
33Q_DECLARE_LOGGING_CATEGORY(Debug)
34Q_DECLARE_LOGGING_CATEGORY(Trace)
35
36KASYNC_EXPORT QString demangleName(const char *name);
37
38namespace Private
39{
40class Execution;
41}
42
43class KASYNC_EXPORT Tracer
44{
45public:
46 Tracer(Private::Execution *execution);
47 ~Tracer();
48
49private:
50 enum MsgType {
51 Start,
52 End
53 };
54 void msg(MsgType);
55
56 int mId;
57 Private::Execution *mExecution;
58
59 static int lastId;
60};
61
62}
63
64#ifndef QT_NO_DEBUG
65 template<typename T>
66 QString storeExecutorNameExpanded() {
67 return KAsync::demangleName(typeid(T).name());
68 }
69
70 template<typename T, typename ... Tail>
71 typename std::enable_if<sizeof ... (Tail) != 0, QString>::type
72 storeExecutorNameExpanded() {
73 return storeExecutorNameExpanded<T>() % QStringLiteral(", ") % storeExecutorNameExpanded<Tail ...>();
74 }
75
76 #define STORE_EXECUTOR_NAME(name, ...) \
77 ExecutorBase::mExecutorName = QStringLiteral(name) % QStringLiteral("<") % storeExecutorNameExpanded<__VA_ARGS__>() % QStringLiteral(">")
78#else
79 #define STORE_EXECUTOR_NAME(...)
80#endif
81
82#endif // KASYNC_DEBUG_H \ No newline at end of file
diff --git a/async/src/future.cpp b/async/src/future.cpp
deleted file mode 100644
index 9281cc8..0000000
--- a/async/src/future.cpp
+++ /dev/null
@@ -1,158 +0,0 @@
1/*
2 * Copyright 2014 Daniel Vrátil <dvratil@redhat.com>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public License as
6 * published by the Free Software Foundation; either version 2 of
7 * the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public License
15 * along with this library. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "future.h"
19#include "async.h"
20
21using namespace KAsync;
22
23FutureBase::PrivateBase::PrivateBase(const Private::ExecutionPtr &execution)
24 : finished(false)
25 , errorCode(0)
26 , mExecution(execution)
27{
28}
29
30FutureBase::PrivateBase::~PrivateBase()
31{
32 Private::ExecutionPtr executionPtr = mExecution.toStrongRef();
33 if (executionPtr) {
34 executionPtr->releaseFuture();
35 releaseExecution();
36 }
37}
38
39void FutureBase::PrivateBase::releaseExecution()
40{
41 mExecution.clear();
42}
43
44
45
46FutureBase::FutureBase()
47 : d(nullptr)
48{
49}
50
51FutureBase::FutureBase(FutureBase::PrivateBase *dd)
52 : d(dd)
53{
54}
55
56FutureBase::FutureBase(const KAsync::FutureBase &other)
57 : d(other.d)
58{
59}
60
61FutureBase::~FutureBase()
62{
63}
64
65void FutureBase::releaseExecution()
66{
67 d->releaseExecution();
68}
69
70void FutureBase::setFinished()
71{
72 if (isFinished()) {
73 return;
74 }
75 d->finished = true;
76 for (auto watcher : d->watchers) {
77 if (watcher) {
78 watcher->futureReadyCallback();
79 }
80 }
81}
82
83bool FutureBase::isFinished() const
84{
85 return d->finished;
86}
87
88void FutureBase::setError(int code, const QString &message)
89{
90 d->errorCode = code;
91 d->errorMessage = message;
92 setFinished();
93}
94
95int FutureBase::errorCode() const
96{
97 return d->errorCode;
98}
99
100QString FutureBase::errorMessage() const
101{
102 return d->errorMessage;
103}
104
105void FutureBase::setProgress(int processed, int total)
106{
107 setProgress((qreal) processed / total);
108}
109
110void FutureBase::setProgress(qreal progress)
111{
112 for (auto watcher : d->watchers) {
113 if (watcher) {
114 watcher->futureProgressCallback(progress);
115 }
116 }
117}
118
119
120
121void FutureBase::addWatcher(FutureWatcherBase* watcher)
122{
123 d->watchers.append(QPointer<FutureWatcherBase>(watcher));
124}
125
126
127
128
129
130FutureWatcherBase::FutureWatcherBase(QObject *parent)
131 : QObject(parent)
132 , d(new FutureWatcherBase::Private)
133{
134}
135
136FutureWatcherBase::~FutureWatcherBase()
137{
138 delete d;
139}
140
141void FutureWatcherBase::futureReadyCallback()
142{
143 Q_EMIT futureReady();
144}
145
146void FutureWatcherBase::futureProgressCallback(qreal progress)
147{
148 Q_EMIT futureProgress(progress);
149}
150
151void FutureWatcherBase::setFutureImpl(const FutureBase &future)
152{
153 d->future = future;
154 d->future.addWatcher(this);
155 if (future.isFinished()) {
156 futureReadyCallback();
157 }
158}
diff --git a/async/src/future.h b/async/src/future.h
deleted file mode 100644
index b2b723e..0000000
--- a/async/src/future.h
+++ /dev/null
@@ -1,257 +0,0 @@
1/*
2 * Copyright 2014 Daniel Vrátil <dvratil@redhat.com>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public License as
6 * published by the Free Software Foundation; either version 2 of
7 * the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public License
15 * along with this library. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#ifndef FUTURE_H
19#define FUTURE_H
20
21#include "kasync_export.h"
22
23class QEventLoop;
24
25#include <type_traits>
26
27#include <QSharedDataPointer>
28#include <QPointer>
29#include <QVector>
30#include <QEventLoop>
31
32namespace KAsync {
33
34class FutureWatcherBase;
35template<typename T>
36class FutureWatcher;
37
38namespace Private {
39class Execution;
40class ExecutorBase;
41
42typedef QSharedPointer<Execution> ExecutionPtr;
43} // namespace Private
44
45class KASYNC_EXPORT FutureBase
46{
47 friend class KAsync::Private::Execution;
48 friend class FutureWatcherBase;
49
50public:
51 virtual ~FutureBase();
52
53 void setFinished();
54 bool isFinished() const;
55 void setError(int code = 1, const QString &message = QString());
56 int errorCode() const;
57 QString errorMessage() const;
58
59 void setProgress(qreal progress);
60 void setProgress(int processed, int total);
61
62protected:
63 class PrivateBase : public QSharedData
64 {
65 public:
66 PrivateBase(const KAsync::Private::ExecutionPtr &execution);
67 virtual ~PrivateBase();
68
69 void releaseExecution();
70
71 bool finished;
72 int errorCode;
73 QString errorMessage;
74
75 QVector<QPointer<FutureWatcherBase>> watchers;
76 private:
77 QWeakPointer<KAsync::Private::Execution> mExecution;
78 };
79
80 FutureBase();
81 FutureBase(FutureBase::PrivateBase *dd);
82 FutureBase(const FutureBase &other);
83
84 void addWatcher(KAsync::FutureWatcherBase *watcher);
85 void releaseExecution();
86
87protected:
88 QExplicitlySharedDataPointer<PrivateBase> d;
89};
90
91template<typename T>
92class FutureWatcher;
93
94template<typename T>
95class Future;
96
97template<typename T>
98class FutureGeneric : public FutureBase
99{
100 friend class FutureWatcher<T>;
101
102public:
103 void waitForFinished() const
104 {
105 if (isFinished()) {
106 return;
107 }
108 FutureWatcher<T> watcher;
109 QEventLoop eventLoop;
110 QObject::connect(&watcher, &KAsync::FutureWatcher<T>::futureReady,
111 &eventLoop, &QEventLoop::quit);
112 watcher.setFuture(*static_cast<const KAsync::Future<T>*>(this));
113 eventLoop.exec();
114 }
115
116protected:
117 FutureGeneric(const KAsync::Private::ExecutionPtr &execution)
118 : FutureBase(new Private(execution))
119 {}
120
121 FutureGeneric(const FutureGeneric<T> &other)
122 : FutureBase(other)
123 {}
124
125protected:
126 class Private : public FutureBase::PrivateBase
127 {
128 public:
129 Private(const KAsync::Private::ExecutionPtr &execution)
130 : FutureBase::PrivateBase(execution)
131 {}
132
133 typename std::conditional<std::is_void<T>::value, int /* dummy */, T>::type
134 value;
135 };
136};
137
138
139template<typename T>
140class Future : public FutureGeneric<T>
141{
142 friend class KAsync::Private::ExecutorBase;
143
144 template<typename T_>
145 friend class KAsync::FutureWatcher;
146
147public:
148 Future()
149 : FutureGeneric<T>(KAsync::Private::ExecutionPtr())
150 {}
151
152 Future(const Future<T> &other)
153 : FutureGeneric<T>(other)
154 {}
155
156 void setValue(const T &value)
157 {
158 static_cast<typename FutureGeneric<T>::Private*>(this->d.data())->value = value;
159 }
160
161 T value() const
162 {
163 return static_cast<typename FutureGeneric<T>::Private*>(this->d.data())->value;
164 }
165
166protected:
167 Future(const KAsync::Private::ExecutionPtr &execution)
168 : FutureGeneric<T>(execution)
169 {}
170
171};
172
173template<>
174class Future<void> : public FutureGeneric<void>
175{
176 friend class KAsync::Private::ExecutorBase;
177
178public:
179 Future()
180 : FutureGeneric<void>(KAsync::Private::ExecutionPtr())
181 {}
182
183 Future(const Future<void> &other)
184 : FutureGeneric<void>(other)
185 {}
186
187protected:
188 Future(const KAsync::Private::ExecutionPtr &execution)
189 : FutureGeneric<void>(execution)
190 {}
191};
192
193
194
195
196
197class KASYNC_EXPORT FutureWatcherBase : public QObject
198{
199 Q_OBJECT
200
201 friend class FutureBase;
202
203Q_SIGNALS:
204 void futureReady();
205 void futureProgress(qreal progress);
206
207protected:
208 FutureWatcherBase(QObject *parent = nullptr);
209 virtual ~FutureWatcherBase();
210
211 void futureReadyCallback();
212 void futureProgressCallback(qreal progress);
213
214 void setFutureImpl(const KAsync::FutureBase &future);
215
216protected:
217 class Private {
218 public:
219 KAsync::FutureBase future;
220 };
221
222 Private * const d;
223
224private:
225 Q_DISABLE_COPY(FutureWatcherBase);
226};
227
228template<typename T>
229class FutureWatcher : public FutureWatcherBase
230{
231 friend class KAsync::FutureGeneric<T>;
232
233public:
234 FutureWatcher(QObject *parent = nullptr)
235 : FutureWatcherBase(parent)
236 {}
237
238 ~FutureWatcher()
239 {}
240
241 void setFuture(const KAsync::Future<T> &future)
242 {
243 setFutureImpl(*static_cast<const KAsync::FutureBase*>(&future));
244 }
245
246 KAsync::Future<T> future() const
247 {
248 return *static_cast<KAsync::Future<T>*>(&d->future);
249 }
250
251private:
252 Q_DISABLE_COPY(FutureWatcher<T>);
253};
254
255} // namespace Async
256
257#endif // FUTURE_H
diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt
index 4fb8a67..2ece210 100644
--- a/common/CMakeLists.txt
+++ b/common/CMakeLists.txt
@@ -50,5 +50,5 @@ generate_flatbuffers(
50generate_export_header(${PROJECT_NAME} BASE_NAME Akonadi2Common EXPORT_FILE_NAME akonadi2common_export.h) 50generate_export_header(${PROJECT_NAME} BASE_NAME Akonadi2Common EXPORT_FILE_NAME akonadi2common_export.h)
51SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES LINKER_LANGUAGE CXX) 51SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES LINKER_LANGUAGE CXX)
52qt5_use_modules(${PROJECT_NAME} Network) 52qt5_use_modules(${PROJECT_NAME} Network)
53target_link_libraries(${PROJECT_NAME} ${storage_LIBS} KF5Async) 53target_link_libraries(${PROJECT_NAME} ${storage_LIBS} KF5::Async)
54install(TARGETS ${PROJECT_NAME} ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) 54install(TARGETS ${PROJECT_NAME} ${KDE_INSTALL_TARGETS_DEFAULT_ARGS})
diff --git a/common/clientapi.h b/common/clientapi.h
index 0ce1691..c098bb5 100644
--- a/common/clientapi.h
+++ b/common/clientapi.h
@@ -28,8 +28,10 @@
28#include <QEventLoop> 28#include <QEventLoop>
29#include <functional> 29#include <functional>
30#include <memory> 30#include <memory>
31
32#include <Async/Async>
33
31#include "threadboundary.h" 34#include "threadboundary.h"
32#include "async/src/async.h"
33#include "resultprovider.h" 35#include "resultprovider.h"
34 36
35namespace async { 37namespace async {
diff --git a/common/facade.h b/common/facade.h
index dcb30b6..5743aa2 100644
--- a/common/facade.h
+++ b/common/facade.h
@@ -23,7 +23,8 @@
23 23
24#include <QByteArray> 24#include <QByteArray>
25 25
26#include "async/src/async.h" 26#include <Async/Async>
27
27#include "resourceaccess.h" 28#include "resourceaccess.h"
28#include "commands.h" 29#include "commands.h"
29#include "createentity_generated.h" 30#include "createentity_generated.h"
diff --git a/common/pipeline.cpp b/common/pipeline.cpp
index ea82720..21cf1c5 100644
--- a/common/pipeline.cpp
+++ b/common/pipeline.cpp
@@ -29,7 +29,6 @@
29#include "metadata_generated.h" 29#include "metadata_generated.h"
30#include "createentity_generated.h" 30#include "createentity_generated.h"
31#include "entitybuffer.h" 31#include "entitybuffer.h"
32#include "async/src/async.h"
33#include "log.h" 32#include "log.h"
34 33
35namespace Akonadi2 34namespace Akonadi2
diff --git a/common/pipeline.h b/common/pipeline.h
index d25fc56..b695bde 100644
--- a/common/pipeline.h
+++ b/common/pipeline.h
@@ -27,7 +27,8 @@
27 27
28#include <akonadi2common_export.h> 28#include <akonadi2common_export.h>
29#include <storage.h> 29#include <storage.h>
30#include "async/src/async.h" 30
31#include <Async/Async>
31 32
32#include "entity_generated.h" 33#include "entity_generated.h"
33 34
diff --git a/common/resource.h b/common/resource.h
index 170e080..ea1e9d8 100644
--- a/common/resource.h
+++ b/common/resource.h
@@ -21,7 +21,8 @@
21#include <akonadi2common_export.h> 21#include <akonadi2common_export.h>
22#include <clientapi.h> 22#include <clientapi.h>
23#include <pipeline.h> 23#include <pipeline.h>
24#include <async/src/async.h> 24
25#include <Async/Async>
25 26
26namespace Akonadi2 27namespace Akonadi2
27{ 28{
diff --git a/common/resourceaccess.h b/common/resourceaccess.h
index 648b12e..b779db9 100644
--- a/common/resourceaccess.h
+++ b/common/resourceaccess.h
@@ -24,8 +24,9 @@
24#include <QObject> 24#include <QObject>
25#include <QTimer> 25#include <QTimer>
26 26
27#include <Async/Async>
28
27#include <flatbuffers/flatbuffers.h> 29#include <flatbuffers/flatbuffers.h>
28#include <async/src/async.h>
29 30
30namespace Akonadi2 31namespace Akonadi2
31{ 32{
diff --git a/examples/dummyresource/resourcefacade.h b/examples/dummyresource/resourcefacade.h
index 82ac41e..5d0291c 100644
--- a/examples/dummyresource/resourcefacade.h
+++ b/examples/dummyresource/resourcefacade.h
@@ -20,7 +20,8 @@
20#pragma once 20#pragma once
21 21
22#include "common/clientapi.h" 22#include "common/clientapi.h"
23#include "async/src/async.h" 23
24#include <Async/Async>
24 25
25class QSettings; 26class QSettings;
26 27
diff --git a/examples/dummyresource/resourcefactory.h b/examples/dummyresource/resourcefactory.h
index 751f2d8..f5caf61 100644
--- a/examples/dummyresource/resourcefactory.h
+++ b/examples/dummyresource/resourcefactory.h
@@ -20,9 +20,10 @@
20#pragma once 20#pragma once
21 21
22#include "common/genericresource.h" 22#include "common/genericresource.h"
23#include "async/src/async.h"
24#include "common/messagequeue.h" 23#include "common/messagequeue.h"
25 24
25#include <Async/Async>
26
26#include <flatbuffers/flatbuffers.h> 27#include <flatbuffers/flatbuffers.h>
27 28
28//TODO: a little ugly to have this in two places, once here and once in Q_PLUGIN_METADATA 29//TODO: a little ugly to have this in two places, once here and once in Q_PLUGIN_METADATA
diff --git a/synchronizer/CMakeLists.txt b/synchronizer/CMakeLists.txt
index 4b6412b..fe938e9 100644
--- a/synchronizer/CMakeLists.txt
+++ b/synchronizer/CMakeLists.txt
@@ -8,6 +8,6 @@ set(akonadi2synchronizer_SRCS
8) 8)
9 9
10add_executable(${PROJECT_NAME} ${akonadi2synchronizer_SRCS}) 10add_executable(${PROJECT_NAME} ${akonadi2synchronizer_SRCS})
11target_link_libraries(${PROJECT_NAME} akonadi2common KF5Async) 11target_link_libraries(${PROJECT_NAME} akonadi2common KF5::Async)
12qt5_use_modules(${PROJECT_NAME} Widgets Network) 12qt5_use_modules(${PROJECT_NAME} Widgets Network)
13install(TARGETS ${PROJECT_NAME} ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) 13install(TARGETS ${PROJECT_NAME} ${KDE_INSTALL_TARGETS_DEFAULT_ARGS})