Imported Upstream version 3.21.92
[platform/upstream/pygobject2.git] / gi / pygi-list.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 "pygi-list.h"
23 #include "pygi-argument.h"
24 #include "pygi-util.h"
25
26 typedef PyGISequenceCache PyGIArgGList;
27
28 /*
29  * GList and GSList from Python
30  */
31 static gboolean
32 _pygi_marshal_from_py_glist (PyGIInvokeState   *state,
33                              PyGICallableCache *callable_cache,
34                              PyGIArgCache      *arg_cache,
35                              PyObject          *py_arg,
36                              GIArgument        *arg,
37                              gpointer          *cleanup_data)
38 {
39     PyGIMarshalFromPyFunc from_py_marshaller;
40     int i;
41     Py_ssize_t length;
42     GList *list_ = NULL;
43     PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache;
44
45
46     if (py_arg == Py_None) {
47         arg->v_pointer = NULL;
48         return TRUE;
49     }
50
51     if (!PySequence_Check (py_arg)) {
52         PyErr_Format (PyExc_TypeError, "Must be sequence, not %s",
53                       py_arg->ob_type->tp_name);
54         return FALSE;
55     }
56
57     length = PySequence_Length (py_arg);
58     if (length < 0)
59         return FALSE;
60
61     from_py_marshaller = sequence_cache->item_cache->from_py_marshaller;
62     for (i = 0; i < length; i++) {
63         GIArgument item = {0};
64         gpointer item_cleanup_data = NULL;
65         PyObject *py_item = PySequence_GetItem (py_arg, i);
66         if (py_item == NULL)
67             goto err;
68
69         if (!from_py_marshaller ( state,
70                                   callable_cache,
71                                   sequence_cache->item_cache,
72                                   py_item,
73                                  &item,
74                                  &item_cleanup_data))
75             goto err;
76
77         Py_DECREF (py_item);
78         list_ = g_list_prepend (list_, _pygi_arg_to_hash_pointer (&item, sequence_cache->item_cache->type_info));
79         continue;
80 err:
81         /* FIXME: clean up list
82         if (sequence_cache->item_cache->from_py_cleanup != NULL) {
83             PyGIMarshalCleanupFunc cleanup = sequence_cache->item_cache->from_py_cleanup;
84         }
85         */
86         Py_XDECREF (py_item);
87         g_list_free (list_);
88         _PyGI_ERROR_PREFIX ("Item %i: ", i);
89         return FALSE;
90     }
91
92     arg->v_pointer = g_list_reverse (list_);
93
94     if (arg_cache->transfer == GI_TRANSFER_NOTHING) {
95         /* Free everything in cleanup. */
96         *cleanup_data = arg->v_pointer;
97     } else if (arg_cache->transfer == GI_TRANSFER_CONTAINER) {
98         /* Make a shallow copy so we can free the elements later in cleanup
99          * because it is possible invoke will free the list before our cleanup. */
100         *cleanup_data = g_list_copy (arg->v_pointer);
101     } else { /* GI_TRANSFER_EVERYTHING */
102         /* No cleanup, everything is given to the callee. */
103         *cleanup_data = NULL;
104     }
105     return TRUE;
106 }
107
108
109 static gboolean
110 _pygi_marshal_from_py_gslist (PyGIInvokeState   *state,
111                               PyGICallableCache *callable_cache,
112                               PyGIArgCache      *arg_cache,
113                               PyObject          *py_arg,
114                               GIArgument        *arg,
115                               gpointer          *cleanup_data)
116 {
117     PyGIMarshalFromPyFunc from_py_marshaller;
118     int i;
119     Py_ssize_t length;
120     GSList *list_ = NULL;
121     PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache;
122
123     if (py_arg == Py_None) {
124         arg->v_pointer = NULL;
125         return TRUE;
126     }
127
128     if (!PySequence_Check (py_arg)) {
129         PyErr_Format (PyExc_TypeError, "Must be sequence, not %s",
130                       py_arg->ob_type->tp_name);
131         return FALSE;
132     }
133
134     length = PySequence_Length (py_arg);
135     if (length < 0)
136         return FALSE;
137
138     from_py_marshaller = sequence_cache->item_cache->from_py_marshaller;
139     for (i = 0; i < length; i++) {
140         GIArgument item = {0};
141         gpointer item_cleanup_data = NULL;
142         PyObject *py_item = PySequence_GetItem (py_arg, i);
143         if (py_item == NULL)
144             goto err;
145
146         if (!from_py_marshaller ( state,
147                              callable_cache,
148                              sequence_cache->item_cache,
149                              py_item,
150                             &item,
151                             &item_cleanup_data))
152             goto err;
153
154         Py_DECREF (py_item);
155         list_ = g_slist_prepend (list_, _pygi_arg_to_hash_pointer (&item, sequence_cache->item_cache->type_info));
156         continue;
157 err:
158         /* FIXME: Clean up list
159         if (sequence_cache->item_cache->from_py_cleanup != NULL) {
160             PyGIMarshalCleanupFunc cleanup = sequence_cache->item_cache->from_py_cleanup;
161         }
162         */
163
164         Py_XDECREF (py_item);
165         g_slist_free (list_);
166         _PyGI_ERROR_PREFIX ("Item %i: ", i);
167         return FALSE;
168     }
169
170     arg->v_pointer = g_slist_reverse (list_);
171
172     if (arg_cache->transfer == GI_TRANSFER_NOTHING) {
173         /* Free everything in cleanup. */
174         *cleanup_data = arg->v_pointer;
175     } else if (arg_cache->transfer == GI_TRANSFER_CONTAINER) {
176         /* Make a shallow copy so we can free the elements later in cleanup
177          * because it is possible invoke will free the list before our cleanup. */
178         *cleanup_data = g_slist_copy (arg->v_pointer);
179     } else { /* GI_TRANSFER_EVERYTHING */
180         /* No cleanup, everything is given to the callee. */
181         *cleanup_data = NULL;
182     }
183
184     return TRUE;
185 }
186
187 static void
188 _pygi_marshal_cleanup_from_py_glist  (PyGIInvokeState *state,
189                                       PyGIArgCache    *arg_cache,
190                                       PyObject        *py_arg,
191                                       gpointer         data,
192                                       gboolean         was_processed)
193 {
194     if (was_processed) {
195         GSList *list_;
196         PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache;
197
198         list_ = (GSList *)data;
199
200         /* clean up items first */
201         if (sequence_cache->item_cache->from_py_cleanup != NULL) {
202             PyGIMarshalCleanupFunc cleanup_func =
203                 sequence_cache->item_cache->from_py_cleanup;
204             GSList *node = list_;
205             gsize i = 0;
206             while (node != NULL) {
207                 PyObject *py_item = PySequence_GetItem (py_arg, i);
208                 cleanup_func (state,
209                               sequence_cache->item_cache,
210                               py_item,
211                               node->data,
212                               TRUE);
213                 Py_XDECREF (py_item);
214                 node = node->next;
215                 i++;
216             }
217         }
218
219         if (arg_cache->type_tag == GI_TYPE_TAG_GLIST) {
220             g_list_free ( (GList *)list_);
221         } else if (arg_cache->type_tag == GI_TYPE_TAG_GSLIST) {
222             g_slist_free (list_);
223         } else {
224             g_assert_not_reached();
225         }
226     }
227 }
228
229
230 /*
231  * GList and GSList to Python
232  */
233 static PyObject *
234 _pygi_marshal_to_py_glist (PyGIInvokeState   *state,
235                            PyGICallableCache *callable_cache,
236                            PyGIArgCache      *arg_cache,
237                            GIArgument        *arg)
238 {
239     GList *list_;
240     gsize length;
241     gsize i;
242
243     PyGIMarshalToPyFunc item_to_py_marshaller;
244     PyGIArgCache *item_arg_cache;
245     PyGISequenceCache *seq_cache = (PyGISequenceCache *)arg_cache;
246
247     PyObject *py_obj = NULL;
248
249     list_ = arg->v_pointer;
250     length = g_list_length (list_);
251
252     py_obj = PyList_New (length);
253     if (py_obj == NULL)
254         return NULL;
255
256     item_arg_cache = seq_cache->item_cache;
257     item_to_py_marshaller = item_arg_cache->to_py_marshaller;
258
259     for (i = 0; list_ != NULL; list_ = g_list_next (list_), i++) {
260         GIArgument item_arg;
261         PyObject *py_item;
262
263         item_arg.v_pointer = list_->data;
264         _pygi_hash_pointer_to_arg (&item_arg, item_arg_cache->type_info);
265         py_item = item_to_py_marshaller (state,
266                                          callable_cache,
267                                          item_arg_cache,
268                                          &item_arg);
269
270         if (py_item == NULL) {
271             Py_CLEAR (py_obj);
272             _PyGI_ERROR_PREFIX ("Item %zu: ", i);
273             return NULL;
274         }
275
276         PyList_SET_ITEM (py_obj, i, py_item);
277     }
278
279     return py_obj;
280 }
281
282 static PyObject *
283 _pygi_marshal_to_py_gslist (PyGIInvokeState   *state,
284                             PyGICallableCache *callable_cache,
285                             PyGIArgCache      *arg_cache,
286                             GIArgument        *arg)
287 {
288     GSList *list_;
289     gsize length;
290     gsize i;
291
292     PyGIMarshalToPyFunc item_to_py_marshaller;
293     PyGIArgCache *item_arg_cache;
294     PyGISequenceCache *seq_cache = (PyGISequenceCache *)arg_cache;
295
296     PyObject *py_obj = NULL;
297
298     list_ = arg->v_pointer;
299     length = g_slist_length (list_);
300
301     py_obj = PyList_New (length);
302     if (py_obj == NULL)
303         return NULL;
304
305     item_arg_cache = seq_cache->item_cache;
306     item_to_py_marshaller = item_arg_cache->to_py_marshaller;
307
308     for (i = 0; list_ != NULL; list_ = g_slist_next (list_), i++) {
309         GIArgument item_arg;
310         PyObject *py_item;
311
312         item_arg.v_pointer = list_->data;
313         _pygi_hash_pointer_to_arg (&item_arg, item_arg_cache->type_info);
314         py_item = item_to_py_marshaller (state,
315                                         callable_cache,
316                                         item_arg_cache,
317                                         &item_arg);
318
319         if (py_item == NULL) {
320             Py_CLEAR (py_obj);
321             _PyGI_ERROR_PREFIX ("Item %zu: ", i);
322             return NULL;
323         }
324
325         PyList_SET_ITEM (py_obj, i, py_item);
326     }
327
328     return py_obj;
329 }
330
331 static void
332 _pygi_marshal_cleanup_to_py_glist (PyGIInvokeState *state,
333                                    PyGIArgCache    *arg_cache,
334                                    PyObject        *dummy,
335                                    gpointer         data,
336                                    gboolean         was_processed)
337 {
338     PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache;
339     if (arg_cache->transfer == GI_TRANSFER_EVERYTHING ||
340             arg_cache->transfer == GI_TRANSFER_CONTAINER) {
341         GSList *list_ = (GSList *)data;
342
343         if (sequence_cache->item_cache->to_py_cleanup != NULL) {
344             PyGIMarshalCleanupFunc cleanup_func =
345                 sequence_cache->item_cache->to_py_cleanup;
346             GSList *node = list_;
347
348             while (node != NULL) {
349                 cleanup_func (state,
350                               sequence_cache->item_cache,
351                               NULL,
352                               node->data,
353                               was_processed);
354                 node = node->next;
355             }
356         }
357
358         if (arg_cache->type_tag == GI_TYPE_TAG_GLIST) {
359             g_list_free ( (GList *)list_);
360         } else if (arg_cache->type_tag == GI_TYPE_TAG_GSLIST) {
361             g_slist_free (list_);
362         } else {
363             g_assert_not_reached();
364         }
365     }
366 }
367
368 static void
369 _arg_cache_from_py_glist_setup (PyGIArgCache *arg_cache,
370                                 GITransfer transfer)
371 {
372     arg_cache->from_py_marshaller = _pygi_marshal_from_py_glist;
373     arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_glist;
374 }
375
376 static void
377 _arg_cache_to_py_glist_setup (PyGIArgCache *arg_cache,
378                               GITransfer transfer)
379 {
380     arg_cache->to_py_marshaller = _pygi_marshal_to_py_glist;
381     arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_glist;
382 }
383
384 static void
385 _arg_cache_from_py_gslist_setup (PyGIArgCache *arg_cache,
386                                  GITransfer transfer)
387 {
388     arg_cache->from_py_marshaller = _pygi_marshal_from_py_gslist;
389     arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_glist;
390 }
391
392 static void
393 _arg_cache_to_py_gslist_setup (PyGIArgCache *arg_cache,
394                                  GITransfer transfer)
395 {
396     arg_cache->to_py_marshaller = _pygi_marshal_to_py_gslist;
397     arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_glist;
398 }
399
400
401 /*
402  * GList/GSList Interface
403  */
404
405 static gboolean
406 pygi_arg_glist_setup_from_info (PyGIArgCache      *arg_cache,
407                                 GITypeInfo        *type_info,
408                                 GIArgInfo         *arg_info,
409                                 GITransfer         transfer,
410                                 PyGIDirection      direction,
411                                 PyGICallableCache *callable_cache)
412 {
413     GITypeTag type_tag = g_type_info_get_tag (type_info);
414
415     if (!pygi_arg_sequence_setup ((PyGISequenceCache *)arg_cache,
416                                   type_info,
417                                   arg_info,
418                                   transfer,
419                                   direction,
420                                   callable_cache))
421         return FALSE;
422
423     switch (type_tag) {
424         case GI_TYPE_TAG_GLIST:
425             {
426                 if (direction & PYGI_DIRECTION_FROM_PYTHON)
427                     _arg_cache_from_py_glist_setup (arg_cache, transfer);
428
429                 if (direction & PYGI_DIRECTION_TO_PYTHON)
430                     _arg_cache_to_py_glist_setup (arg_cache, transfer);
431                 break;
432             }
433         case GI_TYPE_TAG_GSLIST:
434             {
435                 if (direction & PYGI_DIRECTION_FROM_PYTHON)
436                     _arg_cache_from_py_gslist_setup (arg_cache, transfer);
437
438                 if (direction & PYGI_DIRECTION_TO_PYTHON)
439                     _arg_cache_to_py_gslist_setup (arg_cache, transfer);
440
441                 break;
442              }
443        default:
444            g_assert_not_reached ();
445     }
446
447     return TRUE;
448 }
449
450 PyGIArgCache *
451 pygi_arg_glist_new_from_info (GITypeInfo        *type_info,
452                               GIArgInfo         *arg_info,
453                               GITransfer         transfer,
454                               PyGIDirection      direction,
455                               PyGICallableCache *callable_cache)
456 {
457     gboolean res = FALSE;
458
459     PyGIArgCache *arg_cache = (PyGIArgCache *) g_slice_new0 (PyGIArgGList);
460     if (arg_cache == NULL)
461         return NULL;
462
463     res = pygi_arg_glist_setup_from_info (arg_cache,
464                                           type_info,
465                                           arg_info,
466                                           transfer,
467                                           direction,
468                                           callable_cache);
469     if (res) {
470         return arg_cache;
471     } else {
472         pygi_arg_cache_free (arg_cache);
473         return NULL;
474     }
475 }