File: qpycore_chimera.h

package info (click to toggle)
pyqt5 5.11.3%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 15,956 kB
  • sloc: python: 93,806; cpp: 21,390; xml: 285; makefile: 266; sh: 31
file content (283 lines) | stat: -rw-r--r-- 9,693 bytes parent folder | download
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
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
// This is the interface of the Chimera and related classes.
//
// Copyright (c) 2018 Riverbank Computing Limited <info@riverbankcomputing.com>
// 
// This file is part of PyQt5.
// 
// This file may be used under the terms of the GNU General Public License
// version 3.0 as published by the Free Software Foundation and appearing in
// the file LICENSE included in the packaging of this file.  Please review the
// following information to ensure the GNU General Public License version 3.0
// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
// 
// If you do not wish to use this file under the terms of the GPL version 3.0
// then you may purchase a commercial license.  For more information contact
// info@riverbankcomputing.com.
// 
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.


#ifndef _QPYCORE_CHIMERA_H
#define _QPYCORE_CHIMERA_H


#include <Python.h>

#include <QByteArray>
#include <QHash>
#include <QList>
#include <QMetaProperty>
#include <QSet>
#include <QVariant>

#include "sipAPIQtCore.h"


// This describes a type that can be understood by Python and C++ (specifically
// Qt's meta-type system).  The implementation assumes that the GIL is held.
class Chimera
{
public:
    // Construct a copy.
    Chimera(const Chimera &other);

    // Destroy the type.
    ~Chimera();

    // Parses a Python object as a type.  Return 0 if there was an error.
    static const Chimera *parse(PyObject *obj);

    // Parses a Qt meta-property as a type.  Return 0 if there was an error.
    static const Chimera *parse(const QMetaProperty &mprop);

    // Parses a C++ type name as a type.  Return 0 if there was an error.
    static const Chimera *parse(const QByteArray &name);

    // The registered QVariant to PyObject convertors.
    typedef bool (*FromQVariantConvertorFn)(const QVariant &, PyObject **);
    typedef QList<FromQVariantConvertorFn> FromQVariantConvertors;
    static FromQVariantConvertors registeredFromQVariantConvertors;

    // Register a function for converting a Python object to a QVariant.
    typedef bool (*ToQVariantConvertorFn)(PyObject *, QVariant &, bool *);
    typedef QList<ToQVariantConvertorFn> ToQVariantConvertors;
    static ToQVariantConvertors registeredToQVariantConvertors;

    // Register a function for converting a Python object to QVariant data.
    typedef bool (*ToQVariantDataConvertorFn)(PyObject *, void *, int, bool *);
    typedef QList<ToQVariantDataConvertorFn> ToQVariantDataConvertors;
    static ToQVariantDataConvertors registeredToQVariantDataConvertors;

    class Signature
    {
    public:
        // Destroy the signature and any result type objects.
        ~Signature();

        // The list of parsed argument types.
        QList<const Chimera *> parsed_arguments;

        // The optional parsed result type.
        const Chimera *result;

        // The original normalised signature (possibly including a method name
        // but excluding a return type).
        QByteArray signature;

        // The signature as declared by the user for use in exceptions.
        QByteArray py_signature;

        // The revision of a slot.  Putting this here is an awful hack.
        int revision;

        // Return the parsed signature wrapped in a Python object.  Ownership
        // of the signature is passed to the Python object.  Return 0 if there
        // was an error.
        static PyObject *toPyObject(Signature *parsed_signature);

        // Return the parsed signature extracted from a Python object.
        static Signature *fromPyObject(PyObject *py);

        // Return the name from the signature.
        QByteArray name() const {return name(signature);}

        // Return the name from a signature.
        static QByteArray name(const QByteArray &signature);

        // Return the arguments from the signature.
        QByteArray arguments() const {return arguments(signature);}

        // Return the arguments from a signature.
        static QByteArray arguments(const QByteArray &signature);

    private:
        friend class Chimera;

        // Set if the parsed arguments are cached.
        bool _cached;

        Signature(const QByteArray &sig, bool cached)
            : result(0), signature(sig), py_signature(sig), _cached(cached) {}

        Signature(const Signature &);
        Signature &operator=(const Signature &);
    };

    // Parses a normalised C++ signature.  Return 0 if there was an error.
    static Signature *parse(const QByteArray &sig, const char *context);

    // Parses a C++ signature given as a Python tuple of types and an optional
    // name.  Return 0 if there was an error.
    static Signature *parse(PyObject *types, const char *name,
            const char *context);

