Коммит 19e6eeb6 создал по автору Зарубин Виталий Викторович's avatar Зарубин Виталий Викторович
Просмотр файлов

feat: add support macos

владелец 802762b5
auroraApp/kmp.libs/** filter=lfs diff=lfs merge=lfs -text
auroraApp/libs.kmp/** filter=lfs diff=lfs merge=lfs -text
auroraApp/libs.aarch64/** filter=lfs diff=lfs merge=lfs -text
/build*
# IDE
.vscode
.idea
# macOS
.DS_Store
......@@ -3,78 +3,72 @@ TARGET = kmpbindings
CONFIG += staticlib warn_off
HEADERS += \
shared/uriLauncher/AuroraUriLauncher.hpp \
ru/auroraos/kmp/qtbindings/CoroutineOperation.hpp \
ru/auroraos/kmp/qtbindings/CallbackContext.hpp \
ru/auroraos/kmp/qtbindings/CoroutineException.hpp \
ru/auroraos/kmp/qtbindings/cruntime.h \
ru/auroraos/kmp/qtbindings/CoroutineLauncher.hpp \
shared/vibration/AuroraVibration.hpp \
shared/sharedPreferencesSecure/AuroraSharedPreferencesSecure.hpp \
shared/wakelock/AuroraWakeLock.hpp \
shared/cameraInfo/AuroraCameraInfo.hpp \
shared/shareData/AuroraShareData.hpp \
shared/sharedPreferences/AuroraSharedPreferences.hpp \
shared/localNotification/AuroraLocalNotification.hpp \
shared/locationInfo/AuroraLocationInfo.hpp \
shared/deviceInfo/AuroraSimCards.hpp \
shared/deviceInfo/AuroraStorageInfo.hpp \
shared/deviceInfo/AuroraDeviceInfo.hpp \
shared/sharedPreferencesSecure/AuroraSharedPreferencesSecure.hpp \
shared/themeInfo/AuroraThemeInfo.hpp \
shared/shareData/AuroraShareData.hpp \
shared/sharedPreferences/AuroraSharedPreferences.hpp \
shared/cameraInfo/AuroraCameraInfo.hpp \
shared/connectivityInfo/AuroraConnectivityInfo.hpp \
shared/vibration/AuroraVibration.hpp \
shared/sensorsInfo/AuroraSensorsInfo.hpp \
shared/uriLauncher/AuroraUriLauncher.hpp \
shared/pathInfo/AuroraPathInfo.hpp \
shared/wakelock/AuroraWakeLock.hpp \
shared/localNotification/AuroraLocalNotification.hpp \
shared/locationInfo/AuroraLocationInfo.hpp \
shared/batteryInfo/AuroraBatteryInfo.hpp \
shared/sensorsInfo/AuroraSensorsInfo.hpp \
shared/packageInfo/AuroraPackageInfo.hpp \
ru/auroraos/kmp/qtbindings/cruntime.h \
ru/auroraos/kmp/qtbindings/CoroutineLauncher.hpp \
ru/auroraos/kmp/qtbindings/CallbackContext.hpp \
ru/auroraos/kmp/qtbindings/CoroutineException.hpp \
ru/auroraos/kmp/qtbindings/CoroutineOperation.hpp \
SOURCES += \
shared/uriLauncher/AuroraUriLauncher.cpp \
shared/deviceInfo/AuroraSimCards.cpp \
shared/deviceInfo/AuroraDeviceInfo.cpp \
shared/deviceInfo/AuroraStorageInfo.cpp \
ru/auroraos/kmp/qtbindings/CoroutineLauncher.cpp \
ru/auroraos/kmp/qtbindings/CallbackContext.cpp \
ru/auroraos/kmp/qtbindings/CoroutineException.cpp \
shared/vibration/AuroraVibration.cpp \
shared/sharedPreferencesSecure/AuroraSharedPreferencesSecure.cpp \
shared/themeInfo/AuroraThemeInfo.cpp \
shared/wakelock/AuroraWakeLock.cpp \
shared/cameraInfo/AuroraCameraInfo.cpp \
shared/shareData/AuroraShareData.cpp \
shared/sharedPreferences/AuroraSharedPreferences.cpp \
shared/cameraInfo/AuroraCameraInfo.cpp \
shared/connectivityInfo/AuroraConnectivityInfo.cpp \
shared/vibration/AuroraVibration.cpp \
shared/sensorsInfo/AuroraSensorsInfo.cpp \
shared/pathInfo/AuroraPathInfo.cpp \
shared/wakelock/AuroraWakeLock.cpp \
shared/localNotification/AuroraLocalNotification.cpp \
shared/locationInfo/AuroraLocationInfo.cpp \
shared/deviceInfo/AuroraDeviceInfo.cpp \
shared/deviceInfo/AuroraStorageInfo.cpp \
shared/deviceInfo/AuroraSimCards.cpp \
shared/themeInfo/AuroraThemeInfo.cpp \
shared/connectivityInfo/AuroraConnectivityInfo.cpp \
shared/uriLauncher/AuroraUriLauncher.cpp \
shared/pathInfo/AuroraPathInfo.cpp \
shared/batteryInfo/AuroraBatteryInfo.cpp \
shared/sensorsInfo/AuroraSensorsInfo.cpp \
shared/packageInfo/AuroraPackageInfo.cpp \
ru/auroraos/kmp/qtbindings/CallbackContext.cpp \
ru/auroraos/kmp/qtbindings/CoroutineException.cpp \
ru/auroraos/kmp/qtbindings/CoroutineLauncher.cpp \
contains(QMAKE_HOST.arch, armv7l): {
error("Unsupported architecture armv7l")
}
contains(QMAKE_HOST.arch, aarch64): {
LIB_KMP=kmp.libs/arm64
}
contains(QMAKE_HOST.arch, x86_64): {
LIB_KMP=kmp.libs/x64
}
INCLUDEPATH += $$PWD/../$${LIB_KMP}/include
INCLUDEPATH += $$PWD/shared/uriLauncher/
INCLUDEPATH += $$PWD/shared/deviceInfo/
INCLUDEPATH += $$PWD/../libs.kmp/$${QMAKE_HOST.arch}/include
INCLUDEPATH += $$PWD/ru/auroraos/kmp/qtbindings/
INCLUDEPATH += $$PWD/shared/vibration/
INCLUDEPATH += $$PWD/shared/sharedPreferencesSecure/
INCLUDEPATH += $$PWD/shared/themeInfo/
INCLUDEPATH += $$PWD/shared/wakelock/
INCLUDEPATH += $$PWD/shared/cameraInfo/
INCLUDEPATH += $$PWD/shared/shareData/
INCLUDEPATH += $$PWD/shared/sharedPreferences/
INCLUDEPATH += $$PWD/shared/cameraInfo/
INCLUDEPATH += $$PWD/shared/connectivityInfo/
INCLUDEPATH += $$PWD/shared/vibration/
INCLUDEPATH += $$PWD/shared/sensorsInfo/
INCLUDEPATH += $$PWD/shared/pathInfo/
INCLUDEPATH += $$PWD/shared/wakelock/
INCLUDEPATH += $$PWD/shared/localNotification/
INCLUDEPATH += $$PWD/shared/locationInfo/
INCLUDEPATH += $$PWD/shared/deviceInfo/
INCLUDEPATH += $$PWD/shared/themeInfo/
INCLUDEPATH += $$PWD/shared/connectivityInfo/
INCLUDEPATH += $$PWD/shared/uriLauncher/
INCLUDEPATH += $$PWD/shared/pathInfo/
INCLUDEPATH += $$PWD/shared/batteryInfo/
INCLUDEPATH += $$PWD/shared/sensorsInfo/
INCLUDEPATH += $$PWD/shared/packageInfo/
INCLUDEPATH += $$PWD/ru/auroraos/kmp/qtbindings/
......@@ -11,18 +11,21 @@ using OnErrorCallback = Aurora::Kmp::QtBindings::OnErrorCallback;
using OnCancelledCallback = Aurora::Kmp::QtBindings::OnCancelledCallback;
extern "C" {
void onResult(void* context, void* result) {
auto callback = static_cast<CallbackContext*>(context)->onResultCallback;
callback(result);
void onResult(void *context, void *result)
{
auto callback = static_cast<CallbackContext *>(context)->onResultCallback;
callback(result);
}
void onError(void* context, char* errorMessage) {
auto callback = static_cast<CallbackContext*>(context)->onErrorCallback;
callback(errorMessage);
void onError(void *context, char *errorMessage)
{
auto callback = static_cast<CallbackContext *>(context)->onErrorCallback;
callback(errorMessage);
}
void onCancelled(void* context, char* errorMessage) {
auto callback = static_cast<CallbackContext*>(context)->onCancelledCallback;
callback(errorMessage);
void onCancelled(void *context, char *errorMessage)
{
auto callback = static_cast<CallbackContext *>(context)->onCancelledCallback;
callback(errorMessage);
}
}
......@@ -8,27 +8,28 @@
#include <functional>
extern "C" {
void onResult(void* context, void* result);
void onError(void* context, char* errorMessage);
void onCancelled(void* context, char* errorMessage);
void onResult(void *context, void *result);
void onError(void *context, char *errorMessage);
void onCancelled(void *context, char *errorMessage);
}
namespace Aurora {
namespace Kmp {
namespace QtBindings {
using OnResultCallback = std::function<void(void* /* Result */)>;
using OnErrorCallback = std::function<void(char* /* String */)>;
using OnCancelledCallback = std::function<void(char* /* String */)>;
using OnResultCallback = std::function<void(void * /* Result */)>;
using OnErrorCallback = std::function<void(char * /* String */)>;
using OnCancelledCallback = std::function<void(char * /* String */)>;
struct CallbackContext {
OnResultCallback onResultCallback;
OnErrorCallback onErrorCallback;
OnCancelledCallback onCancelledCallback;
struct CallbackContext
{
OnResultCallback onResultCallback;
OnErrorCallback onErrorCallback;
OnCancelledCallback onCancelledCallback;
};
} // namespace QtBindings
} /* namespace Aurora */
} /* namespace Kmp */
} // namespace Aurora
} /* namespace QtBindings */
#endif /* RU_AURORA_KMP_QT_BINDINGS_CALLBACK_CONTEXT_HPP */
......@@ -9,23 +9,30 @@ namespace Aurora {
namespace Kmp {
namespace QtBindings {
CoroutineException::CoroutineException(const QString& message) : m_message(message) {}
CoroutineException::CoroutineException(const CoroutineException& other)
: QException(other), m_message(other.m_message) {}
void CoroutineException::raise() const {
throw *this;
CoroutineException::CoroutineException(const QString &message)
: m_message(message)
{}
CoroutineException::CoroutineException(const CoroutineException &other)
: QException(other)
, m_message(other.m_message)
{}
void CoroutineException::raise() const
{
throw *this;
}
CoroutineException* CoroutineException::clone() const {
return new CoroutineException(*this);
CoroutineException *CoroutineException::clone() const
{
return new CoroutineException(*this);
}
QString CoroutineException::message() const {
return m_message;
QString CoroutineException::message() const
{
return m_message;
}
} // namespace QtBindings
} /* namespace Aurora */
} /* namespace Kmp */
} // namespace Aurora
} /* namespace QtBindings */
......@@ -11,23 +11,24 @@ namespace Aurora {
namespace Kmp {
namespace QtBindings {
class CoroutineException : public QException {
public:
explicit CoroutineException(const QString& message);
virtual ~CoroutineException() = default;
class CoroutineException: public QException
{
public:
explicit CoroutineException(const QString &message);
virtual ~CoroutineException() = default;
CoroutineException(const CoroutineException& other);
CoroutineException(const CoroutineException &other);
void raise() const override;
CoroutineException* clone() const override;
QString message() const;
void raise() const override;
CoroutineException *clone() const override;
QString message() const;
private:
QString m_message;
private:
QString m_message;
};
} // namespace QtBindings
} /* namespace Aurora */
} /* namespace Kmp */
} // namespace Aurora
} /* namespace QtBindings */
#endif /* RU_AURORA_KMP_QT_BINDINGS_EXCEPTION_HPP */
......@@ -9,64 +9,80 @@ namespace Aurora {
namespace Kmp {
namespace QtBindings {
CoroutineLauncher::CoroutineLauncher(KotlinCoroutineLauncher* launcher) : d_ptr(launcher) {}
CoroutineLauncher::CoroutineLauncher(KotlinCoroutineLauncher *launcher)
: d_ptr(launcher)
{}
CoroutineLauncher::CoroutineLauncher(CoroutineLauncher&& other) {
d_ptr = other.d_ptr;
other.d_ptr = nullptr;
CoroutineLauncher::CoroutineLauncher(CoroutineLauncher &&other)
{
d_ptr = other.d_ptr;
other.d_ptr = nullptr;
}
CoroutineLauncher::~CoroutineLauncher() {
if (d_ptr) {
d_ptr->free(d_ptr);
}
CoroutineLauncher::~CoroutineLauncher()
{
if (d_ptr) {
d_ptr->free(d_ptr);
}
}
CoroutineLauncher& CoroutineLauncher::operator=(CoroutineLauncher&& other) {
if (this != &other) {
this->d_ptr = other.d_ptr;
other.d_ptr = nullptr;
return *this;
}
CoroutineLauncher &CoroutineLauncher::operator=(CoroutineLauncher &&other)
{
if (this != &other) {
this->d_ptr = other.d_ptr;
other.d_ptr = nullptr;
return *this;
}
return *this;
return *this;
}
CoroutineLauncher::CancelableCoroutine CoroutineLauncher::launch(CallbackContext* context,
CoroutineLauncher::CancelableCoroutine CoroutineLauncher::launch(CallbackContext *context,
COnResultCallback onResult,
COnErrorCallback onError,
COnCancelledCallback onCancelled) {
return CancelableCoroutine{
d_ptr->coroutineLauncherFunc((void*)context, d_ptr->kotlinContext, onResult, onError, onCancelled)};
COnCancelledCallback onCancelled)
{
return CancelableCoroutine{d_ptr->coroutineLauncherFunc((void *) context,
d_ptr->kotlinContext,
onResult,
onError,
onCancelled)};
}
CoroutineLauncher::CancelableCoroutine::CancelableCoroutine(CCancellableCoroutine* coroutine) : d_ptr(coroutine) {}
CoroutineLauncher::CancelableCoroutine::CancelableCoroutine(CCancellableCoroutine *coroutine)
: d_ptr(coroutine)
{}
CoroutineLauncher::CancelableCoroutine::CancelableCoroutine(CancelableCoroutine&& other) {
d_ptr = other.d_ptr;
other.d_ptr = nullptr;
CoroutineLauncher::CancelableCoroutine::CancelableCoroutine(CancelableCoroutine &&other)
{
d_ptr = other.d_ptr;
other.d_ptr = nullptr;
}
CoroutineLauncher::CancelableCoroutine::~CancelableCoroutine() {
if (d_ptr) {
d_ptr->free(d_ptr);
}
CoroutineLauncher::CancelableCoroutine::~CancelableCoroutine()
{
if (d_ptr) {
d_ptr->free(d_ptr);
}
}
CoroutineLauncher::CancelableCoroutine& CoroutineLauncher::CancelableCoroutine::operator=(CancelableCoroutine&& other) {
if (this != &other) {
this->d_ptr = other.d_ptr;
other.d_ptr = nullptr;
return *this;
}
CoroutineLauncher::CancelableCoroutine &CoroutineLauncher::CancelableCoroutine::operator=(
CancelableCoroutine &&other)
{
if (this != &other) {
this->d_ptr = other.d_ptr;
other.d_ptr = nullptr;
return *this;
}
return *this;
return *this;
}
void CoroutineLauncher::CancelableCoroutine::cancel() {
d_ptr->cancel(d_ptr);
void CoroutineLauncher::CancelableCoroutine::cancel()
{
d_ptr->cancel(d_ptr);
}
} // namespace QtBindings
} /* namespace Aurora */
} /* namespace Kmp */
} // namespace Aurora
} /* namespace QtBindings */
......@@ -12,41 +12,43 @@ namespace Aurora {
namespace Kmp {
namespace QtBindings {
struct CoroutineLauncher {
CoroutineLauncher(KotlinCoroutineLauncher* launcher);
CoroutineLauncher(const CoroutineLauncher& other) = delete;
CoroutineLauncher(CoroutineLauncher&& other);
virtual ~CoroutineLauncher();
CoroutineLauncher& operator=(const CoroutineLauncher& other) = delete;
CoroutineLauncher& operator=(CoroutineLauncher&& other);
struct CancelableCoroutine {
public:
CancelableCoroutine(CCancellableCoroutine* coroutine);
CancelableCoroutine(const CancelableCoroutine& other) = delete;
CancelableCoroutine(CancelableCoroutine&& other);
virtual ~CancelableCoroutine();
CancelableCoroutine& operator=(const CancelableCoroutine& other) = delete;
CancelableCoroutine& operator=(CancelableCoroutine&& other);
void cancel();
private:
CCancellableCoroutine* d_ptr;
};
CancelableCoroutine launch(CallbackContext* context,
COnResultCallback onResult,
COnErrorCallback onError,
COnCancelledCallback onCancelled);
private:
KotlinCoroutineLauncher* d_ptr;
struct CoroutineLauncher
{
CoroutineLauncher(KotlinCoroutineLauncher *launcher);
CoroutineLauncher(const CoroutineLauncher &other) = delete;
CoroutineLauncher(CoroutineLauncher &&other);
virtual ~CoroutineLauncher();
CoroutineLauncher &operator=(const CoroutineLauncher &other) = delete;
CoroutineLauncher &operator=(CoroutineLauncher &&other);
struct CancelableCoroutine
{
public:
CancelableCoroutine(CCancellableCoroutine *coroutine);
CancelableCoroutine(const CancelableCoroutine &other) = delete;
CancelableCoroutine(CancelableCoroutine &&other);
virtual ~CancelableCoroutine();
CancelableCoroutine &operator=(const CancelableCoroutine &other) = delete;
CancelableCoroutine &operator=(CancelableCoroutine &&other);
void cancel();
private:
CCancellableCoroutine *d_ptr;
};
CancelableCoroutine launch(CallbackContext *context,
COnResultCallback onResult,
COnErrorCallback onError,
COnCancelledCallback onCancelled);
private:
KotlinCoroutineLauncher *d_ptr;
};
} // namespace QtBindings
} /* namespace Aurora */
} /* namespace Kmp */
} // namespace Aurora
} /* namespace QtBindings */
#endif /* RU_AURORA_KMP_QT_BINDINGS_COROUTINE_LAUNCHER_HPP */
......@@ -19,156 +19,186 @@ namespace Aurora {
namespace Kmp {
namespace QtBindings {
template <typename T>
using ResultTransformer = std::function<T(void*)>;
template<typename T>
using ResultTransformer = std::function<T(void *)>;
template <typename T>
template<typename T>
std::enable_if_t<!std::is_void_v<T>, QFuture<T>> coroutine(CoroutineLauncher launcher,
const ResultTransformer<T>& transformer);
const ResultTransformer<T> &transformer);
template <typename T>
template<typename T>
std::enable_if_t<std::is_void_v<T>, QFuture<T>> coroutine(CoroutineLauncher launcher);
template <typename T>
class CoroutineOperation {
public:
virtual ~CoroutineOperation() = default;
private:
friend QFuture<T> coroutine<T>(CoroutineLauncher, const ResultTransformer<T>&);
CoroutineOperation(CoroutineLauncher launcher)
: m_launcher(std::move(launcher)),
m_callbackContext{nullptr, [this](char* message) { finishedWithError(QString::fromUtf8(message)); },
// TODO: Do we need to call m_futureInterface.reportCancelled()?
[](char*) {}} {
auto watcher = new QFutureWatcher<T>();
watcher->setFuture(future());
QObject::connect(watcher, &QFutureWatcher<T>::canceled, [=, this]() {
if (m_cancellableCoroutine) {
m_cancellableCoroutine->cancel();
m_cancellableCoroutine.reset();
}
});
QObject::connect(watcher, &QFutureWatcher<T>::finished, [watcher]() { watcher->deleteLater(); });
}
QFuture<T> launch(const ResultTransformer<T>& transformer) {
m_callbackContext.onResultCallback = [this, transformer](void* result) {
auto transformedResult = transformer(result);
finishedWithResult(&transformedResult);
};
m_futureInterface.reportStarted();
m_cancellableCoroutine = m_launcher.launch(&m_callbackContext, &onResult, &onError, &onCancelled);
return future();
}
void finishedWithResult(const T* result) {
// If Qfuture has been cancelled, reportFinished will do nothing
m_futureInterface.reportFinished(result);
}
void finishedWithError(const QString& error) {
// If Qfuture has been cancelled, reportException, reportFinished will do nothing
m_futureInterface.reportException(CoroutineException(error));
m_futureInterface.reportFinished();
}
QFuture<T> future() { return m_futureInterface.future(); }
CoroutineLauncher m_launcher;
std::optional<CoroutineLauncher::CancelableCoroutine> m_cancellableCoroutine;
CallbackContext m_callbackContext;
// We use the undocumented (but not explicitly marked as private) QFutureInterface class
// because that's the only way to manipulate a QFuture's status
QFutureInterface<T> m_futureInterface;
template<typename T>
class CoroutineOperation
{
public:
virtual ~CoroutineOperation() = default;
private:
friend QFuture<T> coroutine<T>(CoroutineLauncher, const ResultTransformer<T> &);
CoroutineOperation(CoroutineLauncher launcher)
: m_launcher(std::move(launcher))
, m_callbackContext{nullptr,
[this](char *message) { finishedWithError(QString::fromUtf8(message)); },
// TODO: Do we need to call m_futureInterface.reportCancelled()?
[](char *) {}}
{
auto watcher = new QFutureWatcher<T>();
watcher->setFuture(future());
QObject::connect(watcher, &QFutureWatcher<T>::canceled, [=, this]() {
if (m_cancellableCoroutine) {
m_cancellableCoroutine->cancel();
m_cancellableCoroutine.reset();
}
});
QObject::connect(watcher, &QFutureWatcher<T>::finished, [watcher]() {
watcher->deleteLater();
});
}
QFuture<T> launch(const ResultTransformer<T> &transformer)
{
m_callbackContext.onResultCallback = [this, transformer](void *result) {
auto transformedResult = transformer(result);
finishedWithResult(&transformedResult);
};
m_futureInterface.reportStarted();
m_cancellableCoroutine = m_launcher.launch(&m_callbackContext,
&onResult,
&onError,
&onCancelled);
return future();
}
void finishedWithResult(const T *result)
{
// If Qfuture has been cancelled, reportFinished will do nothing
m_futureInterface.reportFinished(result);
}
void finishedWithError(const QString &error)
{
// If Qfuture has been cancelled, reportException, reportFinished will do nothing
m_futureInterface.reportException(CoroutineException(error));
m_futureInterface.reportFinished();
}
QFuture<T> future()
{
return m_futureInterface.future();
}
CoroutineLauncher m_launcher;
std::optional<CoroutineLauncher::CancelableCoroutine> m_cancellableCoroutine;
CallbackContext m_callbackContext;
// We use the undocumented (but not explicitly marked as private) QFutureInterface class
// because that's the only way to manipulate a QFuture's status
QFutureInterface<T> m_futureInterface;
};
template <>
class CoroutineOperation<void> {
public:
virtual ~CoroutineOperation() = default;
private:
friend QFuture<void> coroutine<void>(CoroutineLauncher launcher);
CoroutineOperation(CoroutineLauncher launcher)
: m_launcher(std::move(launcher)),
m_callbackContext{nullptr, [this](char* message) { finishedWithError(QString::fromUtf8(message)); },
// TODO: Do we need to call m_futureInterface.reportCancelled()?
[](char*) {}} {
auto watcher = new QFutureWatcher<void>();
watcher->setFuture(future());
QObject::connect(watcher, &QFutureWatcher<void>::canceled, [=]() {
if (m_cancellableCoroutine) {
m_cancellableCoroutine->cancel();
m_cancellableCoroutine.reset();
}
});
QObject::connect(watcher, &QFutureWatcher<void>::finished, [=]() { watcher->deleteLater(); });
}
QFuture<void> launch() {
m_callbackContext.onResultCallback = [this](void*) { finishedWithResult(); };
m_futureInterface.reportStarted();
m_cancellableCoroutine = m_launcher.launch(&m_callbackContext, &onResult, &onError, &onCancelled);
return future();
}
void finishedWithResult() {
// If Qfuture has been cancelled, reportFinished will do nothing
m_futureInterface.reportFinished();
}
void finishedWithError(const QString& error) {
// If Qfuture has been cancelled, reportException, reportFinished will do nothing
m_futureInterface.reportException(CoroutineException(error));
m_futureInterface.reportFinished();
}
QFuture<void> future() { return m_futureInterface.future(); }
CoroutineLauncher m_launcher;
std::optional<CoroutineLauncher::CancelableCoroutine> m_cancellableCoroutine;
CallbackContext m_callbackContext;
// We use the undocumented (but not explicitly marked as private) QFutureInterface class
// because that's the only way to manipulate a QFuture's status
QFutureInterface<void> m_futureInterface;
template<>
class CoroutineOperation<void>
{
public:
virtual ~CoroutineOperation() = default;
private:
friend QFuture<void> coroutine<void>(CoroutineLauncher launcher);
CoroutineOperation(CoroutineLauncher launcher)
: m_launcher(std::move(launcher))
, m_callbackContext{nullptr,
[this](char *message) { finishedWithError(QString::fromUtf8(message)); },
// TODO: Do we need to call m_futureInterface.reportCancelled()?
[](char *) {}}
{
auto watcher = new QFutureWatcher<void>();
watcher->setFuture(future());
QObject::connect(watcher, &QFutureWatcher<void>::canceled, [=]() {
if (m_cancellableCoroutine) {
m_cancellableCoroutine->cancel();
m_cancellableCoroutine.reset();
}
});
QObject::connect(watcher, &QFutureWatcher<void>::finished, [=]() {
watcher->deleteLater();
});
}
QFuture<void> launch()
{
m_callbackContext.onResultCallback = [this](void *) { finishedWithResult(); };
m_futureInterface.reportStarted();
m_cancellableCoroutine = m_launcher.launch(&m_callbackContext,
&onResult,
&onError,
&onCancelled);
return future();
}
void finishedWithResult()
{
// If Qfuture has been cancelled, reportFinished will do nothing
m_futureInterface.reportFinished();
}
void finishedWithError(const QString &error)
{
// If Qfuture has been cancelled, reportException, reportFinished will do nothing
m_futureInterface.reportException(CoroutineException(error));
m_futureInterface.reportFinished();
}
QFuture<void> future()
{
return m_futureInterface.future();
}
CoroutineLauncher m_launcher;
std::optional<CoroutineLauncher::CancelableCoroutine> m_cancellableCoroutine;
CallbackContext m_callbackContext;
// We use the undocumented (but not explicitly marked as private) QFutureInterface class
// because that's the only way to manipulate a QFuture's status
QFutureInterface<void> m_futureInterface;
};
template <typename T>
template<typename T>
std::enable_if_t<!std::is_void_v<T>, QFuture<T>> coroutine(CoroutineLauncher launcher,
const ResultTransformer<T>& transformer) {
auto op = new CoroutineOperation<T>(std::move(launcher));
const ResultTransformer<T> &transformer)
{
auto op = new CoroutineOperation<T>(std::move(launcher));
auto watcher = new QFutureWatcher<T>();
watcher->setFuture(op->future());
QObject::connect(watcher, &QFutureWatcher<T>::finished, [=]() {
watcher->deleteLater();
delete op;
});
auto watcher = new QFutureWatcher<T>();
watcher->setFuture(op->future());
QObject::connect(watcher, &QFutureWatcher<T>::finished, [=]() {
watcher->deleteLater();
delete op;
});
return op->launch(transformer);
return op->launch(transformer);
}
template <typename T>
std::enable_if_t<std::is_void_v<T>, QFuture<T>> coroutine(CoroutineLauncher launcher) {
auto op = new CoroutineOperation<T>(std::move(launcher));
auto watcher = new QFutureWatcher<T>();
watcher->setFuture(op->future());
QObject::connect(watcher, &QFutureWatcher<T>::finished, [=]() {
watcher->deleteLater();
delete op;
});
return op->launch();
template<typename T>
std::enable_if_t<std::is_void_v<T>, QFuture<T>> coroutine(CoroutineLauncher launcher)
{
auto op = new CoroutineOperation<T>(std::move(launcher));
auto watcher = new QFutureWatcher<T>();
watcher->setFuture(op->future());
QObject::connect(watcher, &QFutureWatcher<T>::finished, [=]() {
watcher->deleteLater();
delete op;
});
return op->launch();
}
} // namespace QtBindings
} /* namespace Aurora */
} /* namespace Kmp */
} // namespace Aurora
} /* namespace QtBindings */
#endif /* RU_AURORA_KMP_QT_BINDINGS_COROUTINE_OPERATION_HPP */
......@@ -11,26 +11,28 @@ extern "C" {
struct CCancellableCoroutine;
typedef void (*COnResultCallback)(void* cContext, void* result);
typedef void (*COnStringCallback)(void* cContext, char* message);
typedef void (*COnResultCallback)(void *cContext, void *result);
typedef void (*COnStringCallback)(void *cContext, char *message);
typedef COnStringCallback COnErrorCallback;
typedef COnStringCallback COnCancelledCallback;
typedef void (*CCancelCoroutine)(struct CCancellableCoroutine* coroutine);
typedef void (*CCancelCoroutine)(struct CCancellableCoroutine *coroutine);
typedef struct CCancellableCoroutine {
void* coroutine;
CCancelCoroutine cancel;
void (*free)(struct CCancellableCoroutine* thiz);
typedef struct CCancellableCoroutine
{
void *coroutine;
CCancelCoroutine cancel;
void (*free)(struct CCancellableCoroutine *thiz);
} CCancellableCoroutine;
typedef struct KotlinCoroutineLauncher {
void* kotlinContext;
CCancellableCoroutine* (*coroutineLauncherFunc)(void* cContext,
void* kotlinContext,
COnResultCallback onResult,
COnErrorCallback onError,
COnCancelledCallback onCancelled);
void (*free)(struct KotlinCoroutineLauncher* thiz);
typedef struct KotlinCoroutineLauncher
{
void *kotlinContext;
CCancellableCoroutine *(*coroutineLauncherFunc)(void *cContext,
void *kotlinContext,
COnResultCallback onResult,
COnErrorCallback onError,
COnCancelledCallback onCancelled);
void (*free)(struct KotlinCoroutineLauncher *thiz);
} KotlinCoroutineLauncher;
#ifdef __cplusplus
......
Поддерживает Markdown
0% или .
You are about to add 0 people to the discussion. Proceed with caution.
Сначала завершите редактирование этого сообщения!
Пожалуйста, зарегистрируйтесь или чтобы прокомментировать