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
|