    // Raise an exception after parse() has failed.
    static void raiseParseException(PyObject *type, const char *context = 0);

    class Storage
    {
    public:
        // Destroy the type and any temporary data.
        ~Storage();

        // Return the parsed type.
        const Chimera *type() const {return _parsed_type;}

        // Return the address of the stored value.
        void *address();

        // Convert the stored value to a Python object.
        PyObject *toPyObject() const;

    private:
        friend class Chimera;

        // The parsed type.
        const Chimera *_parsed_type;

        // The storage for fundamental and value types.
        QVariant _value_storage;

        // The storage for pointer types.
        void *_ptr_storage;

        // The state of any temporary stored data.
        int _tmp_state;

        // Set if the value is valid.
        bool _valid;

        Storage(const Chimera *ct);
        Storage(const Chimera *ct, PyObject *py);

        // Return true if the value is valid.
        bool isValid() const {return _valid;}

        // Return true is the value is a pointer type.
        bool isPointerType() const;

        Storage(const Storage &);
        Storage &operator=(const Storage &);
    };

    // Convert a Python object to C++, allocating storage as necessary.  Return
    // 0 if there was an error.
    Storage *fromPyObjectToStorage(PyObject *py) const;

    // Create a storage instance for this type.
    Storage *storageFactory() const;

    // Convert a Python object to C++ at a given address.  Return false if
    // there was an error.
    bool fromPyObject(PyObject *py, void *cpp) const;

    // Convert a Python object to a QVariant.  Return false if there was an
    // error.
    bool fromPyObject(PyObject *py, QVariant *var, bool strict = true) const;

    // Convert a Python object to a QVariant based on the type of the object.
    static QVariant fromAnyPyObject(PyObject *py, int *is_err);

    // Convert a QVariant to a Python object.
    PyObject *toPyObject(const QVariant &var) const;

    // Convert a C++ object at an arbitary address to a Python object.
    PyObject *toPyObject(void *cpp) const;

    // Convert a QVariant to a Python object based on the type of the object.
    static PyObject *toAnyPyObject(const QVariant &var);

    // Add a QVariant to a dict with a QString key.
    static bool addVariantToDict(PyObject *dict, const QString &key_ref,
            const QVariant &val_ref);

    // Returns the Qt meta-type id.  It will be QMetaType::UnknownType if the
    // type isn't known to Qt's meta-type system.
    int metatype() const {return _metatype;}

    // Returns a borrowed reference to the Python type object that was used to
    // define the type (if any).
    PyObject *py_type() const {return (PyObject *)_py_type;}

    // Returns the C++ name of the type.
    const QByteArray &name() const {return _name;}

    // Returns true if the type is a C++ or Python enum (ie. has been passed to
    // Q_ENUMS or Q_FLAGS).
    bool isEnum() const;

    // Returns the SIP generated type structure.
    const sipTypeDef *typeDef() const {return _type;}

    // Register a type as a Python enum.
    static void registerPyEnum(PyObject *enum_type);

private:
    // The generated type structure.  This may be 0 if the type is known by Qt
    // but hasn't been wrapped.
    const sipTypeDef *_type;

    // The Python type object if a Python type (rather than a C++ type string)
    // was given.
    PyTypeObject *_py_type;

    // The Qt meta-type.  This will always be valid but may refer to the
    // PyObject wrapper if the underlying type isn't known to Qt.
    int _metatype;

    // Set if the meta-type needn't be exact.
    bool _inexact;

    // Set if the the type is derived from QFlags.
    bool _is_qflags;

    // The C++ name of the type.
    QByteArray _name;

    // The registered int types.
    static QSet<PyObject *> _py_enum_types;

    // The cache of previously parsed argument type lists.
    static QHash<QByteArray, QList<const Chimera *> > _previously_parsed;

    Chimera();

    bool parse_cpp_type(const QByteArray &type);
    bool parse_py_type(PyTypeObject *type_obj);
    sipAssignFunc get_assign_helper() const;
    void set_qflags();
    bool isCppEnum() const {return (_type && sipTypeIsEnum(_type));}
    bool to_QVariantList(PyObject *py, QVariantList &cpp) const;
    bool to_QVariantHash(PyObject *py, QVariantHash &cpp) const;
    static void raiseParseCppException(const char *type,
            const char *context = 0);
    static QVariant keep_as_pyobject(PyObject *py);
    static int extract_raw_type(const QByteArray &type, QByteArray &raw_type);
    static QByteArray resolve_types(const QByteArray &type);

    Chimera &operator=(const Chimera &);
};


#endif