aboutsummaryrefslogtreecommitdiffstats
path: root/sources/pyside6/libpyside/pysideclassdecorator_p.h
blob: 6068f6a2ec9bef00b97fa3dbb4754c531ef2b771 (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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
// Copyright (C) 2022 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

#ifndef CLASSDECORATOR_P_H
#define CLASSDECORATOR_P_H

#include <pysidemacros.h>

#include <sbkpython.h>
#include <pep384ext.h>

#include <QtCore/QByteArray>

#include <array>
#include <string>

/// Helpers for class decorators with parameters
namespace PySide::ClassDecorator {

/// Base class for private objects of class decorators with parameters
class PYSIDE_API DecoratorPrivate
{
public:
     Q_DISABLE_COPY_MOVE(DecoratorPrivate)

    virtual ~DecoratorPrivate();

    /// Virtual function which is passed the decorated class type
    /// \param args Decorated class type argument
    /// \return class with reference count increased if the call was successful,
    ///         else nullptr
    virtual PyObject *tp_call(PyObject *self, PyObject *args, PyObject * /* kw */) = 0;

    /// Virtual function which is passed the decorator parameters
    /// \param args Decorator arguments
    /// \return 0 if the parameters are correct
    virtual int tp_init(PyObject *self, PyObject *args, PyObject *kwds) = 0;
    virtual const char *name() const = 0;

    /// Helper that returns DecoratorPrivate instance from a PyObject
    template <class DerivedPrivate>
    static DerivedPrivate *get(PyObject *o)
    { return static_cast<DerivedPrivate *>(DecoratorPrivate::getPrivate(o)); }

protected:
    /// Check mode for the arguments of the call operator
    enum class CheckMode { None, WrappedType, QObjectType };

    DecoratorPrivate() noexcept;
    static DecoratorPrivate *getPrivate(PyObject *o);

    /// Helper for checking the arguments of the call operator
    /// \param args Arguments
    /// \param checkMode Type check mode
    /// \return The type object extracted from args tuple (borrowed reference)
    ///         if the argument is a matching type
    PyObject *tp_call_check(PyObject *args,
                            CheckMode checkMode = CheckMode::QObjectType) const;
};

/// Base class for private objects of class decorator with a string parameter
class PYSIDE_API StringDecoratorPrivate : public DecoratorPrivate
{
public:
    /// Init function that retrieves the string parameter using convertToString()
    int tp_init(PyObject *self, PyObject *args, PyObject *kwds) override;

    QByteArray string() const { return m_string; }

protected:
    /// Helper function that retrieves the string parameter
    /// \param self self
    /// \param args Arguments
    /// \return 0 if the parameter is correct, else -1 (for tp_init())
    int convertToString(PyObject *self, PyObject *args);

private:
    QByteArray m_string;
};

/// Base class for private objects of class decorator with a type parameter
class PYSIDE_API TypeDecoratorPrivate : public DecoratorPrivate
{
public:
    /// Init function that retrieves the type parameter using convertToType()
    int tp_init(PyObject *self, PyObject *args, PyObject *kwds) override;

    PyTypeObject *type() const { return m_type; }

protected:
    /// Helper function that retrieves the type parameter
    /// \param self self
    /// \param args Arguments
    /// \return 0 if the parameter is correct, else -1 (for tp_init())
    int convertToType(PyObject *self, PyObject *args);

private:
    PyTypeObject *m_type = nullptr;
};

} // namespace PySide::ClassDecorator

extern "C"
{
LIBSHIBOKEN_API void Sbk_object_dealloc(PyObject *self);

/// Python type for class decorators with DecoratorPrivate
struct PYSIDE_API PySideClassDecorator
{
    PyObject_HEAD
    PySide::ClassDecorator::DecoratorPrivate *d;
};
};

namespace PySide::ClassDecorator {

/// Helper template providing the methods (slots) for class decorators
template <class DecoratorPrivate>
struct Methods
{
    static PyObject *tp_new(PyTypeObject *subtype)
    {
        auto *result = PepExt_TypeCallAlloc<PySideClassDecorator>(subtype, 0);
        result->d = new DecoratorPrivate;
        return reinterpret_cast<PyObject *>(result);
    }

    static void tp_free(void *self)
    {
        auto pySelf = reinterpret_cast<PyObject *>(self);
        auto decorator = reinterpret_cast<PySideClassDecorator *>(self);
        delete decorator->d;
        PepExt_TypeCallFree(Py_TYPE(pySelf)->tp_base, self);
    }

    static PyObject *tp_call(PyObject *self, PyObject *args, PyObject *kwds)
    {
        auto *decorator = reinterpret_cast<PySideClassDecorator *>(self);
        return decorator->d->tp_call(self, args, kwds);
    }

    static int tp_init(PyObject *self, PyObject *args, PyObject *kwds)
    {
        auto *decorator = reinterpret_cast<PySideClassDecorator *>(self);
        return decorator->d->tp_init(self, args, kwds);
    }

    using TypeSlots = std::array<PyType_Slot, 6>;

    static TypeSlots typeSlots()
    {
        return { {{Py_tp_call, reinterpret_cast<void *>(tp_call)},
                  {Py_tp_init, reinterpret_cast<void *>(tp_init)},
                  {Py_tp_new, reinterpret_cast<void *>(tp_new)},
                  {Py_tp_free, reinterpret_cast<void *>(tp_free)},
                  {Py_tp_dealloc, reinterpret_cast<void *>(Sbk_object_dealloc)},
                  {0, nullptr}}
               };
    }
};

} // namespace PySide::ClassDecorator

#endif // CLASSDECORATOR_P_H