Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F140096
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Size
9 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/src/qt-promise-handler.hpp b/src/qt-promise-handler.hpp
new file mode 100644
index 0000000..b12266f
--- /dev/null
+++ b/src/qt-promise-handler.hpp
@@ -0,0 +1,210 @@
+/*
+ * This file is part of kazv.
+ * SPDX-FileCopyrightText: 2020-2021 Tusooa Zhu <tusooa@kazv.moe>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#pragma once
+
+#include <libkazv-config.hpp>
+
+#include <future>
+
+#include <QObject>
+#include <QMetaObject>
+
+#include <promise-interface.hpp>
+
+template<class T>
+class QtPromise;
+
+namespace QtPromiseDetail
+{
+ struct QtPromiseHelper
+ {
+ template<class T>
+ using PromiseType = QtPromise<T>;
+ };
+
+ struct IdentityFunc
+ {
+ template<class T>
+ constexpr T &&operator()(T &&t) const {
+ return std::forward<T>(t);
+ }
+ };
+
+ template<class Func>
+ void post(std::reference_wrapper<QObject> obj, Func &&func)
+ {
+ QMetaObject::invokeMethod(&obj.get(), std::forward<Func>(func), Qt::QueuedConnection);
+ }
+}
+
+template<class T>
+class QtPromise : public Kazv::AbstractPromise<QtPromiseDetail::QtPromiseHelper::PromiseType, T>
+{
+ using BaseT = Kazv::AbstractPromise<QtPromiseDetail::QtPromiseHelper::PromiseType, T>;
+
+ template<class FuncT, class PromiseT, class ResolveT>
+ struct WaitHelper
+ {
+ void wait() const {
+ if (p.ready()) {
+ auto res = func(p.get());
+ using ResT = decltype(res);
+ if constexpr (Kazv::isPromise<ResT>) {
+ QtPromiseDetail::post(
+ executor,
+ [w=WaitHelper<QtPromiseDetail::IdentityFunc, ResT, ResolveT>{
+ executor,
+ res,
+ QtPromiseDetail::IdentityFunc{},
+ resolve,
+ }]() mutable {
+ w.wait();
+ });
+ } else {
+ resolve(res);
+ }
+ } else {
+ QtPromiseDetail::post(
+ executor,
+ [*this]() mutable {
+ wait();
+ }
+ );
+ }
+ }
+
+ std::reference_wrapper<QObject> executor;
+ PromiseT p;
+ FuncT func;
+ ResolveT resolve;
+ };
+
+ struct ResolveHelper
+ {
+ template<class ValT>
+ void operator()(ValT val) const {
+ using ResT = std::decay_t<decltype(val)>;
+ if constexpr (Kazv::isPromise<ResT>) {
+ auto w = WaitHelper<QtPromiseDetail::IdentityFunc, ResT, ResolveHelper>{
+ executor,
+ val,
+ QtPromiseDetail::IdentityFunc{},
+ *this
+ };
+ w.wait();
+ } else {
+ p->set_value(std::move(val));
+ }
+ }
+
+ std::reference_wrapper<QObject> executor;
+ std::shared_ptr<std::promise<T>> p;
+ };
+public:
+ QtPromise(std::reference_wrapper<QObject> executor, T value)
+ : BaseT(this)
+ , m_executor(std::move(executor)) {
+ std::promise<T> p;
+ m_val = p.get_future().share();
+ p.set_value(std::move(value));
+ }
+
+ template<class Func>
+ QtPromise(std::reference_wrapper<QObject> executor, Func &&callback)
+ : BaseT(this)
+ , m_executor(std::move(executor)) {
+ auto p = std::make_shared<std::promise<T>>();
+ m_val = p->get_future().share();
+ auto resolve = ResolveHelper{m_executor, p};
+
+ QtPromiseDetail::post(
+ m_executor,
+ [=, callback=std::forward<Func>(callback),
+ resolve=std::move(resolve)]() {
+ callback(resolve);
+ });
+ }
+
+ // FuncT: (DataT) -> AnotherDataT
+ // where AnotherDataT = PromiseThenResult<FuncT, typename BaseT::DataT>
+ template<class FuncT>
+ auto then(FuncT &&func)
+ -> QtPromise<Kazv::PromiseThenResult<FuncT, typename BaseT::DataT>> {
+ return QtPromise<Kazv::PromiseThenResult<FuncT, typename BaseT::DataT>>(
+ m_executor,
+ [=, func=std::forward<FuncT>(func), *this](auto resolve) {
+ auto waitHelper = WaitHelper<std::decay_t<FuncT>,
+ QtPromise,
+ std::decay_t<decltype(resolve)>>{
+ m_executor,
+ *this,
+ func,
+ resolve
+ };
+ waitHelper.wait();
+ });
+ }
+
+ bool ready() const {
+ return m_val.wait_for(std::chrono::seconds(0)) == std::future_status::ready;
+ }
+
+ T get() const {
+ return m_val.get();
+ }
+private:
+ std::reference_wrapper<QObject> m_executor;
+ std::shared_future<T> m_val;
+};
+
+class QtPromiseHandler : public Kazv::PromiseInterface<QtPromiseHandler,
+ QtPromiseDetail::QtPromiseHelper::PromiseType>
+{
+ using BaseT = Kazv::PromiseInterface<QtPromiseHandler,
+ QtPromiseDetail::QtPromiseHelper::PromiseType>;
+public:
+ template<class T>
+ using PromiseT = QtPromise<T>;
+
+ QtPromiseHandler(std::reference_wrapper<QObject> executor)
+ : BaseT(this)
+ , m_executor(executor)
+ {}
+
+ QtPromiseHandler(const QtPromiseHandler &that)
+ : BaseT(this)
+ , m_executor(that.m_executor)
+ {}
+
+ QtPromiseHandler(QtPromiseHandler &&that)
+ : BaseT(this)
+ , m_executor(std::move(that.m_executor))
+ {}
+
+ QtPromiseHandler &operator=(const QtPromiseHandler &that) {
+ m_executor = that.m_executor;
+ return *this;
+ }
+
+ QtPromiseHandler &operator=(QtPromiseHandler &&that) {
+ m_executor = std::move(that.m_executor);
+ return *this;
+ }
+
+ template<class T, class FuncT>
+ PromiseT<T> create(FuncT &&func) {
+ return PromiseT<T>(m_executor, std::forward<FuncT>(func));
+ }
+
+ template<class T>
+ PromiseT<T> createResolved(T val) {
+ return PromiseT<T>(m_executor, std::move(val));
+ }
+
+private:
+ std::reference_wrapper<QObject> m_executor;
+};
diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt
index 6015c55..fe6caa1 100644
--- a/src/tests/CMakeLists.txt
+++ b/src/tests/CMakeLists.txt
@@ -1,4 +1,5 @@
ecm_add_tests(
qt-job-handler-test.cpp
+ qt-promise-handler-test.cpp
LINK_LIBRARIES Qt5::Test libkazv::kazvall kazvprivlib
)
diff --git a/src/tests/qt-promise-handler-test.cpp b/src/tests/qt-promise-handler-test.cpp
new file mode 100644
index 0000000..d989c3d
--- /dev/null
+++ b/src/tests/qt-promise-handler-test.cpp
@@ -0,0 +1,109 @@
+/*
+ * This file is part of kazv.
+ * SPDX-FileCopyrightText: 2020-2021 Tusooa Zhu <tusooa@kazv.moe>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#include <libkazv-config.hpp>
+
+#include <memory>
+#include <vector>
+
+#include <QTimer>
+
+#include "qt-promise-handler-test.hpp"
+
+#include "qt-promise-handler.hpp"
+
+namespace
+{
+ struct MockDataStruct
+ {
+ int i{};
+ };
+}
+
+void QtPromiseHandlerTest::testPromise()
+{
+ QEventLoop loop;
+ QObject *obj = new QObject(&loop);
+ auto ph = QtPromiseHandler(std::ref(*obj));
+
+ std::vector<int> v;
+
+ auto p1 = ph.create<int>([&v](auto resolve) {
+ qDebug() << "p1";
+ v.push_back(1);
+ resolve(2);
+ });
+
+ auto p2 = p1.then([&v, &ph](int val) {
+ qDebug() << "p2";
+ v.push_back(val);
+ return ph.createResolved(3);
+ });
+
+ auto p3 = p2.then([&v, &ph](int val) {
+ qDebug() << "p3";
+ v.push_back(val);
+ return ph.createResolved(-1);
+ });
+
+ auto p4 = p3.then([](int val) {
+ qDebug() << "p4" << val;
+ [=] { QVERIFY(val == -1); }();
+ return 5;
+ });
+
+ auto p5 = p4.then([](int val) {
+ qDebug() << "p5" << val;
+ [=] { QVERIFY(val == 5); }();
+ return MockDataStruct{6};
+ });
+
+ auto p6 = p5.then([obj, &loop](MockDataStruct m) {
+ qDebug() << "p6" << m.i;
+ [=] { QVERIFY(m.i == 6); }();
+ obj->deleteLater();
+ loop.quit();
+ return 0;
+ });
+
+ QObject::connect(obj, &QObject::destroyed,
+ this, [&v] {
+ qDebug() << "QObject::destroyed()";
+ QVERIFY((v == std::vector<int>{ 1, 2, 3 }));
+ });
+
+ loop.exec();
+}
+
+void QtPromiseHandlerTest::testTimer()
+{
+ QEventLoop loop;
+ QObject *obj = new QObject(&loop);
+ auto ph = QtPromiseHandler(std::ref(*obj));
+
+ auto pTimer = ph.create<int>([](auto resolve) {
+ QTimer::singleShot(300, [resolve]() { resolve(20); });
+ });
+
+ int i;
+
+ auto pTimer2 = pTimer.then([&i, &loop, obj](int val) -> int {
+ i = val;
+ obj->deleteLater();
+ loop.quit();
+ return 0;
+ });
+
+ QObject::connect(obj, &QObject::destroyed,
+ this, [&i] {
+ qDebug() << "QObject::destroyed()";
+ QVERIFY(i == 20);
+ });
+
+ loop.exec();
+}
+
+QTEST_MAIN(QtPromiseHandlerTest)
diff --git a/src/tests/qt-promise-handler-test.hpp b/src/tests/qt-promise-handler-test.hpp
new file mode 100644
index 0000000..239f4a4
--- /dev/null
+++ b/src/tests/qt-promise-handler-test.hpp
@@ -0,0 +1,18 @@
+/*
+ * This file is part of kazv.
+ * SPDX-FileCopyrightText: 2020-2021 Tusooa Zhu <tusooa@kazv.moe>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#pragma once
+
+#include <QtTest>
+
+class QtPromiseHandlerTest : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+ void testPromise();
+ void testTimer();
+};
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sun, Jan 19, 12:34 PM (5 h, 13 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
55165
Default Alt Text
(9 KB)
Attached To
Mode
rK kazv
Attached
Detach File
Event Timeline
Log In to Comment