/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of PySide2. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef CONVERSIONS_H #define CONVERSIONS_H #include "sbkpython.h" #include #include #include "sbkstring.h" #include "sbkenum.h" #include "basewrapper.h" #include "bindingmanager.h" #include "sbkdbg.h" // When the user adds a function with an argument unknown for the typesystem, the generator writes type checks as // TYPENAME_Check, so this macro allows users to add PyObject arguments to their added functions. #define PyObject_Check(X) true #define SbkChar_Check(X) (SbkNumber_Check(X) || Shiboken::String::checkChar(X)) #include "autodecref.h" namespace Shiboken { /** * This function template is used to get the PyTypeObject of a C++ type T. * All implementations should be provided by template specializations generated by the generator when * T isn't a C++ primitive type. * \see SpecialCastFunction */ template PyTypeObject* SbkType() { return 0; } template<> inline PyTypeObject* SbkType() { return &PyInt_Type; } template<> inline PyTypeObject* SbkType() { return &PyLong_Type; } template<> inline PyTypeObject* SbkType() { return &PyInt_Type; } template<> inline PyTypeObject* SbkType() { return &PyInt_Type; } template<> inline PyTypeObject* SbkType() { return &PyLong_Type; } template<> inline PyTypeObject* SbkType() { return &PyLong_Type; } template<> inline PyTypeObject* SbkType() { return &PyLong_Type; } template<> inline PyTypeObject* SbkType() { return &PyLong_Type; } template<> inline PyTypeObject* SbkType() { return &PyBool_Type; } template<> inline PyTypeObject* SbkType() { return &PyFloat_Type; } template<> inline PyTypeObject* SbkType() { return &PyFloat_Type; } template<> inline PyTypeObject* SbkType() { return &PyInt_Type; } template<> inline PyTypeObject* SbkType() { return &PyInt_Type; } template<> inline PyTypeObject* SbkType() { return &PyInt_Type; } /** * Convenience template to create wrappers using the proper Python type for a given C++ class instance. */ template inline PyObject* createWrapper(const T* cppobj, bool hasOwnership = false, bool isExactType = false) { const char* typeName = 0; if (!isExactType) typeName = typeid(*const_cast(cppobj)).name(); return Object::newObject(reinterpret_cast(SbkType()), const_cast(cppobj), hasOwnership, isExactType, typeName); } // Base Conversions ---------------------------------------------------------- // The basic converter must be empty to avoid object types being converted by value. template struct Converter {}; // Pointer conversion specialization for value types. template struct Converter { static inline bool checkType(PyObject* pyObj) { return Converter::checkType(pyObj); } static inline bool isConvertible(PyObject* pyObj) { return pyObj == Py_None || PyObject_TypeCheck(pyObj, SbkType()); } static PyObject* toPython(const T* cppobj) { if (!cppobj) Py_RETURN_NONE; PyObject* pyobj = reinterpret_cast(BindingManager::instance().retrieveWrapper(cppobj)); if (pyobj) Py_INCREF(pyobj); else pyobj = createWrapper(cppobj); return pyobj; } static T* toCpp(PyObject* pyobj) { if (PyObject_TypeCheck(pyobj, SbkType())) return reinterpret_cast(Object::cppPointer(reinterpret_cast(pyobj), SbkType())); else if (Converter::isConvertible(pyobj)) return new T(Converter::toCpp(pyobj)); else if (pyobj == Py_None) return 0; assert(false); return 0; } }; template struct Converter : Converter {}; // Specialization for reference conversions. template struct Converter { static inline bool checkType(PyObject* pyObj) { return Converter::checkType(pyObj); } static inline bool isConvertible(PyObject* pyObj) { return Converter::isConvertible(pyObj); } static inline PyObject* toPython(const T& cppobj) { return Converter::toPython(&cppobj); } static inline T& toCpp(PyObject* pyobj) { return *Converter::toCpp(pyobj); } }; // Void pointer conversions. template<> struct Converter { static inline bool checkType(PyObject *) { return false; } static inline bool isConvertible(PyObject *) { return true; } static PyObject* toPython(void* cppobj) { if (!cppobj) Py_RETURN_NONE; PyObject *result = reinterpret_cast(cppobj); Py_INCREF(result); return result; } static void* toCpp(PyObject* pyobj) { return pyobj; } }; // Base converter meant to be inherited by converters for classes that could be // passed by value. // Example: "struct Converter : ValueTypeConverter" template struct ValueTypeConverter { static inline bool checkType(PyObject* pyObj) { return PyObject_TypeCheck(pyObj, SbkType()); } // The basic version of this method also tries to use the extended 'isConvertible' method. static inline bool isConvertible(PyObject* pyobj) { if (PyObject_TypeCheck(pyobj, SbkType())) return true; SbkObjectType* shiboType = reinterpret_cast(SbkType()); return ObjectType::isExternalConvertible(shiboType, pyobj); } static inline PyObject* toPython(void* cppobj) { return toPython(*reinterpret_cast(cppobj)); } static inline PyObject* toPython(const T& cppobj) { PyObject* obj = createWrapper(new T(cppobj), true, true); // SbkBaseWrapper_setContainsCppWrapper(obj, SbkTypeInfo::isCppWrapper); return obj; } // Classes with implicit conversions are expected to reimplement 'toCpp' to build T from // its various implicit constructors. Even classes without implicit conversions could // get some of those via other modules defining conversion operator for them, thus // the basic Converter for value types checks for extended conversion and tries to // use them if it is the case. static inline T toCpp(PyObject* pyobj) { if (!PyObject_TypeCheck(pyobj, SbkType())) { SbkObjectType* shiboType = reinterpret_cast(SbkType()); if (ObjectType::hasExternalCppConversions(shiboType) && isConvertible(pyobj)) { T* cptr = reinterpret_cast(ObjectType::callExternalCppConversion(shiboType, pyobj)); const T result = *cptr; delete cptr; return result; } assert(false); } return *reinterpret_cast(Object::cppPointer(reinterpret_cast(pyobj), SbkType())); } }; // Base converter meant to be inherited by converters for abstract classes and object types // (i.e. classes with private copy constructors and = operators). // Example: "struct Converter : ObjectTypeConverter" template struct ObjectTypeConverter { static inline bool checkType(PyObject* pyObj) { return pyObj == Py_None || PyObject_TypeCheck(pyObj, SbkType()); } /// Py_None objects are the only objects convertible to an object type (in the form of a NULL pointer). static inline bool isConvertible(PyObject* pyObj) { return pyObj == Py_None || PyObject_TypeCheck(pyObj, SbkType()); } /// Convenience overload that calls "toPython(const T*)" method. static inline PyObject* toPython(void* cppobj) { return toPython(reinterpret_cast(cppobj)); } /// Returns a new Python wrapper for the C++ object or an existing one with its reference counter incremented. static PyObject* toPython(const T* cppobj) { if (!cppobj) Py_RETURN_NONE; PyObject* pyobj = reinterpret_cast(BindingManager::instance().retrieveWrapper(cppobj)); if (pyobj) Py_INCREF(pyobj); else pyobj = createWrapper(cppobj); return pyobj; } /// Returns the wrapped C++ pointer casted properly, or a NULL pointer if the argument is a Py_None. static T* toCpp(PyObject* pyobj) { if (pyobj == Py_None) return 0; SbkObject *sbkObj = reinterpret_cast(pyobj); SbkObjectType* shiboType = reinterpret_cast(pyobj->ob_type); if (ObjectType::hasCast(shiboType)) return reinterpret_cast(ObjectType::cast(shiboType, sbkObj, SbkType())); return reinterpret_cast(Object::cppPointer(sbkObj, SbkType())); } }; template struct ObjectTypeReferenceConverter : ObjectTypeConverter { static inline bool checkType(PyObject* pyObj) { return PyObject_TypeCheck(pyObj, SbkType()); } static inline bool isConvertible(PyObject* pyObj) { return PyObject_TypeCheck(pyObj, SbkType()); } static inline PyObject* toPython(const T& cppobj) { return Converter::toPython(&cppobj); } static inline T& toCpp(PyObject* pyobj) { T* t = Converter::toCpp(pyobj); assert(t); return *t; } }; // PyObject* specialization to avoid converting what doesn't need to be converted. template<> struct Converter : ObjectTypeConverter { static inline PyObject* toCpp(PyObject* pyobj) { return pyobj; } }; // Primitive Conversions ------------------------------------------------------ template <> struct Converter { static inline bool checkType(PyObject* pyobj) { return PyBool_Check(pyobj); } static inline bool isConvertible(PyObject* pyobj) { return PyInt_Check(pyobj); } static inline PyObject* toPython(void* cppobj) { return toPython(*reinterpret_cast(cppobj)); } static inline PyObject* toPython(bool cppobj) { return PyBool_FromLong(cppobj); } static inline bool toCpp(PyObject* pyobj) { return PyInt_AS_LONG(pyobj) != 0; } }; /** * Helper template for checking if a value overflows when casted to type T */ template::is_signed > struct OverFlowChecker; template struct OverFlowChecker { static bool check(const PY_LONG_LONG& value) { return value < std::numeric_limits::min() || value > std::numeric_limits::max(); } }; template struct OverFlowChecker { static bool check(const PY_LONG_LONG& value) { return value < 0 || static_cast(value) > std::numeric_limits::max(); } }; template<> struct OverFlowChecker { static bool check(const PY_LONG_LONG &) { return false; } }; template<> struct OverFlowChecker { static bool check(const double &) { return false; } }; template<> struct OverFlowChecker { static bool check(const double& value) { return value < std::numeric_limits::min() || value > std::numeric_limits::max(); } }; template struct Converter_PyInt { static inline bool checkType(PyObject* pyobj) { return PyInt_Check(pyobj); } static inline bool isConvertible(PyObject* pyobj) { return SbkNumber_Check(pyobj); } static inline PyObject* toPython(void* cppobj) { return toPython(*reinterpret_cast(cppobj)); } static inline PyObject* toPython(const PyIntEquiv& cppobj) { return PyInt_FromLong((long) cppobj); } static PyIntEquiv toCpp(PyObject* pyobj) { if (PyFloat_Check(pyobj)) { double d_result = PyFloat_AS_DOUBLE(pyobj); // If cast to long directly it could overflow silently if (OverFlowChecker::check(d_result)) PyErr_SetObject(PyExc_OverflowError, 0); return static_cast(d_result); } else { PY_LONG_LONG result = PyLong_AsLongLong(pyobj); if (OverFlowChecker::check(result)) PyErr_SetObject(PyExc_OverflowError, 0); return static_cast(result); } } }; template struct Converter_PyULongInt : Converter_PyInt { static inline PyObject* toPython(void* cppobj) { return toPython(*reinterpret_cast(cppobj)); } static inline PyObject* toPython(const T& cppobj) { return PyLong_FromUnsignedLong(cppobj); } }; /// Specialization to convert char and unsigned char, it accepts Python numbers and strings with just one character. template struct CharConverter { static inline bool checkType(PyObject* pyobj) { return SbkChar_Check(pyobj); } static inline bool isConvertible(PyObject* pyobj) { return SbkChar_Check(pyobj); } static inline PyObject* toPython(void* cppobj) { return toPython(*reinterpret_cast(cppobj)); } static inline PyObject* toPython(const CharType& cppobj) { return PyInt_FromLong(cppobj); } static CharType toCpp(PyObject* pyobj) { if (PyBytes_Check(pyobj)) { assert(PyBytes_GET_SIZE(pyobj) == 1); // This check is made on SbkChar_Check return PyBytes_AS_STRING(pyobj)[0]; } else if (PyInt_Check(pyobj)) { PY_LONG_LONG result = PyInt_AsUnsignedLongLongMask(pyobj); if (OverFlowChecker::check(result)) PyErr_SetObject(PyExc_OverflowError, 0); return result; } else if (Shiboken::String::check(pyobj)) { return Shiboken::String::toCString(pyobj)[0]; } else { return 0; } } }; template <> struct Converter : Converter_PyULongInt {}; template <> struct Converter : Converter_PyULongInt {}; template <> struct Converter : CharConverter { // Should we really return a string? using CharConverter::toPython; using CharConverter::isConvertible; using CharConverter::toCpp; static inline bool isConvertible(PyObject* pyobj) { return SbkChar_Check(pyobj); } static inline PyObject* toPython(const char& cppObj) { return Shiboken::String::fromFormat("%c", cppObj); } static char toCpp(PyObject* pyobj) { if (PyBytes_Check(pyobj)) { assert(PyBytes_GET_SIZE(pyobj) == 1); // This check is made on SbkChar_Check return PyBytes_AS_STRING(pyobj)[0]; } else if (PyInt_Check(pyobj)) { PY_LONG_LONG result = PyInt_AsUnsignedLongLongMask(pyobj); if (OverFlowChecker::check(result)) PyErr_SetObject(PyExc_OverflowError, 0); return char(result); } else if (Shiboken::String::check(pyobj)) { return Shiboken::String::toCString(pyobj)[0]; } else { return 0; } } }; template <> struct Converter : CharConverter {}; template <> struct Converter : CharConverter {}; template <> struct Converter : Converter_PyInt {}; template <> struct Converter : Converter_PyInt {}; template <> struct Converter : Converter_PyInt {}; template <> struct Converter : Converter_PyInt {}; template <> struct Converter { static inline PyObject* toPython(void* cppobj) { return toPython(*reinterpret_cast(cppobj)); } static inline PyObject* toPython(PY_LONG_LONG cppobj) { return PyLong_FromLongLong(cppobj); } static inline PY_LONG_LONG toCpp(PyObject* pyobj) { return (PY_LONG_LONG) PyLong_AsLongLong(pyobj); } }; template <> struct Converter { static inline PyObject* toPython(void* cppobj) { return toPython(*reinterpret_cast(cppobj)); } static inline PyObject* toPython(unsigned PY_LONG_LONG cppobj) { return PyLong_FromUnsignedLongLong(cppobj); } static inline unsigned PY_LONG_LONG toCpp(PyObject* pyobj) { #if PY_MAJOR_VERSION >= 3 if (!PyLong_Check(pyobj)) { PyErr_SetString(PyExc_TypeError, "Invalid type for unsigned long long conversion"); return 0; } return PyLong_AsUnsignedLongLong(pyobj); #else if (PyInt_Check(pyobj)) { long result = (unsigned PY_LONG_LONG) PyInt_AsLong(pyobj); if (result < 0) { PyErr_SetObject(PyExc_OverflowError, 0); return 0; } else return (unsigned PY_LONG_LONG) result; } else if (PyLong_Check(pyobj)) { return (unsigned PY_LONG_LONG) PyLong_AsUnsignedLongLong(pyobj); } else { PyErr_SetString(PyExc_TypeError, "Invalid type for unsigned long long conversion"); return 0; } #endif // Python 2 } }; template struct Converter_PyFloat { static inline bool checkType(PyObject* obj) { return PyFloat_Check(obj); } static inline bool isConvertible(PyObject* obj) { return SbkNumber_Check(obj); } static inline PyObject* toPython(void* cppobj) { return toPython(*reinterpret_cast(cppobj)); } static inline PyObject* toPython(PyFloatEquiv cppobj) { return PyFloat_FromDouble((double) cppobj); } static inline PyFloatEquiv toCpp(PyObject* pyobj) { if (PyInt_Check(pyobj) || PyLong_Check(pyobj)) return (PyFloatEquiv) PyLong_AsLong(pyobj); return (PyFloatEquiv) PyFloat_AsDouble(pyobj); } }; template <> struct Converter : Converter_PyFloat {}; template <> struct Converter : Converter_PyFloat {}; // PyEnum Conversions --------------------------------------------------------- template struct EnumConverter { static inline bool checkType(PyObject* pyObj) { return PyObject_TypeCheck(pyObj, SbkType()); } static inline bool isConvertible(PyObject* pyObj) { return PyObject_TypeCheck(pyObj, SbkType()); } static inline PyObject* toPython(void* cppobj) { return toPython(*reinterpret_cast(cppobj)); } static inline PyObject* toPython(CppEnum cppenum) { return Shiboken::Enum::newItem(Shiboken::SbkType(), (long) cppenum); } static inline CppEnum toCpp(PyObject* pyObj) { return (CppEnum) Shiboken::Enum::getValue(pyObj);; } }; // C Sting Types -------------------------------------------------------------- template struct Converter_CString { // Note: 0 is also a const char* in C++, so None is accepted in checkType static inline bool checkType(PyObject* pyObj) { return Shiboken::String::check(pyObj); } static inline bool isConvertible(PyObject* pyObj) { return Shiboken::String::isConvertible(pyObj); } static inline PyObject* toPython(void* cppobj) { return toPython(reinterpret_cast(cppobj)); } static inline PyObject* toPython(CString cppobj) { if (!cppobj) Py_RETURN_NONE; return Shiboken::String::fromCString(cppobj); } static inline CString toCpp(PyObject* pyobj) { if (pyobj == Py_None) return 0; return Shiboken::String::toCString(pyobj); } }; template <> struct Converter : Converter_CString {}; template <> struct Converter : Converter_CString { static inline PyObject* toPython(void* cppobj) { return toPython(*reinterpret_cast(cppobj)); } static inline PyObject* toPython(std::string cppObj) { return Shiboken::String::fromCString(cppObj.c_str()); } static inline std::string toCpp(PyObject* pyobj) { if (pyobj == Py_None) return 0; return std::string(Shiboken::String::toCString(pyobj)); } }; // C++ containers ------------------------------------------------------------- // The following container converters are meant to be used for pairs, lists and maps // that are similar to the STL containers of the same name. // For example to create a converter for a std::list the following code is enough: // template struct Converter > : StdListConverter > {}; // And this for a std::map: // template // struct Converter > : StdMapConverter > {}; template struct StdListConverter { static inline bool checkType(PyObject* pyObj) { return isConvertible(pyObj); } static inline bool isConvertible(PyObject* pyObj) { if (PyObject_TypeCheck(pyObj, SbkType())) return true; // Sequence conversion are made ONLY for python sequences, not for // binded types implementing sequence protocol, otherwise this will // cause a mess like QBitArray being accepted by someone expecting a // QStringList. if ((SbkType() && Object::checkType(pyObj)) || !PySequence_Check(pyObj)) return false; for (int i = 0, max = PySequence_Length(pyObj); i < max; ++i) { AutoDecRef item(PySequence_GetItem(pyObj, i)); if (!Converter::isConvertible(item)) return false; } return true; } static PyObject* toPython(void* cppObj) { return toPython(*reinterpret_cast(cppObj)); } static PyObject* toPython(const StdList& cppobj) { PyObject* result = PyList_New((int) cppobj.size()); typename StdList::const_iterator it = cppobj.begin(); for (int idx = 0; it != cppobj.end(); ++it, ++idx) { typename StdList::value_type vh(*it); PyList_SET_ITEM(result, idx, Converter::toPython(vh)); } return result; } static StdList toCpp(PyObject* pyobj) { if (PyObject_TypeCheck(pyobj, SbkType())) return *reinterpret_cast(Object::cppPointer(reinterpret_cast(pyobj), SbkType())); StdList result; for (int i = 0; i < PySequence_Size(pyobj); i++) { AutoDecRef pyItem(PySequence_GetItem(pyobj, i)); result.push_back(Converter::toCpp(pyItem)); } return result; } }; template struct StdPairConverter { static inline bool checkType(PyObject* pyObj) { return isConvertible(pyObj); } static inline bool isConvertible(PyObject* pyObj) { if (PyObject_TypeCheck(pyObj, SbkType())) return true; if ((SbkType() && Object::checkType(pyObj)) || !PySequence_Check(pyObj) || PySequence_Length(pyObj) != 2) return false; AutoDecRef item1(PySequence_GetItem(pyObj, 0)); AutoDecRef item2(PySequence_GetItem(pyObj, 1)); if (!Converter::isConvertible(item1) && !Converter::isConvertible(item2)) { return false; } return true; } static PyObject* toPython(void* cppObj) { return toPython(*reinterpret_cast(cppObj)); } static PyObject* toPython(const StdPair& cppobj) { typename StdPair::first_type first(cppobj.first); typename StdPair::second_type second(cppobj.second); PyObject* tuple = PyTuple_New(2); PyTuple_SET_ITEM(tuple, 0, Converter::toPython(first)); PyTuple_SET_ITEM(tuple, 1, Converter::toPython(second)); return tuple; } static StdPair toCpp(PyObject* pyobj) { StdPair result; AutoDecRef pyFirst(PySequence_GetItem(pyobj, 0)); AutoDecRef pySecond(PySequence_GetItem(pyobj, 1)); result.first = Converter::toCpp(pyFirst); result.second = Converter::toCpp(pySecond); return result; } }; template struct StdMapConverter { static inline bool checkType(PyObject* pyObj) { return isConvertible(pyObj); } static inline bool isConvertible(PyObject* pyObj) { if (PyObject_TypeCheck(pyObj, SbkType())) return true; if ((SbkType() && Object::checkType(pyObj)) || !PyDict_Check(pyObj)) return false; PyObject* key; PyObject* value; Py_ssize_t pos = 0; while (PyDict_Next(pyObj, &pos, &key, &value)) { if (!Converter::isConvertible(key) || !Converter::isConvertible(value)) { return false; } } return true; } static PyObject* toPython(void* cppObj) { return toPython(*reinterpret_cast(cppObj)); } static PyObject* toPython(const StdMap& cppobj) { PyObject* result = PyDict_New(); typename StdMap::const_iterator it = cppobj.begin(); for (; it != cppobj.end(); ++it) { PyDict_SetItem(result, Converter::toPython(it->first), Converter::toPython(it->second)); } return result; } static StdMap toCpp(PyObject* pyobj) { StdMap result; PyObject* key; PyObject* value; Py_ssize_t pos = 0; while (PyDict_Next(pyobj, &pos, &key, &value)) { result.insert(typename StdMap::value_type( Converter::toCpp(key), Converter::toCpp(value))); } return result; } }; // class used to translate python objects to another type template struct PythonConverter {}; } // namespace Shiboken #endif // CONVERSIONS_H