1 // This is the support code for QMetaObject.
2 //
3 // Copyright (c) 2021 Riverbank Computing Limited <info@riverbankcomputing.com>
4 //
5 // This file is part of PyQt5.
6 //
7 // This file may be used under the terms of the GNU General Public License
8 // version 3.0 as published by the Free Software Foundation and appearing in
9 // the file LICENSE included in the packaging of this file.  Please review the
10 // following information to ensure the GNU General Public License version 3.0
11 // requirements will be met: http://www.gnu.org/copyleft/gpl.html.
12 //
13 // If you do not wish to use this file under the terms of the GPL version 3.0
14 // then you may purchase a commercial license.  For more information contact
15 // info@riverbankcomputing.com.
16 //
17 // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
18 // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19 
20 
21 #include <Python.h>
22 
23 #include <QGenericArgument>
24 #include <QGenericReturnArgument>
25 
26 #include "qpycore_api.h"
27 #include "qpycore_chimera.h"
28 #include "qpycore_misc.h"
29 
30 #include "sipAPIQtCore.h"
31 
32 
33 // Forward declarations.
34 static PyObject *ArgumentStorage_New(PyObject *type, PyObject *data);
35 #if defined(SIP_USE_PYCAPSULE)
36 extern "C" {static void ArgumentStorage_delete(PyObject *cap);}
37 #else
38 extern "C" {static void ArgumentStorage_delete(void *stv);}
39 #endif
40 
41 
42 // Return a wrapped QGenericArgument for the given type and Python object.
qpycore_ArgumentFactory(PyObject * type,PyObject * data)43 PyObject *qpycore_ArgumentFactory(PyObject *type, PyObject *data)
44 {
45     PyObject *as_obj = ArgumentStorage_New(type, data);
46 
47     if (!as_obj)
48     {
49         Chimera::raiseParseException(type, "a Q_ARG()");
50         return 0;
51     }
52 
53 #if defined(SIP_USE_PYCAPSULE)
54     Chimera::Storage *st = reinterpret_cast<Chimera::Storage *>(
55             PyCapsule_GetPointer(as_obj, NULL));
56 #else
57     Chimera::Storage *st = reinterpret_cast<Chimera::Storage *>(
58             PyCObject_AsVoidPtr(as_obj));
59 #endif
60 
61     QGenericArgument *arg = new QGenericArgument(
62             st->type()->name().constData(), st->address());
63 
64     PyObject *ga_obj = sipConvertFromNewType(arg, sipType_QGenericArgument, 0);
65 
66     if (ga_obj)
67     {
68         // Stash the storage in the user field so that everything will be
69         // properly garbage collected.
70         sipSetUserObject((sipSimpleWrapper *)ga_obj, as_obj);
71     }
72     else
73     {
74         delete arg;
75         Py_DECREF(as_obj);
76     }
77 
78     return ga_obj;
79 }
80 
81 
82 // Return a wrapped QGenericReturnArgument for the given type.
qpycore_ReturnFactory(PyObject * type)83 PyObject *qpycore_ReturnFactory(PyObject *type)
84 {
85     PyObject *as_obj = ArgumentStorage_New(type, 0);
86 
87     if (!as_obj)
88     {
89         Chimera::raiseParseException(type, "a Q_RETURN_ARG()");
90         return 0;
91     }
92 
93 #if defined(SIP_USE_PYCAPSULE)
94     Chimera::Storage *st = reinterpret_cast<Chimera::Storage *>(
95             PyCapsule_GetPointer(as_obj, NULL));
96 #else
97     Chimera::Storage *st = reinterpret_cast<Chimera::Storage *>(
98             PyCObject_AsVoidPtr(as_obj));
99 #endif
100 
101     QGenericReturnArgument *arg = new QGenericReturnArgument(
102             st->type()->name().constData(), st->address());
103 
104     PyObject *gra_obj = sipConvertFromNewType(arg,
105             sipType_QGenericReturnArgument, 0);
106 
107     if (gra_obj)
108     {
109         // Stash the storage in the user field so that everything will be
110         // properly garbage collected.
111         sipSetUserObject((sipSimpleWrapper *)gra_obj, as_obj);
112     }
113     else
114     {
115         delete arg;
116         Py_DECREF(as_obj);
117     }
118 
119     return gra_obj;
120 }
121 
122 
123 // Return the Python result from a QGenericReturnArgument.
qpycore_ReturnValue(PyObject * gra_obj)124 PyObject *qpycore_ReturnValue(PyObject *gra_obj)
125 {
126     PyObject *as_obj = sipGetUserObject((sipSimpleWrapper *)gra_obj);
127 
128 #if defined(SIP_USE_PYCAPSULE)
129     Chimera::Storage *st = reinterpret_cast<Chimera::Storage *>(
130             PyCapsule_GetPointer(as_obj, NULL));
131 #else
132     Chimera::Storage *st = reinterpret_cast<Chimera::Storage *>(
133             PyCObject_AsVoidPtr(as_obj));
134 #endif
135 
136     return st->toPyObject();
137 }
138 
139 
140 #if defined(SIP_USE_PYCAPSULE)
141 // The PyCapsule destructor for the ArgumentStorage type.
ArgumentStorage_delete(PyObject * cap)142 static void ArgumentStorage_delete(PyObject *cap)
143 {
144     Chimera::Storage *st = reinterpret_cast<Chimera::Storage *>(
145             PyCapsule_GetPointer(cap, NULL));
146     const Chimera *ct = st->type();
147 
148     delete st;
149     delete ct;
150 }
151 #else
152 // The PyCObject destructor for the ArgumentStorage type.
ArgumentStorage_delete(void * stv)153 static void ArgumentStorage_delete(void *stv)
154 {
155     Chimera::Storage *st = reinterpret_cast<Chimera::Storage *>(stv);
156     const Chimera *ct = st->type();
157 
158     delete st;
159     delete ct;
160 }
161 #endif
162 
163 
164 // Returns a Python object wrapping an ArgumentStorage instance.
ArgumentStorage_New(PyObject * type,PyObject * data)165 static PyObject *ArgumentStorage_New(PyObject *type, PyObject *data)
166 {
167     const Chimera *ct = Chimera::parse(type);
168 
169     if (!ct)
170         return 0;
171 
172     Chimera::Storage *st;
173 
174     if (data)
175         st = ct->fromPyObjectToStorage(data);
176     else
177         st = ct->storageFactory();
178 
179     if (!st)
180     {
181         delete ct;
182         return 0;
183     }
184 
185     // Convert to a Python object.
186 #if defined(SIP_USE_PYCAPSULE)
187     PyObject *as_obj = PyCapsule_New(st, NULL, ArgumentStorage_delete);
188 #else
189     PyObject *as_obj = PyCObject_FromVoidPtr(st, ArgumentStorage_delete);
190 #endif
191 
192     if (!as_obj)
193     {
194         delete st;
195         delete ct;
196     }
197 
198     return as_obj;
199 }
200