From 7a5bf26325ea62c94f0ea3b93c9da91bea117ed3 Mon Sep 17 00:00:00 2001 From: baldurk Date: Tue, 28 Mar 2017 16:31:58 +0100 Subject: [PATCH] Add conversions for certain Qt types to/from python native types --- qrenderdoc/Code/pyrenderdoc/pyconversion.h | 298 +++++++++++++++++++++ 1 file changed, 298 insertions(+) diff --git a/qrenderdoc/Code/pyrenderdoc/pyconversion.h b/qrenderdoc/Code/pyrenderdoc/pyconversion.h index bd92c9e1d..8ae5ee8c1 100644 --- a/qrenderdoc/Code/pyrenderdoc/pyconversion.h +++ b/qrenderdoc/Code/pyrenderdoc/pyconversion.h @@ -444,6 +444,304 @@ struct TypeConversion return PyUnicode_FromStringAndSize(in.elems, in.count); } }; + +#ifdef ENABLE_QT_CONVERT + +template <> +struct TypeConversion +{ + static int ConvertFromPy(PyObject *in, QString &out) + { + if(PyUnicode_Check(in)) + { + PyObject *bytes = PyUnicode_AsUTF8String(in); + + if(!bytes) + return SWIG_ERROR; + + char *buf = NULL; + Py_ssize_t size = 0; + + int ret = PyBytes_AsStringAndSize(bytes, &buf, &size); + + if(ret == 0) + { + out = QString::fromUtf8(buf, (int)(size - 1)); + + Py_DecRef(bytes); + + return SWIG_OK; + } + + Py_DecRef(bytes); + + return SWIG_ERROR; + } + + return SWIG_ERROR; + } + + static PyObject *ConvertToPy(PyObject *self, const QString &in) + { + QByteArray bytes = in.toUtf8(); + return PyUnicode_FromStringAndSize(bytes.data(), bytes.size()); + } +}; + +template <> +struct TypeConversion +{ + static int ConvertFromPy(PyObject *in, QDateTime &out) + { + if(!PyDateTime_Check(in)) + return SWIG_TypeError; + + QDate date(PyDateTime_GET_YEAR(in), PyDateTime_GET_MONTH(in), PyDateTime_GET_DAY(in)); + QTime time(PyDateTime_DATE_GET_HOUR(in), PyDateTime_DATE_GET_MINUTE(in), + PyDateTime_DATE_GET_SECOND(in), PyDateTime_DATE_GET_MICROSECOND(in) / 1000); + + out = QDateTime(date, time, QTimeZone::utc()); + + return SWIG_OK; + } + + static PyObject *ConvertToPy(PyObject *self, const QDateTime &in) + { + QDate date = in.date(); + QTime time = in.time(); + return PyDateTime_FromDateAndTime(date.year(), date.month(), date.day(), time.hour(), + time.minute(), time.second(), time.msec() * 1000); + } +}; + +template +struct ContainerConversion +{ + // we add some extra parameters so the typemaps for array can use these to get + // nicer failure error messages out with the index that failed + static int ConvertFromPy(PyObject *in, Container &out, int *failIdx) + { + if(!PyList_Check(in)) + return SWIG_TypeError; + + Py_ssize_t len = PyList_Size(in); + + for(Py_ssize_t i = 0; i < len; i++) + { + U u; + int ret = TypeConversion::ConvertFromPy(PyList_GetItem(in, i), u); + if(!SWIG_IsOK(ret)) + { + if(failIdx) + *failIdx = i; + return ret; + } + out.append(u); + } + + return SWIG_OK; + } + + static int ConvertFromPy(PyObject *in, Container &out) { return ConvertFromPy(in, out, NULL); } + static PyObject *ConvertToPyInPlace(PyObject *self, PyObject *list, const Container &in, + int *failIdx) + { + for(int i = 0; i < in.size(); i++) + { + PyObject *elem = TypeConversion::ConvertToPy(self, in[i]); + + if(elem) + { + PyList_Append(list, elem); + } + else + { + if(failIdx) + *failIdx = i; + + return NULL; + } + } + + return list; + } + + static PyObject *ConvertToPy(PyObject *self, const Container &in, int *failIdx) + { + PyObject *list = PyList_New(0); + if(!list) + return NULL; + + PyObject *ret = ConvertToPyInPlace(self, list, in, failIdx); + + // if a failure happened, don't leak the list we created + if(!ret) + Py_XDECREF(list); + + return ret; + } + + static PyObject *ConvertToPy(PyObject *self, const Container &in) + { + return ConvertToPy(self, in, NULL); + } +}; + +template +struct TypeConversion, false> : ContainerConversion, U> +{ +}; + +template <> +struct TypeConversion : ContainerConversion, QString> +{ +}; + +template +struct TypeConversion, false> : ContainerConversion, U> +{ +}; + +// specialisation for pair +template +struct TypeConversion, false> +{ + static int ConvertFromPy(PyObject *in, QPair &out) + { + if(!PyTuple_Check(in)) + return SWIG_TypeError; + + Py_ssize_t size = PyTuple_Size(in); + + if(size != 2) + return SWIG_TypeError; + + int ret = TypeConversion::ConvertFromPy(PyTuple_GetItem(in, 0), out.first); + if(SWIG_IsOK(ret)) + ret = TypeConversion::ConvertFromPy(PyTuple_GetItem(in, 1), out.second); + + return ret; + } + + static PyObject *ConvertToPy(PyObject *self, const QPair &in) + { + PyObject *first = TypeConversion::ConvertToPy(self, in.first); + if(!first) + return NULL; + + PyObject *second = TypeConversion::ConvertToPy(self, in.second); + if(!second) + return NULL; + + PyObject *ret = PyTuple_New(2); + if(!ret) + return NULL; + + PyTuple_SetItem(ret, 0, first); + PyTuple_SetItem(ret, 1, second); + + return ret; + } +}; + +template +struct TypeConversion, false> +{ + // we add some extra parameters so the typemaps for array can use these to get + // nicer failure error messages out with the index that failed + static int ConvertFromPy(PyObject *in, QMap &out, int *failIdx) + { + if(!PyDict_Check(in)) + return SWIG_TypeError; + + PyObject *keys = PyDict_Keys(in); + + if(!keys) + return SWIG_TypeError; + + Py_ssize_t len = PyList_Size(keys); + + for(Py_ssize_t i = 0; i < len; i++) + { + K k; + V v; + + PyObject *key = PyList_GetItem(keys, i); + PyObject *value = PyDict_GetItem(in, key); + int ret = TypeConversion::ConvertFromPy(key, k); + int ret2 = TypeConversion::ConvertFromPy(value, v); + if(!SWIG_IsOK(ret) || !SWIG_IsOK(ret2)) + { + if(failIdx) + *failIdx = i; + Py_DecRef(keys); + if(!SWIG_IsOK(ret)) + return ret; + else + return ret2; + } + out.insert(k, v); + } + + Py_DecRef(keys); + + return SWIG_OK; + } + + static int ConvertFromPy(PyObject *in, QMap &out) { return ConvertFromPy(in, out, NULL); } + static PyObject *ConvertToPyInPlace(PyObject *self, PyObject *pymap, const QMap &in, + int *failIdx) + { + QList keys = in.keys(); + + for(int i = 0; i < keys.size(); i++) + { + const K &k = keys[i]; + PyObject *key = TypeConversion::ConvertToPy(self, k); + + if(key) + { + PyObject *value = TypeConversion::ConvertToPy(self, in[k]); + + if(value) + { + PyDict_SetItem(pymap, key, value); + continue; + } + } + + if(failIdx) + *failIdx = i; + + return NULL; + } + + return pymap; + } + + static PyObject *ConvertToPy(PyObject *self, const QMap &in, int *failIdx) + { + PyObject *list = PyDict_New(); + if(!list) + return NULL; + + PyObject *ret = ConvertToPyInPlace(self, list, in, failIdx); + + // if a failure happened, don't leak the map we created + if(!ret) + Py_XDECREF(list); + + return ret; + } + + static PyObject *ConvertToPy(PyObject *self, const QMap &in) + { + return ConvertToPy(self, in, NULL); + } +}; + +#endif + // free functions forward to struct template int ConvertFromPy(PyObject *in, T &out)