From 8f2fed8d2a1b23a8f318047b6592ad64b6ecbd22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dan=20Vr=C3=A1til?= Date: Mon, 30 Mar 2015 17:49:26 +0200 Subject: Async: initial support for native chaining of KJobs It is now possible use KJob-derived jobs with libasync without having to write lambda wrappers. auto job = Async::start(); job.exec(arg1, arg2, ...); The reason for this approach (instead of taking KJob* as an argument is that we usually want the KJob ctor arguments to depend on result of previous job. At least in case of Async::start() however it makes sense to support passing KJob* as an argument (not yet implemented). In future we should also support custom error handlers. The KJob integration is build-time optional, but enabled by default (pass -DWITH_KJOB=FALSE to CMake to disable). Adds KCoreAddons dependency. --- async/CMakeLists.txt | 10 ++++++ async/autotests/CMakeLists.txt | 8 ++++- async/autotests/kjobtest.cpp | 69 ++++++++++++++++++++++++++++++++++++++++++ async/autotests/testkjob.cpp | 28 +++++++++++++++++ async/autotests/testkjob.h | 48 +++++++++++++++++++++++++++++ async/src/CMakeLists.txt | 6 +++- async/src/async.h | 47 +++++++++++++++++++++++++++- 7 files changed, 213 insertions(+), 3 deletions(-) create mode 100644 async/autotests/kjobtest.cpp create mode 100644 async/autotests/testkjob.cpp create mode 100644 async/autotests/testkjob.h (limited to 'async') diff --git a/async/CMakeLists.txt b/async/CMakeLists.txt index 19ac407..a6b53f8 100644 --- a/async/CMakeLists.txt +++ b/async/CMakeLists.txt @@ -1,2 +1,12 @@ +project(libasync) + +option(WITH_KJOB "Enable native support for KJob in libasync API (enabled by default)" ON) + +if (WITH_KJOB) + set(MINUMUM_FRAMEWORKS_VERSION "5.8.0") + find_package(KF5CoreAddons REQUIRED ${MINUMUM_FRAMEWORKS_VERSION}) + add_definitions(-DWITH_KJOB) +endif() + add_subdirectory(src) add_subdirectory(autotests) \ No newline at end of file diff --git a/async/autotests/CMakeLists.txt b/async/autotests/CMakeLists.txt index a2bedc8..8116f13 100644 --- a/async/autotests/CMakeLists.txt +++ b/async/autotests/CMakeLists.txt @@ -2,4 +2,10 @@ include_directories(../src ${CMAKE_CURRENT_BINARY_DIR}) add_executable(asynctest asynctest.cpp) qt5_use_modules(asynctest Test) -target_link_libraries(asynctest akonadi2async Qt5::Core Qt5::Test) \ No newline at end of file +target_link_libraries(asynctest akonadi2async Qt5::Core Qt5::Test) + +if (WITH_KJOB) + add_executable(kjobtest kjobtest.cpp testkjob.cpp) + qt5_use_modules(kjobtest Test) + target_link_libraries(kjobtest akonadi2async Qt5::Core Qt5::Test KF5::CoreAddons) +endif () \ No newline at end of file diff --git a/async/autotests/kjobtest.cpp b/async/autotests/kjobtest.cpp new file mode 100644 index 0000000..be92d68 --- /dev/null +++ b/async/autotests/kjobtest.cpp @@ -0,0 +1,69 @@ +/* + * Copyright 2015 Daniel Vrátil + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License or (at your option) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include "../src/async.h" +#include "testkjob.h" + +#include + +class KJobTest : public QObject +{ + Q_OBJECT + +public: + KJobTest() + {} + + ~KJobTest() + {} + +private Q_SLOTS: + void testSingleKJob(); + void testKJobChain(); + +}; + +void KJobTest::testSingleKJob() +{ + auto job = Async::start(); + + auto future = job.exec(42); + future.waitForFinished(); + + QVERIFY(future.isFinished()); + QCOMPARE(future.value(), 42); +} + +void KJobTest::testKJobChain() +{ + auto job = Async::start() + .then(); + + auto future = job.exec(42); + future.waitForFinished(); + + QVERIFY(future.isFinished()); + QCOMPARE(future.value(), 42); +} + +QTEST_MAIN(KJobTest) + +#include "kjobtest.moc" \ No newline at end of file diff --git a/async/autotests/testkjob.cpp b/async/autotests/testkjob.cpp new file mode 100644 index 0000000..b86f913 --- /dev/null +++ b/async/autotests/testkjob.cpp @@ -0,0 +1,28 @@ +#include "testkjob.h" + +TestKJob::TestKJob(int result) + : mResult(result) +{ + connect(&mTimer, &QTimer::timeout, + this, &TestKJob::onTimeout); + mTimer.setSingleShot(true); + mTimer.setInterval(200); +} + +TestKJob::~TestKJob() +{} + +void TestKJob::start() +{ + mTimer.start(); +} + +int TestKJob::result() +{ + return mResult; +} + +void TestKJob::onTimeout() +{ + emitResult(); +} \ No newline at end of file diff --git a/async/autotests/testkjob.h b/async/autotests/testkjob.h new file mode 100644 index 0000000..eead98e --- /dev/null +++ b/async/autotests/testkjob.h @@ -0,0 +1,48 @@ +/* + * Copyright 2015 Daniel Vrátil + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License or (at your option) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#ifndef TESTKJOB_H +#define TESTKJOB_H + +#include +#include + +class TestKJob : public KJob +{ + Q_OBJECT + +public: + TestKJob(int result); + ~TestKJob(); + + void start(); + + int result(); + +private Q_SLOTS: + void onTimeout(); + +private: + int mResult; + QTimer mTimer; +}; + +#endif // TESTKJOB_H \ No newline at end of file diff --git a/async/src/CMakeLists.txt b/async/src/CMakeLists.txt index 7d17f2b..6f8ab63 100644 --- a/async/src/CMakeLists.txt +++ b/async/src/CMakeLists.txt @@ -8,5 +8,9 @@ set(async_SRCS ) add_library(${PROJECT_NAME} SHARED ${async_SRCS}) -target_link_libraries(${PROJECT_NAME} Qt5::Core) +target_link_libraries(${PROJECT_NAME} PUBLIC Qt5::Core) +if (WITH_KJOB) + target_link_libraries(${PROJECT_NAME} PUBLIC KF5::CoreAddons) +endif () + install(TARGETS ${PROJECT_NAME} ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) diff --git a/async/src/async.h b/async/src/async.h index 2be1260..8da3daa 100644 --- a/async/src/async.h +++ b/async/src/async.h @@ -33,6 +33,11 @@ #include +#ifdef WITH_KJOB +#include +#endif + + /* * TODO: instead of passing the future objects callbacks could be provided for result reporting (we can still use the future object internally */ @@ -196,10 +201,15 @@ Job start(ThenTask func); template Job start(SyncThenTask func); +#ifdef WITH_KJOB +template +Job start(); +#endif + /** * A null job. - * + * * An async noop. * */ @@ -283,6 +293,11 @@ class Job : public JobBase template friend Job start(Async::SyncThenTask func); +#ifdef WITH_KJOB + template + friend Job start(); +#endif + public: template Job then(ThenTask func, ErrorHandler errorFunc = ErrorHandler()) @@ -304,6 +319,14 @@ public: return then(nestedJobWrapper(otherJob), errorFunc); } +#ifdef WITH_KJOB + template + Job then() + { + return start(); + } +#endif + template Job each(EachTask func, ErrorHandler errorFunc = ErrorHandler()) { @@ -442,6 +465,28 @@ Job start(SyncThenTask func) new Private::SyncThenExecutor(func, ErrorHandler(), Private::ExecutorBasePtr()))); } +#ifdef WITH_KJOB +template +Job start() +{ + return Job(Private::ExecutorBasePtr( + new Private::ThenExecutor([](const Args & ... args, Async::Future &future) + { + KJobType *job = new KJobType(args ...); + job->connect(job, &KJob::finished, + [&future](KJob *job) { + if (job->error()) { + future.setError(job->error(), job->errorString()); + } else { + future.setValue((static_cast(job)->*KJobResultMethod)()); + future.setFinished(); + } + }); + job->start(); + }, ErrorHandler(), Private::ExecutorBasePtr()))); +} +#endif + template Job null() { -- cgit v1.2.3