1****************************
2User Defined Type Conversion
3****************************
4
5In the process of creating Python bindings of a C++ library, most of the C++
6classes will have wrappers representing them in Python land.
7But there may be other classes that are very simple and/or have a Python type
8as a direct counter part. (Example: a "Complex" class, that represents complex
9numbers, has a Python equivalent in the "complex" type.) Such classes, instead
10of getting a Python wrapper, normally have conversions rules, from Python to
11C++ and vice-versa.
12
13      .. code-block:: c++
14
15          // C++ class
16          struct Complex {
17              Complex(double real, double imag);
18              double real() const;
19              double imag() const;
20          };
21
22          // Converting from C++ to Python using the CPython API:
23          PyObject* pyCpxObj = PyComplex_FromDoubles(complex.real(), complex.imag());
24
25          // Converting from Python to C++:
26          double real = PyComplex_RealAsDouble(pyCpxObj);
27          double imag = PyComplex_ImagAsDouble(pyCpxObj);
28          Complex cpx(real, imag);
29
30
31For the user defined conversion code to be inserted in the proper places,
32the "<conversion-rule>" tag must be used.
33
34      .. code-block:: xml
35
36        <primitive-type name="Complex" target-lang-api-name="PyComplex">
37          <include file-name="complex.h" location="global"/>
38
39          <conversion-rule>
40
41            <native-to-target>
42            return PyComplex_FromDoubles(%in.real(), %in.imag());
43            </native-to-target>
44
45            <target-to-native>
46              <!-- The 'check' attribute can be derived from the 'type' attribute,
47                   it is defined here to test the CHECKTYPE type system variable. -->
48              <add-conversion type="PyComplex" check="%CHECKTYPE[Complex](%in)">
49              double real = PyComplex_RealAsDouble(%in);
50              double imag = PyComplex_ImagAsDouble(%in);
51              %out = %OUTTYPE(real, imag);
52              </add-conversion>
53            </target-to-native>
54
55          </conversion-rule>
56
57        </primitive-type>
58
59
60The details will be given later, but the gist of it are the tags
61:ref:`native-to-target <native-to-target>`, which has only one conversion from C++ to Python, and
62:ref:`native-to-native <target-to-native>`, that may define the conversion of multiple Python types
63to C++'s "Complex" type.
64
65.. image:: images/converter.png
66    :height: 240px
67    :align: center
68
69|project| expects the code for :ref:`native-to-target <native-to-target>`, to directly return the
70Python result of the conversion, and the added conversions inside the
71:ref:`target-to-native <target-to-native>` must attribute the Python to C++ conversion result to
72the :ref:`%out <out>` variable.
73
74Expanding on the last example, if the binding developer want a Python 2-tuple
75of numbers to be accepted by wrapped C++ functions with "Complex" arguments,
76an :ref:`add-conversion <add-conversion>` tag and a custom check must be added.
77Here's how to do it:
78
79      .. code-block:: xml
80
81        <!-- Code injection at module level. -->
82        <inject-code class="native" position="beginning">
83        static bool Check2TupleOfNumbers(PyObject* pyIn) {
84            if (!PySequence_Check(pyIn) || !(PySequence_Size(pyIn) == 2))
85                return false;
86            Shiboken::AutoDecRef pyReal(PySequence_GetItem(pyIn, 0));
87            if (!SbkNumber_Check(pyReal))
88                return false;
89            Shiboken::AutoDecRef pyImag(PySequence_GetItem(pyIn, 1));
90            if (!SbkNumber_Check(pyImag))
91                return false;
92            return true;
93        }
94        </inject-code>
95
96        <primitive-type name="Complex" target-lang-api-name="PyComplex">
97          <include file-name="complex.h" location="global"/>
98
99          <conversion-rule>
100
101            <native-to-target>
102            return PyComplex_FromDoubles(%in.real(), %in.imag());
103            </native-to-target>
104
105            <target-to-native>
106
107              <add-conversion type="PyComplex">
108              double real = PyComplex_RealAsDouble(%in);
109              double imag = PyComplex_ImagAsDouble(%in);
110              %out = %OUTTYPE(real, imag);
111              </add-conversion>
112
113              <add-conversion type="PySequence" check="Check2TupleOfNumbers(%in)">
114              Shiboken::AutoDecRef pyReal(PySequence_GetItem(%in, 0));
115              Shiboken::AutoDecRef pyImag(PySequence_GetItem(%in, 1));
116              double real = %CONVERTTOCPP[double](pyReal);
117              double imag  = %CONVERTTOCPP[double](pyImag);
118              %out = %OUTTYPE(real, imag);
119              </add-conversion>
120
121            </target-to-native>
122
123          </conversion-rule>
124
125        </primitive-type>
126
127
128.. _container_conversions:
129
130Container Conversions
131=====================
132
133Converters for :ref:`container-type <container-type>` are pretty much the same as for other type,
134except that they make use of the type system variables
135:ref:`%INTYPE_# <intype_n>` and :ref:`%OUTTYPE_# <outtype_n>`.
136|project| combines the conversion code for containers with the conversion
137defined (or automatically generated) for the containers.
138
139      .. code-block:: xml
140
141            <container-type name="std::map" type="map">
142              <include file-name="map" location="global"/>
143
144              <conversion-rule>
145
146                <native-to-target>
147                PyObject* %out = PyDict_New();
148                %INTYPE::const_iterator it = %in.begin();
149                for (; it != %in.end(); ++it) {
150                  %INTYPE_0 key = it->first;
151                  %INTYPE_1 value = it->second;
152                          PyDict_SetItem(%out,
153                                 %CONVERTTOPYTHON[%INTYPE_0](key),
154                         %CONVERTTOPYTHON[%INTYPE_1](value));
155                }
156                return %out;
157                </native-to-target>
158
159                <target-to-native>
160
161                  <add-conversion type="PyDict">
162                  PyObject* key;
163                  PyObject* value;
164                  Py_ssize_t pos = 0;
165                  while (PyDict_Next(%in, &amp;pos, &amp;key, &amp;value)) {
166                      %OUTTYPE_0 cppKey = %CONVERTTOCPP[%OUTTYPE_0](key);
167                      %OUTTYPE_1 cppValue = %CONVERTTOCPP[%OUTTYPE_1](value);
168                      %out.insert(%OUTTYPE::value_type(cppKey, cppValue));
169                  }
170                  </add-conversion>
171
172                </target-to-native>
173              </conversion-rule>
174            </container-type>
175
176
177.. _variables_and_functions:
178
179Variables & Functions
180=====================
181
182
183.. _in:
184
185**%in**
186
187  Variable replaced by the C++ input variable.
188
189
190.. _out:
191
192**%out**
193
194  Variable replaced by the C++ output variable. Needed to convey the
195  result of a Python to C++ conversion.
196
197
198.. _intype:
199
200**%INTYPE**
201
202  Used in Python to C++ conversions. It is replaced by the name of type for
203  which the conversion is being defined. Don't use the type's name directly.
204
205
206.. _intype_n:
207
208**%INTYPE_#**
209
210  Replaced by the name of the #th type used in a container.
211
212
213.. _outtype:
214
215**%OUTTYPE**
216
217  Used in Python to C++ conversions. It is replaced by the name of type for
218  which the conversion is being defined. Don't use the type's name directly.
219
220
221.. _outtype_n:
222
223**%OUTTYPE_#**
224
225  Replaced by the name of the #th type used in a container.
226
227
228.. _checktype:
229
230**%CHECKTYPE[CPPTYPE]**
231
232  Replaced by a |project| type checking function for a Python variable.
233  The C++ type is indicated by ``CPPTYPE``.
234
235
236.. _oldconverters:
237
238Converting The Old Converters
239=============================
240
241If you use |project| for your bindings, and has defined some type conversions
242using the ``Shiboken::Converter`` template, then you must update your converters
243to the new scheme.
244
245Previously your conversion rules were declared in one line, like this:
246
247
248    .. code-block:: xml
249
250        <primitive-type name="Complex" target-lang-api-name="PyComplex">
251          <include file-name="complex.h" location="global"/>
252          <conversion-rule file="complex_conversions.h"/>
253        </primitive-type>
254
255
256And implemented in a separate C++ file, like this:
257
258
259    .. code-block:: c++
260
261        namespace Shiboken {
262        template<> struct Converter<Complex>
263        {
264            static inline bool checkType(PyObject* pyObj) {
265                return PyComplex_Check(pyObj);
266            }
267            static inline bool isConvertible(PyObject* pyObj) {
268                return PyComplex_Check(pyObj);
269            }
270            static inline PyObject* toPython(void* cppobj) {
271                return toPython(*reinterpret_cast<Complex*>(cppobj));
272            }
273            static inline PyObject* toPython(const Complex& cpx) {
274                return PyComplex_FromDoubles(cpx.real(), cpx.imag());
275            }
276            static inline Complex toCpp(PyObject* pyobj) {
277                double real =  PyComplex_RealAsDouble(pyobj);
278                double imag =  PyComplex_ImagAsDouble(pyobj);
279                return Complex(real, imag);
280            }
281        };
282        }
283
284
285In this case, the parts of the implementation that will be used in the new
286conversion-rule are the ones in the two last method
287``static inline PyObject* toPython(const Complex& cpx)`` and
288``static inline Complex toCpp(PyObject* pyobj)``. The ``isConvertible`` method
289is gone, and the ``checkType`` is now an attribute of the :ref:`add-conversion <add-conversion>`
290tag. Refer back to the first example in this page and you will be able to
291correlate the above template with the new scheme of conversion rule definition.
292