File indexing completed on 2024-11-24 03:56:26
0001 /* 0002 * SPDX-FileCopyrightText: 2019-2023 Mattia Basaglia <dev@dragon.best> 0003 * 0004 * SPDX-License-Identifier: GPL-3.0-or-later 0005 */ 0006 0007 #pragma once 0008 #include <QString> 0009 #include <QUuid> 0010 #include <QVariant> 0011 #include <QList> 0012 #include <QVector> 0013 #include <QMap> 0014 #include <QHash> 0015 #include <QByteArray> 0016 #include <QDateTime> 0017 #include <QDate> 0018 #include <QTime> 0019 #include <QImage> 0020 0021 #include <QDebug> 0022 0023 #undef slots 0024 #include <pybind11/embed.h> 0025 #include <pybind11/stl.h> 0026 #include <datetime.h> 0027 0028 0029 namespace pybind11::detail { 0030 template <> struct type_caster<QString> 0031 { 0032 public: 0033 /** 0034 * This macro establishes the name 'QString' in 0035 * function signatures and declares a local variable 0036 * 'value' of type QString 0037 */ 0038 PYBIND11_TYPE_CASTER(QString, _("QString")); 0039 0040 /** 0041 * Conversion part 1 (Python->C++): convert a PyObject into a QString 0042 * instance or return false upon failure. The second argument 0043 * indicates whether implicit conversions should be applied. 0044 */ 0045 bool load(handle src, bool ic) 0046 { 0047 type_caster<std::string> stdc; 0048 if ( stdc.load(src, ic) ) 0049 { 0050 value = QString::fromStdString(stdc); 0051 return true; 0052 } 0053 return false; 0054 } 0055 0056 /** 0057 * Conversion part 2 (C++ -> Python): convert an QString instance into 0058 * a Python object. The second and third arguments are used to 0059 * indicate the return value policy and parent object (for 0060 * ``return_value_policy::reference_internal``) and are generally 0061 * ignored by implicit casters. 0062 */ 0063 static handle cast(QString src, return_value_policy policy, handle parent) 0064 { 0065 return type_caster<std::string>::cast(src.toStdString(), policy, parent); 0066 } 0067 }; 0068 0069 template <> struct type_caster<QUuid> 0070 { 0071 public: 0072 PYBIND11_TYPE_CASTER(QUuid, _("QUuid")); 0073 0074 bool load(handle src, bool ic); 0075 0076 static handle cast(QUuid src, return_value_policy policy, handle parent); 0077 }; 0078 0079 template <> struct type_caster<QVariant> 0080 { 0081 public: 0082 struct CustomConverter 0083 { 0084 std::function<bool (const handle&, QVariant&)> load; 0085 std::function<handle (const QVariant&, return_value_policy, const handle&)> cast; 0086 }; 0087 0088 PYBIND11_TYPE_CASTER(QVariant, _("QVariant")); 0089 0090 bool load(handle src, bool ic); 0091 0092 static handle cast(QVariant, return_value_policy policy, handle parent); 0093 0094 template<class T> 0095 static void add_custom_type() 0096 { 0097 custom_converters[qMetaTypeId<T>()] = { 0098 [](const handle& src, QVariant& value){ 0099 auto caster = pybind11::detail::make_caster<T>(); 0100 if ( caster.load(src, false) ) 0101 { 0102 value = QVariant::fromValue(pybind11::detail::cast_op<T>(caster)); 0103 return true; 0104 } 0105 return false; 0106 }, 0107 [](const QVariant& src, return_value_policy policy, const handle& parent){ 0108 return pybind11::detail::make_caster<T>::cast(src.value<T>(), policy, parent); 0109 } 0110 }; 0111 } 0112 0113 private: 0114 static std::map<int, CustomConverter> custom_converters; 0115 }; 0116 0117 template <> struct type_caster<QByteArray> 0118 { 0119 public: 0120 PYBIND11_TYPE_CASTER(QByteArray, _("QByteArray")); 0121 0122 bool load(handle src, bool) 0123 { 0124 PyObject *source = src.ptr(); 0125 if ( !PyBytes_Check(source) ) 0126 return false; 0127 char* buffer; 0128 Py_ssize_t len; 0129 if ( PyBytes_AsStringAndSize(source, &buffer, &len) == -1) 0130 return false; 0131 value = QByteArray(buffer, len); 0132 return true; 0133 } 0134 0135 static handle cast(const QByteArray& data, return_value_policy, handle) 0136 { 0137 PyObject * obj = PyBytes_FromStringAndSize(data.data(), data.size()); 0138 if ( obj ) 0139 return obj; 0140 return {}; 0141 } 0142 }; 0143 0144 template <> struct type_caster<QDateTime> 0145 { 0146 public: 0147 PYBIND11_TYPE_CASTER(QDateTime, _("QDateTime")); 0148 0149 bool load(handle src, bool) 0150 { 0151 if ( !PyDateTimeAPI ) PyDateTime_IMPORT; 0152 0153 PyObject *source = src.ptr(); 0154 if ( !PyDateTime_Check(source) ) 0155 return false; 0156 0157 value = QDateTime( 0158 QDate( 0159 PyDateTime_GET_YEAR(source), 0160 PyDateTime_GET_MONTH(source), 0161 PyDateTime_GET_DAY(source) 0162 ), 0163 QTime( 0164 PyDateTime_DATE_GET_HOUR(source), 0165 PyDateTime_DATE_GET_MINUTE(source), 0166 PyDateTime_DATE_GET_SECOND(source), 0167 PyDateTime_DATE_GET_MICROSECOND(source) / 1000 0168 ) 0169 ); 0170 0171 return true; 0172 } 0173 0174 static handle cast(QDateTime val, return_value_policy, handle) 0175 { 0176 if ( !PyDateTimeAPI ) PyDateTime_IMPORT; 0177 0178 return PyDateTime_FromDateAndTime( 0179 val.date().year(), val.date().month(), val.date().day(), 0180 val.time().hour(), val.time().minute(), val.time().second(), val.time().msec() * 1000 0181 ); 0182 } 0183 }; 0184 template <> struct type_caster<QDate> 0185 { 0186 public: 0187 PYBIND11_TYPE_CASTER(QDate, _("QDate")); 0188 0189 bool load(handle src, bool) 0190 { 0191 if ( !PyDateTimeAPI ) PyDateTime_IMPORT; 0192 0193 PyObject *source = src.ptr(); 0194 0195 if ( !PyDate_Check(source) ) 0196 return false; 0197 0198 value = QDate( 0199 PyDateTime_GET_YEAR(source), 0200 PyDateTime_GET_MONTH(source), 0201 PyDateTime_GET_DAY(source) 0202 ); 0203 0204 return true; 0205 } 0206 0207 static handle cast(QDate val, return_value_policy, handle) 0208 { 0209 if ( !PyDateTimeAPI ) PyDateTime_IMPORT; 0210 0211 return PyDate_FromDate( 0212 val.year(), val.month(), val.day() 0213 ); 0214 } 0215 }; 0216 template <> struct type_caster<QTime> 0217 { 0218 public: 0219 PYBIND11_TYPE_CASTER(QTime, _("QTime")); 0220 0221 bool load(handle src, bool) 0222 { 0223 if ( !PyDateTimeAPI ) PyDateTime_IMPORT; 0224 0225 PyObject *source = src.ptr(); 0226 if ( PyTime_Check(source) ) 0227 { 0228 value = QTime( 0229 PyDateTime_TIME_GET_HOUR(source), 0230 PyDateTime_TIME_GET_MINUTE(source), 0231 PyDateTime_TIME_GET_SECOND(source), 0232 PyDateTime_TIME_GET_MICROSECOND(source) / 1000 0233 ); 0234 0235 return true; 0236 } 0237 if ( PyDateTime_Check(source) ) 0238 { 0239 value = QTime( 0240 PyDateTime_DATE_GET_HOUR(source), 0241 PyDateTime_DATE_GET_MINUTE(source), 0242 PyDateTime_DATE_GET_SECOND(source), 0243 PyDateTime_DATE_GET_MICROSECOND(source) / 1000 0244 ); 0245 0246 return true; 0247 } 0248 return false; 0249 } 0250 0251 static handle cast(QTime val, return_value_policy, handle) 0252 { 0253 if ( !PyDateTimeAPI ) PyDateTime_IMPORT; 0254 0255 return PyTime_FromTime( 0256 val.hour(), val.minute(), val.second(), val.msec() * 1000 0257 ); 0258 } 0259 }; 0260 0261 template <typename Type> struct type_caster<QList<Type>> : list_caster<QList<Type>, Type> {}; 0262 #if QT_VERSION_MAJOR < 6 // in qt 6 QVector is the same as QList 0263 template <typename Type> struct type_caster<QVector<Type>> : list_caster<QVector<Type>, Type> {}; 0264 #endif 0265 template <> struct type_caster<QStringList> : list_caster<QStringList, QString> {}; 0266 0267 0268 template <typename Type, typename Key, typename Value> struct qt_map_caster { 0269 using key_conv = make_caster<Key>; 0270 using value_conv = make_caster<Value>; 0271 0272 bool load(handle src, bool convert) { 0273 if (!isinstance<dict>(src)) 0274 return false; 0275 auto d = reinterpret_borrow<dict>(src); 0276 value.clear(); 0277 for (auto it : d) { 0278 key_conv kconv; 0279 value_conv vconv; 0280 if (!kconv.load(it.first.ptr(), convert) || 0281 !vconv.load(it.second.ptr(), convert)) 0282 return false; 0283 value.insert(cast_op<Key &&>(std::move(kconv)), cast_op<Value &&>(std::move(vconv))); 0284 } 0285 return true; 0286 } 0287 0288 template <typename T> 0289 static handle cast(T &&src, return_value_policy policy, handle parent) { 0290 dict d; 0291 return_value_policy policy_key = policy; 0292 return_value_policy policy_value = policy; 0293 if (!std::is_lvalue_reference<T>::value) { 0294 policy_key = return_value_policy_override<Key>::policy(policy_key); 0295 policy_value = return_value_policy_override<Value>::policy(policy_value); 0296 } 0297 for (auto it = src.begin(); it != src.end(); ++it ) 0298 { 0299 auto key = reinterpret_steal<object>(key_conv::cast(forward_like<T>(it.key()), policy_key, parent)); 0300 auto value = reinterpret_steal<object>(value_conv::cast(forward_like<T>(*it), policy_value, parent)); 0301 if (!key || !value) 0302 return handle(); 0303 d[key] = value; 0304 } 0305 return d.release(); 0306 } 0307 0308 PYBIND11_TYPE_CASTER(Type, _("Dict[") + key_conv::name + _(", ") + value_conv::name + _("]")); 0309 }; 0310 0311 template <typename Key, typename Value> struct type_caster<QMap<Key, Value>> 0312 : qt_map_caster<QMap<Key, Value>, Key, Value> { }; 0313 template <typename Key, typename Value> struct type_caster<QHash<Key, Value>> 0314 : qt_map_caster<QHash<Key, Value>, Key, Value> { }; 0315 0316 #if QT_VERSION_MAJOR < 6 // In Qt 6 same as std::pair, already defined by pybind 0317 template <typename V1, typename V2> struct type_caster<QPair<V1,V2>> { 0318 using cast1 = make_caster<V1>; 0319 using cast2 = make_caster<V2>; 0320 using pair_t = QPair<V1,V2>; 0321 0322 PYBIND11_TYPE_CASTER(pair_t, _("QPair[") + cast1::name + _(",") + cast2::name + _("]")); 0323 0324 bool load(handle src, bool convert) { 0325 if (!isinstance<tuple>(src)) 0326 return false; 0327 0328 auto d = reinterpret_borrow<tuple>(src); 0329 if ( d.size() != 2 ) 0330 return false; 0331 0332 cast1 conv1; 0333 cast2 conv2; 0334 if ( !conv1.load(d[0].ptr(), convert) || !conv2.load(d[1].ptr(), convert) ) 0335 return false; 0336 0337 value.first = cast_op<V1&&>(std::move(conv1)); 0338 value.second = cast_op<V2&&>(std::move(conv2)); 0339 return true; 0340 } 0341 0342 static handle cast(const pair_t& val, return_value_policy policy, handle parent) 0343 { 0344 tuple t(2); 0345 t[0] = reinterpret_steal<object>(cast1::cast(val.first, policy, parent)); 0346 t[1] = reinterpret_steal<object>(cast2::cast(val.second, policy, parent)); 0347 return t.release(); 0348 } 0349 }; 0350 #endif 0351 0352 0353 template <> struct type_caster<QImage> 0354 { 0355 public: 0356 PYBIND11_TYPE_CASTER(QImage, _("QImage")); 0357 0358 bool load(handle src, bool ic); 0359 0360 static handle cast(QImage src, return_value_policy policy, handle parent); 0361 }; 0362 0363 } // namespace pybind11::detail