diff options
Diffstat (limited to 'sources/pyside6/libpysideremoteobjects/pysidedynamiccommon.cpp')
| -rw-r--r-- | sources/pyside6/libpysideremoteobjects/pysidedynamiccommon.cpp | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/sources/pyside6/libpysideremoteobjects/pysidedynamiccommon.cpp b/sources/pyside6/libpysideremoteobjects/pysidedynamiccommon.cpp new file mode 100644 index 000000000..b1f01fed6 --- /dev/null +++ b/sources/pyside6/libpysideremoteobjects/pysidedynamiccommon.cpp @@ -0,0 +1,124 @@ +// Copyright (C) 2025 Ford Motor Company +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "pysidedynamiccommon_p.h" +#include "pysidedynamicenum_p.h" + +#include <sbkstring.h> + +#include <QtCore/qmetaobject.h> + +using namespace Shiboken; + +PyObject *toPython(const QVariant &variant) +{ + auto metaType = variant.metaType(); + Conversions::SpecificConverter converter(metaType.name()); + auto *value = converter.toPython(variant.data()); + if (metaType.flags().testFlag(QMetaType::IsGadget)) { + // A single converter is used for all POD types - it converts to a Python + // tuple. We need an additional step to convert to our Python type for the POD. + // Thankfully, the converter stores the specific type we created, so we can call + // the constructor with the tuple. + auto *podType = Conversions::getPythonTypeObject(converter); + if (!podType) { + Py_DECREF(value); + PyErr_SetString(PyExc_RuntimeError, "Failed to get Python type for POD"); + return nullptr; + } + PyObject *podValue = PyObject_CallObject(reinterpret_cast<PyObject *>(podType), value); + Py_DECREF(value); + if (!podValue) { + PyErr_SetString(PyExc_RuntimeError, "Failed to create POD instance"); + return nullptr; + } + return podValue; + } + if (metaType.flags().testFlag(QMetaType::IsEnumeration)) { + // Enums are converted to Python ints + auto *enumType = Conversions::getPythonTypeObject(converter); + if (!enumType) { + Py_DECREF(value); + PyErr_SetString(PyExc_RuntimeError, "Failed to get Python type for enum"); + return nullptr; + } + PyObject *enumValue = PyObject_CallFunctionObjArgs(reinterpret_cast<PyObject *>(enumType), + value, nullptr); + Py_DECREF(value); + if (!enumValue) { + PyErr_Print(); + PyErr_SetString(PyExc_RuntimeError, "Failed to create enum instance"); + return nullptr; + } + return enumValue; + } + return value; +} + + +/** + * @brief Creates and manages memory for Python enum types for each QEnum in the + * provided QMetaObject. + * + * This function iterates over the enumerators in the provided QMetaObject, + * creates corresponding Python enum types, and stores them in a dictionary. + * The dictionary is then set as an attribute ()"_enum_data") on the provided + * Python object, to be accessed by the _get_enum that has been added to each + * of our dynamic types. + * + * These are "managed" in the sense that the enums clean up their converters + * using our PyCapsule method, and by adding the dictionary as a Python attribute, + * the dictionary will be cleaned up when the containing type is garbage + * collected. + * + * @param self A pointer to the Python object where the enum data will be stored. + * @param meta A pointer to the QMetaObject containing the enumerators. + * @return Returns 0 on success, or -1 on failure. + */ +int create_managed_py_enums(PyObject *self, QMetaObject *meta) +{ + PyObject *enum_data = PyDict_New(); + for (int i = meta->enumeratorOffset(); i < meta->enumeratorCount(); ++i) { + auto metaEnum = meta->enumerator(i); + auto *enumType = createEnumType(&metaEnum); + if (!enumType) { + PyErr_Print(); + PyErr_Format(PyExc_RuntimeError, "Failed to create enum type for POD '%s'", + meta->className()); + return -1; + } + PyDict_SetItemString(enum_data, metaEnum.enumName(), + reinterpret_cast<PyObject *>(enumType)); + Py_DECREF(enumType); + } + if (PyObject_SetAttrString(self, "_enum_data", enum_data) < 0) { + PyErr_Print(); + qWarning() << "Failed to set _enum_data attribute on type" + << reinterpret_cast<PyTypeObject *>(self)->tp_name; + return -1; + } + Py_DECREF(enum_data); + + return 0; +} + +PyObject *DynamicType_get_enum(PyObject *self, PyObject *name) +{ + // Our enum types are always stored in a dictionary attribute named "_enum_data" + PyObject *enum_dict = PyObject_GetAttrString(self, "_enum_data"); + if (!enum_dict) { + PyErr_SetString(PyExc_RuntimeError, "Failed to get _enum_data attribute"); + return nullptr; + } + + PyObject *enum_type = PyDict_GetItem(enum_dict, name); + Py_DECREF(enum_dict); + + if (!enum_type) { + PyErr_Format(PyExc_KeyError, "Enum '%s' not found", String::toCString(name)); + return nullptr; + } + + Py_INCREF(enum_type); + return enum_type; +} |
