diff options
Diffstat (limited to 'gi/pygi-list.c')
-rw-r--r-- | gi/pygi-list.c | 466 |
1 files changed, 466 insertions, 0 deletions
diff --git a/gi/pygi-list.c b/gi/pygi-list.c new file mode 100644 index 00000000..5244b1af --- /dev/null +++ b/gi/pygi-list.c @@ -0,0 +1,466 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * vim: tabstop=4 shiftwidth=4 expandtab + * + * Copyright (C) 2011 John (J5) Palmieri <johnp@redhat.com> + * Copyright (C) 2014 Simon Feltman <sfeltman@gnome.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "pygi-list.h" +#include "pygi-argument.h" +#include "pygi-private.h" + +typedef PyGISequenceCache PyGIArgGList; + +/* + * GList and GSList from Python + */ +static gboolean +_pygi_marshal_from_py_glist (PyGIInvokeState *state, + PyGICallableCache *callable_cache, + PyGIArgCache *arg_cache, + PyObject *py_arg, + GIArgument *arg, + gpointer *cleanup_data) +{ + PyGIMarshalFromPyFunc from_py_marshaller; + int i; + Py_ssize_t length; + GList *list_ = NULL; + PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache; + + + if (py_arg == Py_None) { + arg->v_pointer = NULL; + return TRUE; + } + + if (!PySequence_Check (py_arg)) { + PyErr_Format (PyExc_TypeError, "Must be sequence, not %s", + py_arg->ob_type->tp_name); + return FALSE; + } + + length = PySequence_Length (py_arg); + if (length < 0) + return FALSE; + + from_py_marshaller = sequence_cache->item_cache->from_py_marshaller; + for (i = 0; i < length; i++) { + GIArgument item = {0}; + gpointer item_cleanup_data = NULL; + PyObject *py_item = PySequence_GetItem (py_arg, i); + if (py_item == NULL) + goto err; + + if (!from_py_marshaller ( state, + callable_cache, + sequence_cache->item_cache, + py_item, + &item, + &item_cleanup_data)) + goto err; + + Py_DECREF (py_item); + list_ = g_list_prepend (list_, _pygi_arg_to_hash_pointer (&item, sequence_cache->item_cache->type_tag)); + continue; +err: + /* FIXME: clean up list + if (sequence_cache->item_cache->from_py_cleanup != NULL) { + PyGIMarshalCleanupFunc cleanup = sequence_cache->item_cache->from_py_cleanup; + } + */ + Py_DECREF (py_item); + g_list_free (list_); + _PyGI_ERROR_PREFIX ("Item %i: ", i); + return FALSE; + } + + arg->v_pointer = g_list_reverse (list_); + + if (arg_cache->transfer == GI_TRANSFER_NOTHING) { + /* Free everything in cleanup. */ + *cleanup_data = arg->v_pointer; + } else if (arg_cache->transfer == GI_TRANSFER_CONTAINER) { + /* Make a shallow copy so we can free the elements later in cleanup + * because it is possible invoke will free the list before our cleanup. */ + *cleanup_data = g_list_copy (arg->v_pointer); + } else { /* GI_TRANSFER_EVERYTHING */ + /* No cleanup, everything is given to the callee. */ + *cleanup_data = NULL; + } + return TRUE; +} + + +static gboolean +_pygi_marshal_from_py_gslist (PyGIInvokeState *state, + PyGICallableCache *callable_cache, + PyGIArgCache *arg_cache, + PyObject *py_arg, + GIArgument *arg, + gpointer *cleanup_data) +{ + PyGIMarshalFromPyFunc from_py_marshaller; + int i; + Py_ssize_t length; + GSList *list_ = NULL; + PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache; + + if (py_arg == Py_None) { + arg->v_pointer = NULL; + return TRUE; + } + + if (!PySequence_Check (py_arg)) { + PyErr_Format (PyExc_TypeError, "Must be sequence, not %s", + py_arg->ob_type->tp_name); + return FALSE; + } + + length = PySequence_Length (py_arg); + if (length < 0) + return FALSE; + + from_py_marshaller = sequence_cache->item_cache->from_py_marshaller; + for (i = 0; i < length; i++) { + GIArgument item = {0}; + gpointer item_cleanup_data = NULL; + PyObject *py_item = PySequence_GetItem (py_arg, i); + if (py_item == NULL) + goto err; + + if (!from_py_marshaller ( state, + callable_cache, + sequence_cache->item_cache, + py_item, + &item, + &item_cleanup_data)) + goto err; + + Py_DECREF (py_item); + list_ = g_slist_prepend (list_, _pygi_arg_to_hash_pointer (&item, sequence_cache->item_cache->type_tag)); + continue; +err: + /* FIXME: Clean up list + if (sequence_cache->item_cache->from_py_cleanup != NULL) { + PyGIMarshalCleanupFunc cleanup = sequence_cache->item_cache->from_py_cleanup; + } + */ + + Py_DECREF (py_item); + g_slist_free (list_); + _PyGI_ERROR_PREFIX ("Item %i: ", i); + return FALSE; + } + + arg->v_pointer = g_slist_reverse (list_); + + if (arg_cache->transfer == GI_TRANSFER_NOTHING) { + /* Free everything in cleanup. */ + *cleanup_data = arg->v_pointer; + } else if (arg_cache->transfer == GI_TRANSFER_CONTAINER) { + /* Make a shallow copy so we can free the elements later in cleanup + * because it is possible invoke will free the list before our cleanup. */ + *cleanup_data = g_slist_copy (arg->v_pointer); + } else { /* GI_TRANSFER_EVERYTHING */ + /* No cleanup, everything is given to the callee. */ + *cleanup_data = NULL; + } + + return TRUE; +} + +static void +_pygi_marshal_cleanup_from_py_glist (PyGIInvokeState *state, + PyGIArgCache *arg_cache, + PyObject *py_arg, + gpointer data, + gboolean was_processed) +{ + if (was_processed) { + GSList *list_; + PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache; + + list_ = (GSList *)data; + + /* clean up items first */ + if (sequence_cache->item_cache->from_py_cleanup != NULL) { + PyGIMarshalCleanupFunc cleanup_func = + sequence_cache->item_cache->from_py_cleanup; + GSList *node = list_; + gsize i = 0; + while (node != NULL) { + PyObject *py_item = PySequence_GetItem (py_arg, i); + cleanup_func (state, + sequence_cache->item_cache, + py_item, + node->data, + TRUE); + Py_XDECREF (py_item); + node = node->next; + i++; + } + } + + if (arg_cache->type_tag == GI_TYPE_TAG_GLIST) { + g_list_free ( (GList *)list_); + } else if (arg_cache->type_tag == GI_TYPE_TAG_GSLIST) { + g_slist_free (list_); + } else { + g_assert_not_reached(); + } + } +} + + +/* + * GList and GSList to Python + */ +static PyObject * +_pygi_marshal_to_py_glist (PyGIInvokeState *state, + PyGICallableCache *callable_cache, + PyGIArgCache *arg_cache, + GIArgument *arg) +{ + GList *list_; + gsize length; + gsize i; + + PyGIMarshalToPyFunc item_to_py_marshaller; + PyGIArgCache *item_arg_cache; + PyGISequenceCache *seq_cache = (PyGISequenceCache *)arg_cache; + + PyObject *py_obj = NULL; + + list_ = arg->v_pointer; + length = g_list_length (list_); + + py_obj = PyList_New (length); + if (py_obj == NULL) + return NULL; + + item_arg_cache = seq_cache->item_cache; + item_to_py_marshaller = item_arg_cache->to_py_marshaller; + + for (i = 0; list_ != NULL; list_ = g_list_next (list_), i++) { + GIArgument item_arg; + PyObject *py_item; + + item_arg.v_pointer = list_->data; + _pygi_hash_pointer_to_arg (&item_arg, item_arg_cache->type_tag); + py_item = item_to_py_marshaller (state, + callable_cache, + item_arg_cache, + &item_arg); + + if (py_item == NULL) { + Py_CLEAR (py_obj); + _PyGI_ERROR_PREFIX ("Item %zu: ", i); + return NULL; + } + + PyList_SET_ITEM (py_obj, i, py_item); + } + + return py_obj; +} + +static PyObject * +_pygi_marshal_to_py_gslist (PyGIInvokeState *state, + PyGICallableCache *callable_cache, + PyGIArgCache *arg_cache, + GIArgument *arg) +{ + GSList *list_; + gsize length; + gsize i; + + PyGIMarshalToPyFunc item_to_py_marshaller; + PyGIArgCache *item_arg_cache; + PyGISequenceCache *seq_cache = (PyGISequenceCache *)arg_cache; + + PyObject *py_obj = NULL; + + list_ = arg->v_pointer; + length = g_slist_length (list_); + + py_obj = PyList_New (length); + if (py_obj == NULL) + return NULL; + + item_arg_cache = seq_cache->item_cache; + item_to_py_marshaller = item_arg_cache->to_py_marshaller; + + for (i = 0; list_ != NULL; list_ = g_slist_next (list_), i++) { + GIArgument item_arg; + PyObject *py_item; + + item_arg.v_pointer = list_->data; + _pygi_hash_pointer_to_arg (&item_arg, item_arg_cache->type_tag); + py_item = item_to_py_marshaller (state, + callable_cache, + item_arg_cache, + &item_arg); + + if (py_item == NULL) { + Py_CLEAR (py_obj); + _PyGI_ERROR_PREFIX ("Item %zu: ", i); + return NULL; + } + + PyList_SET_ITEM (py_obj, i, py_item); + } + + return py_obj; +} + +static void +_pygi_marshal_cleanup_to_py_glist (PyGIInvokeState *state, + PyGIArgCache *arg_cache, + PyObject *dummy, + gpointer data, + gboolean was_processed) +{ + PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache; + if (arg_cache->transfer == GI_TRANSFER_EVERYTHING || + arg_cache->transfer == GI_TRANSFER_CONTAINER) { + GSList *list_ = (GSList *)data; + + if (sequence_cache->item_cache->to_py_cleanup != NULL) { + PyGIMarshalCleanupFunc cleanup_func = + sequence_cache->item_cache->to_py_cleanup; + GSList *node = list_; + + while (node != NULL) { + cleanup_func (state, + sequence_cache->item_cache, + NULL, + node->data, + was_processed); + node = node->next; + } + } + + if (arg_cache->type_tag == GI_TYPE_TAG_GLIST) { + g_list_free ( (GList *)list_); + } else if (arg_cache->type_tag == GI_TYPE_TAG_GSLIST) { + g_slist_free (list_); + } else { + g_assert_not_reached(); + } + } +} + +static void +_arg_cache_from_py_glist_setup (PyGIArgCache *arg_cache, + GITransfer transfer) +{ + arg_cache->from_py_marshaller = _pygi_marshal_from_py_glist; + arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_glist; +} + +static void +_arg_cache_to_py_glist_setup (PyGIArgCache *arg_cache, + GITransfer transfer) +{ + arg_cache->to_py_marshaller = _pygi_marshal_to_py_glist; + arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_glist; +} + +static void +_arg_cache_from_py_gslist_setup (PyGIArgCache *arg_cache, + GITransfer transfer) +{ + arg_cache->from_py_marshaller = _pygi_marshal_from_py_gslist; + arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_glist; +} + +static void +_arg_cache_to_py_gslist_setup (PyGIArgCache *arg_cache, + GITransfer transfer) +{ + arg_cache->to_py_marshaller = _pygi_marshal_to_py_gslist; + arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_glist; +} + + +/* + * GList/GSList Interface + */ + +static gboolean +pygi_arg_glist_setup_from_info (PyGIArgCache *arg_cache, + GITypeInfo *type_info, + GIArgInfo *arg_info, + GITransfer transfer, + PyGIDirection direction) +{ + GITypeTag type_tag = g_type_info_get_tag (type_info); + + if (!pygi_arg_sequence_setup ((PyGISequenceCache *)arg_cache, type_info, arg_info, transfer, direction)) + return FALSE; + + switch (type_tag) { + case GI_TYPE_TAG_GLIST: + { + if (direction & PYGI_DIRECTION_FROM_PYTHON) + _arg_cache_from_py_glist_setup (arg_cache, transfer); + + if (direction & PYGI_DIRECTION_TO_PYTHON) + _arg_cache_to_py_glist_setup (arg_cache, transfer); + break; + } + case GI_TYPE_TAG_GSLIST: + { + if (direction & PYGI_DIRECTION_FROM_PYTHON) + _arg_cache_from_py_gslist_setup (arg_cache, transfer); + + if (direction & PYGI_DIRECTION_TO_PYTHON) + _arg_cache_to_py_gslist_setup (arg_cache, transfer); + + break; + } + default: + g_assert_not_reached (); + } + + return TRUE; +} + +PyGIArgCache * +pygi_arg_glist_new_from_info (GITypeInfo *type_info, + GIArgInfo *arg_info, + GITransfer transfer, + PyGIDirection direction) +{ + gboolean res = FALSE; + + PyGIArgCache *arg_cache = (PyGIArgCache *) g_slice_new0 (PyGIArgGList); + if (arg_cache == NULL) + return NULL; + + res = pygi_arg_glist_setup_from_info (arg_cache, + type_info, + arg_info, + transfer, + direction); + if (res) { + return arg_cache; + } else { + _pygi_arg_cache_free (arg_cache); + return NULL; + } +} |