aboutsummaryrefslogtreecommitdiffstats
path: root/include/qdotnetcallback.h
blob: 9f8c1505a9613bbdf47239fd50200116171dd9f8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/***************************************************************************************************
 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 <QMap>
#ifdef __GNUC__
#   pragma GCC diagnostic pop
#endif

#include <functional>

template<typename T>
struct QDotNetCallbackArg : public QDotNetInbound<T> {};

template<typename T>
struct QDotNetCallbackReturn : public QDotNetOutbound<T> {};

template<>
struct QDotNetCallbackReturn<QString> : public QDotNetOutbound<QString>
{
    using SourceType = QString;
    static inline const QDotNetParameter Parameter = QDotNetParameter::String;
};

class QDotNetCallbackBase
{
protected:
    QDotNetCallbackBase() = default;
public:
    virtual ~QDotNetCallbackBase() = default;
};

template<typename TResult, typename... TArg>
class QDotNetCallback : public QDotNetCallbackBase
{
public:
    using FunctionType = std::function<TResult(void *, TArg... arg)>;
    using CleanUpType = std::function<void(TResult *)>;

    using OutboundType = typename QDotNetCallbackReturn<TResult>::OutboundType;
    using Delegate = OutboundType(QDOTNETFUNCTION_CALLTYPE *)(
        QDotNetCallback *callback, quint64 key,
        void *data, typename QDotNetCallbackArg<TArg>::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<quint64, Box *> boxes;

    static OutboundType QDOTNETFUNCTION_CALLTYPE callbackDelegate(
        QDotNetCallback *callback, quint64 key,
        void *data, typename QDotNetCallbackArg<TArg>::InboundType... arg)
    {
        Box *box = callback->boxes[key] = new Box(
            callback->fnCallback(data, QDotNetCallbackArg<TArg>::convert(arg)...));
        return QDotNetCallbackReturn<TResult>::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<std::remove_const_t<TResult*>>(&(box->returnValue)));
            delete box;
        }
    }

    FunctionType fnCallback = nullptr;
    CleanUpType fnCleanUp = nullptr;
};

template<typename... TArg>
class QDotNetCallback<void, TArg...> : public QDotNetCallbackBase
{
public:
    using FunctionType = std::function<void(void *, TArg... arg)>;
    using CleanUpType = nullptr_t;

    using Delegate = void(QDOTNETFUNCTION_CALLTYPE *)(
        QDotNetCallback *callback, quint64 key,
        void *data, typename QDotNetCallbackArg<TArg>::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<TArg>::InboundType... arg)
    {
        callback->fnCallback(data, QDotNetCallbackArg<TArg>::convert(arg)...);
    }

    FunctionType fnCallback = nullptr;
};