/*************************************************************************************************** Copyright (C) 2023 The Qt Company Ltd. SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only ***************************************************************************************************/ #pragma once #include "qdotnetfunction.h" #ifdef __GNUC__ # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wconversion" #endif #include #ifdef __GNUC__ # pragma GCC diagnostic pop #endif #include template struct QDotNetCallbackArg : public QDotNetInbound {}; template struct QDotNetCallbackReturn : public QDotNetOutbound {}; template<> struct QDotNetCallbackReturn : public QDotNetOutbound { using SourceType = QString; static inline const QDotNetParameter Parameter = QDotNetParameter::String; }; class QDotNetCallbackBase { protected: QDotNetCallbackBase() = default; public: virtual ~QDotNetCallbackBase() = default; }; template class QDotNetCallback : public QDotNetCallbackBase { public: using FunctionType = std::function; using CleanUpType = std::function; using OutboundType = typename QDotNetCallbackReturn::OutboundType; using Delegate = OutboundType(QDOTNETFUNCTION_CALLTYPE *)( QDotNetCallback *callback, quint64 key, void *data, typename QDotNetCallbackArg::InboundType...); using CleanUp = void(QDOTNETFUNCTION_CALLTYPE *)(QDotNetCallback *callback, quint64 key); QDotNetCallback(FunctionType fnCallback, CleanUpType fnCleanUp = nullptr) : fnCallback(fnCallback), fnCleanUp(fnCleanUp) {} ~QDotNetCallback() override = default; static Delegate delegate() { return callbackDelegate; } static CleanUp cleanUp() { return callbackCleanUp; } private: struct Box { TResult returnValue; Box(TResult &&ret) : returnValue(std::move(ret)) {} }; QMap boxes; static OutboundType QDOTNETFUNCTION_CALLTYPE callbackDelegate( QDotNetCallback *callback, quint64 key, void *data, typename QDotNetCallbackArg::InboundType... arg) { Box *box = callback->boxes[key] = new Box( callback->fnCallback(data, QDotNetCallbackArg::convert(arg)...)); return QDotNetCallbackReturn::convert(box->returnValue); } static void QDOTNETFUNCTION_CALLTYPE callbackCleanUp(QDotNetCallback *callback, quint64 key) { if (const Box *box = callback->boxes.take(key)) { if (callback->fnCleanUp) callback->fnCleanUp(const_cast>(&(box->returnValue))); delete box; } } FunctionType fnCallback = nullptr; CleanUpType fnCleanUp = nullptr; }; template class QDotNetCallback : public QDotNetCallbackBase { public: using FunctionType = std::function; using CleanUpType = nullptr_t; using Delegate = void(QDOTNETFUNCTION_CALLTYPE *)( QDotNetCallback *callback, quint64 key, void *data, typename QDotNetCallbackArg::InboundType...); using CleanUp = nullptr_t; QDotNetCallback(FunctionType fnCallback, CleanUpType fnCleanUp = nullptr) : fnCallback(fnCallback) {} ~QDotNetCallback() override = default; static Delegate delegate() { return callbackDelegate; } static CleanUp cleanUp() { return nullptr; } private: static void QDOTNETFUNCTION_CALLTYPE callbackDelegate( QDotNetCallback *callback, quint64 key, void *data, typename QDotNetCallbackArg::InboundType... arg) { callback->fnCallback(data, QDotNetCallbackArg::convert(arg)...); } FunctionType fnCallback = nullptr; };