Imported Upstream version 3.25.1
[platform/upstream/pygobject2.git] / gi / pygi-enum-marshal.c
1 /* -*- Mode: C; c-basic-offset: 4 -*-
2  * vim: tabstop=4 shiftwidth=4 expandtab
3  *
4  * Copyright (C) 2011 John (J5) Palmieri <johnp@redhat.com>
5  * Copyright (C) 2014 Simon Feltman <sfeltman@gnome.org>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include <Python.h>
22 #include <glib.h>
23 #include <pyglib-python-compat.h>
24
25 #include "pygi-enum-marshal.h"
26 #include "pygi-type.h"
27 #include "pygenum.h"
28 #include "pygflags.h"
29
30 static gboolean
31 gi_argument_from_c_long (GIArgument *arg_out,
32                          long        c_long_in,
33                          GITypeTag   type_tag)
34 {
35     switch (type_tag) {
36       case GI_TYPE_TAG_INT8:
37           arg_out->v_int8 = c_long_in;
38           return TRUE;
39       case GI_TYPE_TAG_UINT8:
40           arg_out->v_uint8 = c_long_in;
41           return TRUE;
42       case GI_TYPE_TAG_INT16:
43           arg_out->v_int16 = c_long_in;
44           return TRUE;
45       case GI_TYPE_TAG_UINT16:
46           arg_out->v_uint16 = c_long_in;
47           return TRUE;
48       case GI_TYPE_TAG_INT32:
49           arg_out->v_int32 = c_long_in;
50           return TRUE;
51       case GI_TYPE_TAG_UINT32:
52           arg_out->v_uint32 = c_long_in;
53           return TRUE;
54       case GI_TYPE_TAG_INT64:
55           arg_out->v_int64 = c_long_in;
56           return TRUE;
57       case GI_TYPE_TAG_UINT64:
58           arg_out->v_uint64 = c_long_in;
59           return TRUE;
60       default:
61           PyErr_Format (PyExc_TypeError,
62                         "Unable to marshal C long %ld to %s",
63                         c_long_in,
64                         g_type_tag_to_string (type_tag));
65           return FALSE;
66     }
67 }
68
69 static gboolean
70 gi_argument_to_c_long (GIArgument *arg_in,
71                        long *c_long_out,
72                        GITypeTag type_tag)
73 {
74     switch (type_tag) {
75       case GI_TYPE_TAG_INT8:
76           *c_long_out = arg_in->v_int8;
77           return TRUE;
78       case GI_TYPE_TAG_UINT8:
79           *c_long_out = arg_in->v_uint8;
80           return TRUE;
81       case GI_TYPE_TAG_INT16:
82           *c_long_out = arg_in->v_int16;
83           return TRUE;
84       case GI_TYPE_TAG_UINT16:
85           *c_long_out = arg_in->v_uint16;
86           return TRUE;
87       case GI_TYPE_TAG_INT32:
88           *c_long_out = arg_in->v_int32;
89           return TRUE;
90       case GI_TYPE_TAG_UINT32:
91           *c_long_out = arg_in->v_uint32;
92           return TRUE;
93       case GI_TYPE_TAG_INT64:
94           *c_long_out = arg_in->v_int64;
95           return TRUE;
96       case GI_TYPE_TAG_UINT64:
97           *c_long_out = arg_in->v_uint64;
98           return TRUE;
99       default:
100           PyErr_Format (PyExc_TypeError,
101                         "Unable to marshal %s to C long",
102                         g_type_tag_to_string (type_tag));
103           return FALSE;
104     }
105 }
106
107 static gboolean
108 _pygi_marshal_from_py_interface_enum (PyGIInvokeState   *state,
109                                       PyGICallableCache *callable_cache,
110                                       PyGIArgCache      *arg_cache,
111                                       PyObject          *py_arg,
112                                       GIArgument        *arg,
113                                       gpointer          *cleanup_data)
114 {
115     PyObject *py_long;
116     long c_long;
117     gint is_instance;
118     PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache;
119     GIBaseInfo *interface = NULL;
120
121     is_instance = PyObject_IsInstance (py_arg, iface_cache->py_type);
122
123     py_long = PYGLIB_PyNumber_Long (py_arg);
124     if (py_long == NULL) {
125         PyErr_Clear();
126         goto err;
127     }
128
129     c_long = PYGLIB_PyLong_AsLong (py_long);
130     Py_DECREF (py_long);
131
132     /* Write c_long into arg */
133     interface = g_type_info_get_interface (arg_cache->type_info);
134     assert(g_base_info_get_type (interface) == GI_INFO_TYPE_ENUM);
135     if (!gi_argument_from_c_long(arg,
136                                  c_long,
137                                  g_enum_info_get_storage_type ((GIEnumInfo *)interface))) {
138           g_assert_not_reached();
139           g_base_info_unref (interface);
140           return FALSE;
141     }
142
143     /* If this is not an instance of the Enum type that we want
144      * we need to check if the value is equivilant to one of the
145      * Enum's memebers */
146     if (!is_instance) {
147         int i;
148         gboolean is_found = FALSE;
149
150         for (i = 0; i < g_enum_info_get_n_values (iface_cache->interface_info); i++) {
151             GIValueInfo *value_info =
152                 g_enum_info_get_value (iface_cache->interface_info, i);
153             glong enum_value = g_value_info_get_value (value_info);
154             g_base_info_unref ( (GIBaseInfo *)value_info);
155             if (c_long == enum_value) {
156                 is_found = TRUE;
157                 break;
158             }
159         }
160
161         if (!is_found)
162             goto err;
163     }
164
165     g_base_info_unref (interface);
166     return TRUE;
167
168 err:
169     if (interface)
170         g_base_info_unref (interface);
171     PyErr_Format (PyExc_TypeError, "Expected a %s, but got %s",
172                   iface_cache->type_name, py_arg->ob_type->tp_name);
173     return FALSE;
174 }
175
176 static gboolean
177 _pygi_marshal_from_py_interface_flags (PyGIInvokeState   *state,
178                                        PyGICallableCache *callable_cache,
179                                        PyGIArgCache      *arg_cache,
180                                        PyObject          *py_arg,
181                                        GIArgument        *arg,
182                                        gpointer          *cleanup_data)
183 {
184     PyObject *py_long;
185     long c_long;
186     gint is_instance;
187     PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache;
188     GIBaseInfo *interface;
189
190     is_instance = PyObject_IsInstance (py_arg, iface_cache->py_type);
191
192     py_long = PYGLIB_PyNumber_Long (py_arg);
193     if (py_long == NULL) {
194         PyErr_Clear ();
195         goto err;
196     }
197
198     c_long = PYGLIB_PyLong_AsLong (py_long);
199     Py_DECREF (py_long);
200
201     /* only 0 or argument of type Flag is allowed */
202     if (!is_instance && c_long != 0)
203         goto err;
204
205     /* Write c_long into arg */
206     interface = g_type_info_get_interface (arg_cache->type_info);
207     g_assert (g_base_info_get_type (interface) == GI_INFO_TYPE_FLAGS);
208     if (!gi_argument_from_c_long(arg, c_long,
209                                  g_enum_info_get_storage_type ((GIEnumInfo *)interface))) {
210         g_base_info_unref (interface);
211         return FALSE;
212     }
213
214     g_base_info_unref (interface);
215     return TRUE;
216
217 err:
218     PyErr_Format (PyExc_TypeError, "Expected a %s, but got %s",
219                   iface_cache->type_name, py_arg->ob_type->tp_name);
220     return FALSE;
221
222 }
223
224 static PyObject *
225 _pygi_marshal_to_py_interface_enum (PyGIInvokeState   *state,
226                                     PyGICallableCache *callable_cache,
227                                     PyGIArgCache      *arg_cache,
228                                     GIArgument        *arg)
229 {
230     PyObject *py_obj = NULL;
231     PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache;
232     GIBaseInfo *interface;
233     long c_long;
234
235     interface = g_type_info_get_interface (arg_cache->type_info);
236     g_assert (g_base_info_get_type (interface) == GI_INFO_TYPE_ENUM);
237
238     if (!gi_argument_to_c_long(arg, &c_long,
239                                g_enum_info_get_storage_type ((GIEnumInfo *)interface))) {
240         return NULL;
241     }
242
243     if (iface_cache->g_type == G_TYPE_NONE) {
244         py_obj = PyObject_CallFunction (iface_cache->py_type, "l", c_long);
245     } else {
246         py_obj = pyg_enum_from_gtype (iface_cache->g_type, c_long);
247     }
248     g_base_info_unref (interface);
249     return py_obj;
250 }
251
252 static PyObject *
253 _pygi_marshal_to_py_interface_flags (PyGIInvokeState   *state,
254                                      PyGICallableCache *callable_cache,
255                                      PyGIArgCache      *arg_cache,
256                                      GIArgument        *arg)
257 {
258     PyObject *py_obj = NULL;
259     PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache;
260     GIBaseInfo *interface;
261     long c_long;
262
263     interface = g_type_info_get_interface (arg_cache->type_info);
264     g_assert (g_base_info_get_type (interface) == GI_INFO_TYPE_FLAGS);
265
266     if (!gi_argument_to_c_long(arg, &c_long,
267                                g_enum_info_get_storage_type ((GIEnumInfo *)interface))) {
268         g_base_info_unref (interface);
269         return NULL;
270     }
271
272     g_base_info_unref (interface);
273     if (iface_cache->g_type == G_TYPE_NONE) {
274         /* An enum with a GType of None is an enum without GType */
275
276         PyObject *py_type = _pygi_type_import_by_gi_info (iface_cache->interface_info);
277         PyObject *py_args = NULL;
278
279         if (!py_type)
280             return NULL;
281
282         py_args = PyTuple_New (1);
283         if (PyTuple_SetItem (py_args, 0, PyLong_FromLong (c_long)) != 0) {
284             Py_DECREF (py_args);
285             Py_DECREF (py_type);
286             return NULL;
287         }
288
289         py_obj = PyObject_CallFunction (py_type, "l", c_long);
290
291         Py_DECREF (py_args);
292         Py_DECREF (py_type);
293     } else {
294         py_obj = pyg_flags_from_gtype (iface_cache->g_type, c_long);
295     }
296
297     return py_obj;
298 }
299
300 static gboolean
301 pygi_arg_enum_setup_from_info (PyGIArgCache  *arg_cache,
302                                GITypeInfo    *type_info,
303                                GIArgInfo     *arg_info,
304                                GITransfer     transfer,
305                                PyGIDirection  direction)
306 {
307     if (direction & PYGI_DIRECTION_FROM_PYTHON)
308         arg_cache->from_py_marshaller = _pygi_marshal_from_py_interface_enum;
309
310     if (direction & PYGI_DIRECTION_TO_PYTHON)
311         arg_cache->to_py_marshaller = _pygi_marshal_to_py_interface_enum;
312
313     return TRUE;
314 }
315
316
317 PyGIArgCache *
318 pygi_arg_enum_new_from_info (GITypeInfo      *type_info,
319                              GIArgInfo       *arg_info,
320                              GITransfer       transfer,
321                              PyGIDirection    direction,
322                              GIInterfaceInfo *iface_info)
323 {
324     gboolean res = FALSE;
325     PyGIArgCache *cache = NULL;
326
327     cache = pygi_arg_interface_new_from_info (type_info,
328                                               arg_info,
329                                               transfer,
330                                               direction,
331                                               iface_info);
332     if (cache == NULL)
333         return NULL;
334
335     res = pygi_arg_enum_setup_from_info (cache,
336                                          type_info,
337                                          arg_info,
338                                          transfer,
339                                          direction);
340     if (res) {
341         return cache;
342     } else {
343         pygi_arg_cache_free (cache);
344         return NULL;
345     }
346 }
347
348 static gboolean
349 pygi_arg_flags_setup_from_info (PyGIArgCache  *arg_cache,
350                                 GITypeInfo    *type_info,
351                                 GIArgInfo     *arg_info,
352                                 GITransfer     transfer,
353                                 PyGIDirection  direction)
354 {
355     if (direction & PYGI_DIRECTION_FROM_PYTHON)
356         arg_cache->from_py_marshaller = _pygi_marshal_from_py_interface_flags;
357
358     if (direction & PYGI_DIRECTION_TO_PYTHON)
359         arg_cache->to_py_marshaller = _pygi_marshal_to_py_interface_flags;
360
361     return TRUE;
362 }
363
364
365 PyGIArgCache *
366 pygi_arg_flags_new_from_info (GITypeInfo      *type_info,
367                               GIArgInfo       *arg_info,
368                               GITransfer       transfer,
369                               PyGIDirection    direction,
370                               GIInterfaceInfo *iface_info)
371 {
372     gboolean res = FALSE;
373     PyGIArgCache *cache = NULL;
374
375     cache = pygi_arg_interface_new_from_info (type_info,
376                                               arg_info,
377                                               transfer,
378                                               direction,
379                                               iface_info);
380     if (cache == NULL)
381         return NULL;
382
383     res = pygi_arg_flags_setup_from_info (cache,
384                                           type_info,
385                                           arg_info,
386                                           transfer,
387                                           direction);
388     if (res) {
389         return cache;
390     } else {
391         pygi_arg_cache_free (cache);
392         return NULL;
393     }
394 }