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